diff options
Diffstat (limited to 'src')
214 files changed, 12389 insertions, 3271 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 584bcd21..caae2933 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -158,9 +158,11 @@ nobase_include_HEADERS = \ google/protobuf/compiler/csharp/csharp_generator.h \ google/protobuf/compiler/csharp/csharp_names.h \ google/protobuf/util/type_resolver.h \ - google/protobuf/util/type_resolver_util.h \ - google/protobuf/util/json_util.h \ google/protobuf/util/field_comparator.h \ + google/protobuf/util/field_mask_util.h \ + google/protobuf/util/json_util.h \ + google/protobuf/util/time_util.h \ + google/protobuf/util/type_resolver_util.h \ google/protobuf/util/message_differencer.h lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la @@ -174,6 +176,8 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/stubs/bytestream.h \ google/protobuf/stubs/common.cc \ google/protobuf/stubs/hash.h \ + google/protobuf/stubs/int128.cc \ + google/protobuf/stubs/int128.h \ google/protobuf/stubs/map_util.h \ google/protobuf/stubs/mathutil.h \ google/protobuf/stubs/once.cc \ @@ -187,6 +191,7 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/stubs/stringpiece.h \ google/protobuf/stubs/stringprintf.cc \ google/protobuf/stubs/stringprintf.h \ + google/protobuf/stubs/structurally_valid.cc \ google/protobuf/stubs/strutil.cc \ google/protobuf/stubs/strutil.h \ google/protobuf/stubs/time.cc \ @@ -209,8 +214,8 @@ libprotobuf_la_SOURCES = \ $(libprotobuf_lite_la_SOURCES) \ google/protobuf/any.pb.cc \ google/protobuf/api.pb.cc \ - google/protobuf/stubs/mathlimits.h \ google/protobuf/stubs/mathlimits.cc \ + google/protobuf/stubs/mathlimits.h \ google/protobuf/any.cc \ google/protobuf/descriptor.cc \ google/protobuf/descriptor_database.cc \ @@ -228,7 +233,6 @@ libprotobuf_la_SOURCES = \ google/protobuf/service.cc \ google/protobuf/source_context.pb.cc \ google/protobuf/struct.pb.cc \ - google/protobuf/stubs/structurally_valid.cc \ google/protobuf/stubs/substitute.cc \ google/protobuf/stubs/substitute.h \ google/protobuf/text_format.cc \ @@ -245,6 +249,7 @@ libprotobuf_la_SOURCES = \ google/protobuf/compiler/importer.cc \ google/protobuf/compiler/parser.cc \ google/protobuf/util/field_comparator.cc \ + google/protobuf/util/field_mask_util.cc \ google/protobuf/util/internal/constants.h \ google/protobuf/util/internal/datapiece.cc \ google/protobuf/util/internal/datapiece.h \ @@ -281,8 +286,10 @@ libprotobuf_la_SOURCES = \ google/protobuf/util/internal/utility.cc \ google/protobuf/util/internal/utility.h \ google/protobuf/util/json_util.cc \ - google/protobuf/util/type_resolver_util.cc \ - google/protobuf/util/message_differencer.cc + google/protobuf/util/message_differencer.cc \ + google/protobuf/util/time_util.cc \ + google/protobuf/util/type_resolver_util.cc + nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES) libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la @@ -325,11 +332,13 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/java/java_context.cc \ google/protobuf/compiler/java/java_context.h \ google/protobuf/compiler/java/java_enum.cc \ + google/protobuf/compiler/java/java_enum_lite.cc \ google/protobuf/compiler/java/java_enum_field.cc \ google/protobuf/compiler/java/java_enum_field.h \ google/protobuf/compiler/java/java_enum_field_lite.cc \ google/protobuf/compiler/java/java_enum_field_lite.h \ google/protobuf/compiler/java/java_enum.h \ + google/protobuf/compiler/java/java_enum_lite.h \ google/protobuf/compiler/java/java_extension.cc \ google/protobuf/compiler/java/java_extension.h \ google/protobuf/compiler/java/java_field.cc \ @@ -480,6 +489,8 @@ protoc_inputs = \ google/protobuf/unittest_lite_imports_nonlite.proto \ google/protobuf/unittest_lite.proto \ google/protobuf/unittest_mset.proto \ + google/protobuf/unittest_mset_wire_format.proto \ + google/protobuf/unittest_no_arena_lite.proto \ google/protobuf/unittest_no_arena_import.proto \ google/protobuf/unittest_no_arena.proto \ google/protobuf/unittest_no_field_presence.proto \ @@ -496,6 +507,7 @@ protoc_inputs = \ google/protobuf/util/internal/testdata/default_value_test.proto \ google/protobuf/util/internal/testdata/field_mask.proto \ google/protobuf/util/internal/testdata/maps.proto \ + google/protobuf/util/internal/testdata/oneofs.proto \ google/protobuf/util/internal/testdata/struct.proto \ google/protobuf/util/internal/testdata/timestamp_duration.proto \ google/protobuf/util/json_format_proto3.proto \ @@ -530,6 +542,8 @@ protoc_lite_outputs = \ google/protobuf/map_lite_unittest.pb.h \ google/protobuf/unittest_lite.pb.cc \ google/protobuf/unittest_lite.pb.h \ + google/protobuf/unittest_no_arena_lite.pb.cc \ + google/protobuf/unittest_no_arena_lite.pb.h \ google/protobuf/unittest_import_lite.pb.cc \ google/protobuf/unittest_import_lite.pb.h \ google/protobuf/unittest_import_public_lite.pb.cc \ @@ -567,6 +581,8 @@ protoc_outputs = \ google/protobuf/unittest_lite_imports_nonlite.pb.h \ google/protobuf/unittest_mset.pb.cc \ google/protobuf/unittest_mset.pb.h \ + google/protobuf/unittest_mset_wire_format.pb.cc \ + google/protobuf/unittest_mset_wire_format.pb.h \ google/protobuf/unittest_no_arena_import.pb.cc \ google/protobuf/unittest_no_arena_import.pb.h \ google/protobuf/unittest_no_arena.pb.cc \ @@ -599,6 +615,8 @@ protoc_outputs = \ google/protobuf/util/internal/testdata/field_mask.pb.h \ google/protobuf/util/internal/testdata/maps.pb.cc \ google/protobuf/util/internal/testdata/maps.pb.h \ + google/protobuf/util/internal/testdata/oneofs.pb.cc \ + google/protobuf/util/internal/testdata/oneofs.pb.h \ google/protobuf/util/internal/testdata/struct.pb.cc \ google/protobuf/util/internal/testdata/struct.pb.h \ google/protobuf/util/internal/testdata/timestamp_duration.pb.cc \ @@ -641,7 +659,8 @@ COMMON_TEST_SOURCES = \ google/protobuf/testing/file.h check_PROGRAMS = protoc protobuf-test protobuf-lazy-descriptor-test \ - protobuf-lite-test test_plugin $(GZCHECKPROGRAMS) + protobuf-lite-test test_plugin protobuf-lite-arena-test \ + $(GZCHECKPROGRAMS) protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ ../gmock/gtest/lib/libgtest.la \ ../gmock/lib/libgmock.la \ @@ -655,6 +674,7 @@ protobuf_test_CXXFLAGS = $(NO_OPT_CXXFLAGS) protobuf_test_SOURCES = \ google/protobuf/stubs/bytestream_unittest.cc \ google/protobuf/stubs/common_unittest.cc \ + google/protobuf/stubs/int128_unittest.cc \ google/protobuf/stubs/once_unittest.cc \ google/protobuf/stubs/statusor_test.cc \ google/protobuf/stubs/status_test.cc \ @@ -707,6 +727,7 @@ protobuf_test_SOURCES = \ google/protobuf/compiler/ruby/ruby_generator_unittest.cc \ google/protobuf/compiler/csharp/csharp_generator_unittest.cc \ google/protobuf/util/field_comparator_test.cc \ + google/protobuf/util/field_mask_util_test.cc \ google/protobuf/util/internal/default_value_objectwriter_test.cc \ google/protobuf/util/internal/json_objectwriter_test.cc \ google/protobuf/util/internal/json_stream_parser_test.cc \ @@ -714,6 +735,7 @@ protobuf_test_SOURCES = \ google/protobuf/util/internal/protostream_objectwriter_test.cc \ google/protobuf/util/internal/type_info_test_helper.cc \ google/protobuf/util/json_util_test.cc \ + google/protobuf/util/time_util_test.cc \ google/protobuf/util/type_resolver_util_test.cc \ $(COMMON_TEST_SOURCES) @@ -735,21 +757,40 @@ protobuf_lazy_descriptor_test_SOURCES = \ $(COMMON_TEST_SOURCES) nodist_protobuf_lazy_descriptor_test_SOURCES = $(protoc_outputs) -# Build lite_unittest separately, since it doesn't use gtest. -protobuf_lite_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la -protobuf_lite_test_CXXFLAGS = $(NO_OPT_CXXFLAGS) -protobuf_lite_test_SOURCES = \ +COMMON_LITE_TEST_SOURCES = \ google/protobuf/arena_test_util.cc \ google/protobuf/arena_test_util.h \ - 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 + +# Build lite_unittest separately, since it doesn't use gtest. It can't +# depend on gtest because our internal version of gtest depend on proto +# full runtime and we want to make sure this test builds without full +# runtime. +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 \ + $(COMMON_LITE_TEST_SOURCES) nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs) +# lite_arena_unittest depends on gtest because teboring@ found that without +# gtest when building the test internally our memory sanitizer doesn't detect +# memory leaks (don't know why). +protobuf_lite_arena_test_LDADD = $(PTHREAD_LIBS) libprotobuf-lite.la \ + ../gmock/gtest/lib/libgtest.la \ + ../gmock/lib/libgmock.la \ + ../gmock/lib/libgmock_main.la +protobuf_lite_arena_test_CPPFLAGS = -I$(srcdir)/../gmock/include \ + -I$(srcdir)/../gmock/gtest/include +protobuf_lite_arena_test_CXXFLAGS = $(NO_OPT_CXXFLAGS) +protobuf_lite_arena_test_SOURCES = \ + google/protobuf/lite_arena_unittest.cc \ + $(COMMON_LITE_TEST_SOURCES) +nodist_protobuf_lite_arena_test_SOURCES = $(protoc_lite_outputs) + # Test plugin binary. test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ ../gmock/gtest/lib/libgtest.la @@ -769,4 +810,5 @@ zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc endif TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test \ - google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS) + google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS) \ + protobuf-lite-arena-test diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index c66fdfad..c6ed37ae 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -50,7 +50,7 @@ AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) void AnyMetadata::PackFrom(const Message& message) { type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(), - GetTypeUrl(message.GetDescriptor())); + GetTypeUrl(message.GetDescriptor())); message.SerializeToString(value_->MutableNoArena( &::google::protobuf::internal::GetEmptyStringAlreadyInited())); } @@ -76,7 +76,7 @@ bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { type_url.size() - prefix_len); return true; } - return true; + return false; } diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index f681eceb..7eeb6b70 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -34,9 +34,9 @@ #include <string> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/arenastring.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/message.h> +#include <google/protobuf/arenastring.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index c2e58131..cbb5d233 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -208,10 +208,10 @@ bool Any::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_type_url())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Any.type_url"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Any.type_url")); } else { goto handle_unusual; } @@ -258,9 +258,9 @@ void Any::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Any) // optional string type_url = 1; if (this->type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Any.type_url"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->type_url(), output); @@ -280,9 +280,9 @@ void Any::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any) // optional string type_url = 1; if (this->type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Any.type_url"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index d3ad3acc..423699be 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -42,10 +42,8 @@ option objc_class_prefix = "GPB"; // `Any` contains an arbitrary serialized message along with a URL // that describes the type of the serialized message. // -// The proto runtimes and/or compiler will eventually -// provide utilities to pack/unpack Any values (projected Q1/15). -// -// # JSON +// 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: @@ -93,10 +91,6 @@ message Any { // Schemas other than `http`, `https` (or the empty schema) might be // used with implementation specific semantics. // - // Types originating from the `google.*` package - // namespace should use `type.googleapis.com/full.type.name` (without - // schema and path). A type service will eventually become available which - // serves those URLs (projected Q2/15). string type_url = 1; // Must be valid serialized data of the above specified type. diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index 0feddb31..0a2c4ec0 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -27,6 +27,9 @@ const ::google::protobuf::internal::GeneratedMessageReflection* const ::google::protobuf::Descriptor* Method_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* Method_reflection_ = NULL; +const ::google::protobuf::Descriptor* Mixin_descriptor_ = NULL; +const ::google::protobuf::internal::GeneratedMessageReflection* + Mixin_reflection_ = NULL; } // namespace @@ -38,12 +41,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() { "google/protobuf/api.proto"); GOOGLE_CHECK(file != NULL); Api_descriptor_ = file->message_type(0); - static const int Api_offsets_[5] = { + static const int Api_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, methods_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, version_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, source_context_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, mixins_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, syntax_), }; Api_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -57,13 +62,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Api, _is_default_instance_)); Method_descriptor_ = file->message_type(1); - static const int Method_offsets_[6] = { + static const int Method_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, request_type_url_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, request_streaming_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, response_type_url_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, response_streaming_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, options_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, syntax_), }; Method_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -76,6 +82,22 @@ void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto() { sizeof(Method), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Method, _is_default_instance_)); + Mixin_descriptor_ = file->message_type(2); + static const int Mixin_offsets_[2] = { + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, name_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, root_), + }; + Mixin_reflection_ = + ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( + Mixin_descriptor_, + Mixin::default_instance_, + Mixin_offsets_, + -1, + -1, + -1, + sizeof(Mixin), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, _internal_metadata_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Mixin, _is_default_instance_)); } namespace { @@ -92,6 +114,8 @@ void protobuf_RegisterTypes(const ::std::string&) { Api_descriptor_, &Api::default_instance()); ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( Method_descriptor_, &Method::default_instance()); + ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( + Mixin_descriptor_, &Mixin::default_instance()); } } // namespace @@ -101,6 +125,8 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto() { delete Api_reflection_; delete Method::default_instance_; delete Method_reflection_; + delete Mixin::default_instance_; + delete Mixin_reflection_; } void protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto() { @@ -114,24 +140,30 @@ void protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\031google/protobuf/api.proto\022\017google.prot" "obuf\032$google/protobuf/source_context.pro" - "to\032\032google/protobuf/type.proto\"\260\001\n\003Api\022\014" + "to\032\032google/protobuf/type.proto\"\201\002\n\003Api\022\014" "\n\004name\030\001 \001(\t\022(\n\007methods\030\002 \003(\0132\027.google.p" "rotobuf.Method\022(\n\007options\030\003 \003(\0132\027.google" ".protobuf.Option\022\017\n\007version\030\004 \001(\t\0226\n\016sou" "rce_context\030\005 \001(\0132\036.google.protobuf.Sour" - "ceContext\"\254\001\n\006Method\022\014\n\004name\030\001 \001(\t\022\030\n\020re" - "quest_type_url\030\002 \001(\t\022\031\n\021request_streamin" - "g\030\003 \001(\010\022\031\n\021response_type_url\030\004 \001(\t\022\032\n\022re" - "sponse_streaming\030\005 \001(\010\022(\n\007options\030\006 \003(\0132" - "\027.google.protobuf.OptionBH\n\023com.google.p" - "rotobufB\010ApiProtoP\001\242\002\003GPB\252\002\036Google.Proto" - "buf.WellKnownTypesb\006proto3", 546); + "ceContext\022&\n\006mixins\030\006 \003(\0132\026.google.proto" + "buf.Mixin\022\'\n\006syntax\030\007 \001(\0162\027.google.proto" + "buf.Syntax\"\325\001\n\006Method\022\014\n\004name\030\001 \001(\t\022\030\n\020r" + "equest_type_url\030\002 \001(\t\022\031\n\021request_streami" + "ng\030\003 \001(\010\022\031\n\021response_type_url\030\004 \001(\t\022\032\n\022r" + "esponse_streaming\030\005 \001(\010\022(\n\007options\030\006 \003(\013" + "2\027.google.protobuf.Option\022\'\n\006syntax\030\007 \001(" + "\0162\027.google.protobuf.Syntax\"#\n\005Mixin\022\014\n\004n" + "ame\030\001 \001(\t\022\014\n\004root\030\002 \001(\tBK\n\023com.google.pr" + "otobufB\010ApiProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Pro" + "tobuf.WellKnownTypesb\006proto3", 708); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/api.proto", &protobuf_RegisterTypes); Api::default_instance_ = new Api(); Method::default_instance_ = new Method(); + Mixin::default_instance_ = new Mixin(); Api::default_instance_->InitAsDefaultInstance(); Method::default_instance_->InitAsDefaultInstance(); + Mixin::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto); } @@ -160,6 +192,8 @@ const int Api::kMethodsFieldNumber; const int Api::kOptionsFieldNumber; const int Api::kVersionFieldNumber; const int Api::kSourceContextFieldNumber; +const int Api::kMixinsFieldNumber; +const int Api::kSyntaxFieldNumber; #endif // !_MSC_VER Api::Api() @@ -188,6 +222,7 @@ void Api::SharedCtor() { name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); version_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Api::~Api() { @@ -233,8 +268,10 @@ void Api::Clear() { version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; + syntax_ = 0; methods_.Clear(); options_.Clear(); + mixins_.Clear(); } bool Api::MergePartialFromCodedStream( @@ -252,10 +289,10 @@ bool Api::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Api.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Api.name")); } else { goto handle_unusual; } @@ -302,10 +339,10 @@ bool Api::MergePartialFromCodedStream( parse_version: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_version())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->version().data(), this->version().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Api.version"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Api.version")); } else { goto handle_unusual; } @@ -322,6 +359,39 @@ bool Api::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(50)) goto parse_mixins; + break; + } + + // repeated .google.protobuf.Mixin mixins = 6; + case 6: { + if (tag == 50) { + parse_mixins: + DO_(input->IncrementRecursionDepth()); + parse_loop_mixins: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( + input, add_mixins())); + } else { + goto handle_unusual; + } + if (input->ExpectTag(50)) goto parse_loop_mixins; + input->UnsafeDecrementRecursionDepth(); + if (input->ExpectTag(56)) goto parse_syntax; + break; + } + + // optional .google.protobuf.Syntax syntax = 7; + case 7: { + if (tag == 56) { + parse_syntax: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + set_syntax(static_cast< ::google::protobuf::Syntax >(value)); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -352,9 +422,9 @@ void Api::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Api) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Api.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -374,9 +444,9 @@ void Api::SerializeWithCachedSizes( // optional string version = 4; if (this->version().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->version().data(), this->version().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Api.version"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 4, this->version(), output); @@ -388,6 +458,18 @@ void Api::SerializeWithCachedSizes( 5, *this->source_context_, output); } + // repeated .google.protobuf.Mixin mixins = 6; + for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) { + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( + 6, this->mixins(i), output); + } + + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 7, this->syntax(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Api) } @@ -396,9 +478,9 @@ void Api::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Api.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -421,9 +503,9 @@ void Api::SerializeWithCachedSizes( // optional string version = 4; if (this->version().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->version().data(), this->version().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Api.version"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -437,6 +519,19 @@ void Api::SerializeWithCachedSizes( 5, *this->source_context_, target); } + // repeated .google.protobuf.Mixin mixins = 6; + for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) { + target = ::google::protobuf::internal::WireFormatLite:: + WriteMessageNoVirtualToArray( + 6, this->mixins(i), target); + } + + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 7, this->syntax(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Api) return target; } @@ -465,6 +560,12 @@ int Api::ByteSize() const { *this->source_context_); } + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax()); + } + // repeated .google.protobuf.Method methods = 2; total_size += 1 * this->methods_size(); for (int i = 0; i < this->methods_size(); i++) { @@ -481,6 +582,14 @@ int Api::ByteSize() const { this->options(i)); } + // repeated .google.protobuf.Mixin mixins = 6; + total_size += 1 * this->mixins_size(); + for (int i = 0; i < this->mixins_size(); i++) { + total_size += + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->mixins(i)); + } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; GOOGLE_SAFE_CONCURRENT_WRITES_END(); @@ -503,6 +612,7 @@ void Api::MergeFrom(const Api& from) { if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); methods_.MergeFrom(from.methods_); options_.MergeFrom(from.options_); + mixins_.MergeFrom(from.mixins_); if (from.name().size() > 0) { name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); @@ -514,6 +624,9 @@ void Api::MergeFrom(const Api& from) { if (from.has_source_context()) { mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context()); } + if (from.syntax() != 0) { + set_syntax(from.syntax()); + } } void Api::CopyFrom(const ::google::protobuf::Message& from) { @@ -543,6 +656,8 @@ void Api::InternalSwap(Api* other) { options_.UnsafeArenaSwap(&other->options_); version_.Swap(&other->version_); std::swap(source_context_, other->source_context_); + mixins_.UnsafeArenaSwap(&other->mixins_); + std::swap(syntax_, other->syntax_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -608,28 +723,28 @@ int Api::methods_size() const { void Api::clear_methods() { methods_.Clear(); } - const ::google::protobuf::Method& Api::methods(int index) const { +const ::google::protobuf::Method& Api::methods(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Api.methods) return methods_.Get(index); } - ::google::protobuf::Method* Api::mutable_methods(int index) { +::google::protobuf::Method* Api::mutable_methods(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Api.methods) return methods_.Mutable(index); } - ::google::protobuf::Method* Api::add_methods() { +::google::protobuf::Method* Api::add_methods() { // @@protoc_insertion_point(field_add:google.protobuf.Api.methods) return methods_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& -Api::methods() const { - // @@protoc_insertion_point(field_list:google.protobuf.Api.methods) - return methods_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >* Api::mutable_methods() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods) return &methods_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& +Api::methods() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.methods) + return methods_; +} // repeated .google.protobuf.Option options = 3; int Api::options_size() const { @@ -638,28 +753,28 @@ int Api::options_size() const { void Api::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& Api::options(int index) const { +const ::google::protobuf::Option& Api::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Api.options) return options_.Get(index); } - ::google::protobuf::Option* Api::mutable_options(int index) { +::google::protobuf::Option* Api::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Api.options) return options_.Mutable(index); } - ::google::protobuf::Option* Api::add_options() { +::google::protobuf::Option* Api::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Api.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Api::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Api.options) - return options_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Api::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options) return &options_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Api::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.options) + return options_; +} // optional string version = 4; void Api::clear_version() { @@ -712,11 +827,11 @@ void Api::clear_source_context() { if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } - const ::google::protobuf::SourceContext& Api::source_context() const { +const ::google::protobuf::SourceContext& Api::source_context() const { // @@protoc_insertion_point(field_get:google.protobuf.Api.source_context) return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_; } - ::google::protobuf::SourceContext* Api::mutable_source_context() { +::google::protobuf::SourceContext* Api::mutable_source_context() { if (source_context_ == NULL) { source_context_ = new ::google::protobuf::SourceContext; @@ -724,13 +839,13 @@ void Api::clear_source_context() { // @@protoc_insertion_point(field_mutable:google.protobuf.Api.source_context) return source_context_; } - ::google::protobuf::SourceContext* Api::release_source_context() { +::google::protobuf::SourceContext* Api::release_source_context() { ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; return temp; } - void Api::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { +void Api::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { delete source_context_; source_context_ = source_context; if (source_context) { @@ -741,6 +856,50 @@ void Api::clear_source_context() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context) } +// repeated .google.protobuf.Mixin mixins = 6; +int Api::mixins_size() const { + return mixins_.size(); +} +void Api::clear_mixins() { + mixins_.Clear(); +} +const ::google::protobuf::Mixin& Api::mixins(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins) + return mixins_.Get(index); +} +::google::protobuf::Mixin* Api::mutable_mixins(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins) + return mixins_.Mutable(index); +} +::google::protobuf::Mixin* Api::add_mixins() { + // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins) + return mixins_.Add(); +} +::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* +Api::mutable_mixins() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins) + return &mixins_; +} +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& +Api::mixins() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins) + return mixins_; +} + +// optional .google.protobuf.Syntax syntax = 7; +void Api::clear_syntax() { + syntax_ = 0; +} + ::google::protobuf::Syntax Api::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} + void Api::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax) +} + #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== @@ -752,6 +911,7 @@ const int Method::kRequestStreamingFieldNumber; const int Method::kResponseTypeUrlFieldNumber; const int Method::kResponseStreamingFieldNumber; const int Method::kOptionsFieldNumber; +const int Method::kSyntaxFieldNumber; #endif // !_MSC_VER Method::Method() @@ -781,6 +941,7 @@ void Method::SharedCtor() { request_streaming_ = false; response_type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); response_streaming_ = false; + syntax_ = 0; } Method::~Method() { @@ -830,7 +991,7 @@ void Method::Clear() { ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ } while (0) - ZR_(request_streaming_, response_streaming_); + ZR_(request_streaming_, syntax_); name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); request_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); response_type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -856,10 +1017,10 @@ bool Method::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Method.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Method.name")); } else { goto handle_unusual; } @@ -873,10 +1034,10 @@ bool Method::MergePartialFromCodedStream( parse_request_type_url: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_request_type_url())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->request_type_url().data(), this->request_type_url().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Method.request_type_url"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Method.request_type_url")); } else { goto handle_unusual; } @@ -905,10 +1066,10 @@ bool Method::MergePartialFromCodedStream( parse_response_type_url: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_response_type_url())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->response_type_url().data(), this->response_type_url().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Method.response_type_url"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Method.response_type_url")); } else { goto handle_unusual; } @@ -944,6 +1105,22 @@ bool Method::MergePartialFromCodedStream( } if (input->ExpectTag(50)) goto parse_loop_options; input->UnsafeDecrementRecursionDepth(); + if (input->ExpectTag(56)) goto parse_syntax; + break; + } + + // optional .google.protobuf.Syntax syntax = 7; + case 7: { + if (tag == 56) { + parse_syntax: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + set_syntax(static_cast< ::google::protobuf::Syntax >(value)); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -974,9 +1151,9 @@ void Method::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Method) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -984,9 +1161,9 @@ void Method::SerializeWithCachedSizes( // optional string request_type_url = 2; if (this->request_type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->request_type_url().data(), this->request_type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.request_type_url"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 2, this->request_type_url(), output); @@ -999,9 +1176,9 @@ void Method::SerializeWithCachedSizes( // optional string response_type_url = 4; if (this->response_type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->response_type_url().data(), this->response_type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.response_type_url"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 4, this->response_type_url(), output); @@ -1018,6 +1195,12 @@ void Method::SerializeWithCachedSizes( 6, this->options(i), output); } + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 7, this->syntax(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Method) } @@ -1026,9 +1209,9 @@ void Method::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1037,9 +1220,9 @@ void Method::SerializeWithCachedSizes( // optional string request_type_url = 2; if (this->request_type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->request_type_url().data(), this->request_type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.request_type_url"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1053,9 +1236,9 @@ void Method::SerializeWithCachedSizes( // optional string response_type_url = 4; if (this->response_type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->response_type_url().data(), this->response_type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Method.response_type_url"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1074,6 +1257,12 @@ void Method::SerializeWithCachedSizes( 6, this->options(i), target); } + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 7, this->syntax(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Method) return target; } @@ -1112,6 +1301,12 @@ int Method::ByteSize() const { total_size += 1 + 1; } + // optional .google.protobuf.Syntax syntax = 7; + if (this->syntax() != 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax()); + } + // repeated .google.protobuf.Option options = 6; total_size += 1 * this->options_size(); for (int i = 0; i < this->options_size(); i++) { @@ -1159,6 +1354,9 @@ void Method::MergeFrom(const Method& from) { if (from.response_streaming() != 0) { set_response_streaming(from.response_streaming()); } + if (from.syntax() != 0) { + set_syntax(from.syntax()); + } } void Method::CopyFrom(const ::google::protobuf::Message& from) { @@ -1189,6 +1387,7 @@ void Method::InternalSwap(Method* other) { response_type_url_.Swap(&other->response_type_url_); std::swap(response_streaming_, other->response_streaming_); options_.UnsafeArenaSwap(&other->options_); + std::swap(syntax_, other->syntax_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -1368,27 +1567,409 @@ int Method::options_size() const { void Method::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& Method::options(int index) const { +const ::google::protobuf::Option& Method::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Method.options) return options_.Get(index); } - ::google::protobuf::Option* Method::mutable_options(int index) { +::google::protobuf::Option* Method::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Method.options) return options_.Mutable(index); } - ::google::protobuf::Option* Method::add_options() { +::google::protobuf::Option* Method::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Method.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +Method::mutable_options() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options) + return &options_; +} +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& Method::options() const { // @@protoc_insertion_point(field_list:google.protobuf.Method.options) return options_; } - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* -Method::mutable_options() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options) - return &options_; + +// optional .google.protobuf.Syntax syntax = 7; +void Method::clear_syntax() { + syntax_ = 0; +} + ::google::protobuf::Syntax Method::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} + void Method::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax) +} + +#endif // PROTOBUF_INLINE_NOT_IN_HEADERS + +// =================================================================== + +#ifndef _MSC_VER +const int Mixin::kNameFieldNumber; +const int Mixin::kRootFieldNumber; +#endif // !_MSC_VER + +Mixin::Mixin() + : ::google::protobuf::Message(), _internal_metadata_(NULL) { + SharedCtor(); + // @@protoc_insertion_point(constructor:google.protobuf.Mixin) +} + +void Mixin::InitAsDefaultInstance() { + _is_default_instance_ = true; +} + +Mixin::Mixin(const Mixin& from) + : ::google::protobuf::Message(), + _internal_metadata_(NULL) { + SharedCtor(); + MergeFrom(from); + // @@protoc_insertion_point(copy_constructor:google.protobuf.Mixin) +} + +void Mixin::SharedCtor() { + _is_default_instance_ = false; + ::google::protobuf::internal::GetEmptyString(); + _cached_size_ = 0; + name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + root_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +Mixin::~Mixin() { + // @@protoc_insertion_point(destructor:google.protobuf.Mixin) + SharedDtor(); +} + +void Mixin::SharedDtor() { + name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + root_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + if (this != default_instance_) { + } +} + +void Mixin::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const ::google::protobuf::Descriptor* Mixin::descriptor() { + protobuf_AssignDescriptorsOnce(); + return Mixin_descriptor_; +} + +const Mixin& Mixin::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto(); + return *default_instance_; +} + +Mixin* Mixin::default_instance_ = NULL; + +Mixin* Mixin::New(::google::protobuf::Arena* arena) const { + Mixin* n = new Mixin; + if (arena != NULL) { + arena->Own(n); + } + return n; +} + +void Mixin::Clear() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + +bool Mixin::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure + ::google::protobuf::uint32 tag; + // @@protoc_insertion_point(parse_start:google.protobuf.Mixin) + 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())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Mixin.name")); + } else { + goto handle_unusual; + } + if (input->ExpectTag(18)) goto parse_root; + break; + } + + // optional string root = 2; + case 2: { + if (tag == 18) { + parse_root: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_root())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Mixin.root")); + } 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::WireFormatLite::SkipField(input, tag)); + break; + } + } + } +success: + // @@protoc_insertion_point(parse_success:google.protobuf.Mixin) + return true; +failure: + // @@protoc_insertion_point(parse_failure:google.protobuf.Mixin) + return false; +#undef DO_ +} + +void Mixin::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // @@protoc_insertion_point(serialize_start:google.protobuf.Mixin) + // optional string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Mixin.name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 1, this->name(), output); + } + + // optional string root = 2; + if (this->root().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Mixin.root"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 2, this->root(), output); + } + + // @@protoc_insertion_point(serialize_end:google.protobuf.Mixin) +} + +::google::protobuf::uint8* Mixin::SerializeWithCachedSizesToArray( + ::google::protobuf::uint8* target) const { + // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin) + // optional string name = 1; + if (this->name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Mixin.name"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 1, this->name(), target); + } + + // optional string root = 2; + if (this->root().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Mixin.root"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 2, this->root(), target); + } + + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Mixin) + return target; +} + +int Mixin::ByteSize() const { + int total_size = 0; + + // optional string name = 1; + if (this->name().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->name()); + } + + // optional string root = 2; + if (this->root().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->root()); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void Mixin::MergeFrom(const ::google::protobuf::Message& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + const Mixin* source = + ::google::protobuf::internal::DynamicCastToGenerated<const Mixin>( + &from); + if (source == NULL) { + ::google::protobuf::internal::ReflectionOps::Merge(from, this); + } else { + MergeFrom(*source); + } +} + +void Mixin::MergeFrom(const Mixin& from) { + if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); + if (from.name().size() > 0) { + + name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_); + } + if (from.root().size() > 0) { + + root_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.root_); + } +} + +void Mixin::CopyFrom(const ::google::protobuf::Message& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +void Mixin::CopyFrom(const Mixin& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool Mixin::IsInitialized() const { + + return true; +} + +void Mixin::Swap(Mixin* other) { + if (other == this) return; + InternalSwap(other); +} +void Mixin::InternalSwap(Mixin* other) { + name_.Swap(&other->name_); + root_.Swap(&other->root_); + _internal_metadata_.Swap(&other->_internal_metadata_); + std::swap(_cached_size_, other->_cached_size_); +} + +::google::protobuf::Metadata Mixin::GetMetadata() const { + protobuf_AssignDescriptorsOnce(); + ::google::protobuf::Metadata metadata; + metadata.descriptor = Mixin_descriptor_; + metadata.reflection = Mixin_reflection_; + return metadata; +} + +#if PROTOBUF_INLINE_NOT_IN_HEADERS +// Mixin + +// optional string name = 1; +void Mixin::clear_name() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + const ::std::string& Mixin::name() const { + // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name) + return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Mixin::set_name(const ::std::string& value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name) +} + void Mixin::set_name(const char* value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.name) +} + void Mixin::set_name(const char* value, size_t size) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name) +} + ::std::string* Mixin::mutable_name() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name) + return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + ::std::string* Mixin::release_name() { + + return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Mixin::set_allocated_name(::std::string* name) { + if (name != NULL) { + + } else { + + } + name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name) +} + +// optional string root = 2; +void Mixin::clear_root() { + root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + const ::std::string& Mixin::root() const { + // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root) + return root_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Mixin::set_root(const ::std::string& value) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root) +} + void Mixin::set_root(const char* value) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.root) +} + void Mixin::set_root(const char* value, size_t size) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root) +} + ::std::string* Mixin::mutable_root() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root) + return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + ::std::string* Mixin::release_root() { + + return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Mixin::set_allocated_root(::std::string* root) { + if (root != NULL) { + + } else { + + } + root_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 985adc5d..3c5a6f31 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -41,6 +41,7 @@ void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto(); class Api; class Method; +class Mixin; // =================================================================== @@ -118,10 +119,10 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message { const ::google::protobuf::Method& methods(int index) const; ::google::protobuf::Method* mutable_methods(int index); ::google::protobuf::Method* add_methods(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& - methods() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >* mutable_methods(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& + methods() const; // repeated .google.protobuf.Option options = 3; int options_size() const; @@ -130,10 +131,10 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; // optional string version = 4; void clear_version(); @@ -155,6 +156,24 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message { ::google::protobuf::SourceContext* release_source_context(); void set_allocated_source_context(::google::protobuf::SourceContext* source_context); + // repeated .google.protobuf.Mixin mixins = 6; + int mixins_size() const; + void clear_mixins(); + static const int kMixinsFieldNumber = 6; + const ::google::protobuf::Mixin& mixins(int index) const; + ::google::protobuf::Mixin* mutable_mixins(int index); + ::google::protobuf::Mixin* add_mixins(); + ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* + mutable_mixins(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& + mixins() const; + + // optional .google.protobuf.Syntax syntax = 7; + void clear_syntax(); + static const int kSyntaxFieldNumber = 7; + ::google::protobuf::Syntax syntax() const; + void set_syntax(::google::protobuf::Syntax value); + // @@protoc_insertion_point(class_scope:google.protobuf.Api) private: @@ -165,6 +184,8 @@ class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; ::google::protobuf::internal::ArenaStringPtr version_; ::google::protobuf::SourceContext* source_context_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin > mixins_; + int syntax_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto(); @@ -283,10 +304,16 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; + + // optional .google.protobuf.Syntax syntax = 7; + void clear_syntax(); + static const int kSyntaxFieldNumber = 7; + ::google::protobuf::Syntax syntax() const; + void set_syntax(::google::protobuf::Syntax value); // @@protoc_insertion_point(class_scope:google.protobuf.Method) private: @@ -296,9 +323,10 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message { ::google::protobuf::internal::ArenaStringPtr name_; ::google::protobuf::internal::ArenaStringPtr request_type_url_; ::google::protobuf::internal::ArenaStringPtr response_type_url_; - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; bool request_streaming_; bool response_streaming_; + int syntax_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto(); @@ -307,6 +335,101 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message { void InitAsDefaultInstance(); static Method* default_instance_; }; +// ------------------------------------------------------------------- + +class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message { + public: + Mixin(); + virtual ~Mixin(); + + Mixin(const Mixin& from); + + inline Mixin& operator=(const Mixin& from) { + CopyFrom(from); + return *this; + } + + static const ::google::protobuf::Descriptor* descriptor(); + static const Mixin& default_instance(); + + void Swap(Mixin* other); + + // implements Message ---------------------------------------------- + + inline Mixin* New() const { return New(NULL); } + + Mixin* New(::google::protobuf::Arena* arena) const; + void CopyFrom(const ::google::protobuf::Message& from); + void MergeFrom(const ::google::protobuf::Message& from); + void CopyFrom(const Mixin& from); + void MergeFrom(const Mixin& 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(Mixin* 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; + 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); + + // optional string root = 2; + void clear_root(); + static const int kRootFieldNumber = 2; + const ::std::string& root() const; + void set_root(const ::std::string& value); + void set_root(const char* value); + void set_root(const char* value, size_t size); + ::std::string* mutable_root(); + ::std::string* release_root(); + void set_allocated_root(::std::string* root); + + // @@protoc_insertion_point(class_scope:google.protobuf.Mixin) + private: + + ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; + bool _is_default_instance_; + ::google::protobuf::internal::ArenaStringPtr name_; + ::google::protobuf::internal::ArenaStringPtr root_; + mutable int _cached_size_; + friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fapi_2eproto(); + friend void protobuf_AssignDesc_google_2fprotobuf_2fapi_2eproto(); + friend void protobuf_ShutdownFile_google_2fprotobuf_2fapi_2eproto(); + + void InitAsDefaultInstance(); + static Mixin* default_instance_; +}; // =================================================================== @@ -377,16 +500,16 @@ inline ::google::protobuf::Method* Api::add_methods() { // @@protoc_insertion_point(field_add:google.protobuf.Api.methods) return methods_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& -Api::methods() const { - // @@protoc_insertion_point(field_list:google.protobuf.Api.methods) - return methods_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >* Api::mutable_methods() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.methods) return &methods_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Method >& +Api::methods() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.methods) + return methods_; +} // repeated .google.protobuf.Option options = 3; inline int Api::options_size() const { @@ -407,16 +530,16 @@ inline ::google::protobuf::Option* Api::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Api.options) return options_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Api::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Api.options) - return options_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Api::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.options) return &options_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Api::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.options) + return options_; +} // optional string version = 4; inline void Api::clear_version() { @@ -498,6 +621,50 @@ inline void Api::set_allocated_source_context(::google::protobuf::SourceContext* // @@protoc_insertion_point(field_set_allocated:google.protobuf.Api.source_context) } +// repeated .google.protobuf.Mixin mixins = 6; +inline int Api::mixins_size() const { + return mixins_.size(); +} +inline void Api::clear_mixins() { + mixins_.Clear(); +} +inline const ::google::protobuf::Mixin& Api::mixins(int index) const { + // @@protoc_insertion_point(field_get:google.protobuf.Api.mixins) + return mixins_.Get(index); +} +inline ::google::protobuf::Mixin* Api::mutable_mixins(int index) { + // @@protoc_insertion_point(field_mutable:google.protobuf.Api.mixins) + return mixins_.Mutable(index); +} +inline ::google::protobuf::Mixin* Api::add_mixins() { + // @@protoc_insertion_point(field_add:google.protobuf.Api.mixins) + return mixins_.Add(); +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* +Api::mutable_mixins() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Api.mixins) + return &mixins_; +} +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& +Api::mixins() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins) + return mixins_; +} + +// optional .google.protobuf.Syntax syntax = 7; +inline void Api::clear_syntax() { + syntax_ = 0; +} +inline ::google::protobuf::Syntax Api::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Api.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} +inline void Api::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Api.syntax) +} + // ------------------------------------------------------------------- // Method @@ -678,20 +845,126 @@ inline ::google::protobuf::Option* Method::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Method.options) return options_.Add(); } +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +Method::mutable_options() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options) + return &options_; +} inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& Method::options() const { // @@protoc_insertion_point(field_list:google.protobuf.Method.options) return options_; } -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* -Method::mutable_options() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.Method.options) - return &options_; + +// optional .google.protobuf.Syntax syntax = 7; +inline void Method::clear_syntax() { + syntax_ = 0; +} +inline ::google::protobuf::Syntax Method::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Method.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} +inline void Method::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Method.syntax) +} + +// ------------------------------------------------------------------- + +// Mixin + +// optional string name = 1; +inline void Mixin::clear_name() { + name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& Mixin::name() const { + // @@protoc_insertion_point(field_get:google.protobuf.Mixin.name) + return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Mixin::set_name(const ::std::string& value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Mixin.name) +} +inline void Mixin::set_name(const char* value) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.name) +} +inline void Mixin::set_name(const char* value, size_t size) { + + name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.name) +} +inline ::std::string* Mixin::mutable_name() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.name) + return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* Mixin::release_name() { + + return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Mixin::set_allocated_name(::std::string* name) { + if (name != NULL) { + + } else { + + } + name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.name) +} + +// optional string root = 2; +inline void Mixin::clear_root() { + root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& Mixin::root() const { + // @@protoc_insertion_point(field_get:google.protobuf.Mixin.root) + return root_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Mixin::set_root(const ::std::string& value) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Mixin.root) +} +inline void Mixin::set_root(const char* value) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Mixin.root) +} +inline void Mixin::set_root(const char* value, size_t size) { + + root_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Mixin.root) +} +inline ::std::string* Mixin::mutable_root() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Mixin.root) + return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* Mixin::release_root() { + + return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Mixin::set_allocated_root(::std::string* root) { + if (root != NULL) { + + } else { + + } + root_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Mixin.root) } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- +// ------------------------------------------------------------------- + // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/api.proto b/src/google/protobuf/api.proto index d6c2a8b3..597a6497 100644 --- a/src/google/protobuf/api.proto +++ b/src/google/protobuf/api.proto @@ -34,15 +34,16 @@ package google.protobuf; import "google/protobuf/source_context.proto"; import "google/protobuf/type.proto"; -option java_multiple_files = true; -option java_outer_classname = "ApiProto"; option java_package = "com.google.protobuf"; +option java_outer_classname = "ApiProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // Api is a light-weight descriptor for a protocol buffer service. message Api { + // The fully qualified name of this api, including package name // followed by the api's simple name. string name = 1; @@ -74,18 +75,22 @@ message Api { // be omitted. Zero major versions must only be used for // experimental, none-GA apis. // - // See also: [design doc](http://go/api-versioning). - // - // string version = 4; // Source context for the protocol buffer service represented by this // message. SourceContext source_context = 5; + + // Included APIs. See [Mixin][]. + repeated Mixin mixins = 6; + + // The source syntax of the service. + Syntax syntax = 7; } // Method represents a method of an api. message Method { + // The simple name of this method. string name = 1; @@ -103,4 +108,94 @@ message Method { // Any metadata attached to the method. repeated Option options = 6; + + // The source syntax of this method. + Syntax syntax = 7; +} + +// Declares an API to be included in this API. The including API must +// redeclare all the methods from the included API, but documentation +// and options are inherited as follows: +// +// - If after comment and whitespace stripping, the documentation +// string of the redeclared method is empty, it will be inherited +// from the original method. +// +// - Each annotation belonging to the service config (http, +// visibility) which is not set in the redeclared method will be +// inherited. +// +// - If an http annotation is inherited, the path pattern will be +// modified as follows. Any version prefix will be replaced by the +// version of the including API plus the [root][] path if specified. +// +// Example of a simple mixin: +// +// package google.acl.v1; +// service AccessControl { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +// } +// } +// +// package google.storage.v2; +// service Storage { +// // (-- see AccessControl.GetAcl --) +// rpc GetAcl(GetAclRequest) returns (Acl); +// +// // Get a data record. +// rpc GetData(GetDataRequest) returns (Data) { +// option (google.api.http).get = "/v2/{resource=**}"; +// } +// } +// +// Example of a mixin configuration: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// +// The mixin construct implies that all methods in `AccessControl` are +// also declared with same name and request/response types in +// `Storage`. A documentation generator or annotation processor will +// see the effective `Storage.GetAcl` method after inherting +// documentation and annotations as follows: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +// } +// ... +// } +// +// Note how the version in the path pattern changed from `v1` to `v2`. +// +// If the `root` field in the mixin is specified, it should be a +// relative path under which inherited HTTP paths are placed. Example: +// +// apis: +// - name: google.storage.v2.Storage +// mixins: +// - name: google.acl.v1.AccessControl +// root: acls +// +// This implies the following inherited HTTP annotation: +// +// service Storage { +// // Get the underlying ACL object. +// rpc GetAcl(GetAclRequest) returns (Acl) { +// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +// } +// ... +// } +message Mixin { + // The fully qualified name of the API which is included. + string name = 1; + + // If non-empty specifies a path under which inherited HTTP paths + // are rooted. + string root = 2; } diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index ed1c5ef2..907a6a20 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -66,8 +66,12 @@ void Arena::Init() { first_block->size = options_.initial_block_size; first_block->pos = kHeaderSize; first_block->next = NULL; - first_block->owner = &first_block->owner; - AddBlock(first_block); + // Thread which calls Init() owns the first block. This allows the + // single-threaded case to allocate on the first block without taking any + // locks. + first_block->owner = &thread_cache(); + SetThreadCacheBlock(first_block); + AddBlockInternal(first_block); owns_first_block_ = false; } @@ -80,7 +84,7 @@ void Arena::Init() { } Arena::~Arena() { - uint64 space_allocated = Reset(); + uint64 space_allocated = ResetInternal(); // Call the destruction hook if (options_.on_arena_destruction != NULL) { @@ -89,10 +93,14 @@ Arena::~Arena() { } uint64 Arena::Reset() { - CleanupList(); - uint64 space_allocated = FreeBlocks(); // Invalidate any ThreadCaches pointing to any blocks we just destroyed. lifecycle_id_ = lifecycle_id_generator_.GetNext(); + return ResetInternal(); +} + +uint64 Arena::ResetInternal() { + CleanupList(); + uint64 space_allocated = FreeBlocks(); // Call the reset hook if (options_.on_arena_reset != NULL) { @@ -137,6 +145,10 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n, void Arena::AddBlock(Block* b) { MutexLock l(&blocks_lock_); + AddBlockInternal(b); +} + +void Arena::AddBlockInternal(Block* b) { 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) { @@ -181,16 +193,6 @@ void* Arena::AllocateAligned(const std::type_info* allocated, size_t n) { 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); @@ -267,8 +269,12 @@ uint64 Arena::FreeBlocks() { // 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); + // Thread which calls Reset() owns the first block. This allows the + // single-threaded case to allocate on the first block without taking any + // locks. + first_block->owner = &thread_cache(); + SetThreadCacheBlock(first_block); + AddBlockInternal(first_block); } return space_allocated; } diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index e7e693b2..074a9e54 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -31,6 +31,10 @@ #ifndef GOOGLE_PROTOBUF_ARENA_H__ #define GOOGLE_PROTOBUF_ARENA_H__ +#include <limits> +#ifdef max +#undef max // Visual Studio defines this macro +#endif #if __cplusplus >= 201103L #include <google/protobuf/stubs/type_traits.h> #endif @@ -39,7 +43,8 @@ #include <google/protobuf/stubs/atomic_sequence_num.h> #include <google/protobuf/stubs/atomicops.h> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/platform_macros.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/type_traits.h> namespace google { @@ -414,6 +419,9 @@ class LIBPROTOBUF_EXPORT Arena { // trivially destructible. template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) { + GOOGLE_CHECK_LE(num_elements, + std::numeric_limits<size_t>::max() / sizeof(T)) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { return static_cast<T*>(::operator new[](num_elements * sizeof(T))); } else { @@ -459,7 +467,8 @@ class LIBPROTOBUF_EXPORT Arena { // 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. - GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object, void (*destruct)(void*)) { + GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object, + void (*destruct)(void*)) { AddListNode(object, destruct); } @@ -468,7 +477,7 @@ class LIBPROTOBUF_EXPORT Arena { // 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) { + static ::google::protobuf::Arena* GetArena(const T* value) { return GetArenaInternal(value, static_cast<T*>(0)); } @@ -506,7 +515,7 @@ class LIBPROTOBUF_EXPORT Arena { // 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; } + GOOGLE_ATTRIBUTE_ALWAYS_INLINE size_t avail() const { return size - pos; } // data follows }; @@ -554,6 +563,33 @@ class LIBPROTOBUF_EXPORT Arena { return google::protobuf::internal::has_trivial_destructor<T>::value; } + // Helper typetrait that indicates whether the desctructor of type T should be + // called when arena is destroyed at compile time. This is only to allow + // construction of higher-level templated utilities. + // is_destructor_skippable<T>::value is an instance of google::protobuf::internal::true_type if the + // destructor of the message type T should not be called when arena is + // destroyed or google::protobuf::internal::has_trivial_destructor<T>::value == true, 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_destructor_skippable { + template<typename U> + static char DestructorSkippable( + const typename U::DestructorSkippable_*); + template<typename U> + static double DestructorSkippable(...); + + // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type. + typedef google::protobuf::internal::integral_constant<bool, + sizeof(DestructorSkippable<const T>(static_cast<const T*>(0))) == + sizeof(char) || google::protobuf::internal::has_trivial_destructor<T>::value == true> + type; + static const type 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 @@ -573,14 +609,16 @@ class LIBPROTOBUF_EXPORT 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(size_t num_elements) { + T* CreateInternalRawArray(size_t num_elements) { + GOOGLE_CHECK_LE(num_elements, + std::numeric_limits<size_t>::max() / sizeof(T)) + << "Requested size is too large to fit into size_t."; return static_cast<T*>( AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements)); } template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( - bool skip_explicit_ownership) { + T* CreateInternal(bool skip_explicit_ownership) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object<T>); @@ -589,8 +627,7 @@ class LIBPROTOBUF_EXPORT Arena { } template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( - bool skip_explicit_ownership, const Arg& arg) { + T* CreateInternal(bool skip_explicit_ownership, const Arg& arg) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg); if (!skip_explicit_ownership) { AddListNode(t, &internal::arena_destruct_object<T>); @@ -599,7 +636,7 @@ class LIBPROTOBUF_EXPORT Arena { } template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateInternal( + T* CreateInternal( bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2); if (!skip_explicit_ownership) { @@ -609,10 +646,10 @@ class LIBPROTOBUF_EXPORT Arena { } 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) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3); if (!skip_explicit_ownership) { @@ -623,11 +660,11 @@ class LIBPROTOBUF_EXPORT Arena { 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) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4); if (!skip_explicit_ownership) { @@ -638,12 +675,12 @@ class LIBPROTOBUF_EXPORT Arena { template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5); if (!skip_explicit_ownership) { @@ -654,13 +691,13 @@ class LIBPROTOBUF_EXPORT Arena { template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6); if (!skip_explicit_ownership) { @@ -671,14 +708,14 @@ class LIBPROTOBUF_EXPORT Arena { template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7> - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6, - const Arg7& arg7) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6, arg7); if (!skip_explicit_ownership) { @@ -690,15 +727,15 @@ class LIBPROTOBUF_EXPORT Arena { template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6, typename Arg7, typename Arg8> - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership, - const Arg1& arg1, - const Arg2& arg2, - const Arg3& arg3, - const Arg4& arg4, - const Arg5& arg5, - const Arg6& arg6, - const Arg7& arg7, - const Arg8& arg8) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership, + const Arg1& arg1, + const Arg2& arg2, + const Arg3& arg3, + const Arg4& arg4, + const Arg5& arg5, + const Arg6& arg6, + const Arg7& arg7, + const Arg8& arg8) { T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); if (!skip_explicit_ownership) { @@ -708,21 +745,21 @@ class LIBPROTOBUF_EXPORT Arena { } template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*) { return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)), this); } template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, - const Arg& arg) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg& arg) { return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)), this, arg); } template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE - inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*, - const Arg1& arg1, const Arg2& arg2) { + T* CreateMessageInternal(typename T::InternalArenaConstructable_*, + const Arg1& arg1, const Arg2& arg2) { return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)), this, arg1, arg2); } @@ -733,19 +770,29 @@ class LIBPROTOBUF_EXPORT Arena { template <typename T> static void CreateInArenaStorage(T* ptr, Arena* arena) { CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value); + RegisterDestructorInternal(ptr, arena, is_destructor_skippable<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; } + template <typename T> + static void RegisterDestructorInternal( + T* ptr, Arena* arena, google::protobuf::internal::true_type) {} + template <typename T> + static void RegisterDestructorInternal( + T* ptr, Arena* arena, google::protobuf::internal::false_type) { + arena->OwnDestructor(ptr); + } + // 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 @@ -768,13 +815,13 @@ class LIBPROTOBUF_EXPORT Arena { // 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_*) { + static ::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, ...) { + static ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) { return NULL; } @@ -784,7 +831,7 @@ class LIBPROTOBUF_EXPORT Arena { void* AllocateAligned(const std::type_info* allocated, size_t n); // Allocate an internal allocation, avoiding optional typed monitoring. - GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline void* AllocateAligned(size_t n) { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* AllocateAligned(size_t n) { return AllocateAligned(NULL, n); } @@ -802,6 +849,7 @@ class LIBPROTOBUF_EXPORT Arena { void AddListNode(void* elem, void (*cleanup)(void*)); // Delete or Destruct all objects owned by the arena. void CleanupList(); + uint64 ResetInternal(); inline void SetThreadCacheBlock(Block* block) { thread_cache().last_block_used_ = block; @@ -828,6 +876,9 @@ class LIBPROTOBUF_EXPORT Arena { Mutex blocks_lock_; void AddBlock(Block* b); + // Access must be synchronized, either by blocks_lock_ or by being called from + // Init()/Reset(). + void AddBlockInternal(Block* b); void* SlowAlloc(size_t n); Block* FindBlock(void* me); Block* NewBlock(void* me, Block* my_last_block, size_t n, @@ -853,6 +904,11 @@ const typename Arena::is_arena_constructable<T>::type Arena::is_arena_constructable<T>::value = typename Arena::is_arena_constructable<T>::type(); +template<typename T> +const typename Arena::is_destructor_skippable<T>::type + Arena::is_destructor_skippable<T>::value = + typename Arena::is_destructor_skippable<T>::type(); + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/arena_test_util.cc b/src/google/protobuf/arena_test_util.cc index 21f55c6e..df9c5bd6 100644 --- a/src/google/protobuf/arena_test_util.cc +++ b/src/google/protobuf/arena_test_util.cc @@ -28,6 +28,7 @@ // (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/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/arena_test_util.h> diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 6c185695..c9ca1fd1 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -40,7 +40,9 @@ #include <typeinfo> #include <vector> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/arena_test_util.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> @@ -619,8 +621,6 @@ TEST(ArenaTest, RepeatedPtrFieldAddClearedTest) { } } -// 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; @@ -680,6 +680,55 @@ TEST(ArenaTest, AddAllocatedToRepeatedField) { } } +TEST(ArenaTest, AddAllocatedToRepeatedFieldViaReflection) { + // Heap->arena case. + Arena arena1; + TestAllTypes* arena1_message = Arena::CreateMessage<TestAllTypes>(&arena1); + const Reflection* r = arena1_message->GetReflection(); + const Descriptor* d = arena1_message->GetDescriptor(); + const FieldDescriptor* fd = + d->FindFieldByName("repeated_nested_message"); + for (int i = 0; i < 10; i++) { + TestAllTypes::NestedMessage* heap_submessage = + new TestAllTypes::NestedMessage; + heap_submessage->set_bb(42); + r->AddAllocatedMessage(arena1_message, fd, 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); + r->AddAllocatedMessage(arena1_message, fd, 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); + r->AddAllocatedMessage(heap_message, fd, 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; +} + TEST(ArenaTest, ReleaseLastRepeatedField) { // Release from arena-allocated repeated field and ensure that returned object // is heap-allocated. @@ -1230,7 +1279,7 @@ TEST(ArenaTest, ArenaHooksSanity) { EXPECT_EQ(1, ArenaHooksTestUtil::num_init); EXPECT_EQ(0, ArenaHooksTestUtil::num_allocations); ::google::protobuf::Arena::Create<uint64>(&arena); - if (::google::protobuf::internal::has_trivial_destructor<uint64>::value) { + if (google::protobuf::internal::has_trivial_destructor<uint64>::value) { EXPECT_EQ(1, ArenaHooksTestUtil::num_allocations); } else { EXPECT_EQ(2, ArenaHooksTestUtil::num_allocations); diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h index 7bbf6c76..1dacdc68 100755 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -33,6 +33,7 @@ #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/fastmem.h> @@ -145,7 +146,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // 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 { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(ArenaStringPtr* other) { std::swap(ptr_, other->ptr_); } @@ -283,9 +284,8 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { private: ::std::string* ptr_; - GOOGLE_ATTRIBUTE_NOINLINE - inline void CreateInstance(::google::protobuf::Arena* arena, - const ::std::string* initial_value) { + GOOGLE_ATTRIBUTE_NOINLINE void CreateInstance(::google::protobuf::Arena* arena, + const ::std::string* initial_value) { // Assumes ptr_ is not NULL. if (initial_value != NULL) { ptr_ = new ::std::string(*initial_value); @@ -296,9 +296,7 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { arena->Own(ptr_); } } - - GOOGLE_ATTRIBUTE_NOINLINE - inline void CreateInstanceNoArena(const ::std::string* initial_value) { + GOOGLE_ATTRIBUTE_NOINLINE void CreateInstanceNoArena(const ::std::string* initial_value) { if (initial_value != NULL) { ptr_ = new ::std::string(*initial_value); } else { diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc index 8ebd4b9c..3fb582be 100644 --- a/src/google/protobuf/arenastring_unittest.cc +++ b/src/google/protobuf/arenastring_unittest.cc @@ -42,6 +42,7 @@ #endif #include <cstdlib> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0039b00a..473eb4e6 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index e8871861..26a4f0b0 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -70,6 +70,7 @@ #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/stubs/map_util.h> @@ -1657,7 +1658,11 @@ bool CommandLineInterface::WriteDescriptorSet( &already_seen, file_set.mutable_file()); } } else { + set<const FileDescriptor*> already_seen; for (int i = 0; i < parsed_files.size(); i++) { + if (!already_seen.insert(parsed_files[i]).second) { + continue; + } FileDescriptorProto* file_proto = file_set.add_file(); parsed_files[i]->CopyTo(file_proto); if (source_info_in_descriptor_set_) { diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index e5b77c33..46ea5c4e 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -886,6 +886,39 @@ TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); } +TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithDuplicates) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + CreateTempFile("bar.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Bar {\n" + " optional Foo foo = 1;\n" + "}\n"); + CreateTempFile("baz.proto", + "syntax = \"proto2\";\n" + "import \"foo.proto\";\n" + "message Baz {\n" + " optional Foo foo = 1;\n" + "}\n"); + + Run("protocol_compiler --descriptor_set_out=$tmpdir/descriptor_set " + "--proto_path=$tmpdir bar.proto foo.proto bar.proto baz.proto"); + + ExpectNoErrors(); + + FileDescriptorSet descriptor_set; + ReadDescriptorSet("descriptor_set", &descriptor_set); + if (HasFatalFailure()) return; + EXPECT_EQ(3, descriptor_set.file_size()); + EXPECT_EQ("bar.proto", descriptor_set.file(0).name()); + EXPECT_EQ("foo.proto", descriptor_set.file(1).name()); + EXPECT_EQ("baz.proto", descriptor_set.file(2).name()); + // Descriptor set should not have source code info. + EXPECT_FALSE(descriptor_set.file(0).has_source_code_info()); +} + TEST_F(CommandLineInterfaceTest, WriteDescriptorSetWithSourceInfo) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 13ed0b64..c3e9fe74 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -133,8 +133,7 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { CppGenerator generator; MockGeneratorContext context; string error; - string parameter; - parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; + string parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &context, &error)); parameter = "dllexport_decl=LIBPROTOC_EXPORT"; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 70d3a600..de4d7cc7 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -32,7 +32,6 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <set> #include <map> #include <google/protobuf/compiler/cpp/cpp_enum.h> @@ -70,14 +69,11 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} -void EnumGenerator::GenerateForwardDeclaration(io::Printer* printer) { +void EnumGenerator::FillForwardDeclaration(set<string>* enum_names) { if (!options_.proto_h) { return; } - map<string, string> vars; - vars["classname"] = classname_; - printer->Print(vars, "enum $classname$ : int;\n"); - printer->Print(vars, "bool $classname$_IsValid(int value);\n"); + enum_names->insert(classname_); } void EnumGenerator::GenerateDefinition(io::Printer* printer) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 3e930856..f3aa72e4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -35,6 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#include <set> #include <string> #include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> @@ -60,11 +61,11 @@ class EnumGenerator { // Header stuff. - // Generate header code to forward-declare the enum. This is for use when + // Fills the name to use when declaring the enum. This is for use when // generating other .proto.h files. This code should be placed within the // enum's package namespace, but NOT within any class, even for nested // enums. - void GenerateForwardDeclaration(io::Printer* printer); + void FillForwardDeclaration(set<string>* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 965327b1..824e2205 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -35,7 +35,6 @@ #include <google/protobuf/compiler/cpp/cpp_enum_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> namespace google { diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 43df1d88..8d47d4e0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -47,6 +47,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 1f0a8205..5dae4cdd 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_file.h> +#include <map> #include <memory> #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> @@ -93,22 +94,36 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateHeader(io::Printer* printer) { - GenerateTopHeaderGuard(printer); +void FileGenerator::GenerateProtoHeader(io::Printer* printer) { + if (!options_.proto_h) { + return; + } + + string filename_identifier = FilenameIdentifier(file_->name()); + GenerateTopHeaderGuard(printer, filename_identifier); + GenerateLibraryIncludes(printer); - GenerateDependencyIncludes(printer); + + for (int i = 0; i < file_->public_dependency_count(); i++) { + const FileDescriptor* dep = file_->public_dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\" // IWYU pragma: export\n", + "dependency", dependency); + } printer->Print( "// @@protoc_insertion_point(includes)\n"); + GenerateForwardDeclarations(printer); // Open namespace. GenerateNamespaceOpeners(printer); GenerateGlobalStateFunctionDeclarations(printer); - GenerateMessageForwardDeclarations(printer); printer->Print("\n"); @@ -133,6 +148,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { GenerateInlineFunctionDefinitions(printer); + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n" + "\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -144,19 +164,89 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n" "\n"); - GenerateBottomHeaderGuard(printer); + GenerateBottomHeaderGuard(printer, filename_identifier); +} + +void FileGenerator::GeneratePBHeader(io::Printer* printer) { + string filename_identifier = + FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); + GenerateTopHeaderGuard(printer, filename_identifier); + + if (options_.proto_h) { + printer->Print("#include \"$basename$.proto.h\" // IWYU pragma: export\n", + "basename", StripProto(file_->name())); + } else { + GenerateLibraryIncludes(printer); + } + GenerateDependencyIncludes(printer); + + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + + + + // Open namespace. + GenerateNamespaceOpeners(printer); + + if (!options_.proto_h) { + GenerateGlobalStateFunctionDeclarations(printer); + GenerateMessageForwardDeclarations(printer); + + printer->Print("\n"); + + GenerateEnumDefinitions(printer); + + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateMessageDefinitions(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateServiceDefinitions(printer); + + GenerateExtensionIdentifiers(printer); + + printer->Print("\n"); + printer->Print(kThickSeparator); + printer->Print("\n"); + + GenerateInlineFunctionDefinitions(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + + // Close up namespace. + GenerateNamespaceClosers(printer); + + if (!options_.proto_h) { + // We need to specialize some templates in the ::google::protobuf namespace: + GenerateProto2NamespaceEnumSpecializations(printer); + } + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + + GenerateBottomHeaderGuard(printer, filename_identifier); } void FileGenerator::GenerateSource(io::Printer* printer) { + string header = + StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" "// source: $filename$\n" "\n" - // The generated code calls accessors that might be deprecated. We don't // want the compiler to warn in generated code. "#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" - "#include \"$basename$.pb.h\"\n" + "#include \"$header$\"\n" "\n" "#include <algorithm>\n" // for swap() "\n" @@ -165,7 +255,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/io/coded_stream.h>\n" "#include <google/protobuf/wire_format_lite_inl.h>\n", "filename", file_->name(), - "basename", StripProto(file_->name())); + "header", header); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { @@ -181,6 +271,18 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include <google/protobuf/wire_format.h>\n"); } + if (options_.proto_h) { + // Use the smaller .proto.h files. + for (int i = 0; i < file_->dependency_count(); i++) { + const FileDescriptor* dep = file_->dependency(i); + const char* extension = ".proto.h"; + string dependency = StripProto(dep->name()) + extension; + printer->Print( + "#include \"$dependency$\"\n", + "dependency", dependency); + } + } + printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -276,6 +378,59 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n"); } +class FileGenerator::ForwardDeclarations { + public: + ~ForwardDeclarations() { + for (map<string, ForwardDeclarations *>::iterator it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + delete it->second; + } + namespaces_.clear(); + } + + ForwardDeclarations* AddOrGetNamespace(const string& ns_name) { + ForwardDeclarations*& ns = namespaces_[ns_name]; + if (ns == NULL) { + ns = new ForwardDeclarations; + } + return ns; + } + + set<string>& classes() { return classes_; } + set<string>& enums() { return enums_; } + + void Print(io::Printer* printer) const { + for (set<string>::const_iterator it = enums_.begin(), end = enums_.end(); + it != end; ++it) { + printer->Print("enum $enumname$ : int;\n" + "bool $enumname$_IsValid(int value);\n", + "enumname", it->c_str()); + } + for (set<string>::const_iterator it = classes_.begin(), + end = classes_.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); + } + for (map<string, ForwardDeclarations *>::const_iterator + it = namespaces_.begin(), + end = namespaces_.end(); + it != end; ++it) { + printer->Print("namespace $nsname$ {\n", + "nsname", it->first); + it->second->Print(printer); + printer->Print("} // namespace $nsname$\n", + "nsname", it->first); + } + } + + + private: + map<string, ForwardDeclarations*> namespaces_; + set<string> classes_; + set<string> enums_; +}; + void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // AddDescriptors() is a file-level procedure which adds the encoded // FileDescriptorProto for this .proto file to the global DescriptorPool for @@ -434,12 +589,17 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { string file_data; file_proto.SerializeToString(&file_data); +#ifdef _MSC_VER + bool breakdown_large_file = true; +#else + bool breakdown_large_file = false; +#endif // Workaround for MSVC: "Error C1091: compiler limit: string exceeds 65535 // bytes in length". Declare a static array of characters rather than use a // string literal. - if (file_data.size() > 65535) { + if (breakdown_large_file && file_data.size() > 65535) { printer->Print( - "static const char descriptor[] = {\n"); + "static const char descriptor[] = {\n"); printer->Indent(); // Only write 25 bytes per line. @@ -447,26 +607,25 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_data.size();) { for (int j = 0; j < kBytesPerLine && i < file_data.size(); ++i, ++j) { printer->Print( - "$char$, ", - "char", SimpleItoa(file_data[i])); + "$char$, ", + "char", SimpleItoa(file_data[i])); } printer->Print( - "\n"); + "\n"); } printer->Outdent(); printer->Print( - "};\n"); + "};\n"); printer->Print( - "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", - "size", SimpleItoa(file_data.size())); + "::google::protobuf::DescriptorPool::InternalAddGeneratedFile(descriptor, $size$);\n", + "size", SimpleItoa(file_data.size())); } else { - printer->Print( "::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); - + // Only write 40 bytes per line. static const int kBytesPerLine = 40; for (int i = 0; i < file_data.size(); i += kBytesPerLine) { @@ -474,11 +633,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "data", EscapeTrigraphs( CEscape(file_data.substr(i, kBytesPerLine)))); - } - printer->Print( - ", $size$);\n", + } + printer->Print( + ", $size$);\n", "size", SimpleItoa(file_data.size())); - } // Call MessageFactory::InternalRegisterGeneratedFile(). @@ -548,8 +706,40 @@ void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { } } -void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) { + ForwardDeclarations decls; + for (int i = 0; i < file_->dependency_count(); i++) { + FileGenerator dependency(file_->dependency(i), options_); + dependency.FillForwardDeclarations(&decls); + } + FillForwardDeclarations(&decls); + decls.Print(printer); +} + +void FileGenerator::FillForwardDeclarations(ForwardDeclarations* decls) { + for (int i = 0; i < file_->public_dependency_count(); i++) { + FileGenerator dependency(file_->public_dependency(i), options_); + dependency.FillForwardDeclarations(decls); + } + for (int i = 0; i < package_parts_.size(); i++) { + decls = decls->AddOrGetNamespace(package_parts_[i]); + } + // Generate enum definitions. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillEnumForwardDeclarations(&decls->enums()); + } + for (int i = 0; i < file_->enum_type_count(); i++) { + enum_generators_[i]->FillForwardDeclaration(&decls->enums()); + } + // Generate forward declarations of classes. + for (int i = 0; i < file_->message_type_count(); i++) { + message_generators_[i]->FillMessageForwardDeclarations( + &decls->classes()); + } +} + +void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" @@ -564,8 +754,8 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer) { "filename_identifier", filename_identifier); } -void FileGenerator::GenerateBottomHeaderGuard(io::Printer* printer) { - string filename_identifier = FilenameIdentifier(file_->name()); +void FileGenerator::GenerateBottomHeaderGuard( + io::Printer* printer, const string& filename_identifier) { printer->Print( "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", "filename_identifier", filename_identifier); @@ -696,9 +886,13 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( } void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - // Generate forward declarations of classes. + set<string> classes; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateMessageForwardDeclaration(printer); + message_generators_[i]->FillMessageForwardDeclarations(&classes); + } + for (set<string>::const_iterator it = classes.begin(), end = classes.end(); + it != end; ++it) { + printer->Print("class $classname$;\n", "classname", it->c_str()); } } @@ -804,10 +998,6 @@ void FileGenerator::GenerateInlineFunctionDefinitions(io::Printer* printer) { // Methods of the dependent base class must always be inline in the header. message_generators_[i]->GenerateDependentInlineMethods(printer); } - - printer->Print( - "\n" - "// @@protoc_insertion_point(namespace_scope)\n"); } void FileGenerator::GenerateProto2NamespaceEnumSpecializations( diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index e68f67bb..29cdaea5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -69,10 +69,14 @@ class FileGenerator { const Options& options); ~FileGenerator(); - void GenerateHeader(io::Printer* printer); + void GenerateProtoHeader(io::Printer* printer); + void GeneratePBHeader(io::Printer* printer); void GenerateSource(io::Printer* printer); private: + // Internal type used by GenerateForwardDeclarations (defined in file.cc). + class ForwardDeclarations; + // Generate the BuildDescriptors() procedure, which builds all descriptors // for types defined in the file. void GenerateBuildDescriptors(io::Printer* printer); @@ -80,9 +84,19 @@ class FileGenerator { void GenerateNamespaceOpeners(io::Printer* printer); void GenerateNamespaceClosers(io::Printer* printer); + // For other imports, generates their forward-declarations. + void GenerateForwardDeclarations(io::Printer* printer); + + // Internal helper used by GenerateForwardDeclarations: fills 'decls' + // with all necessary forward-declarations for this file and its + // transient depednencies. + void FillForwardDeclarations(ForwardDeclarations* decls); + // Generates top or bottom of a header file. - void GenerateTopHeaderGuard(io::Printer* printer); - void GenerateBottomHeaderGuard(io::Printer* printer); + void GenerateTopHeaderGuard(io::Printer* printer, + const string& filename_identifier); + void GenerateBottomHeaderGuard(io::Printer* printer, + const string& filename_identifier); // Generates #include directives. void GenerateLibraryIncludes(io::Printer* printer); @@ -92,10 +106,20 @@ class FileGenerator { void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); // Generates types for classes. - void GenerateMessageForwardDeclarations(io::Printer* printer); void GenerateMessageDefinitions(io::Printer* printer); + // Generates forward-declarations for just this file's classes. This is + // used for .pb.h headers, but not in proto_h mode. + void GenerateMessageForwardDeclarations(io::Printer* printer); + + // Fills in types for forward declarations. This is used internally, and + // also by other FileGenerators to determine imports' declarations. + void FillMessageForwardDeclarations(ForwardDeclarations* decls); + void FillMessageDefinitions(ForwardDeclarations* decls); + // Generates enum definitions. + void GenerateEnumForwardDeclarations(io::Printer* printer); + void FillEnumForwardDeclarations(ForwardDeclarations* decls); void GenerateEnumDefinitions(io::Printer* printer); // Generates generic service definitions. diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 99416372..781526b5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -100,16 +100,23 @@ bool CppGenerator::Generate(const FileDescriptor* file, string basename = StripProto(file->name()); - basename.append(".pb"); FileGenerator file_generator(file, file_options); - // Generate header. + // Generate header(s). + if (file_options.proto_h) { + google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(basename + ".proto.h")); + io::Printer printer(output.get(), '$'); + file_generator.GenerateProtoHeader(&printer); + } + + basename.append(".pb"); { google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output( generator_context->Open(basename + ".h")); io::Printer printer(output.get(), '$'); - file_generator.GenerateHeader(&printer); + file_generator.GeneratePBHeader(&printer); } // Generate cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 0f3688d0..09845458 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -39,6 +39,7 @@ #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> @@ -68,7 +69,7 @@ const char* const kKeywordList[] = { "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", + "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", @@ -174,6 +175,14 @@ string SuperClassName(const Descriptor* descriptor) { "::google::protobuf::Message" : "::google::protobuf::MessageLite"; } +string DependentBaseDownCast() { + return "reinterpret_cast<T*>(this)->"; +} + +string DependentBaseConstDownCast() { + return "reinterpret_cast<const T*>(this)->"; +} + string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -208,6 +217,19 @@ string FieldConstantName(const FieldDescriptor *field) { } bool IsFieldDependent(const FieldDescriptor* field) { + if (field->containing_oneof() != NULL && + field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + return true; + } + if (field->is_map()) { + const Descriptor* map_descriptor = field->message_type(); + for (int i = 0; i < map_descriptor->field_count(); i++) { + if (IsFieldDependent(map_descriptor->field(i))) { + return true; + } + } + return false; + } if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { return false; } @@ -578,6 +600,94 @@ bool IsAnyMessage(const Descriptor* descriptor) { descriptor->file()->name() == kAnyProtoFile; } +enum Utf8CheckMode { + STRICT = 0, // Parsing will fail if non UTF-8 data is in string fields. + VERIFY = 1, // Only log an error but parsing will succeed. + NONE = 2, // No UTF-8 check. +}; + +// Which level of UTF-8 enforcemant is placed on this file. +static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { + if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + return STRICT; + } else if (field->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME) { + return VERIFY; + } else { + return NONE; + } +} + +static void GenerateUtf8CheckCode(const FieldDescriptor* field, + bool for_parse, + const map<string, string>& variables, + const char* parameters, + const char* strict_function, + const char* verify_function, + io::Printer* printer) { + switch (GetUtf8CheckMode(field)) { + case STRICT: { + if (for_parse) { + printer->Print("DO_("); + } + printer->Print( + "::google::protobuf::internal::WireFormatLite::$function$(\n", + "function", strict_function); + printer->Indent(); + printer->Print(variables, parameters); + if (for_parse) { + printer->Print("::google::protobuf::internal::WireFormatLite::PARSE,\n"); + } else { + printer->Print("::google::protobuf::internal::WireFormatLite::SERIALIZE,\n"); + } + printer->Print("\"$full_name$\")", "full_name", field->full_name()); + if (for_parse) { + printer->Print(")"); + } + printer->Print(";\n"); + printer->Outdent(); + break; + } + case VERIFY: { + printer->Print( + "::google::protobuf::internal::WireFormat::$function$(\n", + "function", verify_function); + printer->Indent(); + printer->Print(variables, parameters); + if (for_parse) { + printer->Print("::google::protobuf::internal::WireFormat::PARSE,\n"); + } else { + printer->Print("::google::protobuf::internal::WireFormat::SERIALIZE,\n"); + } + printer->Print("\"$full_name$\");\n", "full_name", field->full_name()); + printer->Outdent(); + break; + } + case NONE: + break; + } +} + +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + bool for_parse, + const map<string, string>& variables, + const char* parameters, + io::Printer* printer) { + GenerateUtf8CheckCode(field, for_parse, variables, parameters, + "VerifyUtf8String", "VerifyUTF8StringNamedField", + printer); +} + +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + bool for_parse, + const map<string, string>& variables, + const char* parameters, + io::Printer* printer) { + GenerateUtf8CheckCode(field, for_parse, variables, parameters, + "VerifyUtf8Cord", "VerifyUTF8CordNamedField", + printer); +} + } // 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 4bbf8303..985cb04c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -70,8 +70,15 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); // This is a class name, like "ProtoName_InternalBase". string DependentBaseClassTemplateName(const Descriptor* descriptor); +// Name of the base class: either the dependent base class (for use with +// proto_h) or google::protobuf::Message. string SuperClassName(const Descriptor* descriptor); +// Returns a string that down-casts from the dependent base class to the +// derived class. +string DependentBaseDownCast(); +string DependentBaseConstDownCast(); + // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names @@ -195,11 +202,6 @@ inline bool HasGenericServices(const FileDescriptor* file) { file->options().cc_generic_services(); } -// Should string fields in this file verify that their contents are UTF-8? -inline bool HasUtf8Verification(const FileDescriptor* file) { - return file->options().optimize_for() != FileOptions::LITE_RUNTIME; -} - // Should we generate a separate, super-optimized code path for serializing to // flat arrays? We don't do this in Lite mode because we'd rather reduce code // size. @@ -263,6 +265,20 @@ inline bool SupportsArenas(const FieldDescriptor* field) { bool IsAnyMessage(const FileDescriptor* descriptor); bool IsAnyMessage(const Descriptor* descriptor); +void GenerateUtf8CheckCodeForString( + const FieldDescriptor* field, + bool for_parse, + const map<string, string>& variables, + const char* parameters, + io::Printer* printer); + +void GenerateUtf8CheckCodeForCord( + const FieldDescriptor* field, + bool for_parse, + const map<string, string>& variables, + const char* parameters, + io::Printer* printer); + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 0ff0d27c..25acc61b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -100,8 +100,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor, MapFieldGenerator:: MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { + const Options& options) + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -152,7 +153,9 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MapFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void MapFieldGenerator:: @@ -231,6 +234,20 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "}\n"); } + const FieldDescriptor* key_field = + descriptor_->message_type()->FindFieldByName("key"); + if (key_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + key_field, true, variables_, + "entry->key().data(), entry->key().length(),\n", printer); + } + if (value_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + value_field, true, variables_, + "entry->mutable_value()->data(),\n" + "entry->mutable_value()->length(),\n", printer); + } + // If entry is allocated by arena, its desctructor should be avoided. if (SupportsArenas(descriptor_)) { printer->Print(variables_, @@ -258,7 +275,30 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { 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" + " $number$, *entry, output);\n"); + + printer->Indent(); + printer->Indent(); + + const FieldDescriptor* key_field = + descriptor_->message_type()->FindFieldByName("key"); + const FieldDescriptor* value_field = + descriptor_->message_type()->FindFieldByName("value"); + if (key_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + key_field, false, variables_, + "it->first.data(), it->first.length(),\n", printer); + } + if (value_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + value_field, false, variables_, + "it->second.data(), it->second.length(),\n", printer); + } + + printer->Outdent(); + printer->Outdent(); + + printer->Print( " }\n"); // If entry is allocated by arena, its desctructor should be avoided. @@ -293,7 +333,29 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { " 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" + " $number$, *entry, target);\n"); + + printer->Indent(); + printer->Indent(); + + const FieldDescriptor* key_field = + descriptor_->message_type()->FindFieldByName("key"); + const FieldDescriptor* value_field = + descriptor_->message_type()->FindFieldByName("value"); + if (key_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + key_field, false, variables_, + "it->first.data(), it->first.length(),\n", printer); + } + if (value_field->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + value_field, false, variables_, + "it->second.data(), it->second.length(),\n", printer); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( " }\n"); // If entry is allocated by arena, its desctructor should be avoided. diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index d27d4851..5e205623 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -63,6 +63,7 @@ class MapFieldGenerator : public FieldGenerator { private: const FieldDescriptor* descriptor_; + const bool dependent_field_; map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index b0e38755..aa10b0bb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -39,7 +39,6 @@ #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif -#include <set> #include <utility> #include <vector> #include <google/protobuf/compiler/cpp/cpp_message.h> @@ -415,31 +414,34 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, use_dependent_base_ = true; } } + if (options.proto_h && descriptor->oneof_decl_count() > 0) { + // Always make oneofs dependent. + use_dependent_base_ = true; + } } MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -GenerateMessageForwardDeclaration(io::Printer* printer) { - printer->Print("class $classname$;\n", - "classname", classname_); +FillMessageForwardDeclarations(set<string>* class_names) { + class_names->insert(classname_); for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need forward declaration. Since map entry // message cannot be a top level class, we just need to avoid calling // GenerateForwardDeclaration here. if (IsMapEntryMessage(descriptor_->nested_type(i))) continue; - nested_generators_[i]->GenerateMessageForwardDeclaration(printer); + nested_generators_[i]->FillMessageForwardDeclarations(class_names); } } void MessageGenerator:: -GenerateEnumForwardDeclaration(io::Printer* printer) { +FillEnumForwardDeclarations(set<string>* enum_names) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { - nested_generators_[i]->GenerateEnumForwardDeclaration(printer); + nested_generators_[i]->FillEnumForwardDeclarations(enum_names); } for (int i = 0; i < descriptor_->enum_type_count(); i++) { - enum_generators_[i]->GenerateForwardDeclaration(printer); + enum_generators_[i]->FillForwardDeclaration(enum_names); } } @@ -484,13 +486,6 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); printer->Print("\n"); } - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - const OneofDescriptor* oneof = descriptor_->oneof_decl(i); - PrintFieldComment(printer, oneof); - printer->Print( - "void clear_$oneof_name$();\n", - "oneof_name", oneof->name()); - } } void MessageGenerator:: @@ -505,7 +500,9 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { vars["constant_name"] = FieldConstantName(field); bool dependent_field = use_dependent_base_ && IsFieldDependent(field); - if (dependent_field) { + if (dependent_field && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + !field->is_map()) { // If this field is dependent, the dependent base class determines // the message type from the derived class (which is a template // parameter). This typedef is for that: @@ -594,8 +591,8 @@ GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { vars["tmpl"] = "template<class T>\n"; vars["dependent_classname"] = DependentBaseClassTemplateName(descriptor_) + "<T>"; - vars["this_message"] = "reinterpret_cast<T*>(this)->"; - vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + vars["this_message"] = DependentBaseDownCast(); + vars["this_const_message"] = DependentBaseConstDownCast(); GenerateFieldClear(field, vars, printer); } @@ -721,13 +718,15 @@ GenerateFieldClear(const FieldDescriptor* field, printer->Print(vars, "if ($this_message$has_$name$()) {\n"); printer->Indent(); - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); printer->Print(vars, "$this_message$clear_has_$oneof_name$();\n"); printer->Outdent(); printer->Print("}\n"); } else { - field_generators_.get(field).GenerateClearingCode(printer); + field_generators_.get(field) + .GenerateClearingCode(printer); if (HasFieldPresence(descriptor_->file())) { if (!field->is_repeated()) { printer->Print(vars, @@ -752,6 +751,18 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); vars["inline"] = is_inline ? "inline " : ""; + if (use_dependent_base_ && IsFieldDependent(field)) { + vars["tmpl"] = "template<class T>\n"; + vars["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_) + "<T>"; + vars["this_message"] = "reinterpret_cast<T*>(this)->"; + vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + } else { + vars["tmpl"] = ""; + vars["dependent_classname"] = vars["classname"]; + vars["this_message"] = ""; + vars["this_const_message"] = ""; + } // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -775,10 +786,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer, bool is_inline) { } if (!use_dependent_base_ || !IsFieldDependent(field)) { - vars["tmpl"] = ""; - vars["dependent_classname"] = vars["classname"]; - vars["this_message"] = ""; - vars["this_const_message"] = ""; GenerateFieldClear(field, vars, printer); } @@ -915,15 +922,32 @@ GenerateClassDefinition(io::Printer* printer) { "}\n" "\n"); } else { - printer->Print( - "inline const ::std::string& unknown_fields() const {\n" - " return _unknown_fields_;\n" - "}\n" - "\n" - "inline ::std::string* mutable_unknown_fields() {\n" - " return &_unknown_fields_;\n" - "}\n" - "\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.Get(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.Mutable(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n" + "}\n" + "\n"); + } else { + printer->Print( + "inline const ::std::string& unknown_fields() const {\n" + " return _unknown_fields_.GetNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n" + "inline ::std::string* mutable_unknown_fields() {\n" + " return _unknown_fields_.MutableNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n" + "}\n" + "\n"); + } } } @@ -1068,6 +1092,10 @@ GenerateClassDefinition(io::Printer* printer) { } } uses_string_ = false; + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + uses_string_ = true; + } for (int i = 0; i < descriptors.size(); i++) { const FieldDescriptor* field = descriptors[i]; if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { @@ -1201,18 +1229,11 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - if (use_dependent_base_) { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } else { - printer->Print( - "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" - "inline void clear_has_$oneof_name$();\n\n", - "oneof_name", descriptor_->oneof_decl(i)->name()); - } + printer->Print( + "inline bool has_$oneof_name$() const;\n" + "void clear_$oneof_name$();\n" + "inline void clear_has_$oneof_name$();\n\n", + "oneof_name", descriptor_->oneof_decl(i)->name()); } if (HasGeneratedMethods(descriptor_->file()) && @@ -1262,7 +1283,7 @@ GenerateClassDefinition(io::Printer* printer) { "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { printer->Print( - "::std::string _unknown_fields_;\n" + "::google::protobuf::internal::ArenaStringPtr _unknown_fields_;\n" "::google::protobuf::Arena* _arena_ptr_;\n" "\n"); } @@ -1919,6 +1940,13 @@ GenerateSharedConstructorCode(io::Printer* printer) { uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", "_cached_size_ = 0;\n").c_str()); + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + printer->Print( + "_unknown_fields_.UnsafeSetDefault(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { field_generators_.get(descriptor_->field(i)) @@ -1955,6 +1983,22 @@ GenerateSharedDestructorCode(io::Printer* printer) { "}\n" "\n"); } + + // Write the desctructor for _unknown_fields_ in lite runtime. + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.Destroy(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.DestroyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } + } + // Write the destructors for each field except oneof members. for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { @@ -2463,8 +2507,16 @@ GenerateClear(io::Printer* printer) { " mutable_unknown_fields()->Clear();\n" "}\n"); } else { - printer->Print( - "mutable_unknown_fields()->clear();\n"); + if (SupportsArenas(descriptor_)) { + printer->Print( + "_unknown_fields_.ClearToEmpty(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited(),\n" + " GetArenaNoVirtual());\n"); + } else { + printer->Print( + "_unknown_fields_.ClearToEmptyNoArena(\n" + " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); + } } } @@ -2481,33 +2533,22 @@ GenerateOneofClear(io::Printer* printer) { oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); string message_class; - if (use_dependent_base_) { - oneof_vars["tmpl"] = "template<class T>\n"; - oneof_vars["inline"] = "inline "; - oneof_vars["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_) + "<T>"; - oneof_vars["this_message"] = "reinterpret_cast<T*>(this)->"; - message_class = "T::"; - } else { - oneof_vars["tmpl"] = ""; - oneof_vars["inline"] = ""; - oneof_vars["dependent_classname"] = classname_; - oneof_vars["this_message"] = ""; - } - printer->Print(oneof_vars, - "$tmpl$" - "$inline$" - "void $dependent_classname$::clear_$oneofname$() {\n"); + "void $classname$::clear_$oneofname$() {\n"); printer->Indent(); + // In .proto.h mode, fields with a dependent type will generate + // clearing code that down casts from the dependent base class. + // However, clear_oneof() methods are always in the .cc file, and thus + // must remain in the derived base. So, to make the clearing code work, + // we add a typedef so that the down cast works (it will be a no-op). printer->Print(oneof_vars, - "switch($this_message$$oneofname$_case()) {\n"); + "typedef $classname$ T;\n" + "switch($oneofname$_case()) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "case $message_class$k$field_name$: {\n", - "message_class", message_class, + "case k$field_name$: {\n", "field_name", UnderscoresToCamelCase(field->name(), true)); printer->Indent(); // We clear only allocated objects in oneofs @@ -2524,20 +2565,16 @@ GenerateOneofClear(io::Printer* printer) { "}\n"); } printer->Print( - "case $message_class$$cap_oneof_name$_NOT_SET: {\n" + "case $cap_oneof_name$_NOT_SET: {\n" " break;\n" "}\n", - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n" - "$this_message$_oneof_case_[$oneof_index$] = " - "$message_class$$cap_oneof_name$_NOT_SET;\n", - "this_message", oneof_vars["this_message"], + "_oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n", "oneof_index", SimpleItoa(i), - "message_class", message_class, "cap_oneof_name", ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); @@ -2612,7 +2649,7 @@ GenerateSwap(io::Printer* printer) { printer->Print( "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); } else { - printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n"); + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } } else { // Still swap internal_metadata as it may contain more than just diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 23dad10c..8e19a3f0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -39,8 +39,8 @@ #ifndef _SHARED_PTR_H #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <set> #include <string> -#include <vector> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_options.h> @@ -66,9 +66,10 @@ class MessageGenerator { // Header stuff. - // Generate foward declarations for this class and all its nested types. - void GenerateMessageForwardDeclaration(io::Printer* printer); - void GenerateEnumForwardDeclaration(io::Printer* printer); + // Return names for foward declarations of this class and all its nested + // types. + void FillMessageForwardDeclarations(set<string>* class_names); + void FillEnumForwardDeclarations(set<string>* enum_names); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index ba318d10..b4545892 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -63,6 +63,14 @@ void SetMessageVariables(const FieldDescriptor* descriptor, SafeFunctionName(descriptor->containing_type(), descriptor, "release_"); (*variables)["full_name"] = descriptor->full_name(); + if (options.proto_h && IsFieldDependent(descriptor)) { + (*variables)["dependent_type"] = "T::" + DependentTypeName(descriptor); + (*variables)["dependent_typename"] = + "typename T::" + DependentTypeName(descriptor); + } else { + (*variables)["dependent_type"] = FieldMessageTypeName(descriptor); + (*variables)["dependent_typename"] = FieldMessageTypeName(descriptor); + } } } // namespace @@ -85,7 +93,21 @@ GeneratePrivateMembers(io::Printer* printer) const { } void MessageFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + +void MessageFieldGenerator:: GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + // Arena manipulation code is out-of-line in the derived message class. + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); } void MessageFieldGenerator:: @@ -103,11 +125,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$type$* _slow_$release_name$()$deprecation$;\n" "public:\n"); } - printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n" - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + GenerateGetterDeclaration(printer); + if (!dependent_field_) { + printer->Print(variables_, + "$type$* mutable_$name$()$deprecation$;\n" + "$type$* $release_name$()$deprecation$;\n" + "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + } if (SupportsArenas(descriptor_)) { printer->Print(variables_, "$type$* unsafe_arena_release_$name$()$deprecation$;\n" @@ -123,12 +147,12 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( "void $classname$::_slow_mutable_$name$() {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n" + " GetArenaNoVirtual());\n"); } else { printer->Print(variables_, - " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n" + " GetArenaNoVirtual());\n"); } printer->Print(variables_, "}\n" @@ -151,7 +175,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( if (SupportsArenas(descriptor_->message_type())) { // NOTE: the same logic is mirrored in weak_message_field.cc. Any // arena-related semantics changes should be made in both places. - printer->Print(variables_, + printer->Print(variables_, "void $classname$::_slow_set_allocated_$name$(\n" " ::google::protobuf::Arena* message_arena, $type$** $name$) {\n" " if (message_arena != NULL && \n" @@ -189,15 +213,139 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( void MessageFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } + + map<string, string> variables(variables_); + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = DependentBaseDownCast(); + if (!variables["set_hasbit"].empty()) { + variables["set_hasbit"] = + variables["this_message"] + variables["set_hasbit"]; + } + if (!variables["clear_hasbit"].empty()) { + variables["clear_hasbit"] = + variables["this_message"] + variables["clear_hasbit"]; + } + + if (SupportsArenas(descriptor_)) { + printer->Print(variables, + "template <class T>\n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if ($name$_ == NULL) {\n" + " $this_message$_slow_mutable_$name$();\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $clear_hasbit$\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " return $this_message$_slow_$release_name$();\n" + " } else {\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + " }\n" + "}\n" + "template <class T>\n" + "inline void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " ::google::protobuf::Arena* message_arena = $this_message$GetArenaNoVirtual();\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if (message_arena == NULL) {\n" + " delete $name$_;\n" + " }\n" + " if ($name$ != NULL) {\n"); + if (SupportsArenas(descriptor_->message_type())) { + // If we're on an arena and the incoming message is not, simply Own() it + // rather than copy to the arena -- either way we need a heap dealloc, + // so we might as well defer it. Otherwise, if incoming message is on a + // different ownership domain (specific arena, or the heap) than we are, + // copy to our arena (or heap, as the case may be). + printer->Print(variables, + " $this_message$_slow_set_allocated_$name$(message_arena, " + "&$name$);\n"); + } else { + printer->Print(variables, + " if (message_arena != NULL) {\n" + " message_arena->Own($name$);\n" + " }\n"); + } + printer->Print(variables, + " }\n" + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + // TODO(dlj): move insertion points to message class. + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } else { + printer->Print(variables, + "template <class T>\n" + "inline $type$* $dependent_classname$::mutable_$name$() {\n" + " $set_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " if ($name$_ == NULL) {\n" + " $name$_ = new $dependent_typename$;\n" + " }\n" + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_;\n" + "}\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::$release_name$() {\n" + " $clear_hasbit$\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " $dependent_typename$* temp = $name$_;\n" + " $name$_ = NULL;\n" + " return temp;\n" + "}\n" + "template <class T>\n" + "inline void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" + " delete $name$_;\n"); + + if (SupportsArenas(descriptor_->message_type())) { + printer->Print(variables, + " if ($name$ != NULL && static_cast< $dependent_typename$* >($name$)" + "->GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" + " new_$name$->CopyFrom(*$name$);\n" + " $name$ = new_$name$;\n" + " }\n"); + } + + printer->Print(variables, + " $name$_ = $name$;\n" + " if ($name$) {\n" + " $set_hasbit$\n" + " } else {\n" + " $clear_hasbit$\n" + " }\n" + " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + "}\n"); + } } void MessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" + "$inline$const $type$& $classname$::$name$() const {\n" " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( @@ -206,19 +354,25 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", // Without. " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); + printer->Print(variables, "}\n"); + + if (dependent_field_) { + return; + } if (SupportsArenas(descriptor_)) { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" - " _slow_mutable_$name$();" + " _slow_mutable_$name$();\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" @@ -228,7 +382,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return temp;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$ " + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();\n" " if (message_arena == NULL) {\n" " delete $name$_;\n" @@ -260,8 +415,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" + "$inline$" + "$type$* $classname$::mutable_$name$() {\n" " $set_hasbit$\n" " if ($name$_ == NULL) {\n" " $name$_ = new $type$;\n" @@ -269,13 +424,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" " return $name$_;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" + "$inline$" + "$type$* $classname$::$release_name$() {\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" " return temp;\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" + "$inline$" + "void $classname$::set_allocated_$name$($type$* $name$) {\n" " delete $name$_;\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -301,15 +458,19 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (!HasFieldPresence(descriptor_->file())) { // If we don't have has-bits, message presence is indicated only by ptr != // NULL. Thus on clear, we need to delete the object. - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL && $name$_ != NULL) delete $name$_;\n" - "$name$_ = NULL;\n"); + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL && " + "$this_message$$name$_ != NULL) delete $this_message$$name$_;\n" + "$this_message$$name$_ = NULL;\n"); } else { - printer->Print(variables_, - "if ($name$_ != NULL) $name$_->$type$::Clear();\n"); + printer->Print(variables, + "if ($this_message$$name$_ != NULL) $this_message$$name$_->" + "$dependent_type$::Clear();\n"); } } @@ -370,79 +531,149 @@ GenerateByteSize(io::Printer* printer) const { MessageOneofFieldGenerator:: MessageOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : MessageFieldGenerator(descriptor, options) { + : MessageFieldGenerator(descriptor, options), + dependent_base_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {} + +void MessageOneofFieldGenerator:: +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Otherwise, the logic is the same as MessageFields. + if (!dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); + MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer); +} + +void MessageOneofFieldGenerator:: +GenerateGetterDeclaration(io::Printer* printer) const { + // Oneof field getters must be dependent as they call default_instance(). + // Unlike MessageField, this means there is no (non-dependent) getter to + // generate. + if (dependent_field_) { + return; + } + printer->Print(variables_, + "const $type$& $name$() const$deprecation$;\n"); +} + void MessageOneofFieldGenerator:: GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + if (!dependent_base_) { + return; + } + map<string, string> variables(variables_); + variables["inline"] = "inline "; + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = "reinterpret_cast<T*>(this)->"; + // Const message access is needed for the dependent getter. + variables["this_const_message"] = "reinterpret_cast<const T*>(this)->"; + variables["tmpl"] = "template <class T>\n"; + variables["field_member"] = variables["this_message"] + + variables["oneof_prefix"] + variables["name"] + + "_"; + InternalGenerateInlineAccessorDefinitions(variables, printer); } void MessageOneofFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const { + if (dependent_base_) { + return; + } map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + variables["inline"] = is_inline ? "inline " : ""; + variables["dependent_classname"] = variables["classname"]; + variables["this_message"] = ""; + variables["this_const_message"] = ""; + variables["tmpl"] = ""; + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + variables["dependent_type"] = variables["type"]; + InternalGenerateInlineAccessorDefinitions(variables, printer); +} + +void MessageOneofFieldGenerator:: +GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["field_member"] = + variables["oneof_prefix"] + variables["name"] + "_"; + + //printer->Print(variables, +} + +void MessageOneofFieldGenerator:: +InternalGenerateInlineAccessorDefinitions(const map<string, string>& variables, + io::Printer* printer) const { + printer->Print(variables, + "$tmpl$" + "$inline$ " + "const $type$& $dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$has_$name$()\n" + " ? *$this_const_message$$oneof_prefix$$name$_\n" + " : $dependent_type$::default_instance();\n" + "}\n"); + if (SupportsArenas(descriptor_)) { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n"); + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $field_member$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } else { printer->Print(variables, - " $oneof_prefix$$name$_ = \n" - " ::google::protobuf::Arena::Create< $type$ >(\n" - " GetArenaNoVirtual());\n"); + " $this_message$$oneof_prefix$$name$_ = \n" + " ::google::protobuf::Arena::Create< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n"); } printer->Print(variables, " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " if (GetArenaNoVirtual() != NULL) {\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" // N.B.: safe to use the underlying field pointer here because we are sure // that it is non-NULL (because has_$name$() returned true). - " $type$* temp = new $type$;\n" - " temp->MergeFrom(*$oneof_prefix$$name$_);\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = new $dependent_typename$;\n" + " temp->MergeFrom(*$field_member$);\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " }\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" - " return temp;\n" - " } else {\n" - " return NULL;\n" - " }\n" - "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { @@ -450,32 +681,42 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, // If incoming message is on the heap and we are on an arena, just Own() // it (see above). If it's on a different arena than we are or one of us // is on the heap, we make a copy to our arena/heap. - " if (GetArenaNoVirtual() != NULL &&\n" + " if ($this_message$GetArenaNoVirtual() != NULL &&\n" " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" - " } else if (GetArenaNoVirtual() !=\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" + " } else if ($this_message$GetArenaNoVirtual() !=\n" " ::google::protobuf::Arena::GetArena($name$)) {\n" - " $type$* new_$name$ = \n" - " ::google::protobuf::Arena::CreateMessage< $type$ >(\n" - " GetArenaNoVirtual());\n" + " $dependent_typename$* new_$name$ = \n" + " ::google::protobuf::Arena::CreateMessage< $dependent_typename$ >(\n" + " $this_message$GetArenaNoVirtual());\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } else { printer->Print(variables, - " if (GetArenaNoVirtual() != NULL) {\n" - " GetArenaNoVirtual()->Own($name$);\n" + " if ($this_message$GetArenaNoVirtual() != NULL) {\n" + " $this_message$GetArenaNoVirtual()->Own($name$);\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" - "$inline$ void $classname$::unsafe_arena_set_allocated_$name$(" - "$type$* $name$) {\n" + "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + " if (has_$name$()) {\n" + " clear_has_$oneof_name$();\n" + " $type$* temp = $oneof_prefix$$name$_;\n" + " $oneof_prefix$$name$_ = NULL;\n" + " return temp;\n" + " } else {\n" + " return NULL;\n" + " }\n" + "}\n" + "$inline$ void $classname$::unsafe_arena_set_allocated_$name$" + "($type$* $name$) {\n" // We rely on the oneof clear method to free the earlier contents of this // oneof. We can directly use the pointer we're given to set the new // value. @@ -489,44 +730,47 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n"); } else { printer->Print(variables, - "$inline$ const $type$& $classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return has_$name$() ? *$oneof_prefix$$name$_\n" - " : $type$::default_instance();\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$() {\n" - " if (!has_$name$()) {\n" - " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = new $type$;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::mutable_$name$() {\n" + " if (!$this_message$has_$name$()) {\n" + " $this_message$clear_$oneof_name$();\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = new $dependent_typename$;\n" " }\n" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $oneof_prefix$$name$_;\n" + " return $field_member$;\n" "}\n" - "$inline$ $type$* $classname$::$release_name$() {\n" - " if (has_$name$()) {\n" - " clear_has_$oneof_name$();\n" - " $type$* temp = $oneof_prefix$$name$_;\n" - " $oneof_prefix$$name$_ = NULL;\n" + "$tmpl$" + "$inline$" + "$type$* $dependent_classname$::$release_name$() {\n" + " if ($this_message$has_$name$()) {\n" + " $this_message$clear_has_$oneof_name$();\n" + " $dependent_typename$* temp = $field_member$;\n" + " $field_member$ = NULL;\n" " return temp;\n" " } else {\n" " return NULL;\n" " }\n" "}\n" - "$inline$ void $classname$::set_allocated_$name$($type$* $name$) {\n" - " clear_$oneof_name$();\n" + "$tmpl$" + "$inline$" + "void $dependent_classname$::" + "set_allocated_$name$($type$* $name$) {\n" + " $this_message$clear_$oneof_name$();\n" " if ($name$) {\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables, - " if ($name$->GetArena() != NULL) {\n" - " $type$* new_$name$ = new $type$;\n" + " if (static_cast< $dependent_typename$*>($name$)->" + "GetArena() != NULL) {\n" + " $dependent_typename$* new_$name$ = new $dependent_typename$;\n" " new_$name$->CopyFrom(*$name$);\n" " $name$ = new_$name$;\n" " }\n"); } printer->Print(variables, - " set_has_$name$();\n" - " $oneof_prefix$$name$_ = $name$;\n" + " $this_message$set_has_$name$();\n" + " $field_member$ = $name$;\n" " }\n" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -535,14 +779,16 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void MessageOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "if (GetArenaNoVirtual() == NULL) {\n" - " delete $oneof_prefix$$name$_;\n" + printer->Print(variables, + "if ($this_message$GetArenaNoVirtual() == NULL) {\n" + " delete $this_message$$oneof_prefix$$name$_;\n" "}\n"); } else { - printer->Print(variables_, - "delete $oneof_prefix$$name$_;\n"); + printer->Print(variables, + "delete $this_message$$oneof_prefix$$name$_;\n"); } } @@ -562,7 +808,9 @@ GenerateConstructorCode(io::Printer* printer) const { RepeatedMessageFieldGenerator:: RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + dependent_getter_(dependent_field_ && options.safe_boundary_check) { SetMessageVariables(descriptor, &variables_, options); } @@ -575,60 +823,160 @@ GeneratePrivateMembers(io::Printer* printer) const { } void RepeatedMessageFieldGenerator:: -GenerateDependentAccessorDeclarations(io::Printer* printer) const { -} - -void RepeatedMessageFieldGenerator:: -GenerateAccessorDeclarations(io::Printer* printer) const { +InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n" "$type$* mutable_$name$(int index)$deprecation$;\n" "$type$* add_$name$()$deprecation$;\n"); + if (dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n" "::google::protobuf::RepeatedPtrField< $type$ >*\n" " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: -GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { +GenerateDependentAccessorDeclarations(io::Printer* printer) const { + if (dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } } void RepeatedMessageFieldGenerator:: -GenerateInlineAccessorDefinitions(io::Printer* printer, - bool is_inline) const { +GenerateAccessorDeclarations(io::Printer* printer) const { + if (!dependent_getter_) { + printer->Print(variables_, + "const $type$& $name$(int index) const$deprecation$;\n"); + } + if (!dependent_field_) { + InternalGenerateTypeDependentAccessorDeclarations(printer); + } + if (!dependent_getter_) { + printer->Print(variables_, + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n"); + } +} + +void RepeatedMessageFieldGenerator:: +GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { + if (!dependent_field_) { + return; + } map<string, string> variables(variables_); - variables["inline"] = is_inline ? "inline" : ""; + // For the CRTP base class, all mutation methods are dependent, and so + // they must be in the header. + variables["dependent_classname"] = + DependentBaseClassTemplateName(descriptor_->containing_type()) + "<T>"; + variables["this_message"] = DependentBaseDownCast(); + variables["this_const_message"] = DependentBaseConstDownCast(); + + if (dependent_getter_) { + printer->Print(variables, + "template <class T>\n" + "inline const $type$& $dependent_classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $this_const_message$$name$_.$cppget$(index);\n" + "}\n"); + } + + // Generate per-element accessors: printer->Print(variables, - "$inline$ const $type$& $classname$::$name$(int index) const {\n" - " // @@protoc_insertion_point(field_get:$full_name$)\n" - " return $name$_.$cppget$(index);\n" - "}\n" - "$inline$ $type$* $classname$::mutable_$name$(int index) {\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" + " return $this_message$$name$_.Mutable(index);\n" "}\n" - "$inline$ $type$* $classname$::add_$name$() {\n" + "template <class T>\n" + "inline $type$* $dependent_classname$::add_$name$() {\n" " // @@protoc_insertion_point(field_add:$full_name$)\n" - " return $name$_.Add();\n" + " return $this_message$$name$_.Add();\n" "}\n"); + + + if (dependent_getter_) { + printer->Print(variables, + "template <class T>\n" + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$dependent_classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $this_const_message$$name$_;\n" + "}\n"); + } + + // Generate mutable access to the entire list: printer->Print(variables, - "$inline$ const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" - "}\n" - "$inline$ ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" + "template <class T>\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$dependent_classname$::mutable_$name$() {\n" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" + " return &$this_message$$name$_;\n" "}\n"); } void RepeatedMessageFieldGenerator:: +GenerateInlineAccessorDefinitions(io::Printer* printer, + bool is_inline) const { + map<string, string> variables(variables_); + variables["inline"] = is_inline ? "inline " : ""; + + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const $type$& $classname$::$name$(int index) const {\n" + " // @@protoc_insertion_point(field_get:$full_name$)\n" + " return $name$_.$cppget$(index);\n" + "}\n"); + } + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "$type$* $classname$::mutable_$name$(int index) {\n" + // TODO(dlj): move insertion points + " // @@protoc_insertion_point(field_mutable:$full_name$)\n" + " return $name$_.Mutable(index);\n" + "}\n" + "$inline$" + "$type$* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add:$full_name$)\n" + " return $name$_.Add();\n" + "}\n"); + } + + + if (!dependent_field_) { + printer->Print(variables, + "$inline$" + "::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" + " return &$name$_;\n" + "}\n"); + } + if (!dependent_getter_) { + printer->Print(variables, + "$inline$" + "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " // @@protoc_insertion_point(field_list:$full_name$)\n" + " return $name$_;\n" + "}\n"); + } +} + +void RepeatedMessageFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { - printer->Print(variables_, "$name$_.Clear();\n"); + map<string, string> variables(variables_); + variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; + printer->Print(variables, "$this_message$$name$_.Clear();\n"); } void RepeatedMessageFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 9ddf9643..35efd0fa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -68,6 +68,11 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; protected: + void GenerateArenaManipulationCode(const map<string, string>& variables, + io::Printer* printer) const; + + virtual void GenerateGetterDeclaration(io::Printer* printer) const; + const FieldDescriptor* descriptor_; const bool dependent_field_; map<string, string> variables_; @@ -83,15 +88,23 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- + void GenerateDependentAccessorDeclarations(io::Printer* printer) const; void GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const; void GenerateInlineAccessorDefinitions(io::Printer* printer, bool is_inline) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {} + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; void GenerateClearingCode(io::Printer* printer) const; void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; + protected: + void GenerateGetterDeclaration(io::Printer* printer) const; + private: + void InternalGenerateInlineAccessorDefinitions( + const map<string, string>& variables, io::Printer* printer) const; + + const bool dependent_base_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); }; @@ -118,7 +131,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const; private: + void InternalGenerateTypeDependentAccessorDeclarations( + io::Printer* printer) const; + const FieldDescriptor* descriptor_; + const bool dependent_field_; + const bool dependent_getter_; map<string, string> variables_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 1a3896a1..6b0821a6 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -367,25 +367,19 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "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"); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, true, variables_, + "this->$name$().data(), this->$name$().length(),\n", printer); } } void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { - 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::SERIALIZE,\n" - " \"$full_name$\");\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, false, variables_, + "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, "::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n" @@ -394,13 +388,10 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { void StringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { - 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::SERIALIZE,\n" - " \"$full_name$\");\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, false, variables_, + "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, "target =\n" @@ -421,7 +412,8 @@ GenerateByteSize(io::Printer* printer) const { StringOneofFieldGenerator:: StringOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : StringFieldGenerator(descriptor, options) { + : StringFieldGenerator(descriptor, options), + dependent_field_(options.proto_h) { SetCommonOneofFieldVariables(descriptor, &variables_); } @@ -604,13 +596,29 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, void StringOneofFieldGenerator:: GenerateClearingCode(io::Printer* printer) const { + map<string, string> variables(variables_); + if (dependent_field_) { + variables["this_message"] = DependentBaseDownCast(); + // This clearing code may be in the dependent base class. If the default + // value is an empty string, then the $default_variable$ is a global + // singleton. If the default is not empty, we need to down-cast to get the + // default value's global singleton instance. See SetStringVariables() for + // possible values of default_variable. + if (!descriptor_->default_value_string().empty()) { + variables["default_variable"] = + DependentBaseDownCast() + variables["default_variable"]; + } + } else { + variables["this_message"] = ""; + } if (SupportsArenas(descriptor_)) { - printer->Print(variables_, - "$oneof_prefix$$name$_.Destroy($default_variable$,\n" - " GetArenaNoVirtual());\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_.Destroy($default_variable$,\n" + " $this_message$GetArenaNoVirtual());\n"); } else { - printer->Print(variables_, - "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"); + printer->Print(variables, + "$this_message$$oneof_prefix$$name$_." + "DestroyNoArena($default_variable$);\n"); } } @@ -648,13 +656,10 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "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"); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, true, variables_, + "this->$name$().data(), this->$name$().length(),\n", printer); } } @@ -664,7 +669,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { RepeatedStringFieldGenerator:: RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : descriptor_(descriptor) { + : descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } @@ -800,14 +805,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" " input, this->add_$name$()));\n"); - if (HasUtf8Verification(descriptor_->file()) && - descriptor_->type() == FieldDescriptor::TYPE_STRING) { - printer->Print(variables_, - "::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"); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, true, variables_, + "this->$name$(this->$name$_size() - 1).data(),\n" + "this->$name$(this->$name$_size() - 1).length(),\n", + printer); } } @@ -815,14 +818,13 @@ void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (HasUtf8Verification(descriptor_->file()) && - descriptor_->type() == FieldDescriptor::TYPE_STRING) { - printer->Print(variables_, - "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" - " this->$name$(i).data(), this->$name$(i).length(),\n" - " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$full_name$\");\n"); + printer->Indent(); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, false, variables_, + "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } + printer->Outdent(); printer->Print(variables_, " ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" " $number$, this->$name$(i), output);\n" @@ -833,14 +835,13 @@ void RepeatedStringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n"); - if (HasUtf8Verification(descriptor_->file()) && - descriptor_->type() == FieldDescriptor::TYPE_STRING) { - printer->Print(variables_, - " ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n" - " this->$name$(i).data(), this->$name$(i).length(),\n" - " ::google::protobuf::internal::WireFormat::SERIALIZE,\n" - " \"$full_name$\");\n"); + printer->Indent(); + if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { + GenerateUtf8CheckCodeForString( + descriptor_, false, variables_, + "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } + printer->Outdent(); printer->Print(variables_, " target = ::google::protobuf::internal::WireFormatLite::\n" " Write$declared_type$ToArray($number$, this->$name$(i), target);\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index d1f19cd9..616e2067 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -93,6 +93,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { void GenerateMergeFromCodedStream(io::Printer* printer) const; private: + const bool dependent_field_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index bd1c0fde..7840cfaf 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -55,7 +55,9 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_optimize_for.pb.h> #include <google/protobuf/unittest_embed_optimize_for.pb.h> +#if !defined(_MSC_VER) // Too large for visual studio to compile #include <google/protobuf/unittest_enormous_descriptor.pb.h> +#endif #include <google/protobuf/unittest_no_generic_services.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> @@ -67,7 +69,9 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/dynamic_message.h> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> @@ -131,6 +135,7 @@ TEST(GeneratedDescriptorTest, IdenticalDescriptors) { generated_decsriptor_proto.DebugString()); } +#if !defined(_MSC_VER) // Test that generated code has proper descriptors: // Touch a descriptor generated from an enormous message to validate special // handling for descriptors exceeding the C++ standard's recommended minimum @@ -141,6 +146,7 @@ TEST(GeneratedDescriptorTest, EnormousDescriptor) { EXPECT_TRUE(generated_descriptor != NULL); } +#endif #endif // !PROTOBUF_TEST_NO_DESCRIPTORS diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index 43eb0ed5..33c9328f 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -44,6 +44,7 @@ #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/map_util.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 0353b607..8a09f3a8 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -181,8 +181,8 @@ void EnumGenerator::Generate(io::Printer* printer) { " internalGetValueMap() {\n" " return internalValueMap;\n" "}\n" - "private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" - " internalValueMap =\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" " return $classname$.valueOf(number);\n" diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 39318a19..558da968 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 697a07a7..2c3608c2 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc new file mode 100644 index 00000000..62186386 --- /dev/null +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -0,0 +1,226 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/java/java_context.h> +#include <google/protobuf/compiler/java/java_enum_lite.h> +#include <google/protobuf/compiler/java/java_doc_comment.h> +#include <google/protobuf/compiler/java/java_helpers.h> +#include <google/protobuf/compiler/java/java_name_resolver.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +namespace { +bool EnumHasCustomOptions(const EnumDescriptor* descriptor) { + if (descriptor->options().unknown_fields().field_count() > 0) return true; + for (int i = 0; i < descriptor->value_count(); ++i) { + const EnumValueDescriptor* value = descriptor->value(i); + if (value->options().unknown_fields().field_count() > 0) return true; + } + return false; +} +} // namespace + +EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context) + : descriptor_(descriptor), immutable_api_(immutable_api), + name_resolver_(context->GetNameResolver()) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumLiteGenerator::~EnumLiteGenerator() {} + +void EnumLiteGenerator::Generate(io::Printer* printer) { + WriteEnumDocComment(printer, descriptor_); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.ProtocolMessageEnum {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "public enum $classname$\n" + " implements com.google.protobuf.Internal.EnumLite {\n", + "classname", descriptor_->name()); + } + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + map<string, string> vars; + vars["name"] = canonical_values_[i]->name(); + vars["index"] = SimpleItoa(canonical_values_[i]->index()); + vars["number"] = SimpleItoa(canonical_values_[i]->number()); + WriteEnumValueDocComment(printer, canonical_values_[i]); + if (canonical_values_[i]->options().deprecated()) { + printer->Print("@java.lang.Deprecated\n"); + } + printer->Print(vars, + "$name$($index$, $number$),\n"); + } + + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } + + printer->Print( + ";\n" + "\n"); + + // ----------------------------------------------------------------- + + for (int i = 0; i < aliases_.size(); i++) { + map<string, string> vars; + vars["classname"] = descriptor_->name(); + vars["name"] = aliases_[i].value->name(); + vars["canonical_name"] = aliases_[i].canonical_value->name(); + WriteEnumValueDocComment(printer, aliases_[i].value); + printer->Print(vars, + "public static final $classname$ $name$ = $canonical_name$;\n"); + } + + for (int i = 0; i < descriptor_->value_count(); i++) { + map<string, string> vars; + vars["name"] = descriptor_->value(i)->name(); + vars["number"] = SimpleItoa(descriptor_->value(i)->number()); + WriteEnumValueDocComment(printer, descriptor_->value(i)); + printer->Print(vars, + "public static final int $name$_VALUE = $number$;\n"); + } + printer->Print("\n"); + + // ----------------------------------------------------------------- + + printer->Print( + "\n" + "public final int getNumber() {\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } + printer->Print( + " return value;\n" + "}\n" + "\n" + "public static $classname$ valueOf(int value) {\n" + " switch (value) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print( + "case $number$: return $name$;\n", + "name", canonical_values_[i]->name(), + "number", SimpleItoa(canonical_values_[i]->number())); + } + + printer->Outdent(); + printer->Outdent(); + printer->Print( + " default: return null;\n" + " }\n" + "}\n" + "\n" + "public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" + " internalGetValueMap() {\n" + " return internalValueMap;\n" + "}\n" + "private static final com.google.protobuf.Internal.EnumLiteMap<\n" + " $classname$> internalValueMap =\n" + " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" + " public $classname$ findValueByNumber(int number) {\n" + " return $classname$.valueOf(number);\n" + " }\n" + " };\n" + "\n", + "classname", descriptor_->name()); + + printer->Print( + "private final int value;\n\n" + "private $classname$(int index, int value) {\n", + "classname", descriptor_->name()); + printer->Print( + " this.value = value;\n" + "}\n"); + + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + + printer->Outdent(); + printer->Print("}\n\n"); +} + +bool EnumLiteGenerator::CanUseEnumValues() { + if (canonical_values_.size() != descriptor_->value_count()) { + return false; + } + for (int i = 0; i < descriptor_->value_count(); i++) { + if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { + return false; + } + } + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h new file mode 100644 index 00000000..ee2f5f7a --- /dev/null +++ b/src/google/protobuf/compiler/java/java_enum_lite.h @@ -0,0 +1,99 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ + +#include <string> +#include <vector> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + namespace compiler { + namespace java { + class Context; // context.h + class ClassNameResolver; // name_resolver.h + } + } + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace java { + +class EnumLiteGenerator { + public: + explicit EnumLiteGenerator(const EnumDescriptor* descriptor, + bool immutable_api, + Context* context); + ~EnumLiteGenerator(); + + void Generate(io::Printer* printer); + + private: + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same numeric + // value. Java, however, does not allow multiple enum constants to be + // considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector<Alias> aliases_; + + bool immutable_api_; + + Context* context_; + ClassNameResolver* name_resolver_; + + bool CanUseEnumValues(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index 3f0fa11f..c5434767 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -39,6 +39,7 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_enum_field.h> diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 00f3c601..0e24da24 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -44,6 +44,7 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/logging.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 96d2545f..5392d6d7 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -310,6 +310,12 @@ inline bool SupportFieldPresence(const FileDescriptor* descriptor) { return descriptor->syntax() != FileDescriptor::SYNTAX_PROTO3; } +// Whether generate classes expose public PARSER instances. +inline bool ExposePublicParser(const FileDescriptor* descriptor) { + // TODO(liujisi): Mark the PARSER private in 3.1.x releases. + return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2; +} + // 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. @@ -332,6 +338,15 @@ inline bool PreserveUnknownFields(const Descriptor* descriptor) { return descriptor->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } +inline bool IsAnyMessage(const Descriptor* descriptor) { + return descriptor->full_name() == "google.protobuf.Any"; +} + +inline bool CheckUtf8(const FieldDescriptor* descriptor) { + return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 || + descriptor->file()->options().java_string_check_utf8(); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 44b86cd7..3e035c89 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -314,6 +314,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " internalGetMutable$capitalized_name$().getMutableMap(),\n" " $name$ValueConverter);\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -331,6 +339,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$Value() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -346,6 +362,14 @@ GenerateBuilderMembers(io::Printer* printer) const { "getMutable$capitalized_name$() {\n" " return internalGetMutable$capitalized_name$().getMutableMap();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index cd1698f0..4fe656d3 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -303,6 +303,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$(\n" + " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); if (SupportUnknownEnumValue(descriptor_->file())) { WriteFieldDocComment(printer, descriptor_); printer->Print( @@ -321,6 +329,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$Value();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "$deprecation$public Builder putAll$capitalized_name$Value(\n" + " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n" + " getMutable$capitalized_name$Value().putAll(values);\n" + " return this;\n" + "}\n"); } } else { WriteFieldDocComment(printer, descriptor_); @@ -337,6 +353,14 @@ GenerateBuilderMembers(io::Printer* printer) const { " copyOnWrite();\n" " return instance.getMutable$capitalized_name$();\n" "}\n"); + WriteFieldDocComment(printer, descriptor_); + printer->Print( + variables_, + "public Builder putAll$capitalized_name$(\n" + " java.util.Map<$type_parameters$> values) {\n" + " getMutable$capitalized_name$().putAll(values);\n" + " return this;\n" + "}\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 09b0fd94..19ba0707 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -255,6 +255,18 @@ void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName( + descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -292,8 +304,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { " com.google.protobuf.GeneratedMessage implements\n" " $extra_interfaces$\n" " $classname$OrBuilder {\n"); - - builder_type = "com.google.protobuf.GeneratedMessage.Builder"; + builder_type = "com.google.protobuf.GeneratedMessage.Builder<?>"; } printer->Indent(); // Using builder_type, instead of Builder, prevents the Builder class from @@ -435,6 +446,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "\n"); } + if (IsAnyMessage(descriptor_)) { + GenerateAnyMethods(printer); + } + // Fields for (int i = 0; i < descriptor_->field_count(); i++) { printer->Print("public static final int $constant_name$ = $number$;\n", @@ -578,9 +593,8 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Print( "}\n" "\n" - "private int memoizedSerializedSize = -1;\n" "public int getSerializedSize() {\n" - " int size = memoizedSerializedSize;\n" + " int size = memoizedSize;\n" " if (size != -1) return size;\n" "\n" " size = 0;\n"); @@ -612,7 +626,7 @@ GenerateMessageSerializationMethods(io::Printer* printer) { printer->Outdent(); printer->Print( - " memoizedSerializedSize = size;\n" + " memoizedSize = size;\n" " return size;\n" "}\n" "\n"); @@ -948,22 +962,58 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("boolean result = true;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "result = result && (has$name$() == other.has$name$());\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print( + "}\n"); + } + } + } + + // Compare oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "result = result && get$oneof_capitalized_name$Case().equals(\n" + " other.get$oneof_capitalized_name$Case());\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Print( + "if (!result) return false;\n" + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { + field_generators_.get(field).GenerateEqualsCode(printer); + printer->Print("break;\n"); printer->Outdent(); - printer->Print( - "}\n"); } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); } + if (PreserveUnknownFields(descriptor_)) { // Always consider unknown fields for equality. This will sometimes return // false for non-canonical ordering when running in LITE_RUNTIME but it's @@ -1198,8 +1248,11 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== 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", + "$visibility$ static final com.google.protobuf.Parser<$classname$>\n" + " PARSER = new com.google.protobuf.AbstractParser<$classname$>() {\n", + "visibility", + ExposePublicParser(descriptor_->file()) ? "@java.lang.Deprecated public" + : "private", "classname", descriptor_->name()); printer->Indent(); printer->Print( @@ -1250,6 +1303,10 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { "\n"); printer->Print( + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return PARSER;\n" + "}\n" + "\n" "@java.lang.Override\n" "public com.google.protobuf.Parser<$classname$> getParserForType() {\n" " return PARSER;\n" @@ -1269,6 +1326,50 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { } +void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { + printer->Print( + "private static String getTypeUrl(\n" + " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" + " return \"type.googleapis.com/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "public static <T extends com.google.protobuf.Message> Any pack(\n" + " T message) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "public <T extends com.google.protobuf.Message> boolean is(\n" + " java.lang.Class<T> clazz) {\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " return getTypeUrl().equals(\n" + " getTypeUrl(defaultInstance.getDescriptorForType()));\n" + "}\n" + "\n" + "private volatile com.google.protobuf.Message cachedUnpackValue;\n" + "\n" + "public <T extends com.google.protobuf.Message> T unpack(\n" + " java.lang.Class<T> clazz)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n" + " if (!is(clazz)) {\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " \"Type of the Any messsage does not match the given class.\");\n" + " }\n" + " if (cachedUnpackValue != null) {\n" + " return (T) cachedUnpackValue;\n" + " }\n" + " T defaultInstance =\n" + " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" + " T result = (T) defaultInstance.getParserForType()\n" + " .parseFrom(getValue());\n" + " cachedUnpackValue = result;\n" + " return result;\n" + "}\n"); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index c3c37765..be5bfb07 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -122,6 +122,7 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); void GenerateParsingConstructor(io::Printer* printer); + void GenerateAnyMethods(io::Printer* printer); Context* context_; ClassNameResolver* name_resolver_; diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b180b4a7..b5f8e626 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -452,11 +452,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -736,11 +736,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -1232,11 +1233,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 8332202c..356520ec 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -310,11 +310,11 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -521,11 +521,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$oneof_name$_ = input.readGroup($number$, $type$.PARSER,\n" + "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n" " extensionRegistry);\n"); } else { printer->Print(variables_, - "$oneof_name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); + "$oneof_name$_ =\n" + " input.readMessage($type$.parser(), extensionRegistry);\n"); } printer->Print(variables_, @@ -885,11 +886,12 @@ GenerateParsingCode(io::Printer* printer) const { if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, - "$name$_.add(input.readGroup($number$, $type$.PARSER,\n" + "$name$_.add(input.readGroup($number$, $type$.parser(),\n" " extensionRegistry));\n"); } else { printer->Print(variables_, - "$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); + "$name$_.add(\n" + " input.readMessage($type$.parser(), extensionRegistry));\n"); } } diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 3accee92..8b6c75b8 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -45,7 +45,7 @@ #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> -#include <google/protobuf/compiler/java/java_enum.h> +#include <google/protobuf/compiler/java/java_enum_lite.h> #include <google/protobuf/compiler/java/java_extension.h> #include <google/protobuf/compiler/java/java_generator_factory.h> #include <google/protobuf/compiler/java/java_helpers.h> @@ -143,6 +143,17 @@ void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) { field_generators_.get(descriptor_->field(i)) .GenerateInterfaceMembers(printer); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "\n" + "public $classname$.$oneof_capitalized_name$Case " + "get$oneof_capitalized_name$Case();\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name, + "classname", + context_->GetNameResolver()->GetImmutableClassName(descriptor_)); + } printer->Outdent(); printer->Print("}\n"); @@ -190,7 +201,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator(descriptor_->enum_type(i), true, context_) + EnumLiteGenerator(descriptor_->enum_type(i), true, context_) .Generate(printer); } @@ -321,12 +332,12 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "protected final Object dynamicMethod(\n" " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" - " Object... args) {\n" + " Object arg0, Object arg1) {\n" " switch (method) {\n" " case PARSE_PARTIAL_FROM: {\n" " return new $classname$(" - " (com.google.protobuf.CodedInputStream) args[0],\n" - " (com.google.protobuf.ExtensionRegistryLite) args[1]);\n" + " (com.google.protobuf.CodedInputStream) arg0,\n" + " (com.google.protobuf.ExtensionRegistryLite) arg1);\n" " }\n" " case NEW_INSTANCE: {\n" " return new $classname$(\n" @@ -370,7 +381,25 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Outdent(); printer->Print( - "}\n"); + "}\n" + "case GET_DEFAULT_INSTANCE: {\n" + " return DEFAULT_INSTANCE;\n" + "}\n" + "case GET_PARSER: {\n" + // Generally one would use the lazy initialization holder pattern for + // manipulating static fields but that has exceptional cost on Android as + // it will generate an extra class for every message. Instead, use the + // double-check locking pattern which works just as well. + " if (PARSER == null) {" + " synchronized ($classname$.class) {\n" + " if (PARSER == null) {\n" + " PARSER = new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" + " }\n" + " }\n" + " }\n" + " return PARSER;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Outdent(); printer->Outdent(); @@ -413,18 +442,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateParser(printer); - // LITE_RUNTIME uses this to implement the *ForType methods at the - // GeneratedMessageLite level. - printer->Print( - "static {\n" - " com.google.protobuf.GeneratedMessageLite.onLoad(\n" - " $classname$.class, new com.google.protobuf.GeneratedMessageLite\n" - " .PrototypeHolder<$classname$, Builder>(\n" - " DEFAULT_INSTANCE, PARSER));" - "}\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - // Extensions must be declared after the DEFAULT_INSTANCE is initialized // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. @@ -554,54 +571,54 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data);\n" + " return parser().parseFrom(data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return PARSER.parseFrom(data, extensionRegistry);\n" + " return parser().parseFrom(data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input);\n" + " return parser().parseDelimitedFrom(input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseDelimitedFrom(input, extensionRegistry);\n" + " return parser().parseDelimitedFrom(input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input);\n" + " return parser().parseFrom(input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return PARSER.parseFrom(input, extensionRegistry);\n" + " return parser().parseFrom(input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -652,7 +669,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( "if (isInitialized == 1) return DEFAULT_INSTANCE;\n" "if (isInitialized == 0) return null;\n" "\n" - "boolean shouldMemoize = ((Boolean) args[0]).booleanValue();\n"); + "boolean shouldMemoize = ((Boolean) arg0).booleanValue();\n"); // Check that all required fields in this message are set. // TODO(kenton): We can optimize this when we switch to putting all the @@ -778,7 +795,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( .GenerateDynamicMethodMakeImmutableCode(printer); } printer->Print( - "return null;"); + "return null;\n"); } // =================================================================== @@ -786,7 +803,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( io::Printer* printer) { printer->Print( - "return new Builder();"); + "return new Builder();\n"); } // =================================================================== @@ -796,9 +813,8 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( printer->Print( // Optimization: If other is the default instance, we know none of its // fields are set so we can skip the merge. - "Object arg = args[0];\n" - "if (arg == $classname$.getDefaultInstance()) return this;\n" - "$classname$ other = ($classname$) arg;\n", + "if (arg0 == $classname$.getDefaultInstance()) return this;\n" + "$classname$ other = ($classname$) arg0;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -1151,9 +1167,11 @@ GenerateParsingConstructor(io::Printer* printer) { // =================================================================== void ImmutableMessageLiteGenerator::GenerateParser(io::Printer* printer) { printer->Print( - "public static final com.google.protobuf.Parser<$classname$> PARSER =\n" - " new DefaultInstanceBasedParser(DEFAULT_INSTANCE);\n" - "\n", + "private static volatile com.google.protobuf.Parser<$classname$> PARSER;\n" + "\n" + "public static com.google.protobuf.Parser<$classname$> parser() {\n" + " return DEFAULT_INSTANCE.getParserForType();\n" + "}\n", "classname", descriptor_->name()); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 7bebe12a..178bbe19 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 217ff9b6..392333b8 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -35,6 +35,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc index 7baead15..11bfc12d 100644 --- a/src/google/protobuf/compiler/java/java_service.cc +++ b/src/google/protobuf/compiler/java/java_service.cc @@ -39,7 +39,6 @@ #include <google/protobuf/compiler/java/java_helpers.h> #include <google/protobuf/compiler/java/java_name_resolver.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/strutil.h> namespace google { diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 68e863cc..72ebaeca 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -36,6 +36,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> @@ -77,6 +78,10 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, " if (value == null) {\n" " throw new NullPointerException();\n" " }\n"; + (*variables)["writeString"] = + "com.google.protobuf.GeneratedMessage.writeString"; + (*variables)["computeStringSize"] = + "com.google.protobuf.GeneratedMessage.computeStringSize"; // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported // by the proto compiler @@ -126,10 +131,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, GenerateSetBitToLocal(messageBitIndex); } -bool CheckUtf8(const FieldDescriptor* descriptor) { - return descriptor->file()->options().java_string_check_utf8(); -} - } // namespace // =================================================================== @@ -433,7 +434,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $name$_);\n" "}\n"); } @@ -441,8 +442,7 @@ void ImmutableStringFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($is_field_present_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $name$_);\n" "}\n"); } @@ -689,7 +689,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializationCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " $writeString$(output, $number$, $oneof_name$_);\n" "}\n"); } @@ -697,8 +697,7 @@ void ImmutableStringOneofFieldGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " size += $computeStringSize$($number$, $oneof_name$_);\n" "}\n"); } @@ -1007,12 +1006,12 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " writeStringNoTag(output, $name$_.getRaw(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " $writeString$(output, $number$, $name$_.getRaw(i));\n" "}\n"); } } @@ -1026,8 +1025,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " dataSize += computeStringSizeNoTag($name$_.getRaw(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index 51bb245c..092e3c29 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -36,6 +36,7 @@ #include <map> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/java/java_context.h> #include <google/protobuf/compiler/java/java_doc_comment.h> @@ -64,7 +65,8 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, map<string, string>* variables) { SetCommonFieldVariables(descriptor, info, variables); - (*variables)["empty_list"] = "emptyLazyStringArrayList()"; + (*variables)["empty_list"] = + "com.google.protobuf.GeneratedMessageLite.emptyProtobufList()"; (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_init"] = @@ -101,7 +103,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_message"] = ""; (*variables)["is_field_present_message"] = - "!get" + (*variables)["capitalized_name"] + "Bytes().isEmpty()"; + "!get" + (*variables)["capitalized_name"] + ".isEmpty()"; } // For repeated builders, the underlying list tracks mutability state. @@ -113,10 +115,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, GenerateSetBitToLocal(messageBitIndex); } -bool CheckUtf8(const FieldDescriptor* descriptor) { - return descriptor->file()->options().java_string_check_utf8(); -} - } // namespace // =================================================================== @@ -144,8 +142,9 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { return 0; } -// A note about how strings are handled. This code used to just store a String -// in the Message. This had two issues: +// A note about how strings are handled. In the SPEED and CODE_SIZE runtimes, +// strings are not stored as java.lang.String in the Message because of two +// issues: // // 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded // strings, but rather fields that were raw bytes incorrectly marked @@ -160,22 +159,14 @@ int ImmutableStringFieldLiteGenerator::GetNumBitsForBuilder() const { // it many cases, the field is never even read by the application code. This // avoids unnecessary conversions in the common use cases. // -// So now, the field for String is maintained as an Object reference which can -// either store a String or a ByteString. The code uses an instanceof check -// to see which one it has and converts to the other one if needed. It remembers -// the last value requested (in a thread safe manner) as this is most likely -// the one needed next. The thread safety is such that if two threads both -// convert the field because the changes made by each thread were not visible to -// the other, they may cause a conversion to happen more times than would -// otherwise be necessary. This was deemed better than adding synchronization -// overhead. It will not cause any corruption issues or affect the behavior of -// the API. The instanceof check is also highly optimized in the JVM and we -// decided it was better to reduce the memory overhead by not having two -// separate fields but rather use dynamic type checking. -// -// For single fields, the logic for this is done inside the generated code. For -// repeated fields, the logic is done in LazyStringArrayList and -// UnmodifiableLazyStringList. +// In the LITE_RUNTIME, we store strings as java.lang.String because we assume +// that the users of this runtime are not subject to proto1 constraints and are +// running code on devices that are user facing. That is, the developers are +// properly incentivized to only fetch the data they need to read and wish to +// reduce the number of allocations incurred when running on a user's device. + +// TODO(dweis): Consider dropping all of the *Bytes() methods. They really +// shouldn't be necessary or used on devices. void ImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { @@ -195,7 +186,7 @@ GenerateInterfaceMembers(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private java.lang.Object $name$_;\n"); + "private java.lang.String $name$_;\n"); PrintExtraFieldInfo(variables_, printer); if (SupportFieldPresence(descriptor_->file())) { @@ -209,40 +200,13 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " $name$_ = s;\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8()) {\n" - " $name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" - " }\n" + " return $name$_;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref = $name$_;\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " $name$_ = b;\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" - " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8($name$_);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -273,7 +237,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_has_field_bit_message$\n" - " $name$_ = value;\n" + " $name$_ = value.toStringUtf8();\n" "}\n"); } @@ -368,7 +332,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -377,11 +341,6 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_has_field_bit_message$\n" - "$name$_ = bs;\n"); } } @@ -392,18 +351,24 @@ GenerateParsingDoneCode(io::Printer* printer) const { void ImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($is_field_present_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -458,51 +423,22 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public java.lang.String get$capitalized_name$() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " return (java.lang.String) ref;\n" - " } else {\n" - " com.google.protobuf.ByteString bs = \n" - " (com.google.protobuf.ByteString) ref;\n" - " java.lang.String s = bs.toStringUtf8();\n"); - if (CheckUtf8(descriptor_)) { - printer->Print(variables_, - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } else { - printer->Print(variables_, - " if (bs.isValidUtf8() && ($has_oneof_case_message$)) {\n" - " $oneof_name$_ = s;\n" - " }\n"); - } - printer->Print(variables_, - " return s;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return ref;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes() {\n" - " java.lang.Object ref $default_init$;\n" + " java.lang.String ref $default_init$;\n" " if ($has_oneof_case_message$) {\n" - " ref = $oneof_name$_;\n" - " }\n" - " if (ref instanceof java.lang.String) {\n" - " com.google.protobuf.ByteString b = \n" - " com.google.protobuf.ByteString.copyFromUtf8(\n" - " (java.lang.String) ref);\n" - " if ($has_oneof_case_message$) {\n" - " $oneof_name$_ = b;\n" - " }\n" - " return b;\n" - " } else {\n" - " return (com.google.protobuf.ByteString) ref;\n" + " ref = (java.lang.String) $oneof_name$_;\n" " }\n" + " return com.google.protobuf.ByteString.copyFromUtf8(ref);\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -533,7 +469,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " $set_oneof_case_message$;\n" - " $oneof_name$_ = value;\n" + " $oneof_name$_ = value.toStringUtf8();\n" "}\n"); } @@ -603,7 +539,7 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations @@ -612,28 +548,29 @@ GenerateParsingCode(io::Printer* printer) const { "String s = input.readString();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n" - "$set_oneof_case_message$;\n" - "$oneof_name$_ = bs;\n"); } } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" - " output.writeBytes($number$, get$capitalized_name$Bytes());\n" + " output.writeString($number$, get$capitalized_name$());\n" "}\n"); } void ImmutableStringOneofFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "if ($has_oneof_case_message$) {\n" " size += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSize($number$, get$capitalized_name$Bytes());\n" + " .computeStringSize($number$, get$capitalized_name$());\n" "}\n"); } @@ -667,7 +604,7 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateInterfaceMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$com.google.protobuf.ProtocolStringList\n" + "$deprecation$java.util.List<String>\n" " get$capitalized_name$List();\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -685,12 +622,11 @@ GenerateInterfaceMembers(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, - "private com.google.protobuf.LazyStringArrayList $name$_;\n"); + "private com.google.protobuf.Internal.ProtobufList<String> $name$_;\n"); PrintExtraFieldInfo(variables_, printer); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" - " get$capitalized_name$List() {\n" + "$deprecation$public java.util.List<String> get$capitalized_name$List() {\n" " return $name$_;\n" // note: unmodifiable list "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -707,7 +643,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public com.google.protobuf.ByteString\n" " get$capitalized_name$Bytes(int index) {\n" - " return $name$_.getByteString(index);\n" + " return com.google.protobuf.ByteString.copyFromUtf8(\n" + " $name$_.get(index));\n" "}\n"); if (descriptor_->options().packed() && @@ -719,7 +656,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n" + " $name$_);\n" " }\n" "}\n"); @@ -764,7 +702,7 @@ GenerateMembers(io::Printer* printer) const { } printer->Print(variables_, " ensure$capitalized_name$IsMutable();\n" - " $name$_.add(value);\n" + " $name$_.add(value.toStringUtf8());\n" "}\n"); } @@ -772,10 +710,10 @@ void RepeatedImmutableStringFieldLiteGenerator:: GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, - "$deprecation$public com.google.protobuf.ProtocolStringList\n" + "$deprecation$public java.util.List<String>\n" " get$capitalized_name$List() {\n" - " return ((com.google.protobuf.LazyStringList)\n" - " instance.get$capitalized_name$List()).getUnmodifiableView();\n" + " return java.util.Collections.unmodifiableList(\n" + " instance.get$capitalized_name$List());\n" "}\n"); WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, @@ -875,20 +813,17 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "String s = input.readStringRequireUtf8();\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { + } else { // Lite runtime should attempt to reduce allocations by attempting to // construct the string directly from the input stream buffer. This avoids // spurious intermediary ByteString allocations, cutting overall allocations // in half. printer->Print(variables_, "String s = input.readString();\n"); - } else { - printer->Print(variables_, - "com.google.protobuf.ByteString bs = input.readBytes();\n"); } printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n"); if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { printer->Print(variables_, @@ -905,7 +840,7 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "int length = input.readRawVarint32();\n" "int limit = input.pushLimit(length);\n" "if (!$is_mutable$ && input.getBytesUntilLimit() > 0) {\n" - " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" + " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n" "while (input.getBytesUntilLimit() > 0) {\n"); if (CheckUtf8(descriptor_)) { @@ -932,6 +867,9 @@ GenerateParsingDoneCode(io::Printer* printer) const { void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializationCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by serializing the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. if (descriptor_->options().packed()) { printer->Print(variables_, "if (get$capitalized_name$List().size() > 0) {\n" @@ -939,18 +877,21 @@ GenerateSerializationCode(io::Printer* printer) const { " output.writeRawVarint32($name$MemoizedSerializedSize);\n" "}\n" "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.write$capitalized_type$NoTag($name$_.get(i));\n" + " output.writeStringNoTag($name$_.get(i));\n" "}\n"); } else { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" - " output.writeBytes($number$, $name$_.getByteString(i));\n" + " output.writeString($number$, $name$_.get(i));\n" "}\n"); } } void RepeatedImmutableStringFieldLiteGenerator:: GenerateSerializedSizeCode(io::Printer* printer) const { + // Lite runtime should reduce allocations by computing on the string directly. + // This avoids spurious intermediary ByteString allocations, cutting overall + // allocations in half. printer->Print(variables_, "{\n" " int dataSize = 0;\n"); @@ -959,7 +900,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < $name$_.size(); i++) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" - " .computeBytesSizeNoTag($name$_.getByteString(i));\n" + " .computeStringSizeNoTag($name$_.get(i));\n" "}\n"); printer->Print( diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index a2eeee2d..4d018425 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -44,6 +44,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/io/tokenizer.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/map_util.h> @@ -938,6 +939,42 @@ void Parser::GenerateMapEntry(const MapField& map_field, } else { value_field->set_type_name(map_field.value_type_name); } + // Propagate the "enforce_utf8" option to key and value fields if they + // are strings. This helps simplify the implementation of code generators + // and also reflection-based parsing code. + // + // The following definition: + // message Foo { + // map<string, string> value = 1 [enforce_utf8 = false]; + // } + // will be interpreted as: + // message Foo { + // message ValueEntry { + // option map_entry = true; + // string key = 1 [enforce_utf8 = false]; + // string value = 2 [enforce_utf8 = false]; + // } + // repeated ValueEntry value = 1 [enforce_utf8 = false]; + // } + // + // TODO(xiaofeng): Remove this when the "enforce_utf8" option is removed + // from protocol compiler. + for (int i = 0; i < field->options().uninterpreted_option_size(); ++i) { + const UninterpretedOption& option = + field->options().uninterpreted_option(i); + if (option.name_size() == 1 && + option.name(0).name_part() == "enforce_utf8" && + !option.name(0).is_extension()) { + if (key_field->type() == FieldDescriptorProto::TYPE_STRING) { + key_field->mutable_options()->add_uninterpreted_option() + ->CopyFrom(option); + } + if (value_field->type() == FieldDescriptorProto::TYPE_STRING) { + value_field->mutable_options()->add_uninterpreted_option() + ->CopyFrom(option); + } + } + } } bool Parser::ParseFieldOptions(FieldDescriptorProto* field, diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h index 16012e96..007b001c 100644 --- a/src/google/protobuf/compiler/parser.h +++ b/src/google/protobuf/compiler/parser.h @@ -323,7 +323,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& service_location, const FileDescriptorProto* containing_file); - // Parse one statement within a message, enum, or service block, inclunding + // Parse one statement within a message, enum, or service block, including // final semicolon. bool ParseMessageStatement(DescriptorProto* message, const LocationRecorder& message_location, @@ -364,7 +364,7 @@ class LIBPROTOBUF_EXPORT Parser { const LocationRecorder& extensions_location, const FileDescriptorProto* containing_file); - // Parse an "reserved" declaration. + // Parse a "reserved" declaration. bool ParseReserved(DescriptorProto* message, const LocationRecorder& message_location); bool ParseReservedNames(DescriptorProto* message, @@ -415,7 +415,7 @@ class LIBPROTOBUF_EXPORT Parser { Message* mutable_options); // Parse "required", "optional", or "repeated" and fill in "label" - // with the value. Returns true if shuch a label is consumed. + // with the value. Returns true if such a label is consumed. bool ParseLabel(FieldDescriptorProto::Label* label, const FileDescriptorProto* containing_file); diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index cdcaffde..2bebf1f3 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -48,6 +48,7 @@ #include <unistd.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/plugin.pb.h> #include <google/protobuf/compiler/code_generator.h> diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index e7890fae..0792d875 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -340,10 +340,10 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( // @@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::VerifyUTF8StringNamedField( - this->file_to_generate(i).data(), this->file_to_generate(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->file_to_generate(i).data(), this->file_to_generate(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.compiler.CodeGeneratorRequest.file_to_generate"); ::google::protobuf::internal::WireFormatLite::WriteString( 1, this->file_to_generate(i), output); } @@ -629,28 +629,28 @@ int CodeGeneratorRequest::proto_file_size() const { void CodeGeneratorRequest::clear_proto_file() { proto_file_.Clear(); } - const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { +const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Get(index); } - ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { +::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Mutable(index); } - ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { +::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -CodeGeneratorRequest::proto_file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* CodeGeneratorRequest::mutable_proto_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return &proto_file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -1535,28 +1535,28 @@ int CodeGeneratorResponse::file_size() const { void CodeGeneratorResponse::clear_file() { file_.Clear(); } - const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { +const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Get(index); } - ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { +::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Mutable(index); } - ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { +::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* CodeGeneratorResponse::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) return &file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 6fcaea2e..ab79bdae 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -144,10 +144,10 @@ class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); ::google::protobuf::FileDescriptorProto* add_proto_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& - proto_file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_proto_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + proto_file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest) private: @@ -378,10 +378,10 @@ class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Messag const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& - file() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* mutable_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& + file() const; // @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse) private: @@ -534,16 +534,16 @@ inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_ // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return proto_file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -CodeGeneratorRequest::proto_file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) - return proto_file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* CodeGeneratorRequest::mutable_proto_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) return &proto_file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +CodeGeneratorRequest::proto_file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorRequest.proto_file) + return proto_file_; +} // ------------------------------------------------------------------- @@ -784,16 +784,16 @@ inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorRe // @@protoc_insertion_point(field_add:google.protobuf.compiler.CodeGeneratorResponse.file) return file_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& -CodeGeneratorResponse::file() const { - // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) - return file_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* CodeGeneratorResponse::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.compiler.CodeGeneratorResponse.file) return &file_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& +CodeGeneratorResponse::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.compiler.CodeGeneratorResponse.file) + return file_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index d4c4c405..e81af700 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -57,6 +57,7 @@ #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/io/printer.h> diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 2ddac601..aa0f5fce 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -38,6 +38,7 @@ #include <string> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index a3cff1f8..85429924 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -42,6 +42,7 @@ #include <signal.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/message.h> #include <google/protobuf/stubs/substitute.h> diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 2855c377..5256b83c 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -53,6 +53,8 @@ #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/logging.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/once.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/stubs/strutil.h> @@ -1092,6 +1094,7 @@ const DescriptorPool* DescriptorPool::generated_pool() { return generated_pool_; } + DescriptorPool* DescriptorPool::internal_generated_pool() { InitGeneratedPoolOnce(); return generated_pool_; @@ -3699,6 +3702,14 @@ static bool ExistingFileMatchesProto(const FileDescriptor* existing_file, const FileDescriptorProto& proto) { FileDescriptorProto existing_proto; existing_file->CopyTo(&existing_proto); + // TODO(liujisi): Remove it when CopyTo supports copying syntax params when + // syntax="proto2". + if (existing_file->syntax() == FileDescriptor::SYNTAX_PROTO2 && + proto.has_syntax()) { + existing_proto.set_syntax( + existing_file->SyntaxName(existing_file->syntax())); + } + return existing_proto.SerializeAsString() == proto.SerializeAsString(); } @@ -4649,7 +4660,7 @@ void DescriptorBuilder::CrossLinkMessage( // safe. if (oneof_decl->field_count() > 0 && message->field(i - 1)->containing_oneof() != oneof_decl) { - AddWarning( + AddError( message->full_name() + "." + message->field(i - 1)->name(), proto.field(i - 1), DescriptorPool::ErrorCollector::OTHER, strings::Substitute( @@ -5088,8 +5099,7 @@ void DescriptorBuilder::ValidateProto3Field( field->containing_type()->full_name() + "\" which is a proto3 message type."); } - bool allow_groups = false; - if (field->type() == FieldDescriptor::TYPE_GROUP && !allow_groups) { + if (field->type() == FieldDescriptor::TYPE_GROUP) { AddError(field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, "Groups are not supported in proto3 syntax."); @@ -5307,6 +5317,14 @@ bool DescriptorBuilder::ValidateMapEntry(FieldDescriptor* field, // are added. } + if (value->type() == FieldDescriptor::TYPE_ENUM) { + if (value->enum_type()->value(0)->number() != 0) { + AddError( + field->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, + "Enum value in map must define 0 as the first value."); + } + } + return true; } diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index ca87d634..2ab316a5 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -58,6 +58,7 @@ #include <string> #include <vector> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> // TYPE_BOOL is defined in the MacOS's ConditionalMacros.h. #ifdef TYPE_BOOL @@ -860,7 +861,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { friend class FieldDescriptor; friend class EnumValueDescriptor; friend class FileDescriptor; - friend class LIBPROTOBUF_EXPORT internal::GeneratedMessageReflection; + friend class internal::GeneratedMessageReflection; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumDescriptor); }; @@ -1332,6 +1333,7 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // this pool. Do not add your own descriptors to this pool. static const DescriptorPool* generated_pool(); + // Find a FileDescriptor in the pool by file name. Returns NULL if not // found. const FileDescriptor* FindFileByName(const string& name) const; diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 5e7eeaa7..fe23c0ab 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -755,9 +755,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "tion\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004s" "pan\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022" "\031\n\021trailing_comments\030\004 \001(\t\022!\n\031leading_de" - "tached_comments\030\006 \003(\tB[\n\023com.google.prot" + "tached_comments\030\006 \003(\tB;\n\023com.google.prot" "obufB\020DescriptorProtosH\001Z\ndescriptor\242\002\003G" - "PB\252\002\032Google.Protobuf.Reflection\260\002\001", 4994); + "PB", 4962); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -1066,28 +1066,28 @@ int FileDescriptorSet::file_size() const { void FileDescriptorSet::clear_file() { file_.Clear(); } - const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* FileDescriptorSet::mutable_file() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorSet.file) return &file_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) + return file_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -1466,10 +1466,10 @@ void FileDescriptorProto::SerializeWithCachedSizes( // repeated string dependency = 3; for (int i = 0; i < this->dependency_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->dependency(i).data(), this->dependency(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "google.protobuf.FileDescriptorProto.dependency"); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->dependency(i).data(), this->dependency(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FileDescriptorProto.dependency"); ::google::protobuf::internal::WireFormatLite::WriteString( 3, this->dependency(i), output); } @@ -2091,28 +2091,28 @@ int FileDescriptorProto::message_type_size() const { void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } - const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* FileDescriptorProto::mutable_message_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.message_type) return &message_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.message_type) + return message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; int FileDescriptorProto::enum_type_size() const { @@ -2121,28 +2121,28 @@ int FileDescriptorProto::enum_type_size() const { void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } - const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* FileDescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.enum_type) return &enum_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; int FileDescriptorProto::service_size() const { @@ -2151,28 +2151,28 @@ int FileDescriptorProto::service_size() const { void FileDescriptorProto::clear_service() { service_.Clear(); } - const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* FileDescriptorProto::mutable_service() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.service) return &service_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) + return service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; int FileDescriptorProto::extension_size() const { @@ -2181,28 +2181,28 @@ int FileDescriptorProto::extension_size() const { void FileDescriptorProto::clear_extension() { extension_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* FileDescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileDescriptorProto.extension) return &extension_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) + return extension_; +} // optional .google.protobuf.FileOptions options = 8; bool FileDescriptorProto::has_options() const { @@ -2218,11 +2218,11 @@ void FileDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FileOptions::Clear(); clear_has_options(); } - const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { +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() { +::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::FileOptions; @@ -2230,13 +2230,13 @@ void FileDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.options) return options_; } - ::google::protobuf::FileOptions* FileDescriptorProto::release_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) { +void FileDescriptorProto::set_allocated_options(::google::protobuf::FileOptions* options) { delete options_; options_ = options; if (options) { @@ -2261,11 +2261,11 @@ 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 { +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() { +::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; @@ -2273,13 +2273,13 @@ void FileDescriptorProto::clear_source_code_info() { // @@protoc_insertion_point(field_mutable:google.protobuf.FileDescriptorProto.source_code_info) return source_code_info_; } - ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_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) { +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) { @@ -3269,10 +3269,10 @@ void DescriptorProto::SerializeWithCachedSizes( // repeated string reserved_name = 10; for (int i = 0; i < this->reserved_name_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->reserved_name(i).data(), this->reserved_name(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "google.protobuf.DescriptorProto.reserved_name"); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->reserved_name(i).data(), this->reserved_name(i).length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.DescriptorProto.reserved_name"); ::google::protobuf::internal::WireFormatLite::WriteString( 10, this->reserved_name(i), output); } @@ -3720,28 +3720,28 @@ int DescriptorProto::field_size() const { void DescriptorProto::clear_field() { field_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_field() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.field) return &field_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) + return field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; int DescriptorProto::extension_size() const { @@ -3750,28 +3750,28 @@ int DescriptorProto::extension_size() const { void DescriptorProto::clear_extension() { extension_.Clear(); } - const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* DescriptorProto::mutable_extension() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.extension) return &extension_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) + return extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; int DescriptorProto::nested_type_size() const { @@ -3780,28 +3780,28 @@ int DescriptorProto::nested_type_size() const { void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } - const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* DescriptorProto::mutable_nested_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.nested_type) return &nested_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.nested_type) + return nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; int DescriptorProto::enum_type_size() const { @@ -3810,28 +3810,28 @@ int DescriptorProto::enum_type_size() const { void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } - const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* DescriptorProto::mutable_enum_type() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.enum_type) return &enum_type_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.enum_type) + return enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; int DescriptorProto::extension_range_size() const { @@ -3840,28 +3840,28 @@ int DescriptorProto::extension_range_size() const { void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } - const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { +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) { +::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() { +::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 >* +::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_; } +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_; +} // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; int DescriptorProto::oneof_decl_size() const { @@ -3870,28 +3870,28 @@ int DescriptorProto::oneof_decl_size() const { void DescriptorProto::clear_oneof_decl() { oneof_decl_.Clear(); } - const ::google::protobuf::OneofDescriptorProto& DescriptorProto::oneof_decl(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >* DescriptorProto::mutable_oneof_decl() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.oneof_decl) return &oneof_decl_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& +DescriptorProto::oneof_decl() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.oneof_decl) + return oneof_decl_; +} // optional .google.protobuf.MessageOptions options = 7; bool DescriptorProto::has_options() const { @@ -3907,11 +3907,11 @@ void DescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MessageOptions::Clear(); clear_has_options(); } - const ::google::protobuf::MessageOptions& DescriptorProto::options() const { +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() { +::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::MessageOptions; @@ -3919,13 +3919,13 @@ void DescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.options) return options_; } - ::google::protobuf::MessageOptions* DescriptorProto::release_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) { +void DescriptorProto::set_allocated_options(::google::protobuf::MessageOptions* options) { delete options_; options_ = options; if (options) { @@ -3943,28 +3943,28 @@ int DescriptorProto::reserved_range_size() const { void DescriptorProto::clear_reserved_range() { reserved_range_.Clear(); } - const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { +const ::google::protobuf::DescriptorProto_ReservedRange& DescriptorProto::reserved_range(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Get(index); } - ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { +::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::mutable_reserved_range(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Mutable(index); } - ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { +::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_reserved_range() { // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& -DescriptorProto::reserved_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) - return reserved_range_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* DescriptorProto::mutable_reserved_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) return &reserved_range_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} // repeated string reserved_name = 10; int DescriptorProto::reserved_name_size() const { @@ -5062,11 +5062,11 @@ void FieldDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::FieldOptions::Clear(); clear_has_options(); } - const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { +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() { +::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::FieldOptions; @@ -5074,13 +5074,13 @@ void FieldDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.FieldDescriptorProto.options) return options_; } - ::google::protobuf::FieldOptions* FieldDescriptorProto::release_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) { +void FieldDescriptorProto::set_allocated_options(::google::protobuf::FieldOptions* options) { delete options_; options_ = options; if (options) { @@ -5804,28 +5804,28 @@ int EnumDescriptorProto::value_size() const { void EnumDescriptorProto::clear_value() { value_.Clear(); } - const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* EnumDescriptorProto::mutable_value() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumDescriptorProto.value) return &value_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) + return value_; +} // optional .google.protobuf.EnumOptions options = 3; bool EnumDescriptorProto::has_options() const { @@ -5841,11 +5841,11 @@ void EnumDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumOptions::Clear(); clear_has_options(); } - const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { +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() { +::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::EnumOptions; @@ -5853,13 +5853,13 @@ void EnumDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumDescriptorProto.options) return options_; } - ::google::protobuf::EnumOptions* EnumDescriptorProto::release_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) { +void EnumDescriptorProto::set_allocated_options(::google::protobuf::EnumOptions* options) { delete options_; options_ = options; if (options) { @@ -6304,11 +6304,11 @@ void EnumValueDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::EnumValueOptions::Clear(); clear_has_options(); } - const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() const { +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() { +::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::EnumValueOptions; @@ -6316,13 +6316,13 @@ void EnumValueDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValueDescriptorProto.options) return options_; } - ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_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) { +void EnumValueDescriptorProto::set_allocated_options(::google::protobuf::EnumValueOptions* options) { delete options_; options_ = options; if (options) { @@ -6740,28 +6740,28 @@ int ServiceDescriptorProto::method_size() const { void ServiceDescriptorProto::clear_method() { method_.Clear(); } - const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* ServiceDescriptorProto::mutable_method() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceDescriptorProto.method) return &method_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) + return method_; +} // optional .google.protobuf.ServiceOptions options = 3; bool ServiceDescriptorProto::has_options() const { @@ -6777,11 +6777,11 @@ void ServiceDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::ServiceOptions::Clear(); clear_has_options(); } - const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() const { +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() { +::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::ServiceOptions; @@ -6789,13 +6789,13 @@ void ServiceDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.ServiceDescriptorProto.options) return options_; } - ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_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) { +void ServiceDescriptorProto::set_allocated_options(::google::protobuf::ServiceOptions* options) { delete options_; options_ = options; if (options) { @@ -7480,11 +7480,11 @@ void MethodDescriptorProto::clear_options() { if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); clear_has_options(); } - const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const { +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() { +::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options() { set_has_options(); if (options_ == NULL) { options_ = new ::google::protobuf::MethodOptions; @@ -7492,13 +7492,13 @@ void MethodDescriptorProto::clear_options() { // @@protoc_insertion_point(field_mutable:google.protobuf.MethodDescriptorProto.options) return options_; } - ::google::protobuf::MethodOptions* MethodDescriptorProto::release_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) { +void MethodDescriptorProto::set_allocated_options(::google::protobuf::MethodOptions* options) { delete options_; options_ = options; if (options) { @@ -9025,28 +9025,28 @@ int FileOptions::uninterpreted_option_size() const { void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FileOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FileOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -9568,28 +9568,28 @@ int MessageOptions::uninterpreted_option_size() const { void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MessageOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MessageOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MessageOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -10298,28 +10298,28 @@ int FieldOptions::uninterpreted_option_size() const { void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* FieldOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.FieldOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.FieldOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -10721,28 +10721,28 @@ int EnumOptions::uninterpreted_option_size() const { void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11070,28 +11070,28 @@ int EnumValueOptions::uninterpreted_option_size() const { void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* EnumValueOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValueOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumValueOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11419,28 +11419,28 @@ int ServiceOptions::uninterpreted_option_size() const { void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* ServiceOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ServiceOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -11768,28 +11768,28 @@ int MethodOptions::uninterpreted_option_size() const { void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } - const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* MethodOptions::mutable_uninterpreted_option() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.MethodOptions.uninterpreted_option) return &uninterpreted_option_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + // @@protoc_insertion_point(field_list:google.protobuf.MethodOptions.uninterpreted_option) + return uninterpreted_option_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -12710,28 +12710,28 @@ int UninterpretedOption::name_size() const { void UninterpretedOption::clear_name() { name_.Clear(); } - const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* UninterpretedOption::mutable_name() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.UninterpretedOption.name) return &name_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) + return name_; +} // optional string identifier_value = 3; bool UninterpretedOption::has_identifier_value() const { @@ -13221,10 +13221,10 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( // 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::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); } @@ -13916,28 +13916,28 @@ int SourceCodeInfo::location_size() const { void SourceCodeInfo::clear_location() { location_.Clear(); } - const ::google::protobuf::SourceCodeInfo_Location& SourceCodeInfo::location(int index) const { +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) { +::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() { +::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 >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* SourceCodeInfo::mutable_location() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.SourceCodeInfo.location) return &location_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) + return location_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 2aa076ae..931ff02d 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -38,28 +38,28 @@ void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto( void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); -class FileDescriptorSet; -class FileDescriptorProto; class DescriptorProto; class DescriptorProto_ExtensionRange; class DescriptorProto_ReservedRange; -class FieldDescriptorProto; -class OneofDescriptorProto; class EnumDescriptorProto; +class EnumOptions; class EnumValueDescriptorProto; -class ServiceDescriptorProto; -class MethodDescriptorProto; +class EnumValueOptions; +class FieldDescriptorProto; +class FieldOptions; +class FileDescriptorProto; +class FileDescriptorSet; class FileOptions; class MessageOptions; -class FieldOptions; -class EnumOptions; -class EnumValueOptions; -class ServiceOptions; +class MethodDescriptorProto; class MethodOptions; -class UninterpretedOption; -class UninterpretedOption_NamePart; +class OneofDescriptorProto; +class ServiceDescriptorProto; +class ServiceOptions; class SourceCodeInfo; class SourceCodeInfo_Location; +class UninterpretedOption; +class UninterpretedOption_NamePart; enum FieldDescriptorProto_Type { FieldDescriptorProto_Type_TYPE_DOUBLE = 1, @@ -249,10 +249,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_file(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: @@ -405,10 +405,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; int enum_type_size() const; @@ -417,10 +417,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; // repeated .google.protobuf.ServiceDescriptorProto service = 6; int service_size() const; @@ -429,10 +429,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; // repeated .google.protobuf.FieldDescriptorProto extension = 7; int extension_size() const; @@ -441,10 +441,10 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; // optional .google.protobuf.FileOptions options = 8; bool has_options() const; @@ -797,10 +797,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; // repeated .google.protobuf.FieldDescriptorProto extension = 6; int extension_size() const; @@ -809,10 +809,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; // repeated .google.protobuf.DescriptorProto nested_type = 3; int nested_type_size() const; @@ -821,10 +821,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; int enum_type_size() const; @@ -833,10 +833,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; int extension_range_size() const; @@ -845,10 +845,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; int oneof_decl_size() const; @@ -857,10 +857,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { 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(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::OneofDescriptorProto >& + oneof_decl() const; // optional .google.protobuf.MessageOptions options = 7; bool has_options() const; @@ -878,10 +878,10 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { const ::google::protobuf::DescriptorProto_ReservedRange& reserved_range(int index) const; ::google::protobuf::DescriptorProto_ReservedRange* mutable_reserved_range(int index); ::google::protobuf::DescriptorProto_ReservedRange* add_reserved_range(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& - reserved_range() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* mutable_reserved_range(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& + reserved_range() const; // repeated string reserved_name = 10; int reserved_name_size() const; @@ -1361,10 +1361,10 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; // optional .google.protobuf.EnumOptions options = 3; bool has_options() const; @@ -1596,10 +1596,10 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; // optional .google.protobuf.ServiceOptions options = 3; bool has_options() const; @@ -2014,10 +2014,10 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) @@ -2182,10 +2182,10 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) @@ -2381,10 +2381,10 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) @@ -2508,10 +2508,10 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) @@ -2616,10 +2616,10 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) @@ -2721,10 +2721,10 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) @@ -2826,10 +2826,10 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) @@ -3033,10 +3033,10 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* mutable_name(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; // optional string identifier_value = 3; bool has_identifier_value() const; @@ -3356,10 +3356,10 @@ class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message { 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; ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >* mutable_location(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& + location() const; // @@protoc_insertion_point(class_scope:google.protobuf.SourceCodeInfo) private: @@ -3402,16 +3402,16 @@ 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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorSet.file) + return file_; +} // ------------------------------------------------------------------- @@ -3656,16 +3656,16 @@ inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_typ // @@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_; } +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_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int FileDescriptorProto::enum_type_size() const { @@ -3686,16 +3686,16 @@ inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_ty // @@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_; } +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_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int FileDescriptorProto::service_size() const { @@ -3716,16 +3716,16 @@ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_serv // @@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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.service) + return service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int FileDescriptorProto::extension_size() const { @@ -3746,16 +3746,16 @@ inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extens // @@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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.FileDescriptorProto.extension) + return extension_; +} // optional .google.protobuf.FileOptions options = 8; inline bool FileDescriptorProto::has_options() const { @@ -4076,16 +4076,16 @@ 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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.field) + return field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int DescriptorProto::extension_size() const { @@ -4106,16 +4106,16 @@ 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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.extension) + return extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int DescriptorProto::nested_type_size() const { @@ -4136,16 +4136,16 @@ 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_; } +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_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int DescriptorProto::enum_type_size() const { @@ -4166,16 +4166,16 @@ 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_; } +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_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int DescriptorProto::extension_range_size() const { @@ -4196,16 +4196,16 @@ inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_ // @@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_; } +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_; +} // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8; inline int DescriptorProto::oneof_decl_size() const { @@ -4226,16 +4226,16 @@ 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_; } +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_; +} // optional .google.protobuf.MessageOptions options = 7; inline bool DescriptorProto::has_options() const { @@ -4299,16 +4299,16 @@ inline ::google::protobuf::DescriptorProto_ReservedRange* DescriptorProto::add_r // @@protoc_insertion_point(field_add:google.protobuf.DescriptorProto.reserved_range) return reserved_range_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& -DescriptorProto::reserved_range() const { - // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) - return reserved_range_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >* DescriptorProto::mutable_reserved_range() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.DescriptorProto.reserved_range) return &reserved_range_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ReservedRange >& +DescriptorProto::reserved_range() const { + // @@protoc_insertion_point(field_list:google.protobuf.DescriptorProto.reserved_range) + return reserved_range_; +} // repeated string reserved_name = 10; inline int DescriptorProto::reserved_name_size() const { @@ -4854,16 +4854,16 @@ inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_va // @@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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumDescriptorProto.value) + return value_; +} // optional .google.protobuf.EnumOptions options = 3; inline bool EnumDescriptorProto::has_options() const { @@ -5108,16 +5108,16 @@ inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_me // @@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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + // @@protoc_insertion_point(field_list:google.protobuf.ServiceDescriptorProto.method) + return method_; +} // optional .google.protobuf.ServiceOptions options = 3; inline bool ServiceDescriptorProto::has_options() const { @@ -5945,16 +5945,16 @@ inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_o // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6075,16 +6075,16 @@ inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterprete // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6255,16 +6255,16 @@ inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_ // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6337,16 +6337,16 @@ inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_o // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6395,16 +6395,16 @@ inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpre // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6453,16 +6453,16 @@ inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterprete // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6511,16 +6511,16 @@ inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted // @@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_; } +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_; +} // ------------------------------------------------------------------- @@ -6626,16 +6626,16 @@ inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::ad // @@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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + // @@protoc_insertion_point(field_list:google.protobuf.UninterpretedOption.name) + return name_; +} // optional string identifier_value = 3; inline bool UninterpretedOption::has_identifier_value() const { @@ -7115,16 +7115,16 @@ 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_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::SourceCodeInfo_Location >& +SourceCodeInfo::location() const { + // @@protoc_insertion_point(field_list:google.protobuf.SourceCodeInfo.location) + return location_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 9d3dd8fb..8f90a956 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -42,9 +42,9 @@ syntax = "proto2"; package google.protobuf; option go_package = "descriptor"; option java_package = "com.google.protobuf"; -option javanano_use_deprecated_package = true; option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; +// Re-enable this once the tools have picked up the csharp_namespace option. +// option csharp_namespace = "Google.ProtocolBuffers.DescriptorProtos"; option objc_class_prefix = "GPB"; // descriptor.proto must be optimized for speed because reflection-based @@ -301,10 +301,12 @@ message FileOptions { // If set true, then the Java code generator will generate equals() and // hashCode() methods for all messages defined in the .proto file. - // - In the full runtime, this is purely a speed optimization, as the + // This increases generated code size, potentially substantially for large + // protos, which may harm a memory-constrained application. + // - In the full runtime this is 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 + // - 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 @@ -525,6 +527,7 @@ message FieldOptions { // 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; diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index 1c03c443..a87fa049 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -42,7 +42,9 @@ #include <google/protobuf/text_format.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 760df097..e9b027db 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -49,6 +49,8 @@ #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -368,6 +370,37 @@ TEST_F(FileDescriptorTest, BuildAgain) { EXPECT_TRUE(pool_.BuildFile(file) == NULL); } +TEST_F(FileDescriptorTest, BuildAgainWithSyntax) { + // Test that if te call BuildFile again on the same input we get the same + // FileDescriptor back even if syntax param is specified. + FileDescriptorProto proto_syntax2; + proto_syntax2.set_name("foo_syntax2"); + proto_syntax2.set_syntax("proto2"); + + const FileDescriptor* proto2_descriptor = pool_.BuildFile(proto_syntax2); + EXPECT_TRUE(proto2_descriptor != NULL); + EXPECT_EQ(proto2_descriptor, pool_.BuildFile(proto_syntax2)); + + FileDescriptorProto implicit_proto2; + implicit_proto2.set_name("foo_implicit_syntax2"); + + const FileDescriptor* implicit_proto2_descriptor = + pool_.BuildFile(implicit_proto2); + EXPECT_TRUE(implicit_proto2_descriptor != NULL); + // We get the same FileDescriptor back if syntax param is explicitly + // specified. + implicit_proto2.set_syntax("proto2"); + EXPECT_EQ(implicit_proto2_descriptor, pool_.BuildFile(implicit_proto2)); + + FileDescriptorProto proto_syntax3; + proto_syntax3.set_name("foo_syntax3"); + proto_syntax3.set_syntax("proto3"); + + const FileDescriptor* proto3_descriptor = pool_.BuildFile(proto_syntax3); + EXPECT_TRUE(proto3_descriptor != NULL); + EXPECT_EQ(proto3_descriptor, pool_.BuildFile(proto_syntax3)); +} + TEST_F(FileDescriptorTest, Syntax) { FileDescriptorProto proto; proto.set_name("foo"); @@ -3583,7 +3616,7 @@ TEST_F(ValidationErrorTest, FieldOneofIndexNegative) { TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { // Fields belonging to the same oneof must be defined consecutively. - BuildFileWithWarnings( + BuildFileWithErrors( "name: \"foo.proto\" " "message_type {" " name: \"Foo\"" @@ -3600,7 +3633,7 @@ TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { "\"foos\" oneof definition.\n"); // Prevent interleaved fields, which belong to different oneofs. - BuildFileWithWarnings( + BuildFileWithErrors( "name: \"foo2.proto\" " "message_type {" " name: \"Foo2\"" @@ -3621,6 +3654,25 @@ TEST_F(ValidationErrorTest, OneofFieldsConsecutiveDefinition) { "foo2.proto: Foo2.foo2: OTHER: Fields in the same oneof must be defined " "consecutively. \"foo2\" cannot be defined before the completion of the " "\"bars\" oneof definition.\n"); + + // Another case for normal fields and different oneof fields interleave. + BuildFileWithErrors( + "name: \"foo3.proto\" " + "message_type {" + " name: \"Foo3\"" + " field { name:\"foo1\" number: 1 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " field { name:\"bar1\" number: 2 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 1 }" + " field { name:\"baz\" number: 3 label:LABEL_OPTIONAL type:TYPE_INT32 }" + " field { name:\"foo2\" number: 4 label:LABEL_OPTIONAL type:TYPE_INT32 " + " oneof_index: 0 }" + " oneof_decl { name:\"foos\" }" + " oneof_decl { name:\"bars\" }" + "}", + "foo3.proto: Foo3.baz: OTHER: Fields in the same oneof must be defined " + "consecutively. \"baz\" cannot be defined before the completion of the " + "\"foos\" oneof definition.\n"); } TEST_F(ValidationErrorTest, FieldNumberConflict) { @@ -5369,6 +5421,35 @@ TEST_F(ValidationErrorTest, MapEntryConflictsWithOneof) { "with an existing oneof type.\n"); } +TEST_F(ValidationErrorTest, MapEntryUsesNoneZeroEnumDefaultValue) { + BuildFileWithErrors( + "name: \"foo.proto\" " + "enum_type {" + " name: \"Bar\"" + " value { name:\"ENUM_A\" number:1 }" + " value { name:\"ENUM_B\" number:2 }" + "}" + "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_name:\"Bar\" label:LABEL_OPTIONAL " + " } " + " } " + "}", + "foo.proto: Foo.foo_map: " + "TYPE: Enum value in map must define 0 as the first value.\n"); +} + TEST_F(ValidationErrorTest, Proto3RequiredFields) { BuildFileWithErrors( "name: 'foo.proto' " diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 0762c3c2..7f172aa6 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -80,6 +80,7 @@ option objc_class_prefix = "GPB"; // } // 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; diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 318ce6f9..2324d952 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -65,6 +65,7 @@ #include <algorithm> #include <google/protobuf/stubs/hash.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/dynamic_message.h> @@ -79,6 +80,7 @@ #include <google/protobuf/map_type_handler.h> #include <google/protobuf/extension_set.h> #include <google/protobuf/wire_format.h> +#include <google/protobuf/map_field.h> namespace google { namespace protobuf { @@ -87,7 +89,7 @@ using internal::WireFormat; using internal::ExtensionSet; using internal::GeneratedMessageReflection; using internal::MapField; -using internal::MapFieldBase; +using internal::DynamicMapField; using internal::ArenaStringPtr; @@ -116,7 +118,7 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >); case FD::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - return sizeof(MapFieldBase); + return sizeof(DynamicMapField); } else { return sizeof(RepeatedPtrField<Message>); } @@ -389,7 +391,8 @@ void DynamicMessage::SharedCtor() { new(field_ptr) Message*(NULL); } else { if (IsMapFieldInApi(field)) { - new (field_ptr) MapFieldBase(); + new (field_ptr) DynamicMapField( + type_info_->factory->GetPrototypeNoLock(field->message_type())); } else { new (field_ptr) RepeatedPtrField<Message>(); } @@ -437,8 +440,8 @@ DynamicMessage::~DynamicMessage() { &(reinterpret_cast<const ArenaStringPtr*>( type_info_->prototype->OffsetToPointer( type_info_->offsets[i]))->Get(NULL)); - reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value, - NULL); + reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy( + default_value, NULL); break; } } @@ -480,7 +483,7 @@ DynamicMessage::~DynamicMessage() { case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - reinterpret_cast<MapFieldBase*>(field_ptr)->~MapFieldBase(); + reinterpret_cast<DynamicMapField*>(field_ptr)->~DynamicMapField(); } else { reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr) ->~RepeatedPtrField<Message>(); @@ -496,8 +499,8 @@ DynamicMessage::~DynamicMessage() { &(reinterpret_cast<const ArenaStringPtr*>( type_info_->prototype->OffsetToPointer( type_info_->offsets[i]))->Get(NULL)); - reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(default_value, - NULL); + reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy( + default_value, NULL); break; } } @@ -723,8 +726,14 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( // Allocate the prototype. void* base = operator new(size); memset(base, 0, size); + // The prototype in type_info has to be set before creating the prototype + // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When + // creating prototype for Foo, prototype of the map entry will also be + // created, which needs the address of the prototype of Foo (the value in + // map). To break the cyclic dependency, we have to assgin the address of + // prototype into type_info first. + type_info->prototype = static_cast<DynamicMessage*>(base); DynamicMessage* prototype = new(base) DynamicMessage(type_info); - type_info->prototype = prototype; // Construct the reflection object. if (type->oneof_decl_count() > 0) { diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index b5928a52..f74cd7dd 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -45,6 +45,7 @@ #include <google/protobuf/message.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/mutex.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index 522a092a..b9796c76 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -40,6 +40,7 @@ // reflection_ops_unittest, cover the rest of the functionality used by // DynamicMessage. +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/descriptor.h> @@ -48,6 +49,7 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_no_field_presence.pb.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index 1e1c2c8c..50cbd9a8 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -79,9 +79,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\033google/protobuf/empty.proto\022\017google.pr" - "otobuf\"\007\n\005EmptyBJ\n\023com.google.protobufB\n" - "EmptyProtoP\001\242\002\003GPB\252\002\036Google.Protobuf.Wel" - "lKnownTypesb\006proto3", 139); + "otobuf\"\007\n\005EmptyBM\n\023com.google.protobufB\n" + "EmptyProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf." + "WellKnownTypesb\006proto3", 142); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/empty.proto", &protobuf_RegisterTypes); Empty::default_instance_ = new Empty(); diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto index 363ec175..9dddc6c5 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -34,10 +34,10 @@ package google.protobuf; option java_multiple_files = true; option java_outer_classname = "EmptyProto"; option java_package = "com.google.protobuf"; +option java_generate_equals_and_hash = true; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // A generic empty message that you can re-use to avoid defining duplicated // empty messages in your APIs. A typical example is to use it as the request // or the response type of an API method. For instance: @@ -46,6 +46,5 @@ option objc_class_prefix = "GPB"; // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); // } // -message Empty { - -} +// The JSON representation for `Empty` is empty JSON object `{}`. +message Empty {} diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index c371e011..9ef4e27d 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -45,6 +45,7 @@ #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/repeated_field.h> @@ -330,6 +331,8 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& prototype, desc); MessageLite* AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory); + void AddAllocatedMessage(const FieldDescriptor* descriptor, + MessageLite* new_entry); #undef desc void RemoveLast(int number); @@ -578,6 +581,10 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, Extension** result); + // Gets the repeated extension for the given descriptor, creating it if + // it does not exist. + Extension* MaybeNewRepeatedExtension(const FieldDescriptor* descriptor); + // Parse a single MessageSet item -- called just after the item group start // tag has been read. bool ParseMessageSetItem(io::CodedInputStream* input, diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 330bd828..82e3e099 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -213,8 +213,7 @@ MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor, } } -MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, - MessageFactory* factory) { +ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) { Extension* extension; if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { extension->type = descriptor->type(); @@ -225,6 +224,12 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, } else { GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE); } + return extension; +} + +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, + MessageFactory* factory) { + Extension* extension = MaybeNewRepeatedExtension(descriptor); // RepeatedPtrField<Message> does not know how to Add() since it cannot // allocate an abstract object, so we have to be tricky. @@ -244,6 +249,13 @@ MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, return result; } +void ExtensionSet::AddAllocatedMessage(const FieldDescriptor* descriptor, + MessageLite* new_entry) { + Extension* extension = MaybeNewRepeatedExtension(descriptor); + + extension->repeated_message_value->AddAllocated(new_entry); +} + static bool ValidateEnumUsingDescriptor(const void* arg, int number) { return reinterpret_cast<const EnumDescriptor*>(arg) ->FindValueByNumber(number) != NULL; diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 684ce002..1569120d 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -44,6 +44,7 @@ #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/testing/googletest.h> @@ -173,7 +174,7 @@ TEST(ExtensionSetTest, SetAllocatedExtension) { } TEST(ExtensionSetTest, ReleaseExtension) { - unittest::TestMessageSet message; + proto2_wireformat_unittest::TestMessageSet message; EXPECT_FALSE(message.HasExtension( unittest::TestMessageSetExtension1::message_set_extension)); // Add a extension using SetAllocatedExtension diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index 88020ef2..d8f4ee91 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -81,9 +81,9 @@ void protobuf_AddDesc_google_2fprotobuf_2ffield_5fmask_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n google/protobuf/field_mask.proto\022\017goog" "le.protobuf\"\032\n\tFieldMask\022\r\n\005paths\030\001 \003(\tB" - "N\n\023com.google.protobufB\016FieldMaskProtoP\001" - "\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb" - "\006proto3", 167); + "Q\n\023com.google.protobufB\016FieldMaskProtoP\001" + "\240\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTyp" + "esb\006proto3", 170); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/field_mask.proto", &protobuf_RegisterTypes); FieldMask::default_instance_ = new FieldMask(); @@ -193,11 +193,11 @@ bool FieldMask::MergePartialFromCodedStream( parse_paths: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->add_paths())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->paths(this->paths_size() - 1).data(), this->paths(this->paths_size() - 1).length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.FieldMask.paths"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.FieldMask.paths")); } else { goto handle_unusual; } @@ -232,10 +232,10 @@ void FieldMask::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.FieldMask) // repeated string paths = 1; for (int i = 0; i < this->paths_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->paths(i).data(), this->paths(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "google.protobuf.FieldMask.paths"); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->paths(i).data(), this->paths(i).length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.FieldMask.paths"); ::google::protobuf::internal::WireFormatLite::WriteString( 1, this->paths(i), output); } @@ -248,9 +248,9 @@ void FieldMask::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask) // repeated string paths = 1; for (int i = 0; i < this->paths_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->paths(i).data(), this->paths(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.FieldMask.paths"); target = ::google::protobuf::internal::WireFormatLite:: WriteStringToArray(1, this->paths(i), target); diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index c19f4410..8b21c692 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -31,13 +31,13 @@ syntax = "proto3"; package google.protobuf; +option java_generate_equals_and_hash = true; option java_multiple_files = true; option java_outer_classname = "FieldMaskProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // `FieldMask` represents a set of symbolic field paths, for example: // // paths: "f.a" @@ -52,6 +52,7 @@ option objc_class_prefix = "GPB"; // 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 @@ -97,6 +98,7 @@ option objc_class_prefix = "GPB"; // 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 @@ -124,11 +126,13 @@ option objc_class_prefix = "GPB"; // 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. diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 412c48a1..b9957e75 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -35,6 +35,7 @@ #include <algorithm> #include <set> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> @@ -818,7 +819,16 @@ void GeneratedMessageReflection::ClearField( } case FieldDescriptor::CPPTYPE_MESSAGE: - (*MutableRaw<Message*>(message, field))->Clear(); + if (has_bits_offset_ == -1) { + // Proto3 does not have has-bits and we need to set a message field + // to NULL in order to indicate its un-presence. + if (GetArena(message) == NULL) { + delete *MutableRaw<Message*>(message, field); + } + *MutableRaw<Message*>(message, field) = NULL; + } else { + (*MutableRaw<Message*>(message, field))->Clear(); + } break; } } @@ -1649,6 +1659,25 @@ Message* GeneratedMessageReflection::AddMessage( } } +void GeneratedMessageReflection::AddAllocatedMessage( + Message* message, const FieldDescriptor* field, + Message* new_entry) const { + USAGE_CHECK_ALL(AddAllocatedMessage, REPEATED, MESSAGE); + + if (field->is_extension()) { + MutableExtensionSet(message)->AddAllocatedMessage(field, new_entry); + } else { + RepeatedPtrFieldBase* repeated = NULL; + if (IsMapFieldInApi(field)) { + repeated = + MutableRaw<MapFieldBase>(message, field)->MutableRepeatedField(); + } else { + repeated = MutableRaw<RepeatedPtrFieldBase>(message, field); + } + repeated->AddAllocated<GenericTypeHandler<Message> >(new_entry); + } +} + void* GeneratedMessageReflection::MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpptype, @@ -1675,6 +1704,37 @@ void* GeneratedMessageReflection::MutableRawRepeatedField( } } +const void* GeneratedMessageReflection::GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType cpptype, + int ctype, const Descriptor* desc) const { + USAGE_CHECK_REPEATED("GetRawRepeatedField"); + if (field->cpp_type() != cpptype) + ReportReflectionUsageTypeError(descriptor_, + field, "GetRawRepeatedField", 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()) { + // Should use extension_set::GetRawRepeatedField. However, the required + // parameter "default repeated value" is not very easy to get here. + // Map is not supported in extensions, it is acceptable to use + // extension_set::MutableRawRepeatedField which does not change the message. + return MutableExtensionSet(const_cast<Message*>(&message)) + ->MutableRawRepeatedField( + field->number(), field->type(), field->is_packed(), field); + } else { + // Trigger transform for MapField + if (IsMapFieldInApi(field)) { + return &(reinterpret_cast<const MapFieldBase*>( + reinterpret_cast<const uint8*>(&message) + + offsets_[field->index()])->GetRepeatedField()); + } + return reinterpret_cast<const uint8*>(&message) + offsets_[field->index()]; + } +} + const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor( const Message& message, const OneofDescriptor* oneof_descriptor) const { @@ -1685,6 +1745,69 @@ const FieldDescriptor* GeneratedMessageReflection::GetOneofFieldDescriptor( return descriptor_->FindFieldByNumber(field_number); } +bool GeneratedMessageReflection::ContainsMapKey( + const Message& message, + const FieldDescriptor* field, + const MapKey& key) const { + USAGE_CHECK(IsMapFieldInApi(field), + "LookupMapValue", + "Field is not a map field."); + return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key); +} + +bool GeneratedMessageReflection::InsertOrLookupMapValue( + Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const { + USAGE_CHECK(IsMapFieldInApi(field), + "InsertOrLookupMapValue", + "Field is not a map field."); + val->SetType(field->message_type()->FindFieldByName("value")->cpp_type()); + return MutableRaw<MapFieldBase>(message, field)->InsertMapValue(key, val); +} + +bool GeneratedMessageReflection::DeleteMapValue( + Message* message, + const FieldDescriptor* field, + const MapKey& key) const { + USAGE_CHECK(IsMapFieldInApi(field), + "DeleteMapValue", + "Field is not a map field."); + return MutableRaw<MapFieldBase>(message, field)->DeleteMapValue(key); +} + +MapIterator GeneratedMessageReflection::MapBegin( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapBegin", + "Field is not a map field."); + MapIterator iter(message, field); + GetRaw<MapFieldBase>(*message, field).MapBegin(&iter); + return iter; +} + +MapIterator GeneratedMessageReflection::MapEnd( + Message* message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapEnd", + "Field is not a map field."); + MapIterator iter(message, field); + GetRaw<MapFieldBase>(*message, field).MapEnd(&iter); + return iter; +} + +int GeneratedMessageReflection::MapSize( + const Message& message, + const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "MapSize", + "Field is not a map field."); + return GetRaw<MapFieldBase>(message, field).size(); +} + // ----------------------------------------------------------------------------- const FieldDescriptor* GeneratedMessageReflection::FindKnownExtensionByName( @@ -2098,6 +2221,14 @@ void* GeneratedMessageReflection::RepeatedFieldData( } } +MapFieldBase* GeneratedMessageReflection::MapData( + Message* message, const FieldDescriptor* field) const { + USAGE_CHECK(IsMapFieldInApi(field), + "GetMapData", + "Field is not a map field."); + return MutableRaw<MapFieldBase>(message, field); +} + GeneratedMessageReflection* GeneratedMessageReflection::NewGeneratedMessageReflection( const Descriptor* descriptor, diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index dc8abb98..9ef78710 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -58,7 +58,9 @@ class GMR_Handlers; } // namespace upb namespace protobuf { - class DescriptorPool; +class DescriptorPool; +class MapKey; +class MapValueRef; } namespace protobuf { @@ -261,6 +263,25 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const Message& message, const OneofDescriptor* oneof_descriptor) const; + private: + bool ContainsMapKey(const Message& message, + const FieldDescriptor* field, + const MapKey& key) const; + bool InsertOrLookupMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const; + bool DeleteMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key) const; + MapIterator MapBegin( + Message* message, + const FieldDescriptor* field) const; + MapIterator MapEnd( + Message* message, + const FieldDescriptor* field) const; + int MapSize(const Message& message, const FieldDescriptor* field) const; + public: void SetInt32 (Message* message, const FieldDescriptor* field, int32 value) const; @@ -371,6 +392,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int value) const; Message* AddMessage(Message* message, const FieldDescriptor* field, MessageFactory* factory = NULL) const; + void AddAllocatedMessage( + Message* message, const FieldDescriptor* field, + Message* new_entry) const; const FieldDescriptor* FindKnownExtensionByName(const string& name) const; const FieldDescriptor* FindKnownExtensionByNumber(int number) const; @@ -391,10 +415,15 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { static const int kUnknownFieldSetInMetadata = -1; protected: - virtual void* MutableRawRepeatedField( + void* MutableRawRepeatedField( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType, int ctype, const Descriptor* desc) const; + const void* GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType, int ctype, + const Descriptor* desc) const; + virtual MessageFactory* GetMessageFactory() const; virtual void* RepeatedFieldData( @@ -407,7 +436,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { // 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; + friend class upb::google_opensource::GMR_Handlers; const Descriptor* descriptor_; const Message* default_instance_; @@ -539,6 +568,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { Message* sub_message, const FieldDescriptor* field) const; + internal::MapFieldBase* MapData( + Message* message, const FieldDescriptor* field) const; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection); }; diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc index ca1a2918..df043844 100644 --- a/src/google/protobuf/generated_message_reflection_unittest.cc +++ b/src/google/protobuf/generated_message_reflection_unittest.cc @@ -47,6 +47,7 @@ #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -546,6 +547,57 @@ TEST(GeneratedMessageReflectionTest, SetAllocatedExtensionMessageTest) { &to_message, TestUtil::ReflectionTester::IS_NULL); } +TEST(GeneratedMessageReflectionTest, AddRepeatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + const Reflection* nested_reflection = + unittest::TestAllTypes::NestedMessage::default_instance().GetReflection(); + + const FieldDescriptor* nested_bb = + unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName( + "bb"); + + Message* nested = reflection->AddMessage( + &message, F("repeated_nested_message")); + nested_reflection->SetInt32(nested, nested_bb, 11); + + EXPECT_EQ(11, message.repeated_nested_message(0).bb()); +} + +TEST(GeneratedMessageReflectionTest, MutableRepeatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + const Reflection* nested_reflection = + unittest::TestAllTypes::NestedMessage::default_instance().GetReflection(); + + const FieldDescriptor* nested_bb = + unittest::TestAllTypes::NestedMessage::descriptor()->FindFieldByName( + "bb"); + + message.add_repeated_nested_message()->set_bb(12); + + Message* nested = reflection->MutableRepeatedMessage( + &message, F("repeated_nested_message"), 0); + EXPECT_EQ(12, nested_reflection->GetInt32(*nested, nested_bb)); + nested_reflection->SetInt32(nested, nested_bb, 13); + EXPECT_EQ(13, message.repeated_nested_message(0).bb()); +} + +TEST(GeneratedMessageReflectionTest, AddAllocatedMessage) { + unittest::TestAllTypes message; + + const Reflection* reflection = message.GetReflection(); + + unittest::TestAllTypes::NestedMessage* nested = + new unittest::TestAllTypes::NestedMessage(); + nested->set_bb(11); + reflection->AddAllocatedMessage(&message, F("repeated_nested_message"), nested); + EXPECT_EQ(1, message.repeated_nested_message_size()); + EXPECT_EQ(11, message.repeated_nested_message(0).bb()); +} + TEST(GeneratedMessageReflectionTest, ListFieldsOneOf) { unittest::TestOneof2 message; TestUtil::SetOneof1(&message); diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index 3b8650d6..4bcd354f 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -44,6 +44,7 @@ #include <limits.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/arena.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stl_util.h> @@ -338,9 +339,9 @@ namespace { // The first part of the pair is true iff the read was successful. The second // part is buffer + (number of bytes read). This function is always inlined, // so returning a pair is costless. -inline ::std::pair<bool, const uint8*> ReadVarint32FromArray( +GOOGLE_ATTRIBUTE_ALWAYS_INLINE ::std::pair<bool, const uint8*> ReadVarint32FromArray( uint32 first_byte, const uint8* buffer, - uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + uint32* value); inline ::std::pair<bool, const uint8*> ReadVarint32FromArray( uint32 first_byte, const uint8* buffer, uint32* value) { // Fast path: We have enough bytes left in the buffer to guarantee that diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index ad351dc3..361c406b 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -191,16 +191,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Like GetDirectBufferPointer, but this method is inlined, and does not // attempt to Refresh() if the buffer is currently empty. - inline void GetDirectBufferPointerInline(const void** data, - int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void GetDirectBufferPointerInline(const void** data, + int* size); // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); // Like the above, with inlined optimizations. This should only be used // by the protobuf implementation. - inline bool InternalReadRawInline(void* buffer, - int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadRawInline(void* buffer, int size); // Like ReadRaw, but reads into a string. // @@ -212,8 +211,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream { bool ReadString(string* buffer, int size); // Like the above, with inlined optimizations. This should only be used // by the protobuf implementation. - inline bool InternalReadStringInline(string* buffer, - int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InternalReadStringInline(string* buffer, + int size); // Read a 32-bit little-endian integer. @@ -243,7 +242,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // 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; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTag(); // This usually a faster alternative to ReadTag() when cutoff is a manifest // constant. It does particularly well for cutoff >= 127. The first part @@ -253,8 +252,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // 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; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE std::pair<uint32, bool> ReadTagWithCutoff( + uint32 cutoff); // Usually returns true if calling ReadVarint32() now would produce the given // value. Will always return false if ReadVarint32() would not return the @@ -263,7 +262,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // parameter. // Always inline because this collapses to a small number of instructions // when given a constant parameter, but GCC doesn't want to inline by default. - bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool ExpectTag(uint32 expected); // Like above, except this reads from the specified buffer. The caller is // responsible for ensuring that the buffer is large enough to read a varint @@ -272,9 +271,9 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // // Returns a pointer beyond the expected tag if it was found, or NULL if it // was not. - static const uint8* ExpectTagFromArray( + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static const uint8* ExpectTagFromArray( const uint8* buffer, - uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + uint32 expected); // Usually returns true if no more bytes can be read. Always returns false // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent @@ -766,8 +765,8 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // but GCC by default doesn't want to inline this. void WriteTag(uint32 value); // Like WriteTag() but writing directly to the target array. - static uint8* WriteTagToArray( - uint32 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteTagToArray(uint32 value, + uint8* target); // Returns the number of bytes needed to encode the given value as a varint. static int VarintSize32(uint32 value); @@ -831,8 +830,8 @@ 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* WriteVarint64ToArrayInline( - uint64 value, uint8* target) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteVarint64ToArrayInline( + uint64 value, uint8* target); static int VarintSize32Fallback(uint32 value); }; diff --git a/src/google/protobuf/io/coded_stream_inl.h b/src/google/protobuf/io/coded_stream_inl.h index fa20f208..d95b06e0 100644 --- a/src/google/protobuf/io/coded_stream_inl.h +++ b/src/google/protobuf/io/coded_stream_inl.h @@ -36,6 +36,7 @@ #ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ #define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__ +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl_lite.h> diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index 02d5bad3..630c9086 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -41,6 +41,8 @@ #include <limits.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> #include <google/protobuf/io/zero_copy_stream_impl.h> diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc index dd7c036e..1be6c863 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -33,10 +33,12 @@ // This file contains the implementation of classes GzipInputStream and // GzipOutputStream. + #if HAVE_ZLIB #include <google/protobuf/io/gzip_stream.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 3ae8c268..7d886506 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -34,6 +34,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 1331a8d9..258dd986 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -37,6 +37,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/io/strtod.cc b/src/google/protobuf/io/strtod.cc index 56973439..579de9aa 100644 --- a/src/google/protobuf/io/strtod.cc +++ b/src/google/protobuf/io/strtod.cc @@ -34,6 +34,7 @@ #include <cstring> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 60bd7957..7ccd633d 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -90,6 +90,7 @@ #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/io/strtod.h> #include <google/protobuf/io/zero_copy_stream.h> diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 98576f56..49885eda 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -40,6 +40,7 @@ #include <string> #include <vector> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index de096fb9..6526056a 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -41,6 +41,7 @@ #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> #include <google/protobuf/testing/googletest.h> diff --git a/src/google/protobuf/io/zero_copy_stream.cc b/src/google/protobuf/io/zero_copy_stream.cc index f77c768f..186de001 100644 --- a/src/google/protobuf/io/zero_copy_stream.cc +++ b/src/google/protobuf/io/zero_copy_stream.cc @@ -34,6 +34,7 @@ #include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/io/zero_copy_stream_impl.cc b/src/google/protobuf/io/zero_copy_stream_impl.cc index f7901b27..7ec2b5da 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl.cc @@ -46,6 +46,7 @@ #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/stl_util.h> 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 97b73b88..686e63f2 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -39,6 +39,7 @@ #include <google/protobuf/stubs/casts.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/stl_util.h> namespace google { 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 4360b18f..9cdf0378 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -48,6 +48,7 @@ #include <iosfwd> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/stl_util.h> diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index f2e5b629..3850e76c 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -46,6 +46,7 @@ // "parametized tests" so that one set of tests can be used on all the // implementations. + #ifdef _MSC_VER #include <io.h> #else @@ -66,6 +67,8 @@ #endif #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/testing/googletest.h> #include <google/protobuf/testing/file.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/lite_arena_unittest.cc b/src/google/protobuf/lite_arena_unittest.cc new file mode 100644 index 00000000..f0bee880 --- /dev/null +++ b/src/google/protobuf/lite_arena_unittest.cc @@ -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. + +#include <google/protobuf/arena_test_util.h> +#include <google/protobuf/map_lite_test_util.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace { + +TEST(LiteArenaTest, MapNoHeapAllocation) { + // Allocate a large initial block to avoid mallocs during hooked test. + std::vector<char> arena_block(128 * 1024); + google::protobuf::ArenaOptions options; + options.initial_block = &arena_block[0]; + options.initial_block_size = arena_block.size(); + google::protobuf::Arena arena(options); + string data; + data.reserve(128 * 1024); + + { + // TODO(teboring): Enable no heap check when ArenaStringPtr is used in + // Map. + // google::protobuf::internal::NoHeapChecker no_heap; + + protobuf_unittest::TestArenaMapLite* from = + google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(&arena); + google::protobuf::MapLiteTestUtil::SetArenaMapFields(from); + from->SerializeToString(&data); + + protobuf_unittest::TestArenaMapLite* to = + google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>(&arena); + to->ParseFromString(data); + google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to); + } +} + +TEST(LiteArenaTest, UnknownFieldMemLeak) { + google::protobuf::Arena arena; + protobuf_unittest::ForeignMessageArenaLite* message = + google::protobuf::Arena::CreateMessage<protobuf_unittest::ForeignMessageArenaLite>( + &arena); + string data = "\012\000"; + int original_capacity = data.capacity(); + while (data.capacity() <= original_capacity) { + data.append("a"); + } + data[1] = data.size() - 2; + message->ParseFromString(data); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index 5af8b24d..d1948ab5 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -33,6 +33,7 @@ #include <string> #include <iostream> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/arena_test_util.h> #include <google/protobuf/map_lite_unittest.pb.h> @@ -377,13 +378,6 @@ int main(int argc, char* argv[]) { } { - // Proto2SetMapFieldsInitialized - protobuf_unittest::TestEnumStartWithNonZeroMapLite message; - EXPECT_EQ(protobuf_unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO_LITE, - (*message.mutable_map_field())[0]); - } - - { // Clear protobuf_unittest::TestMapLite message; @@ -692,37 +686,6 @@ int main(int argc, char* argv[]) { EXPECT_TRUE(map_message.IsInitialized()); } - // arena support for map ========================================= - - { - // ParsingAndSerializingNoHeapAllocation - - // Allocate a large initial block to avoid mallocs during hooked test. - std::vector<char> arena_block(128 * 1024); - google::protobuf::ArenaOptions options; - options.initial_block = &arena_block[0]; - options.initial_block_size = arena_block.size(); - google::protobuf::Arena arena(options); - string data; - data.reserve(128 * 1024); - - { - google::protobuf::internal::NoHeapChecker no_heap; - - protobuf_unittest::TestArenaMapLite* from = - google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>( - &arena); - google::protobuf::MapLiteTestUtil::SetArenaMapFields(from); - from->SerializeToString(&data); - - protobuf_unittest::TestArenaMapLite* to = - google::protobuf::Arena::CreateMessage<protobuf_unittest::TestArenaMapLite>( - &arena); - to->ParseFromString(data); - google::protobuf::MapLiteTestUtil::ExpectArenaMapFieldsSet(*to); - } - } - std::cout << "PASS" << std::endl; return 0; } diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index d928b7a7..8b61573d 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -35,9 +35,12 @@ #include <google/protobuf/stubs/hash.h> #include <limits> // To support Visual Studio 2008 +#include <google/protobuf/stubs/common.h> #include <google/protobuf/arena.h> #include <google/protobuf/generated_enum_util.h> #include <google/protobuf/map_type_handler.h> +#include <google/protobuf/message.h> +#include <google/protobuf/descriptor.h> namespace google { namespace protobuf { @@ -47,13 +50,379 @@ class Map; template <typename Enum> struct is_proto_enum; +class MapIterator; + namespace internal { template <typename Key, typename T, WireFormatLite::FieldType key_wire_type, WireFormatLite::FieldType value_wire_type, int default_enum_value> class MapFieldLite; -} + +template <typename Key, typename T, + WireFormatLite::FieldType key_wire_type, + WireFormatLite::FieldType value_wire_type, + int default_enum_value> +class MapField; + +template <typename Key, typename T> +class TypeDefinedMapFieldBase; + +class DynamicMapField; + +class GeneratedMessageReflection; +} // namespace internal + +#define TYPE_CHECK(EXPECTEDTYPE, METHOD) \ + if (type() != EXPECTEDTYPE) { \ + GOOGLE_LOG(FATAL) \ + << "Protocol Buffer map usage error:\n" \ + << METHOD << " type does not match\n" \ + << " Expected : " \ + << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n" \ + << " Actual : " \ + << FieldDescriptor::CppTypeName(type()); \ + } + +// MapKey is an union type for representing any possible +// map key. +class LIBPROTOBUF_EXPORT MapKey { + public: + MapKey() : type_(0) { + } + MapKey(const MapKey& other) : type_(0) { + CopyFrom(other); + } + + ~MapKey() { + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + delete val_.string_value_; + } + } + + FieldDescriptor::CppType type() const { + if (type_ == 0) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer map usage error:\n" + << "MapKey::type MapKey is not initialized. " + << "Call set methods to initialize MapKey."; + } + return (FieldDescriptor::CppType)type_; + } + + void SetInt64Value(int64 value) { + SetType(FieldDescriptor::CPPTYPE_INT64); + val_.int64_value_ = value; + } + void SetUInt64Value(uint64 value) { + SetType(FieldDescriptor::CPPTYPE_UINT64); + val_.uint64_value_ = value; + } + void SetInt32Value(int32 value) { + SetType(FieldDescriptor::CPPTYPE_INT32); + val_.int32_value_ = value; + } + void SetUInt32Value(uint32 value) { + SetType(FieldDescriptor::CPPTYPE_UINT32); + val_.uint32_value_ = value; + } + void SetBoolValue(bool value) { + SetType(FieldDescriptor::CPPTYPE_BOOL); + val_.bool_value_ = value; + } + void SetStringValue(const string& val) { + SetType(FieldDescriptor::CPPTYPE_STRING); + *val_.string_value_ = val; + } + + int64 GetInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapKey::GetInt64Value"); + return val_.int64_value_; + } + uint64 GetUInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapKey::GetUInt64Value"); + return val_.uint64_value_; + } + int32 GetInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapKey::GetInt32Value"); + return val_.int32_value_; + } + uint32 GetUInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapKey::GetUInt32Value"); + return val_.uint32_value_; + } + int32 GetBoolValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapKey::GetBoolValue"); + return val_.bool_value_; + } + const string& GetStringValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapKey::GetStringValue"); + return *val_.string_value_; + } + + bool operator==(const MapKey& other) const { + if (type_ != other.type_) { + return false; + } + switch (type()) { + case FieldDescriptor::CPPTYPE_STRING: + return *val_.string_value_ == *other.val_.string_value_; + case FieldDescriptor::CPPTYPE_INT64: + return val_.int64_value_ == other.val_.int64_value_; + case FieldDescriptor::CPPTYPE_INT32: + return val_.int32_value_ == other.val_.int32_value_; + case FieldDescriptor::CPPTYPE_UINT64: + return val_.uint64_value_ == other.val_.uint64_value_; + case FieldDescriptor::CPPTYPE_UINT32: + return val_.uint32_value_ == other.val_.uint32_value_; + case FieldDescriptor::CPPTYPE_BOOL: + return val_.bool_value_ == other.val_.bool_value_; + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; + } + } + + void CopyFrom(const MapKey& other) { + SetType(other.type()); + switch (type_) { + case FieldDescriptor::CPPTYPE_STRING: + *val_.string_value_ = *other.val_.string_value_; + break; + case FieldDescriptor::CPPTYPE_INT64: + val_.int64_value_ = other.val_.int64_value_; + break; + case FieldDescriptor::CPPTYPE_INT32: + val_.int32_value_ = other.val_.int32_value_; + break; + case FieldDescriptor::CPPTYPE_UINT64: + val_.uint64_value_ = other.val_.uint64_value_; + break; + case FieldDescriptor::CPPTYPE_UINT32: + val_.uint32_value_ = other.val_.uint32_value_; + break; + case FieldDescriptor::CPPTYPE_BOOL: + val_.bool_value_ = other.val_.bool_value_; + break; + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + } + + private: + template <typename K, typename V> + friend class internal::TypeDefinedMapFieldBase; + friend class MapIterator; + friend class internal::DynamicMapField; + + union KeyValue { + KeyValue() {} + string* string_value_; + int64 int64_value_; + int32 int32_value_; + uint64 uint64_value_; + uint32 uint32_value_; + bool bool_value_; + } val_; + + void SetType(FieldDescriptor::CppType type) { + if (type_ == type) return; + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + delete val_.string_value_; + } + type_ = type; + if (type_ == FieldDescriptor::CPPTYPE_STRING) { + val_.string_value_ = new string; + } + } + + // type_ is 0 or a valid FieldDescriptor::CppType. + int type_; +}; + +// MapValueRef points to a map value. +class LIBPROTOBUF_EXPORT MapValueRef { + public: + MapValueRef() : data_(NULL), type_(0) {} + + void SetInt64Value(int64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapValueRef::SetInt64Value"); + *reinterpret_cast<int64*>(data_) = value; + } + void SetUInt64Value(uint64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapValueRef::SetUInt64Value"); + *reinterpret_cast<uint64*>(data_) = value; + } + void SetInt32Value(int32 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapValueRef::SetInt32Value"); + *reinterpret_cast<int32*>(data_) = value; + } + void SetUInt32Value(uint64 value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapValueRef::SetUInt32Value"); + *reinterpret_cast<uint32*>(data_) = value; + } + void SetBoolValue(bool value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapValueRef::SetBoolValue"); + *reinterpret_cast<bool*>(data_) = value; + } + // TODO(jieluo) - Checks that enum is member. + void SetEnumValue(int value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, + "MapValueRef::SetEnumValue"); + *reinterpret_cast<int*>(data_) = value; + } + void SetStringValue(const string& value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapValueRef::SetStringValue"); + *reinterpret_cast<string*>(data_) = value; + } + void SetFloatValue(float value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, + "MapValueRef::SetFloatValue"); + *reinterpret_cast<float*>(data_) = value; + } + void SetDoubleValue(double value) { + TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, + "MapValueRef::SetDoubleValue"); + *reinterpret_cast<double*>(data_) = value; + } + + int64 GetInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, + "MapValueRef::GetInt64Value"); + return *reinterpret_cast<int64*>(data_); + } + uint64 GetUInt64Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, + "MapValueRef::GetUInt64Value"); + return *reinterpret_cast<uint64*>(data_); + } + int32 GetInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, + "MapValueRef::GetInt32Value"); + return *reinterpret_cast<int32*>(data_); + } + uint32 GetUInt32Value() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, + "MapValueRef::GetUInt32Value"); + return *reinterpret_cast<uint32*>(data_); + } + bool GetBoolValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, + "MapValueRef::GetBoolValue"); + return *reinterpret_cast<bool*>(data_); + } + int GetEnumValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, + "MapValueRef::GetEnumValue"); + return *reinterpret_cast<int*>(data_); + } + const string& GetStringValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, + "MapValueRef::GetStringValue"); + return *reinterpret_cast<string*>(data_); + } + float GetFloatValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, + "MapValueRef::GetFloatValue"); + return *reinterpret_cast<float*>(data_); + } + double GetDoubleValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, + "MapValueRef::GetDoubleValue"); + return *reinterpret_cast<double*>(data_); + } + + const Message& GetMessageValue() const { + TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, + "MapValueRef::GetMessageValue"); + return *reinterpret_cast<Message*>(data_); + } + + Message* MutableMessageValue() { + TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, + "MapValueRef::MutableMessageValue"); + return reinterpret_cast<Message*>(data_); + } + + private: + template <typename K, typename V, + internal::WireFormatLite::FieldType key_wire_type, + internal::WireFormatLite::FieldType value_wire_type, + int default_enum_value> + friend class internal::MapField; + template <typename K, typename V> + friend class internal::TypeDefinedMapFieldBase; + friend class MapIterator; + friend class internal::GeneratedMessageReflection; + friend class internal::DynamicMapField; + + void SetType(FieldDescriptor::CppType type) { + type_ = type; + } + + FieldDescriptor::CppType type() const { + if (type_ == 0 || data_ == NULL) { + GOOGLE_LOG(FATAL) + << "Protocol Buffer map usage error:\n" + << "MapValueRef::type MapValueRef is not initialized."; + } + return (FieldDescriptor::CppType)type_; + } + void SetValue(const void* val) { + data_ = const_cast<void*>(val); + } + void CopyFrom(const MapValueRef& other) { + type_ = other.type_; + data_ = other.data_; + } + // Only used in DynamicMapField + void DeleteData() { + switch (type_) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + delete reinterpret_cast<TYPE*>(data_); \ + 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); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); + HANDLE_TYPE(MESSAGE, Message); +#undef HANDLE_TYPE + } + } + // data_ point to a map value. MapValueRef does not + // own this value. + void* data_; + // type_ is 0 or a valid FieldDescriptor::CppType. + int type_; +}; + +#undef TYPE_CHECK // 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 @@ -82,7 +451,6 @@ class MapPair { T second; private: - typedef void DestructorSkippable_; friend class ::google::protobuf::Arena; friend class Map<Key, T>; }; @@ -92,9 +460,6 @@ class MapPair { // 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; @@ -118,7 +483,9 @@ class Map { : arena_(arena), allocator_(arena_), elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) {} + default_enum_value_(0) { + arena_->OwnDestructor(&elements_); + } Map(const Map& other) : arena_(NULL), @@ -127,6 +494,14 @@ class Map { default_enum_value_(other.default_enum_value_) { insert(other.begin(), other.end()); } + template <class InputIt> + explicit Map(const InputIt& first, const InputIt& last) + : arena_(NULL), + allocator_(arena_), + elements_(0, hasher(), key_equal(), allocator_), + default_enum_value_(0) { + insert(first, last); + } ~Map() { clear(); } @@ -172,7 +547,7 @@ class Map { !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) template<class NodeType, class... Args> void construct(NodeType* p, Args&&... args) { - new ((void*)p) NodeType(std::forward<Args>(args)...); + new (static_cast<void*>(p)) NodeType(std::forward<Args>(args)...); } template<class NodeType> @@ -206,6 +581,7 @@ class Map { } private: + typedef void DestructorSkippable_; Arena* arena_; template <typename X> @@ -449,6 +825,58 @@ class Map { }; } // namespace protobuf - } // namespace google + +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START +template<> +struct hash<google::protobuf::MapKey> { + size_t + operator()(const google::protobuf::MapKey& map_key) const { + switch (map_key.type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + return hash<string>()(map_key.GetStringValue()); + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + return hash< ::google::protobuf::int64>()(map_key.GetInt64Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + return hash< ::google::protobuf::int32>()(map_key.GetInt32Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + return hash< ::google::protobuf::uint64>()(map_key.GetUInt64Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + return hash< ::google::protobuf::uint32>()(map_key.GetUInt32Value()); + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + return hash<bool>()(map_key.GetBoolValue()); + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + return 0; + } + } + bool + operator()(const google::protobuf::MapKey& map_key1, + const google::protobuf::MapKey& map_key2) const { + switch (map_key1.type()) { +#define COMPARE_CPPTYPE(CPPTYPE, CPPTYPE_METHOD) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \ + return map_key1.Get##CPPTYPE_METHOD##Value() < \ + map_key2.Get##CPPTYPE_METHOD##Value(); + COMPARE_CPPTYPE(STRING, String) + COMPARE_CPPTYPE(INT64, Int64) + COMPARE_CPPTYPE(INT32, Int32) + COMPARE_CPPTYPE(UINT64, UInt64) + COMPARE_CPPTYPE(UINT32, UInt32) + COMPARE_CPPTYPE(BOOL, Bool) +#undef COMPARE_CPPTYPE + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + return true; + } + } +}; +GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END + #endif // GOOGLE_PROTOBUF_MAP_H__ diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h index e93d0348..987c4e29 100644 --- a/src/google/protobuf/map_entry.h +++ b/src/google/protobuf/map_entry.h @@ -34,6 +34,7 @@ #include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/map_entry_lite.h> #include <google/protobuf/map_type_handler.h> +#include <google/protobuf/metadata.h> #include <google/protobuf/reflection_ops.h> #include <google/protobuf/unknown_field_set.h> #include <google/protobuf/wire_format_lite_inl.h> @@ -79,40 +80,46 @@ class LIBPROTOBUF_EXPORT MapEntryBase : public Message { // 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. +// reflection, its in-memory type is the same as generated message with the same +// fields. However, in order to decide the in-memory type of key/value, we need +// to know both their cpp type in generated api and proto type. In +// implmentation, all in-memory types have related wire format functions to +// support except ArenaStringPtr. Therefore, we need to define another type with +// supporting wire format functions. Since this type is only used as return type +// of MapEntry accessors, it's named MapEntry accessor type. // -// cpp type | proto type | internal layout -// int32 TYPE_INT32 int32 -// int32 TYPE_FIXED32 int32 -// FooEnum TYPE_ENUM int -// FooMessage TYPE_MESSAGE FooMessage* +// cpp type: the type visible to users in public API. +// proto type: WireFormatLite::FieldType of the field. +// in-memory type: type of the data member used to stored this field. +// MapEntry accessor type: type used in MapEntry getters/mutators to access the +// field. // -// 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. +// cpp type | proto type | in-memory type | MapEntry accessor type +// int32 TYPE_INT32 int32 int32 +// int32 TYPE_FIXED32 int32 int32 +// string TYPE_STRING ArenaStringPtr string +// FooEnum TYPE_ENUM int int +// FooMessage TYPE_MESSAGE FooMessage* FooMessage +// +// The in-memory types of primitive types can be inferred from its proto type, +// while we need to explicitly specify the cpp type if proto type is +// TYPE_MESSAGE to infer the in-memory type. 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 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; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; + typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler; + + // Enum type cannot be used for MapTypeHandler::Read. Define a type + // which will replace Enum with int. + typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; + typedef typename ValueTypeHandler::MapEntryAccessorType + ValueMapEntryAccessorType; // Abbreviation for MapEntry typedef typename google::protobuf::internal::MapEntry< @@ -132,16 +139,16 @@ class MapEntry : public MapEntryBase { // accessors ====================================================== - virtual inline const KeyCppType& key() const { + virtual inline const KeyMapEntryAccessorType& key() const { return entry_lite_.key(); } - inline KeyCppType* mutable_key() { + inline KeyMapEntryAccessorType* mutable_key() { return entry_lite_.mutable_key(); } - virtual inline const ValCppType& value() const { + virtual inline const ValueMapEntryAccessorType& value() const { return entry_lite_.value(); } - inline ValCppType* mutable_value() { + inline ValueMapEntryAccessorType* mutable_value() { return entry_lite_.mutable_value(); } @@ -240,7 +247,9 @@ class MapEntry : public MapEntryBase { 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); + ::google::protobuf::MessageFactory::generated_factory(), + sizeof(MapEntry), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MapEntry, _internal_metadata_)); entry->descriptor_ = descriptor; entry->reflection_ = reflection; entry->set_default_instance(entry); @@ -250,10 +259,13 @@ class MapEntry : public MapEntryBase { } private: - MapEntry() : default_instance_(NULL), entry_lite_() {} + MapEntry() + : _internal_metadata_(NULL), default_instance_(NULL), entry_lite_() {} explicit MapEntry(Arena* arena) - : default_instance_(NULL), entry_lite_(arena) {} + : _internal_metadata_(arena), + default_instance_(NULL), + entry_lite_(arena) {} inline Arena* GetArenaNoVirtual() const { return entry_lite_.GetArenaNoVirtual(); @@ -266,6 +278,7 @@ class MapEntry : public MapEntryBase { static int offsets_[2]; UnknownFieldSet _unknown_fields_; + InternalMetadataWithArena _internal_metadata_; MapEntry* default_instance_; EntryLiteType entry_lite_; diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h index 52746da5..7cdf1b93 100644 --- a/src/google/protobuf/map_entry_lite.h +++ b/src/google/protobuf/map_entry_lite.h @@ -61,38 +61,21 @@ template <typename Key, typename Value, WireFormatLite::FieldType kValueFieldType, int default_enum_value> class 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; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; + typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler; // 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; + typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory; + typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory; + + // Enum type cannot be used for MapTypeHandler::Read. Define a type + // which will replace Enum with int. + typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType; + typedef typename ValueTypeHandler::MapEntryAccessorType + ValueMapEntryAccessorType; // Constants for field number. static const int kKeyFieldNumber = 1; @@ -100,38 +83,37 @@ class MapEntryLite : public MessageLite { // Constants for field tag. static const uint8 kKeyTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( - kKeyFieldNumber, KeyWireHandler::kWireType); + kKeyFieldNumber, KeyTypeHandler::kWireType); static const uint8 kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG( - kValueFieldNumber, ValueWireHandler::kWireType); + kValueFieldNumber, ValueTypeHandler::kWireType); static const int kTagSize = 1; public: ~MapEntryLite() { if (this != default_instance_) { - KeyCppHandler::Delete(key_); - ValueCppHandler::Delete(value_); + if (GetArenaNoVirtual() != NULL) return; + KeyTypeHandler::DeleteNoArena(key_); + ValueTypeHandler::DeleteNoArena(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 KeyMapEntryAccessorType& key() const { + return KeyTypeHandler::GetExternalReference(key_); } - virtual inline const ValCppType& value() const { + virtual inline const ValueMapEntryAccessorType& value() const { GOOGLE_CHECK(default_instance_ != NULL); - return ValueCppHandler::DefaultIfNotInitialized(value_, + return ValueTypeHandler::DefaultIfNotInitialized(value_, default_instance_->value_); } - inline ValCppType* mutable_value() { + inline KeyMapEntryAccessorType* mutable_key() { + set_has_key(); + return KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); + } + inline ValueMapEntryAccessorType* mutable_value() { set_has_value(); - ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual()); - return ValueCppHandler::Pointer(value_); + return ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); } // implements MessageLite ========================================= @@ -159,13 +141,17 @@ class MapEntryLite : public MessageLite { tag = input->ReadTag(); switch (tag) { case kKeyTag: - if (!KeyWireHandler::Read(input, mutable_key())) return false; + if (!KeyTypeHandler::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; + if (!ValueTypeHandler::Read(input, mutable_value())) { + return false; + } set_has_value(); if (input->ExpectAtEnd()) return true; break; @@ -184,32 +170,35 @@ class MapEntryLite : public MessageLite { int ByteSize() const { int size = 0; - size += has_key() ? kTagSize + KeyWireHandler::ByteSize(key()) : 0; - size += has_value() ? kTagSize + ValueWireHandler::ByteSize(value()) : 0; + size += has_key() ? kTagSize + KeyTypeHandler::ByteSize(key()) : 0; + size += has_value() ? kTagSize + ValueTypeHandler::ByteSize(value()) : 0; return size; } void SerializeWithCachedSizes(::google::protobuf::io::CodedOutputStream* output) const { - KeyWireHandler::Write(kKeyFieldNumber, key(), output); - ValueWireHandler::Write(kValueFieldNumber, value(), output); + KeyTypeHandler::Write(kKeyFieldNumber, key(), output); + ValueTypeHandler::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); + output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output); + output = ValueTypeHandler::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; + size += has_key() + ? kTagSize + KeyTypeHandler::GetCachedSize(key()) + : 0; + size += has_value() + ? kTagSize + ValueTypeHandler::GetCachedSize( + value()) + : 0; return size; } - bool IsInitialized() const { return ValueCppHandler::IsInitialized(value_); } + bool IsInitialized() const { return ValueTypeHandler::IsInitialized(value_); } MessageLite* New() const { MapEntryLite* entry = new MapEntryLite; @@ -225,36 +214,37 @@ class MapEntryLite : public MessageLite { int SpaceUsed() const { int size = sizeof(MapEntryLite); - size += KeyCppHandler::SpaceUsedInMapEntry(key_); - size += ValueCppHandler::SpaceUsedInMapEntry(value_); + size += KeyTypeHandler::SpaceUsedInMapEntry(key_); + size += ValueTypeHandler::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_); + KeyTypeHandler::EnsureMutable(&key_, GetArenaNoVirtual()); + KeyTypeHandler::Merge(from.key(), &key_, GetArenaNoVirtual()); set_has_key(); } if (from.has_value()) { - ValueCppHandler::EnsureMutable(&value_, GetArenaNoVirtual()); - ValueCppHandler::Merge(from.value(), &value_); + ValueTypeHandler::EnsureMutable(&value_, GetArenaNoVirtual()); + ValueTypeHandler::Merge(from.value(), &value_, GetArenaNoVirtual()); set_has_value(); } } } void Clear() { - KeyCppHandler::Clear(&key_); - ValueCppHandler::ClearMaybeByDefaultEnum(&value_, default_enum_value); + KeyTypeHandler::Clear(&key_, GetArenaNoVirtual()); + ValueTypeHandler::ClearMaybeByDefaultEnum( + &value_, GetArenaNoVirtual(), default_enum_value); clear_has_key(); clear_has_value(); } void InitAsDefaultInstance() { - KeyCppHandler::AssignDefaultValue(&key_); - ValueCppHandler::AssignDefaultValue(&value_); + KeyTypeHandler::AssignDefaultValue(&key_); + ValueTypeHandler::AssignDefaultValue(&value_); } Arena* GetArena() const { @@ -305,8 +295,8 @@ class MapEntryLite : public MessageLite { class 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; + typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: MapEntryWrapper(Arena* arena, const K& key, const V& value) @@ -316,8 +306,8 @@ class MapEntryLite : public MessageLite { Base::set_has_key(); Base::set_has_value(); } - inline const KeyCppType& key() const { return key_; } - inline const ValCppType& value() const { return value_; } + inline const KeyMapEntryAccessorType& key() const { return key_; } + inline const ValueMapEntryAccessorType& value() const { return value_; } private: const Key& key_; @@ -339,8 +329,8 @@ class MapEntryLite : public MessageLite { class 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; + typedef typename Base::KeyMapEntryAccessorType KeyMapEntryAccessorType; + typedef typename Base::ValueMapEntryAccessorType ValueMapEntryAccessorType; public: MapEnumEntryWrapper(Arena* arena, const K& key, const V& value) @@ -350,28 +340,28 @@ class MapEntryLite : public MessageLite { Base::set_has_key(); Base::set_has_value(); } - inline const KeyCppType& key() const { return key_; } - inline const ValCppType& value() const { return value_; } + inline const KeyMapEntryAccessorType& key() const { return key_; } + inline const ValueMapEntryAccessorType& value() const { return value_; } private: - const KeyCppType& key_; - const ValCppType value_; + const KeyMapEntryAccessorType& key_; + const ValueMapEntryAccessorType value_; friend class google::protobuf::Arena; typedef void DestructorSkippable_; }; MapEntryLite() : default_instance_(NULL), arena_(NULL) { - KeyCppHandler::Initialize(&key_, NULL); - ValueCppHandler::InitializeMaybeByDefaultEnum( + KeyTypeHandler::Initialize(&key_, NULL); + ValueTypeHandler::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( + KeyTypeHandler::Initialize(&key_, arena); + ValueTypeHandler::InitializeMaybeByDefaultEnum( &value_, default_enum_value, arena); _has_bits_[0] = 0; } @@ -386,8 +376,8 @@ class MapEntryLite : public MessageLite { MapEntryLite* default_instance_; - KeyBase key_; - ValueBase value_; + KeyOnMemory key_; + ValueOnMemory value_; Arena* arena_; uint32 _has_bits_[1]; diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index 6ff1936e..eddc95c4 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -29,6 +29,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <google/protobuf/map_field.h> +#include <google/protobuf/map_field_inl.h> #include <vector> @@ -145,6 +146,321 @@ void MapFieldBase::SyncMapWithRepeatedField() const { } } +// ------------------DynamicMapField------------------ +DynamicMapField::DynamicMapField(const Message* default_entry) + : default_entry_(default_entry) { +} + +DynamicMapField::DynamicMapField(const Message* default_entry, + Arena* arena) + : TypeDefinedMapFieldBase<MapKey, MapValueRef>(arena), + default_entry_(default_entry) { +} + +DynamicMapField::~DynamicMapField() { + // DynamicMapField owns map values. Need to delete them before clearing + // the map. + for (Map<MapKey, MapValueRef>::iterator iter = map_.begin(); + iter != map_.end(); ++iter) { + iter->second.DeleteData(); + } + map_.clear(); +} + +int DynamicMapField::size() const { + return GetMap().size(); +} + +bool DynamicMapField::ContainsMapKey( + const MapKey& map_key) const { + const Map<MapKey, MapValueRef>& map = GetMap(); + Map<MapKey, MapValueRef>::const_iterator iter = map.find(map_key); + return iter != map.end(); +} + +bool DynamicMapField::InsertMapValue( + const MapKey& map_key, MapValueRef* val) { + bool result = false; + + MapValueRef& map_val = (*MutableMap())[map_key]; + // If map_val.data_ is not set, it is newly inserted by map_[map_key]. + if (map_val.data_ == NULL) { + result = true; + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + map_val.SetType(val_des->cpp_type()); + // Allocate momery for the inserted MapValueRef, and initialize to + // default value. + switch (val_des->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + TYPE * value = new TYPE(); \ + map_val.SetValue(value); \ + 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); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = default_entry_->GetReflection()->GetMessage( + *default_entry_, val_des); + Message* value = message.New(); + map_val.SetValue(value); + break; + } + } + } + val->CopyFrom(map_val); + return result; +} + +bool DynamicMapField::DeleteMapValue(const MapKey& map_key) { + MapFieldBase::SyncMapWithRepeatedField(); + Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key); + if (iter == map_.end()) { + return false; + } + // Set map dirty only if the delete is successful. + MapFieldBase::SetMapDirty(); + iter->second.DeleteData(); + map_.erase(iter); + return true; +} + +const Map<MapKey, MapValueRef>& DynamicMapField::GetMap() const { + MapFieldBase::SyncMapWithRepeatedField(); + return map_; +} + +Map<MapKey, MapValueRef>* DynamicMapField::MutableMap() { + MapFieldBase::SyncMapWithRepeatedField(); + MapFieldBase::SetMapDirty(); + return &map_; +} + +void DynamicMapField::SetMapIteratorValue(MapIterator* map_iter) const { + Map<MapKey, MapValueRef>::const_iterator iter = + TypeDefinedMapFieldBase<MapKey, MapValueRef>::InternalGetIterator( + map_iter); + if (iter == map_.end()) return; + map_iter->key_.CopyFrom(iter->first); + map_iter->value_.CopyFrom(iter->second); +} + +void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const { + const Reflection* reflection = default_entry_->GetReflection(); + const FieldDescriptor* key_des = + default_entry_->GetDescriptor()->FindFieldByName("key"); + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + if (MapFieldBase::repeated_field_ == NULL) { + if (MapFieldBase::arena_ == NULL) { + MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>(); + } else { + MapFieldBase::repeated_field_ = + Arena::CreateMessage<RepeatedPtrField<Message> >( + MapFieldBase::arena_); + } + } + + MapFieldBase::repeated_field_->Clear(); + + for (Map<MapKey, MapValueRef>::const_iterator it = map_.begin(); + it != map_.end(); ++it) { + Message* new_entry = default_entry_->New(); + MapFieldBase::repeated_field_->AddAllocated(new_entry); + const MapKey& map_key = it->first; + switch (key_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(new_entry, key_des, map_key.GetStringValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(new_entry, key_des, map_key.GetBoolValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + const MapValueRef& map_val = it->second; + switch (val_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + reflection->SetString(new_entry, val_des, map_val.GetStringValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + reflection->SetBool(new_entry, val_des, map_val.GetBoolValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue()); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = map_val.GetMessageValue(); + reflection->MutableMessage(new_entry, val_des)->CopyFrom(message); + break; + } + } + } +} + +void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const { + Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_; + const Reflection* reflection = default_entry_->GetReflection(); + const FieldDescriptor* key_des = + default_entry_->GetDescriptor()->FindFieldByName("key"); + const FieldDescriptor* val_des = + default_entry_->GetDescriptor()->FindFieldByName("value"); + // DynamicMapField owns map values. Need to delete them before clearing + // the map. + for (Map<MapKey, MapValueRef>::iterator iter = map->begin(); + iter != map->end(); ++iter) { + iter->second.DeleteData(); + } + map->clear(); + for (RepeatedPtrField<Message>::iterator it = + MapFieldBase::repeated_field_->begin(); + it != MapFieldBase::repeated_field_->end(); ++it) { + MapKey map_key; + switch (key_des->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_STRING: + map_key.SetStringValue(reflection->GetString(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT64: + map_key.SetInt64Value(reflection->GetInt64(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: + map_key.SetInt32Value(reflection->GetInt32(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: + map_key.SetUInt64Value(reflection->GetUInt64(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: + map_key.SetUInt32Value(reflection->GetUInt32(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: + map_key.SetBoolValue(reflection->GetBool(*it, key_des)); + break; + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Can't get here."; + break; + } + MapValueRef& map_val = (*map)[map_key]; + map_val.SetType(val_des->cpp_type()); + switch (val_des->cpp_type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + TYPE * value = new TYPE; \ + *value = reflection->Get##METHOD(*it, val_des); \ + map_val.SetValue(value); \ + break; \ + } + HANDLE_TYPE(INT32, int32, Int32); + HANDLE_TYPE(INT64, int64, Int64); + HANDLE_TYPE(UINT32, uint32, UInt32); + HANDLE_TYPE(UINT64, uint64, UInt64); + HANDLE_TYPE(DOUBLE, double, Double); + HANDLE_TYPE(FLOAT, float, Float); + HANDLE_TYPE(BOOL, bool, Bool); + HANDLE_TYPE(STRING, string, String); + HANDLE_TYPE(ENUM, int32, EnumValue); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + const Message& message = reflection->GetMessage(*it, val_des); + Message* value = message.New(); + value->CopyFrom(message); + map_val.SetValue(value); + break; + } + } + } +} + +int DynamicMapField::SpaceUsedExcludingSelfNoLock() const { + int size = 0; + if (MapFieldBase::repeated_field_ != NULL) { + size += MapFieldBase::repeated_field_->SpaceUsedExcludingSelf(); + } + size += sizeof(map_); + int map_size = map_.size(); + if (map_size) { + Map<MapKey, MapValueRef>::const_iterator it = map_.begin(); + size += sizeof(it->first) * map_size; + size += sizeof(it->second) * map_size; + // If key is string, add the allocated space. + if (it->first.type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING) { + size += sizeof(string) * map_size; + } + // Add the allocated space in MapValueRef. + switch (it->second.type()) { +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + size += sizeof(TYPE) * map_size; \ + 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); + HANDLE_TYPE(STRING, string); + HANDLE_TYPE(ENUM, int32); +#undef HANDLE_TYPE + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { + while (it != map_.end()) { + const Message& message = it->second.GetMessageValue(); + size += message.GetReflection()->SpaceUsed(message); + ++it; + } + break; + } + } + } + return size; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 56d3d0f4..9130166b 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -32,6 +32,7 @@ #define GOOGLE_PROTOBUF_MAP_FIELD_H__ #include <google/protobuf/stubs/atomicops.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/arena.h> @@ -45,7 +46,8 @@ namespace google { namespace protobuf { - +class DynamicMessage; +class MapKey; namespace internal { class ContendedMapCleanTest; @@ -83,6 +85,17 @@ class LIBPROTOBUF_EXPORT MapFieldBase { // Like above. Returns mutable pointer to the internal repeated field. RepeatedPtrFieldBase* MutableRepeatedField(); + // Pure virtual map APIs for Map Reflection. + virtual bool ContainsMapKey(const MapKey& map_key) const = 0; + virtual bool InsertMapValue(const MapKey& map_key, MapValueRef* val) = 0; + virtual bool DeleteMapValue(const MapKey& map_key) = 0; + virtual bool EqualIterator(const MapIterator& a, + const MapIterator& b) const = 0; + virtual void MapBegin(MapIterator* map_iter) const = 0; + virtual void MapEnd(MapIterator* map_iter) const = 0; + // Sync Map with repeated field and returns the size of map. + virtual int size() const = 0; + // Returns the number of bytes used by the repeated field, excluding // sizeof(*this) int SpaceUsedExcludingSelf() const; @@ -141,6 +154,57 @@ class LIBPROTOBUF_EXPORT MapFieldBase { friend class ContendedMapCleanTest; friend class GeneratedMessageReflection; friend class MapFieldAccessor; + friend class ::google::protobuf::DynamicMessage; + + // Virtual helper methods for MapIterator. MapIterator doesn't have the + // type helper for key and value. Call these help methods to deal with + // different types. Real helper methods are implemented in + // TypeDefinedMapFieldBase. + friend class ::google::protobuf::MapIterator; + // Allocate map<...>::iterator for MapIterator. + virtual void InitializeIterator(MapIterator* map_iter) const = 0; + + // DeleteIterator() is called by the destructor of MapIterator only. + // It deletes map<...>::iterator for MapIterator. + virtual void DeleteIterator(MapIterator* map_iter) const = 0; + + // Copy the map<...>::iterator from other_iterator to + // this_iterator. + virtual void CopyIterator(MapIterator* this_iterator, + const MapIterator& other_iterator) const = 0; + + // IncreaseIterator() is called by operator++() of MapIterator only. + // It implements the ++ operator of MapIterator. + virtual void IncreaseIterator(MapIterator* map_iter) const = 0; +}; + +// This class provides common Map Reflection implementations for generated +// message and dynamic message. +template<typename Key, typename T> +class TypeDefinedMapFieldBase : public MapFieldBase { + public: + TypeDefinedMapFieldBase() {} + explicit TypeDefinedMapFieldBase(Arena* arena) : MapFieldBase(arena) {} + ~TypeDefinedMapFieldBase() {} + void MapBegin(MapIterator* map_iter) const; + void MapEnd(MapIterator* map_iter) const; + bool EqualIterator(const MapIterator& a, const MapIterator& b) const; + + virtual const Map<Key, T>& GetMap() const = 0; + virtual Map<Key, T>* MutableMap() = 0; + + protected: + typename Map<Key, T>::const_iterator& InternalGetIterator( + const MapIterator* map_iter) const; + + private: + void InitializeIterator(MapIterator* map_iter) const; + void DeleteIterator(MapIterator* map_iter) const; + void CopyIterator(MapIterator* this_iteratorm, + const MapIterator& that_iterator) const; + void IncreaseIterator(MapIterator* map_iter) const; + + virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0; }; // This class provides accesss to map field using generated api. It is used for @@ -150,25 +214,13 @@ template <typename Key, typename T, WireFormatLite::FieldType kKeyFieldType, WireFormatLite::FieldType kValueFieldType, int default_enum_value = 0> -class MapField : public MapFieldBase, +class MapField : public TypeDefinedMapFieldBase<Key, T>, 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; + // Provide utilities to parse/serialize key/value. Provide utilities to + // manipulate internal stored type. + typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler; + typedef MapTypeHandler<kValueFieldType, T> ValueTypeHandler; // Define message type for internal repeated field. typedef MapEntry<Key, T, kKeyFieldType, kValueFieldType, default_enum_value> @@ -183,8 +235,8 @@ class MapField : public MapFieldBase, // 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; + // SyncMapWithRepeatedFieldNoLock. + static const bool kIsValueEnum = ValueTypeHandler::kIsEnum; typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType; public: @@ -197,6 +249,11 @@ class MapField : public MapFieldBase, MapField(Arena* arena, const Message* default_entry); ~MapField(); + // Implement MapFieldBase + bool ContainsMapKey(const MapKey& map_key) const; + bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool DeleteMapValue(const MapKey& map_key); + // Accessors const Map<Key, T>& GetMap() const; Map<Key, T>* MutableMap(); @@ -230,12 +287,109 @@ class MapField : public MapFieldBase, void SyncMapWithRepeatedFieldNoLock() const; int SpaceUsedExcludingSelfNoLock() const; + void SetMapIteratorValue(MapIterator* map_iter) const; + mutable const EntryType* default_entry_; friend class ::google::protobuf::Arena; }; +class LIBPROTOBUF_EXPORT DynamicMapField: public TypeDefinedMapFieldBase<MapKey, MapValueRef> { + public: + explicit DynamicMapField(const Message* default_entry); + DynamicMapField(const Message* default_entry, Arena* arena); + ~DynamicMapField(); + + // Implement MapFieldBase + bool ContainsMapKey(const MapKey& map_key) const; + bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool DeleteMapValue(const MapKey& map_key); + + const Map<MapKey, MapValueRef>& GetMap() const; + Map<MapKey, MapValueRef>* MutableMap(); + + int size() const; + + private: + Map<MapKey, MapValueRef> map_; + const Message* default_entry_; + + // Implements MapFieldBase + void SyncRepeatedFieldWithMapNoLock() const; + void SyncMapWithRepeatedFieldNoLock() const; + int SpaceUsedExcludingSelfNoLock() const; + void SetMapIteratorValue(MapIterator* map_iter) const; +}; + } // namespace internal + +class LIBPROTOBUF_EXPORT MapIterator { + public: + MapIterator(Message* message, const FieldDescriptor* field) { + const Reflection* reflection = message->GetReflection(); + map_ = reflection->MapData(message, field); + key_.SetType(field->message_type()->FindFieldByName("key")->cpp_type()); + value_.SetType(field->message_type()->FindFieldByName("value")->cpp_type()); + map_->InitializeIterator(this); + } + MapIterator(const MapIterator& other) { + map_ = other.map_; + map_->InitializeIterator(this); + map_->CopyIterator(this, other); + } + ~MapIterator() { + map_->DeleteIterator(this); + } + friend bool operator==(const MapIterator& a, const MapIterator& b) { + return a.map_->EqualIterator(a, b); + } + friend bool operator!=(const MapIterator& a, const MapIterator& b) { + return !a.map_->EqualIterator(a, b); + } + MapIterator& operator++() { + map_->IncreaseIterator(this); + return *this; + } + MapIterator operator++(int) { + // iter_ is copied from Map<...>::iterator, no need to + // copy from its self again. Use the same implementation + // with operator++() + map_->IncreaseIterator(this); + return *this; + } + const MapKey& GetKey() { + return key_; + } + const MapValueRef& GetValueRef() { + return value_; + } + MapValueRef* MutableValueRef() { + map_->SetMapDirty(); + return &value_; + } + + private: + template <typename Key, typename T> + friend class internal::TypeDefinedMapFieldBase; + friend class internal::DynamicMapField; + template <typename Key, typename T, + internal::WireFormatLite::FieldType kKeyFieldType, + internal::WireFormatLite::FieldType kValueFieldType, + int default_enum_value> + friend class internal::MapField; + + // reinterpret_cast from heap-allocated Map<...>::iterator*. MapIterator owns + // the iterator. It is allocated by MapField<...>::InitializeIterator() called + // in constructor and deleted by MapField<...>::DeleteIterator() called in + // destructor. + void* iter_; + // Point to a MapField to call helper methods implemented in MapField. + // MapIterator does not own this object. + internal::MapFieldBase* map_; + MapKey key_; + MapValueRef value_; +}; + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 5b4305f9..16c4a08f 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -36,12 +36,130 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <google/protobuf/map.h> #include <google/protobuf/map_field.h> #include <google/protobuf/map_type_handler.h> namespace google { namespace protobuf { namespace internal { +// UnwrapMapKey template +template<typename T> +T UnwrapMapKey(const MapKey& map_key); +template<> +inline int32 UnwrapMapKey<int32>(const MapKey& map_key) { + return map_key.GetInt32Value(); +} +template<> +inline uint32 UnwrapMapKey<uint32>(const MapKey& map_key) { + return map_key.GetUInt32Value(); +} +template<> +inline int64 UnwrapMapKey<int64>(const MapKey& map_key) { + return map_key.GetInt64Value(); +} +template<> +inline uint64 UnwrapMapKey<uint64>(const MapKey& map_key) { + return map_key.GetUInt64Value(); +} +template<> +inline bool UnwrapMapKey<bool>(const MapKey& map_key) { + return map_key.GetBoolValue(); +} +template<> +inline string UnwrapMapKey<string>(const MapKey& map_key) { + return map_key.GetStringValue(); +} + +// SetMapKey template +template<typename T> +inline void SetMapKey(MapKey* map_key, const T& value); +template<> +inline void SetMapKey<int32>(MapKey* map_key, const int32& value) { + map_key->SetInt32Value(value); +} +template<> +inline void SetMapKey<uint32>(MapKey* map_key, const uint32& value) { + map_key->SetUInt32Value(value); +} +template<> +inline void SetMapKey<int64>(MapKey* map_key, const int64& value) { + map_key->SetInt64Value(value); +} +template<> +inline void SetMapKey<uint64>(MapKey* map_key, const uint64& value) { + map_key->SetUInt64Value(value); +} +template<> +inline void SetMapKey<bool>(MapKey* map_key, const bool& value) { + map_key->SetBoolValue(value); +} +template<> +inline void SetMapKey<string>(MapKey* map_key, const string& value) { + map_key->SetStringValue(value); +} + +// ------------------------TypeDefinedMapFieldBase--------------- +template <typename Key, typename T> +typename Map<Key, T>::const_iterator& +TypeDefinedMapFieldBase<Key, T>::InternalGetIterator( + const MapIterator* map_iter) const { + return *reinterpret_cast<typename Map<Key, T>::const_iterator *>( + map_iter->iter_); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::MapBegin(MapIterator* map_iter) const { + InternalGetIterator(map_iter) = GetMap().begin(); + SetMapIteratorValue(map_iter); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::MapEnd(MapIterator* map_iter) const { + InternalGetIterator(map_iter) = GetMap().end(); +} + +template <typename Key, typename T> +bool TypeDefinedMapFieldBase<Key, T>::EqualIterator(const MapIterator& a, + const MapIterator& b) + const { + return InternalGetIterator(&a) == InternalGetIterator(&b); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::IncreaseIterator(MapIterator* map_iter) + const { + ++InternalGetIterator(map_iter); + SetMapIteratorValue(map_iter); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::InitializeIterator( + MapIterator* map_iter) const { + map_iter->iter_ = new typename Map<Key, T>::const_iterator; + GOOGLE_CHECK(map_iter->iter_ != NULL); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::DeleteIterator(MapIterator* map_iter) + const { + delete reinterpret_cast<typename Map<Key, T>::const_iterator *>( + map_iter->iter_); +} + +template <typename Key, typename T> +void TypeDefinedMapFieldBase<Key, T>::CopyIterator( + MapIterator* this_iter, + const MapIterator& that_iter) const { + InternalGetIterator(this_iter) = InternalGetIterator(&that_iter); + this_iter->key_.SetType(that_iter.key_.type()); + // MapValueRef::type() fails when containing data is null. However, if + // this_iter points to MapEnd, data can be null. + this_iter->value_.SetType((FieldDescriptor::CppType)that_iter.value_.type_); + SetMapIteratorValue(this_iter); +} + +// ---------------------------------------------------------------------- template <typename Key, typename T, WireFormatLite::FieldType kKeyFieldType, @@ -56,7 +174,7 @@ template <typename Key, typename T, int default_enum_value> MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField( Arena* arena) - : MapFieldBase(arena), + : TypeDefinedMapFieldBase<Key, T>(arena), MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>( arena), default_entry_(NULL) {} @@ -75,7 +193,7 @@ template <typename Key, typename T, int default_enum_value> MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MapField( Arena* arena, const Message* default_entry) - : MapFieldBase(arena), + : TypeDefinedMapFieldBase<Key, T>(arena), MapFieldLite<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>( arena), default_entry_(down_cast<const EntryType*>(default_entry)) {} @@ -94,7 +212,7 @@ template <typename Key, typename T, int MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::size() const { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); return MapFieldLiteType::GetInternalMap().size(); } @@ -105,9 +223,65 @@ template <typename Key, typename T, void MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::Clear() { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); MapFieldLiteType::MutableInternalMap()->clear(); - SetMapDirty(); + MapFieldBase::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>::SetMapIteratorValue( + MapIterator* map_iter) const { + const Map<Key, T>& map = GetMap(); + typename Map<Key, T>::const_iterator iter = + TypeDefinedMapFieldBase<Key, T>::InternalGetIterator(map_iter); + if (iter == map.end()) return; + SetMapKey(&map_iter->key_, iter->first); + map_iter->value_.SetValue(&iter->second); +} + +template <typename Key, typename T, + WireFormatLite::FieldType kKeyFieldType, + WireFormatLite::FieldType kValueFieldType, + int default_enum_value> +bool MapField<Key, T, kKeyFieldType, kValueFieldType, + default_enum_value>::ContainsMapKey( + const MapKey& map_key) const { + const Map<Key, T>& map = GetMap(); + const Key& key = UnwrapMapKey<Key>(map_key); + typename Map<Key, T>::const_iterator iter = map.find(key); + return iter != map.end(); +} + +template <typename Key, typename T, + WireFormatLite::FieldType kKeyFieldType, + WireFormatLite::FieldType kValueFieldType, + int default_enum_value> +bool MapField<Key, T, kKeyFieldType, kValueFieldType, + default_enum_value>::InsertMapValue(const MapKey& map_key, + MapValueRef* val) { + Map<Key, T>* map = MutableMap(); + bool result = false; + const Key& key = UnwrapMapKey<Key>(map_key); + if (map->end() == map->find(key)) { + result = true; + } + val->SetValue(&((*map)[key])); + return result; +} + +template <typename Key, typename T, + WireFormatLite::FieldType kKeyFieldType, + WireFormatLite::FieldType kValueFieldType, + int default_enum_value> +bool MapField<Key, T, kKeyFieldType, kValueFieldType, + default_enum_value>::DeleteMapValue( + const MapKey& map_key) { + const Key& key = UnwrapMapKey<Key>(map_key); + return MutableMap()->erase(key); } template <typename Key, typename T, @@ -117,7 +291,7 @@ template <typename Key, typename T, const Map<Key, T>& MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::GetMap() const { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); return MapFieldLiteType::GetInternalMap(); } @@ -128,9 +302,9 @@ template <typename Key, typename T, Map<Key, T>* MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MutableMap() { - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); Map<Key, T>* result = MapFieldLiteType::MutableInternalMap(); - SetMapDirty(); + MapFieldBase::SetMapDirty(); return result; } @@ -143,10 +317,10 @@ MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::MergeFrom( const MapFieldLiteType& other) { const MapField& down_other = down_cast<const MapField&>(other); - SyncMapWithRepeatedField(); + MapFieldBase::SyncMapWithRepeatedField(); down_other.SyncMapWithRepeatedField(); MapFieldLiteType::MergeFrom(other); - SetMapDirty(); + MapFieldBase::SetMapDirty(); } template <typename Key, typename T, @@ -158,9 +332,9 @@ 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_); + std::swap(MapFieldBase::repeated_field_, down_other->repeated_field_); MapFieldLiteType::Swap(other); - std::swap(state_, down_other->state_); + std::swap(MapFieldBase::state_, down_other->state_); } template <typename Key, typename T, @@ -171,7 +345,7 @@ void MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::SetEntryDescriptor( const Descriptor** descriptor) { - entry_descriptor_ = descriptor; + MapFieldBase::entry_descriptor_ = descriptor; } template <typename Key, typename T, @@ -181,7 +355,7 @@ template <typename Key, typename T, void MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::SetAssignDescriptorCallback(void (*callback)()) { - assign_descriptor_callback_ = callback; + MapFieldBase::assign_descriptor_callback_ = callback; } template <typename Key, typename T, @@ -211,17 +385,19 @@ template <typename Key, typename T, void MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::SyncRepeatedFieldWithMapNoLock() const { - if (repeated_field_ == NULL) { + if (MapFieldBase::repeated_field_ == NULL) { if (MapFieldBase::arena_ == NULL) { - repeated_field_ = new RepeatedPtrField<Message>(); + MapFieldBase::repeated_field_ = new RepeatedPtrField<Message>(); } else { - repeated_field_ = Arena::CreateMessage<RepeatedPtrField<Message> >( - MapFieldBase::arena_); + MapFieldBase::repeated_field_ = + Arena::CreateMessage<RepeatedPtrField<Message> >( + MapFieldBase::arena_); } } const Map<Key, T>& map = GetInternalMap(); RepeatedPtrField<EntryType>* repeated_field = - reinterpret_cast<RepeatedPtrField<EntryType>*>(repeated_field_); + reinterpret_cast<RepeatedPtrField<EntryType>*>( + MapFieldBase::repeated_field_); repeated_field->Clear(); @@ -246,7 +422,9 @@ 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_); + reinterpret_cast<RepeatedPtrField<EntryType>*>( + MapFieldBase::repeated_field_); + GOOGLE_CHECK(MapFieldBase::repeated_field_ != NULL); map->clear(); for (typename RepeatedPtrField<EntryType>::iterator it = repeated_field->begin(); it != repeated_field->end(); ++it) { @@ -267,15 +445,15 @@ int MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::SpaceUsedExcludingSelfNoLock() const { int size = 0; - if (repeated_field_ != NULL) { - size += repeated_field_->SpaceUsedExcludingSelf(); + if (MapFieldBase::repeated_field_ != NULL) { + size += MapFieldBase::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); + size += KeyTypeHandler::SpaceUsedInMap(it->first); + size += ValueTypeHandler::SpaceUsedInMap(it->second); } return size; } @@ -289,10 +467,11 @@ MapField<Key, T, kKeyFieldType, kValueFieldType, default_enum_value>::InitDefaultEntryOnce() const { if (default_entry_ == NULL) { - InitMetadataOnce(); - GOOGLE_CHECK(*entry_descriptor_ != NULL); + MapFieldBase::InitMetadataOnce(); + GOOGLE_CHECK(*MapFieldBase::entry_descriptor_ != NULL); default_entry_ = down_cast<const EntryType*>( - MessageFactory::generated_factory()->GetPrototype(*entry_descriptor_)); + MessageFactory::generated_factory()->GetPrototype( + *MapFieldBase::entry_descriptor_)); } } diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index e3a64079..2ff1d6bb 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc @@ -34,6 +34,7 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/arena.h> #include <google/protobuf/map.h> @@ -74,6 +75,28 @@ class MapFieldBaseStub : public MapFieldBase { bool IsRepeatedClean() { return state_ != 1; } void SetMapDirty() { state_ = 0; } void SetRepeatedDirty() { state_ = 1; } + bool ContainsMapKey(const MapKey& map_key) const { + return false; + } + bool InsertMapValue(const MapKey& map_key, MapValueRef* val) { + return false; + } + bool DeleteMapValue(const MapKey& map_key) { + return false; + } + bool EqualIterator(const MapIterator& a, const MapIterator& b) const { + return false; + } + int size() const { return 0; } + void MapBegin(MapIterator* map_iter) const {} + void MapEnd(MapIterator* map_iter) const {} + void InitializeIterator(MapIterator* map_iter) const {} + void DeleteIterator(MapIterator* map_iter) const {} + void CopyIterator(MapIterator* this_iterator, + const MapIterator& other_iterator) const {} + void IncreaseIterator(MapIterator* map_iter) const {} + void SetDefaultMessageEntry(const Message* message) const {} + const Message* GetDefaultMessageEntry() const { return NULL; } }; class MapFieldBasePrimitiveTest : public ::testing::Test { diff --git a/src/google/protobuf/map_lite_unittest.proto b/src/google/protobuf/map_lite_unittest.proto index c69e8d94..0592dd7a 100644 --- a/src/google/protobuf/map_lite_unittest.proto +++ b/src/google/protobuf/map_lite_unittest.proto @@ -34,6 +34,7 @@ option cc_enable_arenas = true; option optimize_for = LITE_RUNTIME; import "google/protobuf/unittest_lite.proto"; +import "google/protobuf/unittest_no_arena_lite.proto"; package protobuf_unittest; @@ -72,8 +73,12 @@ message TestArenaMapLite { 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; + map<string , string > map_string_string = 14; + map<int32 , bytes > map_int32_bytes = 15; + map<int32 , MapEnumLite> map_int32_enum = 16; + map<int32 , ForeignMessageArenaLite> map_int32_foreign_message = 17; + map<int32, .protobuf_unittest_no_arena.ForeignMessageLite> + map_int32_foreign_message_no_arena = 18; } // Test embeded message with required fields @@ -81,10 +86,6 @@ 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; @@ -112,10 +113,6 @@ enum Proto2MapEnumPlusExtraLite { 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; diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto index 3d4af28e..6f9d6165 100644 --- a/src/google/protobuf/map_proto2_unittest.proto +++ b/src/google/protobuf/map_proto2_unittest.proto @@ -49,10 +49,6 @@ enum Proto2MapEnumPlusExtra { 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; @@ -62,7 +58,3 @@ 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 index d62ec85f..a74801d9 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -36,7 +36,9 @@ #include <sstream> #include <google/protobuf/stubs/casts.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/arena_test_util.h> @@ -70,6 +72,7 @@ namespace google { using google::protobuf::unittest::ForeignMessage; using google::protobuf::unittest::TestAllTypes; using google::protobuf::unittest::TestMap; +using google::protobuf::unittest::TestRecursiveMapMessage; namespace protobuf { namespace internal { @@ -200,6 +203,21 @@ TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) { EXPECT_DEATH(const_map_.at(0), ""); } +TEST_F(MapImplTest, UsageErrors) { + MapKey key; + key.SetInt64Value(1); + EXPECT_DEATH(key.GetUInt64Value(), + "Protocol Buffer map usage error:\n" + "MapKey::GetUInt64Value type does not match\n" + " Expected : uint64\n" + " Actual : int64"); + + MapValueRef value; + EXPECT_DEATH(value.SetFloatValue(0.1), + "Protocol Buffer map usage error:\n" + "MapValueRef::type MapValueRef is not initialized."); +} + #endif // PROTOBUF_HAS_DEATH_TEST TEST_F(MapImplTest, CountNonExist) { @@ -475,6 +493,23 @@ TEST_F(MapImplTest, CopyConstructor) { EXPECT_EQ(value2, other.at(key2)); } +TEST_F(MapImplTest, IterConstructor) { + int32 key1 = 0; + int32 key2 = 1; + int32 value1 = 100; + int32 value2 = 101; + + std::map<int32, int32> map; + map[key1] = value1; + map[key2] = value2; + + Map<int32, int32> new_map(map.begin(), map.end()); + + EXPECT_EQ(2, new_map.size()); + EXPECT_EQ(value1, new_map.at(key1)); + EXPECT_EQ(value2, new_map.at(key2)); +} + TEST_F(MapImplTest, Assigner) { int32 key1 = 0; int32 key2 = 1; @@ -1140,6 +1175,19 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { mmf_int32_foreign_message.Add(*entry_int32_foreign_message); EXPECT_EQ(1234, message.map_int32_foreign_message().at(4321).c()); + // Test Reflection::AddAllocatedMessage + Message* free_entry_string_string = MessageFactory::generated_factory() + ->GetPrototype(fd_map_string_string->message_type()) + ->New(); + entry_string_string->GetReflection()->SetString( + free_entry_string_string, + fd_map_string_string->message_type()->field(0), "4321"); + entry_string_string->GetReflection()->SetString( + free_entry_string_string, fd_map_string_string->message_type()->field(1), + "1234"); + refl->AddAllocatedMessage(&message, fd_map_string_string, + free_entry_string_string); + // Test MutableRepeatedFieldRef::RemoveLast() mmf_int32_int32.RemoveLast(); mmf_int32_double.RemoveLast(); @@ -1147,7 +1195,7 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { 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(11, message.map_string_string().size()); EXPECT_EQ(10, message.map_int32_foreign_message().size()); // Test MutableRepeatedFieldRef::SwapElements() @@ -1398,9 +1446,9 @@ TEST(GeneratedMapFieldTest, SetMapFieldsInitialized) { } TEST(GeneratedMapFieldTest, Proto2SetMapFieldsInitialized) { - unittest::TestEnumStartWithNonZeroMap message; - EXPECT_EQ(unittest::PROTO2_NON_ZERO_MAP_ENUM_FOO, - (*message.mutable_map_field())[0]); + unittest::TestEnumMap message; + EXPECT_EQ(unittest::PROTO2_MAP_ENUM_FOO, + (*message.mutable_known_map_field())[0]); } TEST(GeneratedMapFieldTest, Clear) { @@ -1526,12 +1574,28 @@ TEST(GeneratedMapFieldTest, CopyFromDynamicMessage) { google::protobuf::scoped_ptr<Message> message1; message1.reset( factory.GetPrototype(unittest::TestMap::descriptor())->New()); - - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(message1.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); + message2.CopyFrom(*message1); + MapTestUtil::ExpectMapFieldsSet(message2); +} + +TEST(GeneratedMapFieldTest, CopyFromDynamicMessageMapReflection) { + 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()); + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(message1.get()); + reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); message2.CopyFrom(*message1); MapTestUtil::ExpectMapFieldsSet(message2); } @@ -1547,12 +1611,43 @@ TEST(GeneratedMapFieldTest, DynamicMessageCopyFrom) { message1.reset( factory.GetPrototype(unittest::TestMap::descriptor())->New()); - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + message1->MergeFrom(message2); + reflection_tester.ExpectMapFieldsSetViaReflection(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); +} + +TEST(GeneratedMapFieldTest, DynamicMessageCopyFromMapReflection) { + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); + unittest::TestMap message2; + reflection_tester.SetMapFieldsViaMapReflection(&message2); + + // Construct a dynamic message via the factory. + DynamicMessageFactory factory; + google::protobuf::scoped_ptr<Message> message1; + message1.reset( + factory.GetPrototype(unittest::TestMap::descriptor())->New()); + message1->MergeFrom(message2); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message1); } +TEST(GeneratedMapFieldTest, SyncDynamicMapWithRepeatedField) { + // Construct a dynamic message via the factory. + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + DynamicMessageFactory factory; + google::protobuf::scoped_ptr<Message> message; + message.reset( + factory.GetPrototype(unittest::TestMap::descriptor())->New()); + reflection_tester.SetMapFieldsViaReflection(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflection(*message); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS TEST(GeneratedMapFieldTest, NonEmptyMergeFrom) { @@ -1779,7 +1874,7 @@ TEST(GeneratedMapFieldTest, IsInitialized) { TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(&message); @@ -1790,11 +1885,12 @@ 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( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.SetMapFieldsViaReflection(&message); MapTestUtil::ExpectMapFieldsSet(message); reflection_tester.ExpectMapFieldsSetViaReflection(message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message); reflection_tester.ModifyMapFieldsViaReflection(&message); MapTestUtil::ExpectMapFieldsModified(message); @@ -1848,15 +1944,16 @@ TEST(GeneratedMapFieldReflectionTest, ClearField) { MapTestUtil::SetMapFields(&message); MapTestUtil::ExpectMapFieldsSet(message); - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.ClearMapFieldsViaReflection(&message); - MapTestUtil::ExpectClear(message); + reflection_tester.ExpectClearViaReflection(message); + reflection_tester.ExpectClearViaReflectionIterator(&message); } TEST(GeneratedMapFieldReflectionTest, RemoveLast) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); MapTestUtil::SetMapFields(&message); @@ -1875,7 +1972,7 @@ TEST(GeneratedMapFieldReflectionTest, RemoveLast) { TEST(GeneratedMapFieldReflectionTest, ReleaseLast) { unittest::TestMap message; const Descriptor* descriptor = message.GetDescriptor(); - MapTestUtil::MapReflectionTester reflection_tester(descriptor); + MapReflectionTester reflection_tester(descriptor); MapTestUtil::SetMapFields(&message); @@ -1904,7 +2001,7 @@ TEST(GeneratedMapFieldReflectionTest, ReleaseLast) { TEST(GeneratedMapFieldReflectionTest, SwapElements) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); MapTestUtil::SetMapFields(&message); @@ -1944,7 +2041,7 @@ TEST(GeneratedMapFieldReflectionTest, SwapElements) { TEST(GeneratedMapFieldReflectionTest, MutableUnknownFields) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message); } @@ -2000,24 +2097,35 @@ TEST(GeneratedMapFieldReflectionTest, MergeFromClearMapEntry) { TEST(GeneratedMapFieldReflectionTest, MapEntryClear) { unittest::TestMap message; - MapTestUtil::MapReflectionTester reflection_tester( + MapReflectionTester reflection_tester( unittest::TestMap::descriptor()); reflection_tester.MutableUnknownFieldsOfMapFieldsViaReflection(&message); } TEST(GeneratedMapFieldReflectionTest, Proto2MapEntryClear) { - unittest::TestEnumStartWithNonZeroMap message; + unittest::TestEnumMap message; const Descriptor* descriptor = message.GetDescriptor(); const FieldDescriptor* field_descriptor = - descriptor->FindFieldByName("map_field"); + descriptor->FindFieldByName("known_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, + EXPECT_EQ(0, sub_message->GetReflection()->GetEnumValue(*sub_message, value_descriptor)); } +// Map Reflection API Test ========================================= + +TEST(GeneratedMapFieldReflectionTest, SetViaMapReflection) { + unittest::TestMap message; + MapReflectionTester reflection_tester( + unittest::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message); + reflection_tester.ExpectMapFieldsSetViaReflection(message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message); +} + // Dynamic Message Test ============================================= class MapFieldInDynamicMessageTest : public testing::Test { @@ -2025,6 +2133,7 @@ class MapFieldInDynamicMessageTest : public testing::Test { const DescriptorPool* pool_; DynamicMessageFactory factory_; const Descriptor* map_descriptor_; + const Descriptor* recursive_map_descriptor_; const Message* map_prototype_; MapFieldInDynamicMessageTest() @@ -2033,7 +2142,10 @@ class MapFieldInDynamicMessageTest : public testing::Test { virtual void SetUp() { map_descriptor_ = pool_->FindMessageTypeByName("protobuf_unittest.TestMap"); + recursive_map_descriptor_ = + pool_->FindMessageTypeByName("protobuf_unittest.TestRecursiveMapMessage"); ASSERT_TRUE(map_descriptor_ != NULL); + ASSERT_TRUE(recursive_map_descriptor_ != NULL); map_prototype_ = factory_.GetPrototype(map_descriptor_); } }; @@ -2043,19 +2155,19 @@ TEST_F(MapFieldInDynamicMessageTest, MapIndependentOffsets) { // 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_); + MapReflectionTester reflection_tester(map_descriptor_); reflection_tester.SetMapFieldsViaReflection(message.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message); } -TEST_F(MapFieldInDynamicMessageTest, Map) { +TEST_F(MapFieldInDynamicMessageTest, DynamicMapReflection) { // 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()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(message.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message); } @@ -2066,7 +2178,7 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { // 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_); + MapReflectionTester reflection_tester(map_descriptor_); int initial_space_used = message->SpaceUsed(); @@ -2074,6 +2186,15 @@ TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { EXPECT_LT(initial_space_used, message->SpaceUsed()); } +TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) { + TestRecursiveMapMessage from; + (*from.mutable_a())[0]; + string data = from.SerializeAsString(); + google::protobuf::scoped_ptr<Message> to( + factory_.GetPrototype(recursive_map_descriptor_)->New()); + ASSERT_TRUE(to->ParseFromString(data)); +} + // ReflectionOps Test =============================================== TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) { @@ -2260,7 +2381,7 @@ TEST(TextFormatMapTest, SerializeAndParse) { TEST(TextFormatMapTest, Sorted) { unittest::TestMap message; - MapTestUtil::MapReflectionTester tester(message.GetDescriptor()); + MapReflectionTester tester(message.GetDescriptor()); tester.SetMapFieldsViaReflection(&message); string expected_text; @@ -2292,7 +2413,8 @@ TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) { data.reserve(128 * 1024); { - NoHeapChecker no_heap; + // TODO(teboring): Enable no heap check when ArenaStringPtr is used in map. + // NoHeapChecker no_heap; unittest::TestArenaMap* from = Arena::CreateMessage<unittest::TestArenaMap>(&arena); @@ -2326,6 +2448,22 @@ TEST(ArenaTest, RelfectionInTextFormat) { MapTestUtil::ExpectArenaMapFieldsSet(*to); } +// Make sure the memory allocated for string in map is deallocated. +TEST(ArenaTest, StringMapNoLeak) { + Arena arena; + unittest::TestArenaMap* message = + Arena::CreateMessage<unittest::TestArenaMap>(&arena); + string data; + // String with length less than 16 will not be allocated from heap. + int original_capacity = data.capacity(); + while (data.capacity() <= original_capacity) { + data.append("a"); + } + (*message->mutable_map_string_string())[data] = data; + // We rely on heap checkers to detect memory leak for us. + ASSERT_FALSE(message == NULL); +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/map_test_util.cc b/src/google/protobuf/map_test_util.cc index 1713e373..ae094647 100644 --- a/src/google/protobuf/map_test_util.cc +++ b/src/google/protobuf/map_test_util.cc @@ -209,7 +209,7 @@ std::vector<const Message*> MapTestUtil::GetMapEntriesFromRelease( return result; } -MapTestUtil::MapReflectionTester::MapReflectionTester( +MapReflectionTester::MapReflectionTester( const Descriptor* base_descriptor) : base_descriptor_(base_descriptor) { const DescriptorPool* pool = base_descriptor->file()->pool(); @@ -329,14 +329,14 @@ MapTestUtil::MapReflectionTester::MapReflectionTester( } // Shorthand to get a FieldDescriptor for a field of unittest::TestMap. -const FieldDescriptor* MapTestUtil::MapReflectionTester::F(const string& name) { +const FieldDescriptor* MapReflectionTester::F(const string& name) { const FieldDescriptor* result = NULL; result = base_descriptor_->FindFieldByName(name); GOOGLE_CHECK(result != NULL); return result; } -void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection( +void MapReflectionTester::SetMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); Message* sub_message = NULL; @@ -555,7 +555,196 @@ void MapTestUtil::MapReflectionTester::SetMapFieldsViaReflection( SetInt32(sub_foreign_message, foreign_c_, 1); } -void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection( +void MapReflectionTester::SetMapFieldsViaMapReflection( + Message* message) { + const Reflection* reflection = message->GetReflection(); + + Message* sub_foreign_message = NULL; + MapValueRef map_val; + + // Add first element. + MapKey map_key; + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetUInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val)); + map_val.SetUInt32Value(0); + + map_key.SetUInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val)); + map_val.SetUInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetUInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val)); + map_val.SetUInt32Value(0); + + map_key.SetUInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val)); + map_val.SetUInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val)); + map_val.SetInt32Value(0); + + map_key.SetInt64Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val)); + map_val.SetInt64Value(0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val)); + map_val.SetFloatValue(0.0); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val)); + map_val.SetDoubleValue(0.0); + + map_key.SetBoolValue(false); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val)); + map_val.SetBoolValue(false); + + map_key.SetStringValue("0"); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val)); + map_val.SetStringValue("0"); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val)); + map_val.SetStringValue("0"); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val)); + map_val.SetEnumValue(map_enum_bar_->number()); + + map_key.SetInt32Value(0); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 0); + + // Add second element + map_key.SetInt32Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + + map_key.SetInt64Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val); + map_val.SetUInt32Value(1); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val); + map_val.SetUInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val); + map_val.SetInt32Value(1); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val); + map_val.SetInt64Value(1); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val); + map_val.SetUInt32Value(1); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val); + map_val.SetUInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val); + map_val.SetInt32Value(1); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val); + map_val.SetInt64Value(1); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val); + map_val.SetFloatValue(1.0); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val); + map_val.SetDoubleValue(1.0); + + map_key.SetBoolValue(true); + reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val); + map_val.SetBoolValue(true); + + map_key.SetStringValue("1"); + reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val); + map_val.SetStringValue("1"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val); + map_val.SetStringValue("1"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val); + map_val.SetEnumValue(map_enum_baz_->number()); + + map_key.SetInt32Value(1); + EXPECT_TRUE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 1); +} + +void MapReflectionTester::ClearMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -578,97 +767,103 @@ void MapTestUtil::MapReflectionTester::ClearMapFieldsViaReflection( reflection->ClearField(message, F("map_int32_foreign_message")); } -void MapTestUtil::MapReflectionTester::ModifyMapFieldsViaReflection( +void MapReflectionTester::ModifyMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); - Message* sub_message; + MapValueRef map_val; 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); + // Modify the second element + MapKey map_key; + map_key.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_int32"), map_key, &map_val)); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int64_int64"), map_key, &map_val)); + map_val.SetInt64Value(2); + + map_key.SetUInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_uint32_uint32"), map_key, &map_val)); + map_val.SetUInt32Value(2); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_uint64_uint64"), map_key, &map_val); + map_val.SetUInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint32_sint32"), map_key, &map_val); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sint64_sint64"), map_key, &map_val); + map_val.SetInt64Value(2); + + map_key.SetUInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed32_fixed32"), map_key, &map_val); + map_val.SetUInt32Value(2); + + map_key.SetUInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_fixed64_fixed64"), map_key, &map_val); + map_val.SetUInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed32_sfixed32"), map_key, &map_val); + map_val.SetInt32Value(2); + + map_key.SetInt64Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_sfixed64_sfixed64"), map_key, &map_val); + map_val.SetInt64Value(2); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_float"), map_key, &map_val); + map_val.SetFloatValue(2.0); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_double"), map_key, &map_val); + map_val.SetDoubleValue(2.0); + + map_key.SetBoolValue(true); + reflection->InsertOrLookupMapValue( + message, F("map_bool_bool"), map_key, &map_val); + map_val.SetBoolValue(false); + + map_key.SetStringValue("1"); + reflection->InsertOrLookupMapValue( + message, F("map_string_string"), map_key, &map_val); + map_val.SetStringValue("2"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_bytes"), map_key, &map_val); + map_val.SetStringValue("2"); + + map_key.SetInt32Value(1); + reflection->InsertOrLookupMapValue( + message, F("map_int32_enum"), map_key, &map_val); + map_val.SetEnumValue(map_enum_foo_->number()); + + map_key.SetInt32Value(1); + EXPECT_FALSE(reflection->InsertOrLookupMapValue( + message, F("map_int32_foreign_message"), map_key, &map_val)); + sub_foreign_message = map_val.MutableMessageValue(); + sub_foreign_message->GetReflection()->SetInt32( + sub_foreign_message, foreign_c_, 2); } -void MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection( +void MapReflectionTester::RemoveLastMapsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -681,7 +876,7 @@ void MapTestUtil::MapReflectionTester::RemoveLastMapsViaReflection( } } -void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection( +void MapReflectionTester::ReleaseLastMapsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -699,7 +894,7 @@ void MapTestUtil::MapReflectionTester::ReleaseLastMapsViaReflection( } } -void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) { +void MapReflectionTester::SwapMapsViaReflection(Message* message) { const Reflection* reflection = message->GetReflection(); vector<const FieldDescriptor*> output; reflection->ListFields(*message, &output); @@ -710,7 +905,7 @@ void MapTestUtil::MapReflectionTester::SwapMapsViaReflection(Message* message) { } } -void MapTestUtil::MapReflectionTester:: +void MapReflectionTester:: MutableUnknownFieldsOfMapFieldsViaReflection(Message* message) { const Reflection* reflection = message->GetReflection(); Message* sub_message = NULL; @@ -768,11 +963,12 @@ void MapTestUtil::MapReflectionTester:: NULL); } -void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( +void MapReflectionTester::ExpectMapFieldsSetViaReflection( const Message& message) { string scratch; const Reflection* reflection = message.GetReflection(); const Message* sub_message; + MapKey map_key; // ----------------------------------------------------------------- @@ -799,6 +995,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i); int32 key = sub_message->GetReflection()->GetInt32( @@ -806,6 +1003,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_int32_int32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_int32_int32"), map_key)); } } { @@ -813,6 +1014,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i); int64 key = sub_message->GetReflection()->GetInt64( @@ -820,6 +1022,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_int64_int64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_int64_int64"), map_key)); } } { @@ -827,6 +1033,7 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( map[0] = 0; map[1] = 1; for (int i = 0; i < 2; i++) { + // Check with RepeatedField Reflection sub_message = &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i); uint32 key = sub_message->GetReflection()->GetUInt32( @@ -834,6 +1041,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint32 val = sub_message->GetReflection()->GetUInt32( *sub_message, map_uint32_uint32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt32Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_uint32_uint32"), map_key)); } } { @@ -848,6 +1059,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint64 val = sub_message->GetReflection()->GetUInt64( *sub_message, map_uint64_uint64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt64Value(key); + EXPECT_TRUE(reflection->ContainsMapKey( + message, F("map_uint64_uint64"), map_key)); } } { @@ -862,6 +1077,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_sint32_sint32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sint32_sint32"), map_key)); } } { @@ -876,6 +1095,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_sint64_sint64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sint64_sint64"), map_key)); } } { @@ -890,6 +1113,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint32 val = sub_message->GetReflection()->GetUInt32( *sub_message, map_fixed32_fixed32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_fixed32_fixed32"), map_key)); } } { @@ -904,6 +1131,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( uint64 val = sub_message->GetReflection()->GetUInt64( *sub_message, map_fixed64_fixed64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetUInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_fixed64_fixed64"), map_key)); } } { @@ -918,6 +1149,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = sub_message->GetReflection()->GetInt32( *sub_message, map_sfixed32_sfixed32_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sfixed32_sfixed32"), map_key)); } } { @@ -932,6 +1167,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int64 val = sub_message->GetReflection()->GetInt64( *sub_message, map_sfixed64_sfixed64_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt64Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_sfixed64_sfixed64"), map_key)); } } { @@ -946,6 +1185,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( float val = sub_message->GetReflection()->GetFloat( *sub_message, map_int32_float_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_float"), map_key)); } } { @@ -960,6 +1203,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( double val = sub_message->GetReflection()->GetDouble( *sub_message, map_int32_double_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_double"), map_key)); } } { @@ -974,6 +1221,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( bool val = sub_message->GetReflection()->GetBool( *sub_message, map_bool_bool_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetBoolValue(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_bool_bool"), map_key)); } } { @@ -988,6 +1239,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( string val = sub_message->GetReflection()->GetString( *sub_message, map_string_string_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetStringValue(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_string_string"), map_key)); } } { @@ -1002,6 +1257,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( string val = sub_message->GetReflection()->GetString( *sub_message, map_int32_bytes_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_bytes"), map_key)); } } { @@ -1016,6 +1275,10 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum( *sub_message, map_int32_enum_val_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_enum"), map_key)); } } { @@ -1032,11 +1295,245 @@ void MapTestUtil::MapReflectionTester::ExpectMapFieldsSetViaReflection( int32 val = foreign_message.GetReflection()->GetInt32( foreign_message, foreign_c_); EXPECT_EQ(map[key], val); + // Check with Map Reflection + map_key.SetInt32Value(key); + EXPECT_EQ(true, reflection->ContainsMapKey( + message, F("map_int32_foreign_message"), map_key)); } } } -void MapTestUtil::MapReflectionTester::ExpectClearViaReflection( +void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator( + Message* message) { + string scratch; + string serialized; + const Reflection* reflection = message->GetReflection(); + + 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; + int size = 0; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_int32")); + iter != reflection->MapEnd(message, F("map_int32_int32")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + EXPECT_EQ(size, 2); + } + { + std::map<int64, int64> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin(message, F("map_int64_int64")); + iter != reflection->MapEnd(message, F("map_int64_int64")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt64Value()], + iter.GetValueRef().GetInt64Value()); + } + } + { + std::map<uint32, uint32> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_uint32_uint32")); + iter != reflection->MapEnd(message, F("map_uint32_uint32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], + iter.GetValueRef().GetUInt32Value()); + } + } + { + std::map<uint64, uint64> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_uint64_uint64")); + iter != reflection->MapEnd(message, F("map_uint64_uint64")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], + iter.GetValueRef().GetUInt64Value()); + } + } + { + std::map<int32, int32> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sint32_sint32")); + iter != reflection->MapEnd(message, F("map_sint32_sint32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + } + { + std::map<int64, int64> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sint64_sint64")); + iter != reflection->MapEnd(message, F("map_sint64_sint64")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt64Value()], + iter.GetValueRef().GetInt64Value()); + } + } + { + std::map<uint32, uint32> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_fixed32_fixed32")); + iter != reflection->MapEnd(message, F("map_fixed32_fixed32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], + iter.GetValueRef().GetUInt32Value()); + } + } + { + std::map<uint64, uint64> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_fixed64_fixed64")); + iter != reflection->MapEnd(message, F("map_fixed64_fixed64")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], + iter.GetValueRef().GetUInt64Value()); + } + } + { + std::map<int32, int32> map; + map[0] = 0; + map[1] = 1; + for (MapIterator iter = reflection->MapBegin( + message, F("map_sfixed32_sfixed32")); + iter != reflection->MapEnd(message, F("map_sfixed32_sfixed32")); + ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetInt32Value()); + } + } + { + std::map<int32, float> map; + map[0] = 0.0; + map[1] = 1.0; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_float")); + iter != reflection->MapEnd(message, F("map_int32_float")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetFloatValue()); + } + } + { + std::map<int32, double> map; + map[0] = 0.0; + map[1] = 1.0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_int32_double")); + iter != reflection->MapEnd(message, F("map_int32_double")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetDoubleValue()); + } + } + { + std::map<bool, bool> map; + map[false] = false; + map[true] = true; + for (MapIterator iter = reflection->MapBegin(message, F("map_bool_bool")); + iter != reflection->MapEnd(message, F("map_bool_bool")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetBoolValue()], + iter.GetValueRef().GetBoolValue()); + } + } + { + std::map<string, string> map; + map["0"] = "0"; + map["1"] = "1"; + int size = 0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_string_string")); + iter != reflection->MapEnd(message, F("map_string_string")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + EXPECT_EQ(map[iter.GetKey().GetStringValue()], + iter.GetValueRef().GetStringValue()); + } + EXPECT_EQ(size, 2); + } + { + std::map<int32, string> map; + map[0] = "0"; + map[1] = "1"; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_bytes")); + iter != reflection->MapEnd(message, F("map_int32_bytes")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + iter.GetValueRef().GetStringValue()); + } + } + { + std::map<int32, const EnumValueDescriptor*> map; + map[0] = map_enum_bar_; + map[1] = map_enum_baz_; + for (MapIterator iter = reflection->MapBegin(message, F("map_int32_enum")); + iter != reflection->MapEnd(message, F("map_int32_enum")); ++iter) { + EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(), + iter.GetValueRef().GetEnumValue()); + } + } + { + std::map<int32, int32> map; + map[0] = 0; + map[1] = 1; + int size = 0; + for (MapIterator iter = reflection->MapBegin( + message, F("map_int32_foreign_message")); + iter != reflection->MapEnd(message, F("map_int32_foreign_message")); + ++iter, ++size) { + // Check const methods do not invalidate map. + message->DebugString(); + message->ShortDebugString(); + message->SerializeToString(&serialized); + message->SpaceUsed(); + message->ByteSize(); + const Message& sub_message = iter.GetValueRef().GetMessageValue(); + EXPECT_EQ(map[iter.GetKey().GetInt32Value()], + sub_message.GetReflection()->GetInt32(sub_message, foreign_c_)); + } + EXPECT_EQ(size, 2); + } +} + +void MapReflectionTester::ExpectClearViaReflection( const Message& message) { const Reflection* reflection = message.GetReflection(); // Map fields are empty. @@ -1059,7 +1556,46 @@ void MapTestUtil::MapReflectionTester::ExpectClearViaReflection( EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message"))); } -void MapTestUtil::MapReflectionTester::ExpectMapEntryClearViaReflection( +void MapReflectionTester::ExpectClearViaReflectionIterator( + Message* message) { + const Reflection* reflection = message->GetReflection(); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_int32")) == + reflection->MapEnd(message, F("map_int32_int32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int64_int64")) == + reflection->MapEnd(message, F("map_int64_int64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_uint32_uint32")) == + reflection->MapEnd(message, F("map_uint32_uint32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_uint64_uint64")) == + reflection->MapEnd(message, F("map_uint64_uint64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sint32_sint32")) == + reflection->MapEnd(message, F("map_sint32_sint32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sint64_sint64")) == + reflection->MapEnd(message, F("map_sint64_sint64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed32_fixed32")) == + reflection->MapEnd(message, F("map_fixed32_fixed32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_fixed64_fixed64")) == + reflection->MapEnd(message, F("map_fixed64_fixed64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed32_sfixed32")) == + reflection->MapEnd(message, F("map_sfixed32_sfixed32"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_sfixed64_sfixed64")) == + reflection->MapEnd(message, F("map_sfixed64_sfixed64"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_float")) == + reflection->MapEnd(message, F("map_int32_float"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_double")) == + reflection->MapEnd(message, F("map_int32_double"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_bool_bool")) == + reflection->MapEnd(message, F("map_bool_bool"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_string_string")) == + reflection->MapEnd(message, F("map_string_string"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_bytes")) == + reflection->MapEnd(message, F("map_int32_bytes"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_enum")) == + reflection->MapEnd(message, F("map_int32_enum"))); + EXPECT_TRUE(reflection->MapBegin(message, F("map_int32_foreign_message")) == + reflection->MapEnd(message, F("map_int32_foreign_message"))); +} + +void MapReflectionTester::ExpectMapEntryClearViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); const Message* sub_message; diff --git a/src/google/protobuf/map_test_util.h b/src/google/protobuf/map_test_util.h index f437e33e..107a639d 100644 --- a/src/google/protobuf/map_test_util.h +++ b/src/google/protobuf/map_test_util.h @@ -83,71 +83,74 @@ class MapTestUtil { // 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_; - }; +// 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 SetMapFieldsViaMapReflection(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 ExpectMapFieldsSetViaReflectionIterator(Message* message); + void ExpectClearViaReflection(const Message& message); + void ExpectClearViaReflectionIterator(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 diff --git a/src/google/protobuf/map_test_util_impl.h b/src/google/protobuf/map_test_util_impl.h index 5e7882a1..7e8757ed 100644 --- a/src/google/protobuf/map_test_util_impl.h +++ b/src/google/protobuf/map_test_util_impl.h @@ -31,6 +31,7 @@ #ifndef GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__ #define GOOGLE_PROTOBUF_MAP_TEST_UTIL_IMPL_H__ +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> @@ -167,8 +168,11 @@ void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) { (*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); + (*message->mutable_map_int32_foreign_message_no_arena())[0].set_c(0); // Add second element (*message->mutable_map_int32_int32())[1] = 1; @@ -184,8 +188,11 @@ void MapTestUtilImpl::SetArenaMapFields(MapMessage* message) { (*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); + (*message->mutable_map_int32_foreign_message_no_arena())[1].set_c(1); } template <typename MapMessage> @@ -329,8 +336,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { 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(2, message.map_int32_foreign_message_no_arena().size()); EXPECT_EQ(0, message.map_int32_int32().at(0)); EXPECT_EQ(0, message.map_int64_int64().at(0)); @@ -345,8 +355,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { 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(0, message.map_int32_foreign_message_no_arena().at(0).c()); EXPECT_EQ(1, message.map_int32_int32().at(1)); EXPECT_EQ(1, message.map_int64_int64().at(1)); @@ -361,8 +374,11 @@ void MapTestUtilImpl::ExpectArenaMapFieldsSet(const MapMessage& message) { 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()); + EXPECT_EQ(1, message.map_int32_foreign_message_no_arena().at(1).c()); } template <typename EnumType, EnumType enum_value, typename MapMessage> diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h index ffdb6dfb..5040e605 100644 --- a/src/google/protobuf/map_type_handler.h +++ b/src/google/protobuf/map_type_handler.h @@ -54,22 +54,6 @@ 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> @@ -110,174 +94,29 @@ 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)->Clear(); - } - static inline void ClearMaybeByDefaultEnum(Type** value, - int default_enum_value) { - if (*value != NULL) (*value)->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); + return Arena::Create<Type>(arena); } - 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> +template <WireFormatLite::FieldType field_type, typename 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; \ +#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \ + template <typename Type> \ + class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> { \ + public: \ + static const bool kIsMessage = IsMessage; \ + static const bool kIsEnum = IsEnum; \ + typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory; \ + typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \ + 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(MESSAGE , Type, LENGTH_DELIMITED, true, false) +TYPE_TRAITS(STRING , ArenaStringPtr, LENGTH_DELIMITED, false, false) +TYPE_TRAITS(BYTES , ArenaStringPtr , 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) @@ -295,46 +134,149 @@ TYPE_TRAITS(BOOL , bool , VARINT , false, false) #undef TYPE_TRAITS -template <WireFormatLite::FieldType field_type> -class MapWireFieldTypeHandler { +template <WireFormatLite::FieldType field_type, typename Type> +class MapTypeHandler {}; + +template <typename Type> +class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> { public: + // Enum type cannot be used for MapTypeHandler::Read. Define a type which will + // replace Enum with int. + typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, + Type>::MapEntryAccessorType MapEntryAccessorType; // Internal stored type in MapEntryLite for given wire field type. - typedef typename MapWireFieldTypeTraits<field_type>::CppType CppType; + typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, + Type>::TypeOnMemory TypeOnMemory; // Corresponding wire type for field type. static const WireFormatLite::WireType kWireType = - MapWireFieldTypeTraits<field_type>::kWireType; + MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType; // Whether wire type is for message. - static const bool kIsMessage = MapWireFieldTypeTraits<field_type>::kIsMessage; + static const bool kIsMessage = + MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage; // Whether wire type is for enum. - static const bool kIsEnum = MapWireFieldTypeTraits<field_type>::kIsEnum; + static const bool kIsEnum = + MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, 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, + static inline int ByteSize(const MapEntryAccessorType& value); + static inline int GetCachedSize(const MapEntryAccessorType& value); + static inline bool Read(io::CodedInputStream* input, + MapEntryAccessorType* value); + static inline void Write(int field, const MapEntryAccessorType& value, io::CodedOutputStream* output); - static inline uint8* WriteToArray(int field, const CppType& value, + static inline uint8* WriteToArray(int field, + const MapEntryAccessorType& value, uint8* output); + + // Functions to manipulate data on memory. ======================== + static inline const Type& GetExternalReference(const Type* value); + static inline void DeleteNoArena(const Type* x); + static inline void Merge(const Type& from, Type** to, Arena* arena); + static inline void Clear(Type** value, Arena* arena); + static inline void ClearMaybeByDefaultEnum(Type** value, Arena* arena, + int default_enum_value); + static inline void Initialize(Type** x, Arena* arena); + + static inline void InitializeMaybeByDefaultEnum(Type** x, + int default_enum_value, + Arena* arena); + static inline Type* EnsureMutable(Type** value, Arena* arena); + // SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding + // those already calculate in sizeof(MapField). + static inline int SpaceUsedInMapEntry(const Type* value); + // Return bytes used by value in Map. + static inline int SpaceUsedInMap(const Type& value); + // Assign default value to given instance. + static inline void AssignDefaultValue(Type** value); + // 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); + // Check if all required fields have values set. + static inline bool IsInitialized(Type* value); }; -template <> -template <typename ValueType> -inline int MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::ByteSize( - const ValueType& value) { +#define MAP_HANDLER(FieldType) \ + template <typename Type> \ + class MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type> { \ + public: \ + typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType \ + MapEntryAccessorType; \ + typedef typename MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \ + Type>::TypeOnMemory TypeOnMemory; \ + static const WireFormatLite::WireType kWireType = \ + MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \ + Type>::kWireType; \ + static const bool kIsMessage = \ + MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \ + Type>::kIsMessage; \ + static const bool kIsEnum = \ + MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \ + Type>::kIsEnum; \ + static inline int ByteSize(const MapEntryAccessorType& value); \ + static inline int GetCachedSize(const MapEntryAccessorType& value); \ + static inline bool Read(io::CodedInputStream* input, \ + MapEntryAccessorType* value); \ + static inline void Write(int field, const MapEntryAccessorType& value, \ + io::CodedOutputStream* output); \ + static inline uint8* WriteToArray(int field, \ + const MapEntryAccessorType& value, \ + uint8* output); \ + static inline const MapEntryAccessorType& GetExternalReference( \ + const TypeOnMemory& value); \ + static inline void DeleteNoArena(const TypeOnMemory& x); \ + static inline void Merge(const MapEntryAccessorType& from, \ + TypeOnMemory* to, Arena* arena); \ + static inline void Clear(TypeOnMemory* value, Arena* arena); \ + static inline void ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum); \ + static inline int SpaceUsedInMapEntry(const TypeOnMemory& value); \ + static inline int SpaceUsedInMap(const TypeOnMemory& value); \ + static inline int SpaceUsedInMap(const string& value); \ + static inline void AssignDefaultValue(TypeOnMemory* value); \ + static inline const MapEntryAccessorType& DefaultIfNotInitialized( \ + const TypeOnMemory& value, const TypeOnMemory& default_value); \ + static inline bool IsInitialized(const TypeOnMemory& value); \ + static void DeleteNoArena(TypeOnMemory& value); \ + static inline void Initialize(TypeOnMemory* value, Arena* arena); \ + static inline void InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena); \ + static inline MapEntryAccessorType* EnsureMutable(TypeOnMemory* value, \ + Arena* arena); \ + }; +MAP_HANDLER(STRING) +MAP_HANDLER(BYTES) +MAP_HANDLER(INT64) +MAP_HANDLER(UINT64) +MAP_HANDLER(INT32) +MAP_HANDLER(UINT32) +MAP_HANDLER(SINT64) +MAP_HANDLER(SINT32) +MAP_HANDLER(ENUM) +MAP_HANDLER(DOUBLE) +MAP_HANDLER(FLOAT) +MAP_HANDLER(FIXED64) +MAP_HANDLER(FIXED32) +MAP_HANDLER(SFIXED64) +MAP_HANDLER(SFIXED32) +MAP_HANDLER(BOOL) +#undef MAP_HANDLER + +template <typename Type> +inline int +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::ByteSize( + const MapEntryAccessorType& 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); \ +#define BYTE_SIZE(FieldType, DeclaredType) \ + template <typename Type> \ + inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::DeclaredType##Size(value); \ } BYTE_SIZE(STRING, String) @@ -349,13 +291,11 @@ 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; \ +#define FIXED_BYTE_SIZE(FieldType, DeclaredType) \ + template <typename Type> \ + inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::ByteSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::k##DeclaredType##Size; \ } FIXED_BYTE_SIZE(DOUBLE , Double) @@ -368,20 +308,19 @@ FIXED_BYTE_SIZE(BOOL , Bool) #undef FIXED_BYTE_SIZE -template <> -template <typename ValueType> -inline int MapWireFieldTypeHandler< - WireFormatLite::TYPE_MESSAGE>::GetCachedSize(const ValueType& value) { +template <typename Type> +inline int +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetCachedSize( + const MapEntryAccessorType& 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); \ +#define GET_CACHED_SIZE(FieldType, DeclaredType) \ + template <typename Type> \ + inline int \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::DeclaredType##Size(value); \ } GET_CACHED_SIZE(STRING, String) @@ -396,13 +335,12 @@ 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; \ +#define GET_FIXED_CACHED_SIZE(FieldType, DeclaredType) \ + template <typename Type> \ + inline int \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::GetCachedSize( \ + const MapEntryAccessorType& value) { \ + return WireFormatLite::k##DeclaredType##Size; \ } GET_FIXED_CACHED_SIZE(DOUBLE , Double) @@ -415,30 +353,31 @@ 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) { +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Write( + int field, const MapEntryAccessorType& value, + io::CodedOutputStream* output) { WireFormatLite::WriteMessageMaybeToArray(field, value, output); } -template <> +template <typename Type> inline uint8* -MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::WriteToArray( - int field, const MessageLite& value, uint8* output) { +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray( + int field, const MapEntryAccessorType& 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) { \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Write( \ + int field, const MapEntryAccessorType& value, \ + io::CodedOutputStream* output) { \ return WireFormatLite::Write##DeclaredType(field, value, output); \ } \ - template <> \ + template <typename Type> \ inline uint8* \ - MapWireFieldTypeHandler<WireFormatLite::TYPE_##FieldType>::WriteToArray( \ - int field, const CppType& value, uint8* output) { \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray( \ + int field, const MapEntryAccessorType& value, uint8* output) { \ return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \ } @@ -461,35 +400,31 @@ WRITE_METHOD(BOOL , Bool) #undef WRITE_METHOD -template <> -template <typename ValueType> -inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_MESSAGE>::Read( - io::CodedInputStream* input, ValueType* value) { +template <typename Type> +inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Read( + io::CodedInputStream* input, MapEntryAccessorType* value) { return WireFormatLite::ReadMessageNoVirtual(input, value); } -template <> -template <typename ValueType> -inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_STRING>::Read( - io::CodedInputStream* input, ValueType* value) { +template <typename Type> +inline bool MapTypeHandler<WireFormatLite::TYPE_STRING, Type>::Read( + io::CodedInputStream* input, MapEntryAccessorType* value) { return WireFormatLite::ReadString(input, value); } -template <> -template <typename ValueType> -inline bool MapWireFieldTypeHandler<WireFormatLite::TYPE_BYTES>::Read( - io::CodedInputStream* input, ValueType* value) { +template <typename Type> +inline bool MapTypeHandler<WireFormatLite::TYPE_BYTES, Type>::Read( + io::CodedInputStream* input, MapEntryAccessorType* 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); \ +#define READ_METHOD(FieldType) \ + template <typename Type> \ + inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Read( \ + io::CodedInputStream* input, MapEntryAccessorType* value) { \ + return WireFormatLite::ReadPrimitive<TypeOnMemory, \ + WireFormatLite::TYPE_##FieldType>( \ + input, value); \ } READ_METHOD(INT64) @@ -509,6 +444,282 @@ READ_METHOD(BOOL) #undef READ_METHOD +// Definition for message handler + +template <typename Type> +inline const Type& +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::GetExternalReference(const Type* value) { + return *value; +} + +template <typename Type> +inline int +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::SpaceUsedInMapEntry(const Type* value) { + return value->SpaceUsed(); +} + +template <typename Type> +int MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::SpaceUsedInMap( + const Type& value) { + return value.SpaceUsed(); +} + +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear( + Type** value, Arena* arena) { + if (*value != NULL) (*value)->Clear(); +} +template <typename Type> +inline void +MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::ClearMaybeByDefaultEnum(Type** value, + Arena* arena, + int default_enum_value) { + if (*value != NULL) (*value)->Clear(); +} +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Merge( + const Type& from, Type** to, Arena* arena) { + (*to)->MergeFrom(from); +} + +template <typename Type> +void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena( + const Type* ptr) { + delete ptr; +} + +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::AssignDefaultValue(Type** value) { + *value = const_cast<Type*>(&Type::default_instance()); +} + +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::Initialize(Type** x, + Arena* arena) { + *x = NULL; +} + +template <typename Type> +inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>:: + InitializeMaybeByDefaultEnum(Type** x, int default_enum_value, + Arena* arena) { + *x = NULL; +} + +template <typename Type> +inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::EnsureMutable(Type** value, + Arena* arena) { + if (*value == NULL) { + *value = + MapArenaMessageCreator<Type, Arena::is_arena_constructable<Type>:: + type::value>::CreateMessage(arena); + } + return *value; +} + +template <typename Type> +inline const Type& MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>:: + DefaultIfNotInitialized(const Type* value, const Type* default_value) { + return value != NULL ? *value : *default_value; +} + +template <typename Type> +inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, + Type>::IsInitialized(Type* value) { + return value->IsInitialized(); +} + +// Definition for string/bytes handler + +#define STRING_OR_BYTES_HANDLER_FUNCTIONS(FieldType) \ + template <typename Type> \ + inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType& \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::GetExternalReference(const TypeOnMemory& value) { \ + return value.Get(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template <typename Type> \ + inline int \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapEntry( \ + const TypeOnMemory& value) { \ + return sizeof(value); \ + } \ + template <typename Type> \ + inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::SpaceUsedInMap(const TypeOnMemory& value) { \ + return sizeof(value); \ + } \ + template <typename Type> \ + inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::SpaceUsedInMap(const string& value) { \ + return sizeof(value); \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \ + TypeOnMemory* value, Arena* arena) { \ + value->ClearToEmpty(&::google::protobuf::internal::GetEmptyString(), arena); \ + } \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum) { \ + Clear(value, arena); \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \ + const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \ + to->Set(&::google::protobuf::internal::GetEmptyString(), from, arena); \ + } \ + template <typename Type> \ + void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \ + TypeOnMemory& value) { \ + value.DestroyNoArena(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::AssignDefaultValue(TypeOnMemory* value) {} \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize( \ + TypeOnMemory* value, Arena* arena) { \ + value->UnsafeSetDefault(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena) { \ + Initialize(value, arena); \ + } \ + template <typename Type> \ + inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType* \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \ + TypeOnMemory* value, Arena* arena) { \ + return value->Mutable(&::google::protobuf::internal::GetEmptyString(), arena); \ + } \ + template <typename Type> \ + inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType& \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::DefaultIfNotInitialized(const TypeOnMemory& value, \ + const TypeOnMemory& \ + default_value) { \ + return value.Get(&::google::protobuf::internal::GetEmptyString()); \ + } \ + template <typename Type> \ + inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::IsInitialized(const TypeOnMemory& value) { \ + return true; \ + } +STRING_OR_BYTES_HANDLER_FUNCTIONS(STRING) +STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES) +#undef STRING_OR_BYTES_HANDLER_FUNCTIONS + +#define PRIMITIVE_HANDLER_FUNCTIONS(FieldType) \ + template <typename Type> \ + inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType& \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::GetExternalReference(const TypeOnMemory& value) { \ + return value; \ + } \ + template <typename Type> \ + inline int \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::SpaceUsedInMapEntry( \ + const TypeOnMemory& value) { \ + return 0; \ + } \ + template <typename Type> \ + inline int MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::SpaceUsedInMap(const TypeOnMemory& value) { \ + return sizeof(Type); \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \ + TypeOnMemory* value, Arena* arena) { \ + *value = 0; \ + } \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::ClearMaybeByDefaultEnum(TypeOnMemory* value, \ + Arena* arena, \ + int default_enum_value) { \ + *value = static_cast<TypeOnMemory>(default_enum_value); \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \ + const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \ + *to = from; \ + } \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::DeleteNoArena(TypeOnMemory& x) {} \ + template <typename Type> \ + inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::AssignDefaultValue(TypeOnMemory* value) {} \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize( \ + TypeOnMemory* value, Arena* arena) { \ + *value = 0; \ + } \ + template <typename Type> \ + inline void \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::InitializeMaybeByDefaultEnum(TypeOnMemory* value, \ + int default_enum_value, \ + Arena* arena) { \ + *value = static_cast<TypeOnMemory>(default_enum_value); \ + } \ + template <typename Type> \ + inline typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType* \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable( \ + TypeOnMemory* value, Arena* arena) { \ + return value; \ + } \ + template <typename Type> \ + inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::MapEntryAccessorType& \ + MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::DefaultIfNotInitialized(const TypeOnMemory& value, \ + const TypeOnMemory& \ + default_value) { \ + return value; \ + } \ + template <typename Type> \ + inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType, \ + Type>::IsInitialized(const TypeOnMemory& value) { \ + return true; \ + } +PRIMITIVE_HANDLER_FUNCTIONS(INT64) +PRIMITIVE_HANDLER_FUNCTIONS(UINT64) +PRIMITIVE_HANDLER_FUNCTIONS(INT32) +PRIMITIVE_HANDLER_FUNCTIONS(UINT32) +PRIMITIVE_HANDLER_FUNCTIONS(SINT64) +PRIMITIVE_HANDLER_FUNCTIONS(SINT32) +PRIMITIVE_HANDLER_FUNCTIONS(ENUM) +PRIMITIVE_HANDLER_FUNCTIONS(DOUBLE) +PRIMITIVE_HANDLER_FUNCTIONS(FLOAT) +PRIMITIVE_HANDLER_FUNCTIONS(FIXED64) +PRIMITIVE_HANDLER_FUNCTIONS(FIXED32) +PRIMITIVE_HANDLER_FUNCTIONS(SFIXED64) +PRIMITIVE_HANDLER_FUNCTIONS(SFIXED32) +PRIMITIVE_HANDLER_FUNCTIONS(BOOL) +#undef PRIMITIVE_HANDLER_FUNCTIONS + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index b308c7ff..d3b525a0 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -33,6 +33,7 @@ syntax = "proto3"; option cc_enable_arenas = true; import "google/protobuf/unittest.proto"; +import "google/protobuf/unittest_no_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. @@ -58,6 +59,7 @@ message TestMap { map<int32 , bytes > map_int32_bytes = 15; map<int32 , MapEnum > map_int32_enum = 16; map<int32 , ForeignMessage> map_int32_foreign_message = 17; + map<string , ForeignMessage> map_string_foreign_message = 18; } message TestMapSubmessage { @@ -100,8 +102,12 @@ message TestArenaMap { 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; + 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; + map<int32, .protobuf_unittest_no_arena.ForeignMessage> + map_int32_foreign_message_no_arena = 18; } // Previously, message containing enum called Type cannot be used as value of @@ -117,3 +123,7 @@ message MessageContainingEnumCalledType { message MessageContainingMapCalledEntry { map<int32, int32> entry = 1; } + +message TestRecursiveMapMessage { + map<int32, TestRecursiveMapMessage> a = 1; +} diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 123bd789..2f6416d0 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -38,12 +38,15 @@ #include <google/protobuf/message.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/mutex.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/map_field.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/reflection_ops.h> @@ -257,6 +260,22 @@ void Reflection::AddEnumValue(Message* message, GOOGLE_LOG(FATAL) << "Unimplemented EnumValue API."; } +MapIterator Reflection::MapBegin( + Message* message, + const FieldDescriptor* field) const { + GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; + MapIterator iter(message, field); + return iter; +} + +MapIterator Reflection::MapEnd( + Message* message, + const FieldDescriptor* field) const { + GOOGLE_LOG(FATAL) << "Unimplemented Map Reflection API."; + MapIterator iter(message, field); + return iter; +} + // ============================================================================= // MessageFactory diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 18c092d0..348e7c7f 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -134,12 +134,23 @@ class Reflection; class MessageFactory; // Defined in other files. +class MapKey; +class MapValueRef; +class MapIterator; +class MapReflectionTester; + +namespace internal { +class MapFieldBase; +} 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 ZeroCopyInputStream; // zero_copy_stream.h +class ZeroCopyOutputStream; // zero_copy_stream.h +class CodedInputStream; // coded_stream.h +class CodedOutputStream; // coded_stream.h +} +namespace python { +class MapReflectionFriend; // scalar_map_container.h } @@ -724,6 +735,14 @@ class LIBPROTOBUF_EXPORT Reflection { const FieldDescriptor* field, MessageFactory* factory = NULL) const = 0; + // Appends an already-allocated object 'new_entry' to the repeated field + // specifyed by 'field' passing ownership to the message. + // TODO(tmarek): Make virtual after all subclasses have been + // updated. + virtual void AddAllocatedMessage(Message* message, + const FieldDescriptor* field, + Message* new_entry) const {} + // Get a RepeatedFieldRef object that can be used to read the underlying // repeated field. The type parameter T must be set according to the @@ -868,11 +887,20 @@ class LIBPROTOBUF_EXPORT Reflection { // 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). + // We use 2 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; + // TODO(jieluo) - make it pure virtual after updating all the subclasses. + virtual const void* GetRawRepeatedField( + const Message& message, const FieldDescriptor* field, + FieldDescriptor::CppType cpptype, int ctype, + const Descriptor* message_type) const { + return MutableRawRepeatedField( + const_cast<Message*>(&message), field, cpptype, ctype, message_type); + } + // 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 @@ -887,6 +915,8 @@ class LIBPROTOBUF_EXPORT Reflection { // "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. + // We use 1 routine rather than 2 (const vs mutable) because it is protected + // and it doesn't change the message. virtual void* RepeatedFieldData( Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpp_type, @@ -902,14 +932,73 @@ class LIBPROTOBUF_EXPORT Reflection { friend class RepeatedFieldRef; template<typename T, typename Enable> friend class MutableRepeatedFieldRef; + friend class ::google::protobuf::python::MapReflectionFriend; // 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. + // We use 1 routine rather than 2 (const vs mutable) because it is private + // and mutable a repeated string field doesn't change the message. void* MutableRawRepeatedString( Message* message, const FieldDescriptor* field, bool is_string) const; + friend class MapReflectionTester; + // TODO(jieluo) - make the map APIs pure virtual after updating + // all the subclasses. + // Returns true if key is in map. Returns false if key is not in map field. + virtual bool ContainsMapKey(const Message& message, + const FieldDescriptor* field, + const MapKey& key) const { + return false; + } + + // If key is in map field: Saves the value pointer to val and returns + // false. If key in not in map field: Insert the key into map, saves + // value pointer to val and retuns true. + virtual bool InsertOrLookupMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key, + MapValueRef* val) const { + return false; + } + + // Delete and returns true if key is in the map field. Returns false + // otherwise. + virtual bool DeleteMapValue(Message* message, + const FieldDescriptor* field, + const MapKey& key) const { + return false; + } + + // Returns a MaIterator referring to the first element in the map field. + // If the map field is empty, this function returns the same as + // reflection::MapEnd. Mutation to the field may invalidate the iterator. + virtual MapIterator MapBegin( + Message* message, + const FieldDescriptor* field) const; + + // Returns a MapIterator referring to the theoretical element that would + // follow the last element in the map field. It does not point to any + // real element. Mutation to the field may invalidate the iterator. + virtual MapIterator MapEnd( + Message* message, + const FieldDescriptor* field) const; + + // Get the number of <key, value> pair of a map field. The result may be + // different from FieldSize which can have duplicate keys. + virtual int MapSize(const Message& message, + const FieldDescriptor* field) const { + return 0; + } + + // Help method for MapIterator. + friend class MapIterator; + virtual internal::MapFieldBase* MapData( + Message* message, const FieldDescriptor* field) const { + return NULL; + } + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection); }; @@ -1025,10 +1114,9 @@ inline RepeatedPtrField<string>* Reflection::MutableRepeatedPtrField<string>( 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)); + return *static_cast<const RepeatedPtrField<Message>* >( + GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, + -1, NULL)); } template<> @@ -1043,10 +1131,9 @@ inline RepeatedPtrField<Message>* Reflection::MutableRepeatedPtrField( 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())); + return *static_cast<const RepeatedPtrField<PB>* >( + GetRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_MESSAGE, + -1, PB::default_instance().GetDescriptor())); } template<typename PB> diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 4f63ad2b..5bd8bcfb 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -35,7 +35,9 @@ #include <google/protobuf/message_lite.h> #include <google/protobuf/arena.h> +#include <google/protobuf/repeated_field.h> #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl_lite.h> @@ -98,27 +100,19 @@ string InitializationErrorMessage(const char* action, // call MergePartialFromCodedStream(). However, when parsing very small // messages, every function call introduces significant overhead. To avoid // this without reproducing code, we use these forced-inline helpers. -// -// Note: GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not -// definitions. +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream( + io::CodedInputStream* input, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray( + const void* data, int size, MessageLite* message); +GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray( + const void* data, int size, MessageLite* message); + inline bool InlineMergeFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParseFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParseFromArray(const void* data, int size, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -inline bool InlineParsePartialFromArray(const void* data, int size, - MessageLite* message) - GOOGLE_ATTRIBUTE_ALWAYS_INLINE; - -bool InlineMergeFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { + MessageLite* message) { if (!message->MergePartialFromCodedStream(input)) return false; if (!message->IsInitialized()) { GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message); @@ -127,26 +121,27 @@ bool InlineMergeFromCodedStream(io::CodedInputStream* input, return true; } -bool InlineParseFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { +inline bool InlineParseFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { message->Clear(); return InlineMergeFromCodedStream(input, message); } -bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, - MessageLite* message) { +inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input, + MessageLite* message) { message->Clear(); return message->MergePartialFromCodedStream(input); } -bool InlineParseFromArray(const void* data, int size, MessageLite* message) { +inline bool InlineParseFromArray( + const void* data, int size, MessageLite* message) { io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size); return InlineParseFromCodedStream(&input, message) && input.ConsumedEntireMessage(); } -bool InlineParsePartialFromArray(const void* data, int size, - MessageLite* message) { +inline bool InlineParsePartialFromArray( + const void* data, int size, MessageLite* message) { io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size); return InlineParsePartialFromCodedStream(&input, message) && input.ConsumedEntireMessage(); @@ -353,5 +348,18 @@ string MessageLite::SerializePartialAsString() const { return output; } +namespace internal { +template<> +MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype( + const MessageLite* prototype, google::protobuf::Arena* arena) { + return prototype->New(arena); +} +template <> +void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, + MessageLite* to) { + to->CheckTypeAndMergeFrom(from); +} +} // namespace internal + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index 75d60b8b..2d4780fe 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -53,6 +53,7 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/generated_message_reflection.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h index c5bab0a8..fdee150b 100644 --- a/src/google/protobuf/metadata.h +++ b/src/google/protobuf/metadata.h @@ -69,8 +69,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { ptr_ = NULL; } - inline const UnknownFieldSet& unknown_fields() const - GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE const UnknownFieldSet& unknown_fields() const { if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { return PtrValue<Container>()->unknown_fields_; } else { @@ -78,7 +77,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline UnknownFieldSet* mutable_unknown_fields() GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE UnknownFieldSet* mutable_unknown_fields() { if (GOOGLE_PREDICT_TRUE(have_unknown_fields())) { return &PtrValue<Container>()->unknown_fields_; } else { @@ -86,7 +85,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline Arena* arena() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE Arena* arena() const { if (GOOGLE_PREDICT_FALSE(have_unknown_fields())) { return PtrValue<Container>()->arena_; } else { @@ -94,11 +93,11 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline bool have_unknown_fields() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool have_unknown_fields() const { return PtrTag() == kTagContainer; } - inline void Swap(InternalMetadataWithArena* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(InternalMetadataWithArena* other) { // 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 @@ -110,7 +109,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { } } - inline void* raw_arena_ptr() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* raw_arena_ptr() const { return ptr_; } @@ -128,7 +127,7 @@ class LIBPROTOBUF_EXPORT InternalMetadataWithArena { static const intptr_t kPtrValueMask = ~kPtrTagMask; // Accessors for pointer tag and pointer value. - inline int PtrTag() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { + GOOGLE_ATTRIBUTE_ALWAYS_INLINE int PtrTag() const { return reinterpret_cast<intptr_t>(ptr_) & kPtrTagMask; } diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc index 4b7b31d9..bc41beec 100644 --- a/src/google/protobuf/no_field_presence_test.cc +++ b/src/google/protobuf/no_field_presence_test.cc @@ -341,6 +341,46 @@ TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { EXPECT_EQ(false, r->HasField(message, field_string)); } +TEST(NoFieldPresenceTest, ReflectionClearFieldTest) { + proto2_nofieldpresence_unittest::TestAllTypes message; + + const google::protobuf::Reflection* r = message.GetReflection(); + const google::protobuf::Descriptor* desc = message.GetDescriptor(); + + 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"); + const google::protobuf::FieldDescriptor* field_message = desc->FindFieldByName( + "optional_nested_message"); + const google::protobuf::FieldDescriptor* field_lazy = desc->FindFieldByName( + "optional_lazy_message"); + + message.set_optional_int32(42); + r->ClearField(&message, field_int32); + EXPECT_EQ(0, message.optional_int32()); + + message.set_optional_double(42.0); + r->ClearField(&message, field_double); + EXPECT_EQ(0.0, message.optional_double()); + + message.set_optional_string("test"); + r->ClearField(&message, field_string); + EXPECT_EQ("", message.optional_string()); + + message.mutable_optional_nested_message()->set_bb(1234); + r->ClearField(&message, field_message); + EXPECT_FALSE(message.has_optional_nested_message()); + EXPECT_EQ(0, message.optional_nested_message().bb()); + + message.mutable_optional_lazy_message()->set_bb(42); + r->ClearField(&message, field_lazy); + EXPECT_FALSE(message.has_optional_lazy_message()); + EXPECT_EQ(0, message.optional_lazy_message().bb()); +} + TEST(NoFieldPresenceTest, HasFieldOneofsTest) { // check that HasField behaves properly for oneofs. proto2_nofieldpresence_unittest::TestAllTypes message; diff --git a/src/google/protobuf/proto3_arena_unittest.cc b/src/google/protobuf/proto3_arena_unittest.cc index da4be673..2838e0fc 100644 --- a/src/google/protobuf/proto3_arena_unittest.cc +++ b/src/google/protobuf/proto3_arena_unittest.cc @@ -119,7 +119,7 @@ void ExpectAllFieldsSet(const TestAllTypes& m) { // proto3 and expect the arena support to be fully tested in proto2 unittests // because proto3 shares most code with proto2. -TEST(ArenaTest, Parsing) { +TEST(Proto3ArenaTest, Parsing) { TestAllTypes original; SetAllFields(&original); @@ -129,7 +129,7 @@ TEST(ArenaTest, Parsing) { ExpectAllFieldsSet(*arena_message); } -TEST(ArenaTest, UnknownFields) { +TEST(Proto3ArenaTest, UnknownFields) { TestAllTypes original; SetAllFields(&original); @@ -150,7 +150,7 @@ TEST(ArenaTest, UnknownFields) { arena_message->GetReflection()->GetUnknownFields(*arena_message).empty()); } -TEST(ArenaTest, Swap) { +TEST(Proto3ArenaTest, Swap) { Arena arena1; Arena arena2; @@ -162,7 +162,7 @@ TEST(ArenaTest, Swap) { EXPECT_EQ(&arena2, arena2_message->GetArena()); } -TEST(ArenaTest, SetAllocatedMessage) { +TEST(Proto3ArenaTest, SetAllocatedMessage) { Arena arena; TestAllTypes *arena_message = Arena::CreateMessage<TestAllTypes>(&arena); TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; @@ -171,7 +171,7 @@ TEST(ArenaTest, SetAllocatedMessage) { EXPECT_EQ(118, arena_message->optional_nested_message().bb()); } -TEST(ArenaTest, ReleaseMessage) { +TEST(Proto3ArenaTest, ReleaseMessage) { Arena arena; TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); arena_message->mutable_optional_nested_message()->set_bb(118); @@ -180,7 +180,7 @@ TEST(ArenaTest, ReleaseMessage) { EXPECT_EQ(118, nested->bb()); } -TEST(ArenaTest, MessageFieldClear) { +TEST(Proto3ArenaTest, MessageFieldClear) { // GitHub issue #310: https://github.com/google/protobuf/issues/310 Arena arena; TestAllTypes* arena_message = Arena::CreateMessage<TestAllTypes>(&arena); @@ -190,6 +190,20 @@ TEST(ArenaTest, MessageFieldClear) { arena_message->Clear(); } +TEST(Proto3ArenaTest, MessageFieldClearViaReflection) { + Arena arena; + TestAllTypes* message = Arena::CreateMessage<TestAllTypes>(&arena); + const Reflection* r = message->GetReflection(); + const Descriptor* d = message->GetDescriptor(); + const FieldDescriptor* msg_field = d->FindFieldByName( + "optional_nested_message"); + + message->mutable_optional_nested_message()->set_bb(1); + r->ClearField(message, msg_field); + EXPECT_FALSE(message->has_optional_nested_message()); + EXPECT_EQ(0, message->optional_nested_message().bb()); +} + } // namespace } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/proto_cast.h b/src/google/protobuf/proto_cast.h index e25c219f..dc0e9aca 100644 --- a/src/google/protobuf/proto_cast.h +++ b/src/google/protobuf/proto_cast.h @@ -33,6 +33,7 @@ #include <string> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> // proto_cast<> is used to simulate over-the-wire conversion of one diff --git a/src/google/protobuf/proto_cast_test.cc b/src/google/protobuf/proto_cast_test.cc index eb101eb6..a8f43ae4 100644 --- a/src/google/protobuf/proto_cast_test.cc +++ b/src/google/protobuf/proto_cast_test.cc @@ -32,7 +32,7 @@ #include <google/protobuf/util/unknown_enum_test.pb.h> #include <gtest/gtest.h> -#include <google/protobuf/testing/gmock.h> +#include <gmock/gmock.h> namespace google { using google::protobuf::util::UpRevision; diff --git a/src/google/protobuf/reflection.h b/src/google/protobuf/reflection.h index 4ff0f6b4..671aafdc 100755 --- a/src/google/protobuf/reflection.h +++ b/src/google/protobuf/reflection.h @@ -553,7 +553,7 @@ struct RefTypeTraits< template<typename T> struct RefTypeTraits< - T, typename internal::enable_if<internal::is_same<string, T>::value>::type> { + T, typename internal::enable_if< ::google::protobuf::internal::is_same<string, T>::value>::type> { typedef RepeatedFieldRefIterator<T> iterator; typedef RepeatedFieldAccessor AccessorType; typedef string AccessorValueType; diff --git a/src/google/protobuf/reflection_ops_unittest.cc b/src/google/protobuf/reflection_ops_unittest.cc index 32740ea4..88d6bfb6 100644 --- a/src/google/protobuf/reflection_ops_unittest.cc +++ b/src/google/protobuf/reflection_ops_unittest.cc @@ -37,6 +37,7 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/test_util.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index e5aedadc..949e0a23 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -35,6 +35,7 @@ #include <algorithm> #include <google/protobuf/repeated_field.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> namespace google { @@ -53,13 +54,17 @@ void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { Arena* arena = GetArenaNoVirtual(); new_size = max(kMinRepeatedFieldAllocationSize, max(total_size_ * 2, new_size)); + GOOGLE_CHECK_LE(new_size, + (std::numeric_limits<size_t>::max() - kRepHeaderSize) / + sizeof(old_rep->elements[0])) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { rep_ = reinterpret_cast<Rep*>( - new char[kRepHeaderSize + sizeof(old_rep->elements[0])*new_size]); + 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)); + kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size)); } total_size_ = new_size; if (old_rep && old_rep->allocated_size > 0) { diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 9c84ed98..b42d4790 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -54,6 +54,7 @@ #include <string> #include <iterator> #include <google/protobuf/stubs/casts.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/type_traits.h> #include <google/protobuf/arena.h> @@ -361,7 +362,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { // 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; + friend class upb::google_opensource::GMR_Handlers; RepeatedPtrFieldBase(); explicit RepeatedPtrFieldBase(::google::protobuf::Arena* arena); @@ -408,7 +409,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { const typename TypeHandler::Type* const* data() const; template <typename TypeHandler> - inline void Swap(RepeatedPtrFieldBase* other) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + GOOGLE_ATTRIBUTE_ALWAYS_INLINE void Swap(RepeatedPtrFieldBase* other); void SwapElements(int index1, int index2); @@ -461,8 +462,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template <typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE void AddAllocatedSlowWithCopy(typename TypeHandler::Type* value, Arena* value_arena, - Arena* my_arena) -; + Arena* my_arena); template <typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE void AddAllocatedSlowWithoutCopy(typename TypeHandler::Type* value); @@ -472,7 +472,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { typename TypeHandler::Type* ReleaseLastInternal(google::protobuf::internal::false_type); template<typename TypeHandler> GOOGLE_ATTRIBUTE_NOINLINE - inline void SwapFallback(RepeatedPtrFieldBase* other); + void SwapFallback(RepeatedPtrFieldBase* other); inline Arena* GetArenaNoVirtual() const { return arena_; @@ -541,20 +541,10 @@ class GenericTypeHandler { } // 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. - GOOGLE_ATTRIBUTE_NOINLINE - static inline GenericType* NewFromPrototype(const GenericType* prototype, - ::google::protobuf::Arena* arena = NULL) { - return New(arena); - } - GOOGLE_ATTRIBUTE_NOINLINE - static inline void Delete(GenericType* value, Arena* arena) { - if (arena == NULL) { - delete value; - } - } + // constructors and destructors. + GOOGLE_ATTRIBUTE_NOINLINE static GenericType* NewFromPrototype( + const GenericType* prototype, ::google::protobuf::Arena* arena = NULL); + GOOGLE_ATTRIBUTE_NOINLINE static void Delete(GenericType* value, Arena* arena); static inline ::google::protobuf::Arena* GetArena(GenericType* value) { return ::google::protobuf::Arena::GetArena<Type>(value); } @@ -563,11 +553,8 @@ class GenericTypeHandler { } static inline void Clear(GenericType* value) { value->Clear(); } - - GOOGLE_ATTRIBUTE_NOINLINE - static inline void Merge(const GenericType& from, GenericType* to) { - to->MergeFrom(from); - } + GOOGLE_ATTRIBUTE_NOINLINE static void Merge(const GenericType& from, + GenericType* to); static inline int SpaceUsed(const GenericType& value) { return value.SpaceUsed(); } @@ -576,11 +563,31 @@ class GenericTypeHandler { } }; -template<> -inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype( - const MessageLite* prototype, google::protobuf::Arena* arena) { - return prototype->New(arena); +template <typename GenericType> +GenericType* GenericTypeHandler<GenericType>::NewFromPrototype( + const GenericType* prototype, ::google::protobuf::Arena* arena) { + return New(arena); } +template <typename GenericType> +void GenericTypeHandler<GenericType>::Delete(GenericType* value, Arena* arena) { + if (arena == NULL) { + delete value; + } +} +template <typename GenericType> +void GenericTypeHandler<GenericType>::Merge(const GenericType& from, + GenericType* to) { + to->MergeFrom(from); +} + +// NewFromPrototype() and Merge() cannot be defined here; if they're declared +// inline the compiler will complain about not matching GOOGLE_ATTRIBUTE_NOINLINE +// above, and if not, compilation will result in multiple definitions. These +// are therefore declared as specializations here and defined in +// message_lite.cc. +template<> +MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype( + const MessageLite* prototype, google::protobuf::Arena* arena); template<> inline google::protobuf::Arena* GenericTypeHandler<MessageLite>::GetArena( MessageLite* value) { @@ -591,14 +598,9 @@ inline void* GenericTypeHandler<MessageLite>::GetMaybeArenaPointer( MessageLite* value) { return value->GetMaybeArenaPointer(); } - -// 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); -} +void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, + MessageLite* to); // Declarations of the specialization as we cannot define them here, as the // header that defines ProtocolMessage depends on types defined in this header. @@ -1221,13 +1223,17 @@ void RepeatedField<Element>::Reserve(int new_size) { Arena* arena = GetArenaNoVirtual(); new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, max(total_size_ * 2, new_size)); + GOOGLE_CHECK_LE(new_size, + (std::numeric_limits<size_t>::max() - kRepHeaderSize) / + sizeof(Element)) + << "Requested size is too large to fit into size_t."; if (arena == NULL) { rep_ = reinterpret_cast<Rep*>( - new char[kRepHeaderSize + sizeof(Element)*new_size]); + new char[kRepHeaderSize + sizeof(Element) * new_size]); } else { rep_ = reinterpret_cast<Rep*>( ::google::protobuf::Arena::CreateArray<char>(arena, - kRepHeaderSize + sizeof(Element)*new_size)); + kRepHeaderSize + sizeof(Element) * new_size)); } rep_->arena = arena; int old_total_size = total_size_; @@ -1342,7 +1348,7 @@ inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { } template <typename TypeHandler> -inline void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { +void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { GOOGLE_DCHECK(other->GetArenaNoVirtual() != GetArenaNoVirtual()); // Copy semantics in this case. We try to improve efficiency by placing the diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index af397932..b45664b0 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -42,6 +42,7 @@ #include <google/protobuf/repeated_field.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/unittest.pb.h> #include <google/protobuf/stubs/strutil.h> @@ -1429,7 +1430,6 @@ class RepeatedFieldInsertionIteratorsTest : public testing::Test { std::copy(nested_ptrs.begin(), nested_ptrs.end(), RepeatedFieldBackInserter( protobuffer.mutable_repeated_nested_message())); - } virtual void TearDown() { diff --git a/src/google/protobuf/service.h b/src/google/protobuf/service.h index cc0b45d4..ad6f9685 100644 --- a/src/google/protobuf/service.h +++ b/src/google/protobuf/service.h @@ -74,12 +74,12 @@ // // To call a remote MyServiceImpl, first you need an RpcChannel connected to it. // How to construct a channel depends, again, on your RPC implementation. -// Here we use a hypothentical "MyRpcChannel" as an example: +// Here we use a hypothetical "MyRpcChannel" as an example: // MyRpcChannel channel("rpc:hostname:1234/myservice"); // MyRpcController controller; // MyServiceImpl::Stub stub(&channel); // FooRequest request; -// FooRespnose response; +// FooResponse response; // // // ... fill in request ... // @@ -102,6 +102,7 @@ #include <string> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/callback.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index 5c88363f..c8397639 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -81,9 +81,9 @@ void protobuf_AddDesc_google_2fprotobuf_2fsource_5fcontext_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n$google/protobuf/source_context.proto\022\017" "google.protobuf\"\"\n\rSourceContext\022\021\n\tfile" - "_name\030\001 \001(\tBR\n\023com.google.protobufB\022Sour" - "ceContextProtoP\001\242\002\003GPB\252\002\036Google.Protobuf" - ".WellKnownTypesb\006proto3", 183); + "_name\030\001 \001(\tBU\n\023com.google.protobufB\022Sour" + "ceContextProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Proto" + "buf.WellKnownTypesb\006proto3", 186); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/source_context.proto", &protobuf_RegisterTypes); SourceContext::default_instance_ = new SourceContext(); @@ -194,10 +194,10 @@ bool SourceContext::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_file_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->file_name().data(), this->file_name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.SourceContext.file_name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.SourceContext.file_name")); } else { goto handle_unusual; } @@ -231,9 +231,9 @@ void SourceContext::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.SourceContext) // optional string file_name = 1; if (this->file_name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->file_name().data(), this->file_name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.SourceContext.file_name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->file_name(), output); @@ -247,9 +247,9 @@ void SourceContext::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext) // optional string file_name = 1; if (this->file_name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->file_name().data(), this->file_name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.SourceContext.file_name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto index 98d4920a..e9a27d65 100644 --- a/src/google/protobuf/source_context.proto +++ b/src/google/protobuf/source_context.proto @@ -34,10 +34,10 @@ package google.protobuf; option java_multiple_files = true; option java_outer_classname = "SourceContextProto"; option java_package = "com.google.protobuf"; +option java_generate_equals_and_hash = true; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // `SourceContext` represents information about the source of a // protobuf element, like the file in which it is defined. message SourceContext { diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index a7e2eafd..c2b27c4c 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -301,6 +301,10 @@ bool Struct::MergePartialFromCodedStream( DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( input, entry.get())); (*mutable_fields())[entry->key()].Swap(entry->mutable_value()); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + entry->key().data(), entry->key().length(), + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Struct.FieldsEntry.key")); } else { goto handle_unusual; } @@ -343,6 +347,10 @@ void Struct::SerializeWithCachedSizes( entry.reset(fields_.NewEntryWrapper(it->first, it->second)); ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 1, *entry, output); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + it->first.data(), it->first.length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Struct.FieldsEntry.key"); } } @@ -362,6 +370,10 @@ void Struct::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite:: WriteMessageNoVirtualToArray( 1, *entry, target); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + it->first.data(), it->first.length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Struct.FieldsEntry.key"); } } @@ -547,6 +559,7 @@ Value* Value::New(::google::protobuf::Arena* arena) const { } void Value::clear_kind() { + typedef Value T; switch(kind_case()) { case kNullValue: { // No need to clear @@ -631,10 +644,10 @@ bool Value::MergePartialFromCodedStream( parse_string_value: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_string_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->string_value().data(), this->string_value().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Value.string_value"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Value.string_value")); } else { goto handle_unusual; } @@ -721,9 +734,9 @@ void Value::SerializeWithCachedSizes( // optional string string_value = 3; if (has_string_value()) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->string_value().data(), this->string_value().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Value.string_value"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 3, this->string_value(), output); @@ -765,9 +778,9 @@ void Value::SerializeWithCachedSizes( // optional string string_value = 3; if (has_string_value()) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->string_value().data(), this->string_value().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Value.string_value"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1114,10 +1127,11 @@ void Value::clear_struct_value() { } const ::google::protobuf::Struct& Value::struct_value() const { // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value) - return has_struct_value() ? *kind_.struct_value_ - : ::google::protobuf::Struct::default_instance(); + return has_struct_value() + ? *kind_.struct_value_ + : ::google::protobuf::Struct::default_instance(); } - ::google::protobuf::Struct* Value::mutable_struct_value() { +::google::protobuf::Struct* Value::mutable_struct_value() { if (!has_struct_value()) { clear_kind(); set_has_struct_value(); @@ -1126,7 +1140,7 @@ void Value::clear_struct_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.Value.struct_value) return kind_.struct_value_; } - ::google::protobuf::Struct* Value::release_struct_value() { +::google::protobuf::Struct* Value::release_struct_value() { if (has_struct_value()) { clear_has_kind(); ::google::protobuf::Struct* temp = kind_.struct_value_; @@ -1136,7 +1150,7 @@ void Value::clear_struct_value() { return NULL; } } - void Value::set_allocated_struct_value(::google::protobuf::Struct* struct_value) { +void Value::set_allocated_struct_value(::google::protobuf::Struct* struct_value) { clear_kind(); if (struct_value) { set_has_struct_value(); @@ -1160,10 +1174,11 @@ void Value::clear_list_value() { } const ::google::protobuf::ListValue& Value::list_value() const { // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value) - return has_list_value() ? *kind_.list_value_ - : ::google::protobuf::ListValue::default_instance(); + return has_list_value() + ? *kind_.list_value_ + : ::google::protobuf::ListValue::default_instance(); } - ::google::protobuf::ListValue* Value::mutable_list_value() { +::google::protobuf::ListValue* Value::mutable_list_value() { if (!has_list_value()) { clear_kind(); set_has_list_value(); @@ -1172,7 +1187,7 @@ void Value::clear_list_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.Value.list_value) return kind_.list_value_; } - ::google::protobuf::ListValue* Value::release_list_value() { +::google::protobuf::ListValue* Value::release_list_value() { if (has_list_value()) { clear_has_kind(); ::google::protobuf::ListValue* temp = kind_.list_value_; @@ -1182,7 +1197,7 @@ void Value::clear_list_value() { return NULL; } } - void Value::set_allocated_list_value(::google::protobuf::ListValue* list_value) { +void Value::set_allocated_list_value(::google::protobuf::ListValue* list_value) { clear_kind(); if (list_value) { set_has_list_value(); @@ -1422,28 +1437,28 @@ int ListValue::values_size() const { void ListValue::clear_values() { values_.Clear(); } - const ::google::protobuf::Value& ListValue::values(int index) const { +const ::google::protobuf::Value& ListValue::values(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.ListValue.values) return values_.Get(index); } - ::google::protobuf::Value* ListValue::mutable_values(int index) { +::google::protobuf::Value* ListValue::mutable_values(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.ListValue.values) return values_.Mutable(index); } - ::google::protobuf::Value* ListValue::add_values() { +::google::protobuf::Value* ListValue::add_values() { // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values) return values_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& -ListValue::values() const { - // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values) - return values_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >* ListValue::mutable_values() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values) return &values_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& +ListValue::values() const { + // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values) + return values_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 2889c8fe..0527c812 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -40,9 +40,9 @@ void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto(); void protobuf_AssignDesc_google_2fprotobuf_2fstruct_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2fstruct_2eproto(); +class ListValue; class Struct; class Value; -class ListValue; enum NullValue { NULL_VALUE = 0, @@ -383,10 +383,10 @@ class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message { const ::google::protobuf::Value& values(int index) const; ::google::protobuf::Value* mutable_values(int index); ::google::protobuf::Value* add_values(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& - values() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >* mutable_values(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& + values() const; // @@protoc_insertion_point(class_scope:google.protobuf.ListValue) private: @@ -612,10 +612,11 @@ inline void Value::clear_struct_value() { clear_has_kind(); } } -inline const ::google::protobuf::Struct& Value::struct_value() const { +inline const ::google::protobuf::Struct& Value::struct_value() const { // @@protoc_insertion_point(field_get:google.protobuf.Value.struct_value) - return has_struct_value() ? *kind_.struct_value_ - : ::google::protobuf::Struct::default_instance(); + return has_struct_value() + ? *kind_.struct_value_ + : ::google::protobuf::Struct::default_instance(); } inline ::google::protobuf::Struct* Value::mutable_struct_value() { if (!has_struct_value()) { @@ -658,10 +659,11 @@ inline void Value::clear_list_value() { clear_has_kind(); } } -inline const ::google::protobuf::ListValue& Value::list_value() const { +inline const ::google::protobuf::ListValue& Value::list_value() const { // @@protoc_insertion_point(field_get:google.protobuf.Value.list_value) - return has_list_value() ? *kind_.list_value_ - : ::google::protobuf::ListValue::default_instance(); + return has_list_value() + ? *kind_.list_value_ + : ::google::protobuf::ListValue::default_instance(); } inline ::google::protobuf::ListValue* Value::mutable_list_value() { if (!has_list_value()) { @@ -723,16 +725,16 @@ inline ::google::protobuf::Value* ListValue::add_values() { // @@protoc_insertion_point(field_add:google.protobuf.ListValue.values) return values_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& -ListValue::values() const { - // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values) - return values_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >* ListValue::mutable_values() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.ListValue.values) return &values_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Value >& +ListValue::values() const { + // @@protoc_insertion_point(field_list:google.protobuf.ListValue.values) + return values_; +} #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS // ------------------------------------------------------------------- diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto index 4ff10cd0..b3e9e699 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.proto @@ -45,6 +45,8 @@ option objc_class_prefix = "GPB"; // 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. +// +// The JSON representation for `Struct` is JSON object. message Struct { // Map of dynamically typed values. map<string, Value> fields = 1; @@ -54,37 +56,39 @@ message Struct { // 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. +// +// The JSON representation for `Value` is JSON value. message Value { + // The kind of 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. +// +// The JSON representation for `NullValue` is JSON `null`. +enum NullValue { + // Null value. + NULL_VALUE = 0; +} + // `ListValue` is a wrapper around a repeated field of values. +// +// The JSON representation for `ListValue` is JSON array. message ListValue { // Repeated field of dynamically typed values. repeated Value values = 1; } - -// `NullValue` is a singleton enumeration to represent the null -// value for the `Value` type union. -enum NullValue { - // Null value. - NULL_VALUE = 0; -} diff --git a/src/google/protobuf/stubs/common.cc b/src/google/protobuf/stubs/common.cc index d470fc72..54dbafab 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -35,8 +35,10 @@ #include <google/protobuf/stubs/status.h> #include <google/protobuf/stubs/stringpiece.h> #include <google/protobuf/stubs/strutil.h> -#include <stdio.h> +#include <google/protobuf/stubs/int128.h> #include <errno.h> +#include <sstream> +#include <stdio.h> #include <vector> #ifdef _WIN32 @@ -48,6 +50,9 @@ #else #error "No suitable threading library available." #endif +#if defined(__ANDROID__) +#include <android/log.h> +#endif namespace google { namespace protobuf { @@ -104,7 +109,43 @@ string VersionString(int version) { // emulates google3/base/logging.cc namespace internal { +#if defined(__ANDROID__) +inline void DefaultLogHandler(LogLevel level, const char* filename, int line, + const string& message) { +#ifdef GOOGLE_PROTOBUF_MIN_LOG_LEVEL + if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) { + return; + } + static const char* level_names[] = {"INFO", "WARNING", "ERROR", "FATAL"}; + + static const int android_log_levels[] = { + ANDROID_LOG_INFO, // LOG(INFO), + ANDROID_LOG_WARN, // LOG(WARNING) + ANDROID_LOG_ERROR, // LOG(ERROR) + ANDROID_LOG_FATAL, // LOG(FATAL) + }; + // Bound the logging level. + const int android_log_level = android_log_levels[level]; + ::std::ostringstream ostr; + ostr << "[libprotobuf " << level_names[level] << " " << filename << ":" + << line << "] " << message.c_str(); + + // Output the log string the Android log at the appropriate level. + __android_log_write(android_log_level, "libprotobuf-native", + ostr.str().c_str()); + // Also output to std::cerr. + fprintf(stderr, "%s", ostr.str().c_str()); + fflush(stderr); + + // Indicate termination if needed. + if (android_log_level == ANDROID_LOG_FATAL) { + __android_log_write(ANDROID_LOG_FATAL, "libprotobuf-native", + "terminating.\n"); + } +#endif +} +#else void DefaultLogHandler(LogLevel level, const char* filename, int line, const string& message) { static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" }; @@ -115,6 +156,7 @@ void DefaultLogHandler(LogLevel level, const char* filename, int line, level_names[level], filename, line, message.c_str()); fflush(stderr); // Needed on MSVC. } +#endif void NullLogHandler(LogLevel /* level */, const char* /* filename */, int /* line */, const string& /* message */) { @@ -154,22 +196,19 @@ LogMessage& LogMessage::operator<<(const StringPiece& value) { return *this; } -LogMessage& LogMessage::operator<<(long long value) { - message_ += SimpleItoa(value); - return *this; -} - -LogMessage& LogMessage::operator<<(unsigned long long value) { - message_ += SimpleItoa(value); - return *this; -} - LogMessage& LogMessage::operator<<( const ::google::protobuf::util::Status& status) { message_ += status.ToString(); return *this; } +LogMessage& LogMessage::operator<<(const uint128& value) { + std::ostringstream str; + str << value; + message_ += str.str(); + return *this; +} + // Since this is just for logging, we don't care if the current locale changes // the results -- in fact, we probably prefer that. So we use snprintf() // instead of Simple*toa(). @@ -194,6 +233,8 @@ DECLARE_STREAM_OPERATOR(long , "%ld") DECLARE_STREAM_OPERATOR(unsigned long, "%lu") DECLARE_STREAM_OPERATOR(double , "%g" ) DECLARE_STREAM_OPERATOR(void* , "%p" ) +DECLARE_STREAM_OPERATOR(long long , "%" GOOGLE_LL_FORMAT "d") +DECLARE_STREAM_OPERATOR(unsigned long long, "%" GOOGLE_LL_FORMAT "u") #undef DECLARE_STREAM_OPERATOR LogMessage::LogMessage(LogLevel level, const char* filename, int line) diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index de866e14..88e7084f 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -35,6 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMMON_H__ #define GOOGLE_PROTOBUF_COMMON_H__ +#include <string> #include <google/protobuf/stubs/port.h> #include <google/protobuf/stubs/macros.h> @@ -137,12 +138,35 @@ std::string LIBPROTOBUF_EXPORT VersionString(int version); // =================================================================== // from google3/util/utf8/public/unilib.h +class StringPiece; namespace internal { // Checks if the buffer contains structurally-valid UTF-8. Implemented in // structurally_valid.cc. LIBPROTOBUF_EXPORT bool IsStructurallyValidUTF8(const char* buf, int len); +inline bool IsStructurallyValidUTF8(const std::string& str) { + return IsStructurallyValidUTF8(str.data(), str.length()); +} + +// Returns initial number of bytes of structually valid UTF-8. +LIBPROTOBUF_EXPORT int UTF8SpnStructurallyValid(const StringPiece& str); + +// Coerce UTF-8 byte string in src_str to be +// a structurally-valid equal-length string by selectively +// overwriting illegal bytes with replace_char (typically ' ' or '?'). +// replace_char must be legal printable 7-bit Ascii 0x20..0x7e. +// src_str is read-only. +// +// Returns pointer to output buffer, src_str.data() if no changes were made, +// or idst if some bytes were changed. idst is allocated by the caller +// and must be at least as big as src_str +// +// Optimized for: all structurally valid and no byte copying is done. +// +LIBPROTOBUF_EXPORT char* UTF8CoerceToStructurallyValid( + const StringPiece& str, char* dst, char replace_char); + } // namespace internal diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index 9a6b217a..c6f210f0 100755 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -103,8 +103,8 @@ # define GOOGLE_PROTOBUF_HAS_CXX11_HASH # define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare # elif _MSC_VER >= 1500 // Since Visual Studio 2008 -# define GOOGLE_PROTOBUF_HAS_TR1 -# define GOOGLE_PROTOBUF_HASH_COMPARE stdext::hash_compare +# undef GOOGLE_PROTOBUF_HAVE_HASH_MAP +# undef GOOGLE_PROTOBUF_HAVE_HASH_SET # elif _MSC_VER >= 1310 # define GOOGLE_PROTOBUF_HASH_NAMESPACE stdext # include <hash_map> @@ -143,6 +143,11 @@ # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set #endif +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ + namespace google { \ + namespace protobuf { +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }} + #undef GOOGLE_PROTOBUF_HAS_CXX11_HASH #undef GOOGLE_PROTOBUF_HAS_TR1 diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc new file mode 100644 index 00000000..9f4fb824 --- /dev/null +++ b/src/google/protobuf/stubs/int128.cc @@ -0,0 +1,200 @@ +// 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/stubs/int128.h> + +#include <iomanip> +#include <iostream> // NOLINT(readability/streams) +#include <sstream> + +namespace google { +namespace protobuf { + +const uint128_pod kuint128max = { + static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)), + static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)) +}; + +// Returns the 0-based position of the last set bit (i.e., most significant bit) +// in the given uint64. The argument may not be 0. +// +// For example: +// Given: 5 (decimal) == 101 (binary) +// Returns: 2 +#define STEP(T, n, pos, sh) \ + do { \ + if ((n) >= (static_cast<T>(1) << (sh))) { \ + (n) = (n) >> (sh); \ + (pos) |= (sh); \ + } \ + } while (0) +static inline int Fls64(uint64 n) { + GOOGLE_DCHECK_NE(0, n); + int pos = 0; + STEP(uint64, n, pos, 0x20); + uint32 n32 = n; + STEP(uint32, n32, pos, 0x10); + STEP(uint32, n32, pos, 0x08); + STEP(uint32, n32, pos, 0x04); + return pos + ((GOOGLE_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3); +} +#undef STEP + +// Like Fls64() above, but returns the 0-based position of the last set bit +// (i.e., most significant bit) in the given uint128. The argument may not be 0. +static inline int Fls128(uint128 n) { + if (uint64 hi = Uint128High64(n)) { + return Fls64(hi) + 64; + } + return Fls64(Uint128Low64(n)); +} + +// Long division/modulo for uint128 implemented using the shift-subtract +// division algorithm adapted from: +// http://stackoverflow.com/questions/5386377/division-without-using +void uint128::DivModImpl(uint128 dividend, uint128 divisor, + uint128* quotient_ret, uint128* remainder_ret) { + if (divisor == 0) { + GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_ + << ", lo=" << dividend.lo_; + } + + if (divisor > dividend) { + *quotient_ret = 0; + *remainder_ret = dividend; + return; + } + + if (divisor == dividend) { + *quotient_ret = 1; + *remainder_ret = 0; + return; + } + + uint128 denominator = divisor; + uint128 position = 1; + uint128 quotient = 0; + + // Left aligns the MSB of the denominator and the dividend. + int shift = Fls128(dividend) - Fls128(denominator); + denominator <<= shift; + position <<= shift; + + // Uses shift-subtract algorithm to divide dividend by denominator. The + // remainder will be left in dividend. + while (position > 0) { + if (dividend >= denominator) { + dividend -= denominator; + quotient |= position; + } + position >>= 1; + denominator >>= 1; + } + + *quotient_ret = quotient; + *remainder_ret = dividend; +} + +uint128& uint128::operator/=(const uint128& divisor) { + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(*this, divisor, "ient, &remainder); + *this = quotient; + return *this; +} +uint128& uint128::operator%=(const uint128& divisor) { + uint128 quotient = 0; + uint128 remainder = 0; + DivModImpl(*this, divisor, "ient, &remainder); + *this = remainder; + return *this; +} + +std::ostream& operator<<(std::ostream& o, const uint128& b) { + std::ios_base::fmtflags flags = o.flags(); + + // Select a divisor which is the largest power of the base < 2^64. + uint128 div; + std::streamsize div_base_log; + switch (flags & std::ios::basefield) { + case std::ios::hex: + div = GOOGLE_ULONGLONG(0x1000000000000000); // 16^15 + div_base_log = 15; + break; + case std::ios::oct: + div = GOOGLE_ULONGLONG(01000000000000000000000); // 8^21 + div_base_log = 21; + break; + default: // std::ios::dec + div = GOOGLE_ULONGLONG(10000000000000000000); // 10^19 + div_base_log = 19; + break; + } + + // Now piece together the uint128 representation from three chunks of + // the original value, each less than "div" and therefore representable + // as a uint64. + std::ostringstream os; + std::ios_base::fmtflags copy_mask = + std::ios::basefield | std::ios::showbase | std::ios::uppercase; + os.setf(flags & copy_mask, copy_mask); + uint128 high = b; + uint128 low; + uint128::DivModImpl(high, div, &high, &low); + uint128 mid; + uint128::DivModImpl(high, div, &high, &mid); + if (high.lo_ != 0) { + os << high.lo_; + os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); + os << mid.lo_; + os << std::setw(div_base_log); + } else if (mid.lo_ != 0) { + os << mid.lo_; + os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); + } + os << low.lo_; + std::string rep = os.str(); + + // Add the requisite padding. + std::streamsize width = o.width(0); + if (width > rep.size()) { + if ((flags & std::ios::adjustfield) == std::ios::left) { + rep.append(width - rep.size(), o.fill()); + } else { + rep.insert(0, width - rep.size(), o.fill()); + } + } + + // Stream the final representation in a single "<<" call. + return o << rep; +} + +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/int128.h b/src/google/protobuf/stubs/int128.h new file mode 100644 index 00000000..1499bb76 --- /dev/null +++ b/src/google/protobuf/stubs/int128.h @@ -0,0 +1,383 @@ +// 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_STUBS_INT128_H_ +#define GOOGLE_PROTOBUF_STUBS_INT128_H_ + +#include <google/protobuf/stubs/common.h> + +#include <iosfwd> + +namespace google { +namespace protobuf { + +struct uint128_pod; + +// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is +// available. +#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR +# define UINT128_CONSTEXPR constexpr +#else +# define UINT128_CONSTEXPR +#endif + +// An unsigned 128-bit integer type. Thread-compatible. +class LIBPROTOBUF_EXPORT uint128 { + public: + UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior. + UINT128_CONSTEXPR uint128(uint64 top, uint64 bottom); +#ifndef SWIG + UINT128_CONSTEXPR uint128(int bottom); + UINT128_CONSTEXPR uint128(uint32 bottom); // Top 96 bits = 0 +#endif + UINT128_CONSTEXPR uint128(uint64 bottom); // hi_ = 0 + UINT128_CONSTEXPR uint128(const uint128_pod &val); + + // Trivial copy constructor, assignment operator and destructor. + + void Initialize(uint64 top, uint64 bottom); + + // Arithmetic operators. + uint128& operator+=(const uint128& b); + uint128& operator-=(const uint128& b); + uint128& operator*=(const uint128& b); + // Long division/modulo for uint128. + uint128& operator/=(const uint128& b); + uint128& operator%=(const uint128& b); + uint128 operator++(int); + uint128 operator--(int); + uint128& operator<<=(int); + uint128& operator>>=(int); + uint128& operator&=(const uint128& b); + uint128& operator|=(const uint128& b); + uint128& operator^=(const uint128& b); + uint128& operator++(); + uint128& operator--(); + + friend uint64 Uint128Low64(const uint128& v); + friend uint64 Uint128High64(const uint128& v); + + // We add "std::" to avoid including all of port.h. + LIBPROTOBUF_EXPORT friend std::ostream& operator<<(std::ostream& o, + const uint128& b); + + private: + static void DivModImpl(uint128 dividend, uint128 divisor, + uint128* quotient_ret, uint128* remainder_ret); + + // Little-endian memory order optimizations can benefit from + // having lo_ first, hi_ last. + // See util/endian/endian.h and Load128/Store128 for storing a uint128. + uint64 lo_; + uint64 hi_; + + // Not implemented, just declared for catching automatic type conversions. + uint128(uint8); + uint128(uint16); + uint128(float v); + uint128(double v); +}; + +// This is a POD form of uint128 which can be used for static variables which +// need to be operated on as uint128. +struct uint128_pod { + // Note: The ordering of fields is different than 'class uint128' but the + // same as its 2-arg constructor. This enables more obvious initialization + // of static instances, which is the primary reason for this struct in the + // first place. This does not seem to defeat any optimizations wrt + // operations involving this struct. + uint64 hi; + uint64 lo; +}; + +LIBPROTOBUF_EXPORT extern const uint128_pod kuint128max; + +// allow uint128 to be logged +LIBPROTOBUF_EXPORT extern std::ostream& operator<<(std::ostream& o, + const uint128& b); + +// Methods to access low and high pieces of 128-bit value. +// Defined externally from uint128 to facilitate conversion +// to native 128-bit types when compilers support them. +inline uint64 Uint128Low64(const uint128& v) { return v.lo_; } +inline uint64 Uint128High64(const uint128& v) { return v.hi_; } + +// TODO: perhaps it would be nice to have int128, a signed 128-bit type? + +// -------------------------------------------------------------------------- +// Implementation details follow +// -------------------------------------------------------------------------- +inline bool operator==(const uint128& lhs, const uint128& rhs) { + return (Uint128Low64(lhs) == Uint128Low64(rhs) && + Uint128High64(lhs) == Uint128High64(rhs)); +} +inline bool operator!=(const uint128& lhs, const uint128& rhs) { + return !(lhs == rhs); +} + +inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {} +inline UINT128_CONSTEXPR uint128::uint128(uint64 top, uint64 bottom) + : lo_(bottom), hi_(top) {} +inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v) + : lo_(v.lo), hi_(v.hi) {} +inline UINT128_CONSTEXPR uint128::uint128(uint64 bottom) + : lo_(bottom), hi_(0) {} +#ifndef SWIG +inline UINT128_CONSTEXPR uint128::uint128(uint32 bottom) + : lo_(bottom), hi_(0) {} +inline UINT128_CONSTEXPR uint128::uint128(int bottom) + : lo_(bottom), hi_(static_cast<int64>((bottom < 0) ? -1 : 0)) {} +#endif + +#undef UINT128_CONSTEXPR + +inline void uint128::Initialize(uint64 top, uint64 bottom) { + hi_ = top; + lo_ = bottom; +} + +// Comparison operators. + +#define CMP128(op) \ +inline bool operator op(const uint128& lhs, const uint128& rhs) { \ + return (Uint128High64(lhs) == Uint128High64(rhs)) ? \ + (Uint128Low64(lhs) op Uint128Low64(rhs)) : \ + (Uint128High64(lhs) op Uint128High64(rhs)); \ +} + +CMP128(<) +CMP128(>) +CMP128(>=) +CMP128(<=) + +#undef CMP128 + +// Unary operators + +inline uint128 operator-(const uint128& val) { + const uint64 hi_flip = ~Uint128High64(val); + const uint64 lo_flip = ~Uint128Low64(val); + const uint64 lo_add = lo_flip + 1; + if (lo_add < lo_flip) { + return uint128(hi_flip + 1, lo_add); + } + return uint128(hi_flip, lo_add); +} + +inline bool operator!(const uint128& val) { + return !Uint128High64(val) && !Uint128Low64(val); +} + +// Logical operators. + +inline uint128 operator~(const uint128& val) { + return uint128(~Uint128High64(val), ~Uint128Low64(val)); +} + +#define LOGIC128(op) \ +inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \ + return uint128(Uint128High64(lhs) op Uint128High64(rhs), \ + Uint128Low64(lhs) op Uint128Low64(rhs)); \ +} + +LOGIC128(|) +LOGIC128(&) +LOGIC128(^) + +#undef LOGIC128 + +#define LOGICASSIGN128(op) \ +inline uint128& uint128::operator op(const uint128& other) { \ + hi_ op other.hi_; \ + lo_ op other.lo_; \ + return *this; \ +} + +LOGICASSIGN128(|=) +LOGICASSIGN128(&=) +LOGICASSIGN128(^=) + +#undef LOGICASSIGN128 + +// Shift operators. + +inline uint128 operator<<(const uint128& val, int amount) { + // uint64 shifts of >= 64 are undefined, so we will need some special-casing. + if (amount < 64) { + if (amount == 0) { + return val; + } + uint64 new_hi = (Uint128High64(val) << amount) | + (Uint128Low64(val) >> (64 - amount)); + uint64 new_lo = Uint128Low64(val) << amount; + return uint128(new_hi, new_lo); + } else if (amount < 128) { + return uint128(Uint128Low64(val) << (amount - 64), 0); + } else { + return uint128(0, 0); + } +} + +inline uint128 operator>>(const uint128& val, int amount) { + // uint64 shifts of >= 64 are undefined, so we will need some special-casing. + if (amount < 64) { + if (amount == 0) { + return val; + } + uint64 new_hi = Uint128High64(val) >> amount; + uint64 new_lo = (Uint128Low64(val) >> amount) | + (Uint128High64(val) << (64 - amount)); + return uint128(new_hi, new_lo); + } else if (amount < 128) { + return uint128(0, Uint128High64(val) >> (amount - 64)); + } else { + return uint128(0, 0); + } +} + +inline uint128& uint128::operator<<=(int amount) { + // uint64 shifts of >= 64 are undefined, so we will need some special-casing. + if (amount < 64) { + if (amount != 0) { + hi_ = (hi_ << amount) | (lo_ >> (64 - amount)); + lo_ = lo_ << amount; + } + } else if (amount < 128) { + hi_ = lo_ << (amount - 64); + lo_ = 0; + } else { + hi_ = 0; + lo_ = 0; + } + return *this; +} + +inline uint128& uint128::operator>>=(int amount) { + // uint64 shifts of >= 64 are undefined, so we will need some special-casing. + if (amount < 64) { + if (amount != 0) { + lo_ = (lo_ >> amount) | (hi_ << (64 - amount)); + hi_ = hi_ >> amount; + } + } else if (amount < 128) { + lo_ = hi_ >> (amount - 64); + hi_ = 0; + } else { + lo_ = 0; + hi_ = 0; + } + return *this; +} + +inline uint128 operator+(const uint128& lhs, const uint128& rhs) { + return uint128(lhs) += rhs; +} + +inline uint128 operator-(const uint128& lhs, const uint128& rhs) { + return uint128(lhs) -= rhs; +} + +inline uint128 operator*(const uint128& lhs, const uint128& rhs) { + return uint128(lhs) *= rhs; +} + +inline uint128 operator/(const uint128& lhs, const uint128& rhs) { + return uint128(lhs) /= rhs; +} + +inline uint128 operator%(const uint128& lhs, const uint128& rhs) { + return uint128(lhs) %= rhs; +} + +inline uint128& uint128::operator+=(const uint128& b) { + hi_ += b.hi_; + uint64 lolo = lo_ + b.lo_; + if (lolo < lo_) + ++hi_; + lo_ = lolo; + return *this; +} + +inline uint128& uint128::operator-=(const uint128& b) { + hi_ -= b.hi_; + if (b.lo_ > lo_) + --hi_; + lo_ -= b.lo_; + return *this; +} + +inline uint128& uint128::operator*=(const uint128& b) { + uint64 a96 = hi_ >> 32; + uint64 a64 = hi_ & 0xffffffffu; + uint64 a32 = lo_ >> 32; + uint64 a00 = lo_ & 0xffffffffu; + uint64 b96 = b.hi_ >> 32; + uint64 b64 = b.hi_ & 0xffffffffu; + uint64 b32 = b.lo_ >> 32; + uint64 b00 = b.lo_ & 0xffffffffu; + // multiply [a96 .. a00] x [b96 .. b00] + // terms higher than c96 disappear off the high side + // terms c96 and c64 are safe to ignore carry bit + uint64 c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96; + uint64 c64 = a64 * b00 + a32 * b32 + a00 * b64; + this->hi_ = (c96 << 32) + c64; + this->lo_ = 0; + // add terms after this one at a time to capture carry + *this += uint128(a32 * b00) << 32; + *this += uint128(a00 * b32) << 32; + *this += a00 * b00; + return *this; +} + +inline uint128 uint128::operator++(int) { + uint128 tmp(*this); + *this += 1; + return tmp; +} + +inline uint128 uint128::operator--(int) { + uint128 tmp(*this); + *this -= 1; + return tmp; +} + +inline uint128& uint128::operator++() { + *this += 1; + return *this; +} + +inline uint128& uint128::operator--() { + *this -= 1; + return *this; +} + +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_STUBS_INT128_H_ diff --git a/src/google/protobuf/stubs/int128_unittest.cc b/src/google/protobuf/stubs/int128_unittest.cc new file mode 100644 index 00000000..5d33292c --- /dev/null +++ b/src/google/protobuf/stubs/int128_unittest.cc @@ -0,0 +1,513 @@ +// 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/stubs/int128.h> + +#include <algorithm> +#include <sstream> +#include <utility> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { + +TEST(Int128, AllTests) { + uint128 zero(0); + uint128 one(1); + uint128 one_2arg(0, 1); + uint128 two(0, 2); + uint128 three(0, 3); + uint128 big(2000, 2); + uint128 big_minus_one(2000, 1); + uint128 bigger(2001, 1); + uint128 biggest(kuint128max); + uint128 high_low(1, 0); + uint128 low_high(0, kuint64max); + EXPECT_LT(one, two); + EXPECT_GT(two, one); + EXPECT_LT(one, big); + EXPECT_LT(one, big); + EXPECT_EQ(one, one_2arg); + EXPECT_NE(one, two); + EXPECT_GT(big, one); + EXPECT_GE(big, two); + EXPECT_GE(big, big_minus_one); + EXPECT_GT(big, big_minus_one); + EXPECT_LT(big_minus_one, big); + EXPECT_LE(big_minus_one, big); + EXPECT_NE(big_minus_one, big); + EXPECT_LT(big, biggest); + EXPECT_LE(big, biggest); + EXPECT_GT(biggest, big); + EXPECT_GE(biggest, big); + EXPECT_EQ(big, ~~big); + EXPECT_EQ(one, one | one); + EXPECT_EQ(big, big | big); + EXPECT_EQ(one, one | zero); + EXPECT_EQ(one, one & one); + EXPECT_EQ(big, big & big); + EXPECT_EQ(zero, one & zero); + EXPECT_EQ(zero, big & ~big); + EXPECT_EQ(zero, one ^ one); + EXPECT_EQ(zero, big ^ big); + EXPECT_EQ(one, one ^ zero); + + // Shift operators. + EXPECT_EQ(big, big << 0); + EXPECT_EQ(big, big >> 0); + EXPECT_GT(big << 1, big); + EXPECT_LT(big >> 1, big); + EXPECT_EQ(big, (big << 10) >> 10); + EXPECT_EQ(big, (big >> 1) << 1); + EXPECT_EQ(one, (one << 80) >> 80); + EXPECT_EQ(zero, (one >> 80) << 80); + EXPECT_EQ(zero, big >> 128); + EXPECT_EQ(zero, big << 128); + + // Shift assignments. + uint128 big_copy = big; + EXPECT_EQ(big << 0, big_copy <<= 0); + big_copy = big; + EXPECT_EQ(big >> 0, big_copy >>= 0); + big_copy = big; + EXPECT_EQ(big << 1, big_copy <<= 1); + big_copy = big; + EXPECT_EQ(big >> 1, big_copy >>= 1); + big_copy = big; + EXPECT_EQ(big << 10, big_copy <<= 10); + big_copy = big; + EXPECT_EQ(big >> 10, big_copy >>= 10); + big_copy = big; + EXPECT_EQ(big << 64, big_copy <<= 64); + big_copy = big; + EXPECT_EQ(big >> 64, big_copy >>= 64); + big_copy = big; + EXPECT_EQ(big << 73, big_copy <<= 73); + big_copy = big; + EXPECT_EQ(big >> 73, big_copy >>= 73); + big_copy = big; + EXPECT_EQ(big << 128, big_copy <<= 128); + big_copy = big; + EXPECT_EQ(big >> 128, big_copy >>= 128); + + EXPECT_EQ(Uint128High64(biggest), kuint64max); + EXPECT_EQ(Uint128Low64(biggest), kuint64max); + EXPECT_EQ(zero + one, one); + EXPECT_EQ(one + one, two); + EXPECT_EQ(big_minus_one + one, big); + EXPECT_EQ(one - one, zero); + EXPECT_EQ(one - zero, one); + EXPECT_EQ(zero - one, biggest); + EXPECT_EQ(big - big, zero); + EXPECT_EQ(big - one, big_minus_one); + EXPECT_EQ(big + kuint64max, bigger); + EXPECT_EQ(biggest + 1, zero); + EXPECT_EQ(zero - 1, biggest); + EXPECT_EQ(high_low - one, low_high); + EXPECT_EQ(low_high + one, high_low); + EXPECT_EQ(Uint128High64((uint128(1) << 64) - 1), 0); + EXPECT_EQ(Uint128Low64((uint128(1) << 64) - 1), kuint64max); + EXPECT_TRUE(!!one); + EXPECT_TRUE(!!high_low); + EXPECT_FALSE(!!zero); + EXPECT_FALSE(!one); + EXPECT_FALSE(!high_low); + EXPECT_TRUE(!zero); + EXPECT_TRUE(zero == 0); + EXPECT_FALSE(zero != 0); + EXPECT_FALSE(one == 0); + EXPECT_TRUE(one != 0); + + uint128 test = zero; + EXPECT_EQ(++test, one); + EXPECT_EQ(test, one); + EXPECT_EQ(test++, one); + EXPECT_EQ(test, two); + EXPECT_EQ(test -= 2, zero); + EXPECT_EQ(test, zero); + EXPECT_EQ(test += 2, two); + EXPECT_EQ(test, two); + EXPECT_EQ(--test, one); + EXPECT_EQ(test, one); + EXPECT_EQ(test--, one); + EXPECT_EQ(test, zero); + EXPECT_EQ(test |= three, three); + EXPECT_EQ(test &= one, one); + EXPECT_EQ(test ^= three, two); + EXPECT_EQ(test >>= 1, one); + EXPECT_EQ(test <<= 1, two); + + EXPECT_EQ(big, -(-big)); + EXPECT_EQ(two, -((-one) - 1)); + EXPECT_EQ(kuint128max, -one); + EXPECT_EQ(zero, -zero); + + GOOGLE_LOG(INFO) << one; + GOOGLE_LOG(INFO) << big_minus_one; +} + +TEST(Int128, PodTests) { + uint128_pod pod = { 12345, 67890 }; + uint128 from_pod(pod); + EXPECT_EQ(12345, Uint128High64(from_pod)); + EXPECT_EQ(67890, Uint128Low64(from_pod)); + + uint128 zero(0); + uint128_pod zero_pod = {0, 0}; + uint128 one(1); + uint128_pod one_pod = {0, 1}; + uint128 two(2); + uint128_pod two_pod = {0, 2}; + uint128 three(3); + uint128_pod three_pod = {0, 3}; + uint128 big(1, 0); + uint128_pod big_pod = {1, 0}; + + EXPECT_EQ(zero, zero_pod); + EXPECT_EQ(zero_pod, zero); + EXPECT_EQ(zero_pod, zero_pod); + EXPECT_EQ(one, one_pod); + EXPECT_EQ(one_pod, one); + EXPECT_EQ(one_pod, one_pod); + EXPECT_EQ(two, two_pod); + EXPECT_EQ(two_pod, two); + EXPECT_EQ(two_pod, two_pod); + + EXPECT_NE(one, two_pod); + EXPECT_NE(one_pod, two); + EXPECT_NE(one_pod, two_pod); + + EXPECT_LT(one, two_pod); + EXPECT_LT(one_pod, two); + EXPECT_LT(one_pod, two_pod); + EXPECT_LE(one, one_pod); + EXPECT_LE(one_pod, one); + EXPECT_LE(one_pod, one_pod); + EXPECT_LE(one, two_pod); + EXPECT_LE(one_pod, two); + EXPECT_LE(one_pod, two_pod); + + EXPECT_GT(two, one_pod); + EXPECT_GT(two_pod, one); + EXPECT_GT(two_pod, one_pod); + EXPECT_GE(two, two_pod); + EXPECT_GE(two_pod, two); + EXPECT_GE(two_pod, two_pod); + EXPECT_GE(two, one_pod); + EXPECT_GE(two_pod, one); + EXPECT_GE(two_pod, one_pod); + + EXPECT_EQ(three, one | two_pod); + EXPECT_EQ(three, one_pod | two); + EXPECT_EQ(three, one_pod | two_pod); + EXPECT_EQ(one, three & one_pod); + EXPECT_EQ(one, three_pod & one); + EXPECT_EQ(one, three_pod & one_pod); + EXPECT_EQ(two, three ^ one_pod); + EXPECT_EQ(two, three_pod ^ one); + EXPECT_EQ(two, three_pod ^ one_pod); + EXPECT_EQ(two, three & (~one)); + EXPECT_EQ(three, ~~three); + + EXPECT_EQ(two, two_pod << 0); + EXPECT_EQ(two, one_pod << 1); + EXPECT_EQ(big, one_pod << 64); + EXPECT_EQ(zero, one_pod << 128); + EXPECT_EQ(two, two_pod >> 0); + EXPECT_EQ(one, two_pod >> 1); + EXPECT_EQ(one, big_pod >> 64); + + EXPECT_EQ(one, zero + one_pod); + EXPECT_EQ(one, zero_pod + one); + EXPECT_EQ(one, zero_pod + one_pod); + EXPECT_EQ(one, two - one_pod); + EXPECT_EQ(one, two_pod - one); + EXPECT_EQ(one, two_pod - one_pod); +} + +TEST(Int128, OperatorAssignReturnRef) { + uint128 v(1); + (v += 4) -= 3; + EXPECT_EQ(2, v); +} + +TEST(Int128, Multiply) { + uint128 a, b, c; + + // Zero test. + a = 0; + b = 0; + c = a * b; + EXPECT_EQ(0, c); + + // Max carries. + a = uint128(0) - 1; + b = uint128(0) - 1; + c = a * b; + EXPECT_EQ(1, c); + + // Self-operation with max carries. + c = uint128(0) - 1; + c *= c; + EXPECT_EQ(1, c); + + // 1-bit x 1-bit. + for (int i = 0; i < 64; ++i) { + for (int j = 0; j < 64; ++j) { + a = uint128(1) << i; + b = uint128(1) << j; + c = a * b; + EXPECT_EQ(uint128(1) << (i+j), c); + } + } + + // Verified with dc. + a = uint128(GOOGLE_ULONGLONG(0xffffeeeeddddcccc), + GOOGLE_ULONGLONG(0xbbbbaaaa99998888)); + b = uint128(GOOGLE_ULONGLONG(0x7777666655554444), + GOOGLE_ULONGLONG(0x3333222211110000)); + c = a * b; + EXPECT_EQ(uint128(GOOGLE_ULONGLONG(0x530EDA741C71D4C3), + GOOGLE_ULONGLONG(0xBF25975319080000)), c); + EXPECT_EQ(0, c - b * a); + EXPECT_EQ(a*a - b*b, (a+b) * (a-b)); + + // Verified with dc. + a = uint128(GOOGLE_ULONGLONG(0x0123456789abcdef), + GOOGLE_ULONGLONG(0xfedcba9876543210)); + b = uint128(GOOGLE_ULONGLONG(0x02468ace13579bdf), + GOOGLE_ULONGLONG(0xfdb97531eca86420)); + c = a * b; + EXPECT_EQ(uint128(GOOGLE_ULONGLONG(0x97a87f4f261ba3f2), + GOOGLE_ULONGLONG(0x342d0bbf48948200)), c); + EXPECT_EQ(0, c - b * a); + EXPECT_EQ(a*a - b*b, (a+b) * (a-b)); +} + +TEST(Int128, AliasTests) { + uint128 x1(1, 2); + uint128 x2(2, 4); + x1 += x1; + EXPECT_EQ(x2, x1); + + uint128 x3(1, static_cast<uint64>(1) << 63); + uint128 x4(3, 0); + x3 += x3; + EXPECT_EQ(x4, x3); +} + +#ifdef PROTOBUF_HAS_DEATH_TEST +TEST(Int128, DivideByZeroCheckFails) { + uint128 a = 0; + uint128 b = 0; + EXPECT_DEATH(a / b, "Division or mod by zero:"); + a = 123; + EXPECT_DEATH(a / b, "Division or mod by zero:"); +} + +TEST(Int128, ModByZeroCheckFails) { + uint128 a = 0; + uint128 b = 0; + EXPECT_DEATH(a % b, "Division or mod by zero:"); + a = 123; + EXPECT_DEATH(a % b, "Division or mod by zero:"); +} +#endif // PROTOBUF_HAS_DEATH_TEST + +TEST(Int128, DivideAndMod) { + // a := q * b + r + uint128 a, b, q, r; + + // Zero test. + a = 0; + b = 123; + q = a / b; + r = a % b; + EXPECT_EQ(0, q); + EXPECT_EQ(0, r); + + a = uint128(GOOGLE_ULONGLONG(0x530eda741c71d4c3), + GOOGLE_ULONGLONG(0xbf25975319080000)); + q = uint128(GOOGLE_ULONGLONG(0x4de2cab081), + GOOGLE_ULONGLONG(0x14c34ab4676e4bab)); + b = uint128(0x1110001); + r = uint128(0x3eb455); + ASSERT_EQ(a, q * b + r); // Sanity-check. + + uint128 result_q, result_r; + result_q = a / b; + result_r = a % b; + EXPECT_EQ(q, result_q); + EXPECT_EQ(r, result_r); + + // Try the other way around. + swap(q, b); + result_q = a / b; + result_r = a % b; + EXPECT_EQ(q, result_q); + EXPECT_EQ(r, result_r); + // Restore. + swap(b, q); + + // Dividend < divisor; result should be q:0 r:<dividend>. + swap(a, b); + result_q = a / b; + result_r = a % b; + EXPECT_EQ(0, result_q); + EXPECT_EQ(a, result_r); + // Try the other way around. + swap(a, q); + result_q = a / b; + result_r = a % b; + EXPECT_EQ(0, result_q); + EXPECT_EQ(a, result_r); + // Restore. + swap(q, a); + swap(b, a); + + // Try a large remainder. + b = a / 2 + 1; + uint128 expected_r(GOOGLE_ULONGLONG(0x29876d3a0e38ea61), + GOOGLE_ULONGLONG(0xdf92cba98c83ffff)); + // Sanity checks. + ASSERT_EQ(a / 2 - 1, expected_r); + ASSERT_EQ(a, b + expected_r); + result_q = a / b; + result_r = a % b; + EXPECT_EQ(1, result_q); + EXPECT_EQ(expected_r, result_r); +} + +static uint64 RandomUint64() { + uint64 v1 = rand(); + uint64 v2 = rand(); + uint64 v3 = rand(); + return v1 * v2 + v3; +} + +TEST(Int128, DivideAndModRandomInputs) { + const int kNumIters = 1 << 18; + for (int i = 0; i < kNumIters; ++i) { + const uint128 a(RandomUint64(), RandomUint64()); + const uint128 b(RandomUint64(), RandomUint64()); + if (b == 0) { + continue; // Avoid a div-by-zero. + } + const uint128 q = a / b; + const uint128 r = a % b; + ASSERT_EQ(a, b * q + r); + } +} + +#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR +TEST(Int128, ConstexprTest) { + constexpr uint128 zero; + constexpr uint128 one = 1; + constexpr uint128_pod pod = {2, 3}; + constexpr uint128 from_pod = pod; + constexpr uint128 minus_two = -2; + EXPECT_EQ(one, uint128(1)); + EXPECT_EQ(from_pod, uint128(2, 3)); + EXPECT_EQ(minus_two, uint128(-1ULL, -2ULL)); +} + +TEST(Int128, Traits) { + EXPECT_TRUE(std::is_trivially_copy_constructible<uint128>::value); + EXPECT_TRUE(std::is_trivially_copy_assignable<uint128>::value); + EXPECT_TRUE(std::is_trivially_destructible<uint128>::value); +} +#endif // GOOGLE_PROTOBUF_HAS_CONSTEXPR + +TEST(Int128, OStream) { + struct { + uint128 val; + std::ios_base::fmtflags flags; + std::streamsize width; + char fill; + const char* rep; + } cases[] = { + // zero with different bases + {uint128(0), std::ios::dec, 0, '_', "0"}, + {uint128(0), std::ios::oct, 0, '_', "0"}, + {uint128(0), std::ios::hex, 0, '_', "0"}, + // crossover between lo_ and hi_ + {uint128(0, -1), std::ios::dec, 0, '_', "18446744073709551615"}, + {uint128(0, -1), std::ios::oct, 0, '_', "1777777777777777777777"}, + {uint128(0, -1), std::ios::hex, 0, '_', "ffffffffffffffff"}, + {uint128(1, 0), std::ios::dec, 0, '_', "18446744073709551616"}, + {uint128(1, 0), std::ios::oct, 0, '_', "2000000000000000000000"}, + {uint128(1, 0), std::ios::hex, 0, '_', "10000000000000000"}, + // just the top bit + {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::dec, 0, '_', + "170141183460469231731687303715884105728"}, + {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::oct, 0, '_', + "2000000000000000000000000000000000000000000"}, + {uint128(GOOGLE_ULONGLONG(0x8000000000000000), 0), std::ios::hex, 0, '_', + "80000000000000000000000000000000"}, + // maximum uint128 value + {uint128(-1, -1), std::ios::dec, 0, '_', + "340282366920938463463374607431768211455"}, + {uint128(-1, -1), std::ios::oct, 0, '_', + "3777777777777777777777777777777777777777777"}, + {uint128(-1, -1), std::ios::hex, 0, '_', + "ffffffffffffffffffffffffffffffff"}, + // uppercase + {uint128(-1, -1), std::ios::hex | std::ios::uppercase, 0, '_', + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"}, + // showbase + {uint128(1), std::ios::dec | std::ios::showbase, 0, '_', "1"}, + {uint128(1), std::ios::oct | std::ios::showbase, 0, '_', "01"}, + {uint128(1), std::ios::hex | std::ios::showbase, 0, '_', "0x1"}, + // showbase does nothing on zero + {uint128(0), std::ios::dec | std::ios::showbase, 0, '_', "0"}, + {uint128(0), std::ios::oct | std::ios::showbase, 0, '_', "0"}, + {uint128(0), std::ios::hex | std::ios::showbase, 0, '_', "0"}, + // showpos does nothing on unsigned types + {uint128(1), std::ios::dec | std::ios::showpos, 0, '_', "1"}, + // padding + {uint128(9), std::ios::dec, 6, '_', "_____9"}, + {uint128(12345), std::ios::dec, 6, '_', "_12345"}, + // left adjustment + {uint128(9), std::ios::dec | std::ios::left, 6, '_', "9_____"}, + {uint128(12345), std::ios::dec | std::ios::left, 6, '_', "12345_"}, + }; + for (size_t i = 0; i < GOOGLE_ARRAYSIZE(cases); ++i) { + ostringstream os; + os.flags(cases[i].flags); + os.width(cases[i].width); + os.fill(cases[i].fill); + os << cases[i].val; + EXPECT_EQ(cases[i].rep, os.str()); + } +} +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/stubs/logging.h b/src/google/protobuf/stubs/logging.h index 330d33d2..3108db8c 100644 --- a/src/google/protobuf/stubs/logging.h +++ b/src/google/protobuf/stubs/logging.h @@ -65,6 +65,7 @@ class StringPiece; namespace util { class Status; } +class uint128; namespace internal { class LogFinisher; @@ -78,7 +79,7 @@ class LIBPROTOBUF_EXPORT LogMessage { LogMessage& operator<<(const char* value); LogMessage& operator<<(char value); LogMessage& operator<<(int value); - LogMessage& operator<<(unsigned int value); + LogMessage& operator<<(uint value); LogMessage& operator<<(long value); LogMessage& operator<<(unsigned long value); LogMessage& operator<<(long long value); @@ -87,6 +88,7 @@ class LIBPROTOBUF_EXPORT LogMessage { LogMessage& operator<<(void* value); LogMessage& operator<<(const StringPiece& value); LogMessage& operator<<(const ::google::protobuf::util::Status& status); + LogMessage& operator<<(const uint128& value); private: friend class LogFinisher; diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h index 99c4d452..3a1ef8a8 100644 --- a/src/google/protobuf/stubs/mathutil.h +++ b/src/google/protobuf/stubs/mathutil.h @@ -45,9 +45,21 @@ bool IsNan(T value) { return false; } template<> -inline bool IsNan(float value) { return isnan(value); } +inline bool IsNan(float value) { +#ifdef _MSC_VER + return _isnan(value); +#else + return isnan(value); +#endif +} template<> -inline bool IsNan(double value) { return isnan(value); } +inline bool IsNan(double value) { +#ifdef _MSC_VER + return _isnan(value); +#else + return isnan(value); +#endif +} template<typename T> bool AlmostEquals(T a, T b) { diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h index a3c53dd9..5158a6f9 100644 --- a/src/google/protobuf/stubs/port.h +++ b/src/google/protobuf/stubs/port.h @@ -100,20 +100,12 @@ typedef unsigned __int64 uint64; typedef signed char int8; typedef short int16; typedef int int32; -// NOTE: This should be "long long" for consistency with upstream, but -// something is stacked against this particular type for 64bit hashing. -// Switching it causes an obvious missing hash function (with an unobvious -// cause) when building the tests. -typedef int64_t int64; +typedef long long int64; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; -// NOTE: This should be "unsigned long long" for consistency with upstream, but -// something is stacked against this particular type for 64bit hashing. -// Switching it causes an obvious missing hash function (with an unobvious -// cause) when building the tests. -typedef uint64_t uint64; +typedef unsigned long long uint64; #endif // long long macros to be used because gcc and vc++ use different suffixes, diff --git a/src/google/protobuf/stubs/status.cc b/src/google/protobuf/stubs/status.cc index 7314c563..dd1bd614 100644 --- a/src/google/protobuf/stubs/status.cc +++ b/src/google/protobuf/stubs/status.cc @@ -30,7 +30,6 @@ #include <google/protobuf/stubs/status.h> #include <ostream> -#include <stdint.h> #include <stdio.h> #include <string> #include <utility> diff --git a/src/google/protobuf/stubs/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc index 0f6afe6d..d79a6ee4 100644 --- a/src/google/protobuf/stubs/structurally_valid.cc +++ b/src/google/protobuf/stubs/structurally_valid.cc @@ -3,6 +3,8 @@ #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/stringpiece.h> + namespace google { namespace protobuf { namespace internal { @@ -531,6 +533,56 @@ bool IsStructurallyValidUTF8(const char* buf, int len) { return (bytes_consumed == len); } +int UTF8SpnStructurallyValid(const StringPiece& str) { + if (!module_initialized_) return str.size(); + + int bytes_consumed = 0; + UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj, + str.data(), str.size(), &bytes_consumed); + return bytes_consumed; +} + +// Coerce UTF-8 byte string in src_str to be +// a structurally-valid equal-length string by selectively +// overwriting illegal bytes with replace_char (typically blank). +// replace_char must be legal printable 7-bit Ascii 0x20..0x7e. +// src_str is read-only. If any overwriting is needed, a modified byte string +// is created in idst, length isrclen. +// +// Returns pointer to output buffer, isrc if no changes were made, +// or idst if some bytes were changed. +// +// Fast case: all is structurally valid and no byte copying is done. +// +char* UTF8CoerceToStructurallyValid(const StringPiece& src_str, + char* idst, + const char replace_char) { + const char* isrc = src_str.data(); + const int len = src_str.length(); + int n = UTF8SpnStructurallyValid(src_str); + if (n == len) { // Normal case -- all is cool, return + return const_cast<char*>(isrc); + } else { // Unusual case -- copy w/o bad bytes + const char* src = isrc; + const char* srclimit = isrc + len; + char* dst = idst; + memmove(dst, src, n); // Copy initial good chunk + src += n; + dst += n; + while (src < srclimit) { // src points to bogus byte or is off the end + dst[0] = replace_char; // replace one bad byte + src++; + dst++; + StringPiece str2(src, srclimit - src); + n = UTF8SpnStructurallyValid(str2); // scan the remainder + memmove(dst, src, n); // copy next good chunk + src += n; + dst += n; + } + } + return idst; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index be1c90e0..07aa1d77 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -42,6 +42,7 @@ #include <google/protobuf/descriptor.h> #include <google/protobuf/message.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> diff --git a/src/google/protobuf/test_util_lite.cc b/src/google/protobuf/test_util_lite.cc index 88eca0ad..388c0cbd 100644 --- a/src/google/protobuf/test_util_lite.cc +++ b/src/google/protobuf/test_util_lite.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/test_util_lite.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 76ce9875..1aafd8e6 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -38,11 +38,13 @@ #include <stdlib.h> #include <limits> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/file.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_mset.pb.h> +#include <google/protobuf/unittest_mset_wire_format.pb.h> #include <google/protobuf/io/tokenizer.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/stubs/strutil.h> diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index 11f258da..06b60e6f 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -38,7 +38,6 @@ option java_package = "com.google.protobuf"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // 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 @@ -85,14 +84,16 @@ option objc_class_prefix = "GPB"; // 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 +// Example 5: Compute Timestamp from current time in Python. +// +// now = time.time() +// seconds = int(now) +// nanos = int((now - seconds) * 10**9) // 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. diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 029a72c6..8f993561 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -38,6 +38,7 @@ const ::google::protobuf::internal::GeneratedMessageReflection* const ::google::protobuf::Descriptor* Option_descriptor_ = NULL; const ::google::protobuf::internal::GeneratedMessageReflection* Option_reflection_ = NULL; +const ::google::protobuf::EnumDescriptor* Syntax_descriptor_ = NULL; } // namespace @@ -49,12 +50,13 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { "google/protobuf/type.proto"); GOOGLE_CHECK(file != NULL); Type_descriptor_ = file->message_type(0); - static const int Type_offsets_[5] = { + static const int Type_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, fields_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, oneofs_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, source_context_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, syntax_), }; Type_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -68,7 +70,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Type, _is_default_instance_)); Field_descriptor_ = file->message_type(1); - static const int Field_offsets_[8] = { + static const int Field_offsets_[9] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, kind_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, cardinality_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, number_), @@ -77,6 +79,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, oneof_index_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, packed_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, options_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Field, json_name_), }; Field_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -92,11 +95,12 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { Field_Kind_descriptor_ = Field_descriptor_->enum_type(0); Field_Cardinality_descriptor_ = Field_descriptor_->enum_type(1); Enum_descriptor_ = file->message_type(2); - static const int Enum_offsets_[4] = { + static const int Enum_offsets_[5] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, enumvalue_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, options_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, source_context_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Enum, syntax_), }; Enum_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -142,6 +146,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto() { sizeof(Option), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, _internal_metadata_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Option, _is_default_instance_)); + Syntax_descriptor_ = file->enum_type(0); } namespace { @@ -192,38 +197,43 @@ void protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\032google/protobuf/type.proto\022\017google.pro" "tobuf\032\031google/protobuf/any.proto\032$google" - "/protobuf/source_context.proto\"\256\001\n\004Type\022" + "/protobuf/source_context.proto\"\327\001\n\004Type\022" "\014\n\004name\030\001 \001(\t\022&\n\006fields\030\002 \003(\0132\026.google.p" "rotobuf.Field\022\016\n\006oneofs\030\003 \003(\t\022(\n\007options" "\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc" "e_context\030\005 \001(\0132\036.google.protobuf.Source" - "Context\"\233\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.google" - ".protobuf.Field.Kind\0227\n\013cardinality\030\002 \001(" - "\0162\".google.protobuf.Field.Cardinality\022\016\n" - "\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url\030" - "\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 \001" - "(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.Op" - "tion\"\270\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TYPE_" - "DOUBLE\020\001\022\016\n\nTYPE_FLOAT\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\014TYP" - "E_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE_BO" - "OL\020\010\022\017\n\013TYPE_STRING\020\t\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_SFIXE" - "D64\020\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"" - "t\n\013Cardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022" - "\030\n\024CARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY" - "_REQUIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\245\001" - "\n\004Enum\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132" - "\032.google.protobuf.EnumValue\022(\n\007options\030\003" - " \003(\0132\027.google.protobuf.Option\0226\n\016source_" - "context\030\004 \001(\0132\036.google.protobuf.SourceCo" - "ntext\"S\n\tEnumValue\022\014\n\004name\030\001 \001(\t\022\016\n\006numb" - "er\030\002 \001(\005\022(\n\007options\030\003 \003(\0132\027.google.proto" - "buf.Option\";\n\006Option\022\014\n\004name\030\001 \001(\t\022#\n\005va" - "lue\030\002 \001(\0132\024.google.protobuf.AnyBI\n\023com.g" - "oogle.protobufB\tTypeProtoP\001\242\002\003GPB\252\002\036Goog" - "le.Protobuf.WellKnownTypesb\006proto3", 1354); + "Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu" + "f.Syntax\"\276\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl" + "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001" + "(\0162\".google.protobuf.Field.Cardinality\022\016" + "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url" + "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 " + "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O" + "ption\022\021\n\tjson_name\030\n \001(\t\"\310\002\n\004Kind\022\020\n\014TYP" + "E_UNKNOWN\020\000\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLO" + "AT\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\nT" + "YPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENU" + "M\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\"t\n\013C" + "ardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022\030\n\024C" + "ARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY_REQ" + "UIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\316\001\n\004En" + "um\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132\032.go" + "ogle.protobuf.EnumValue\022(\n\007options\030\003 \003(\013" + "2\027.google.protobuf.Option\0226\n\016source_cont" + "ext\030\004 \001(\0132\036.google.protobuf.SourceContex" + "t\022\'\n\006syntax\030\005 \001(\0162\027.google.protobuf.Synt" + "ax\"S\n\tEnumValue\022\014\n\004name\030\001 \001(\t\022\016\n\006number\030" + "\002 \001(\005\022(\n\007options\030\003 \003(\0132\027.google.protobuf" + ".Option\";\n\006Option\022\014\n\004name\030\001 \001(\t\022#\n\005value" + "\030\002 \001(\0132\024.google.protobuf.Any*.\n\006Syntax\022\021" + "\n\rSYNTAX_PROTO2\020\000\022\021\n\rSYNTAX_PROTO3\020\001BL\n\023" + "com.google.protobufB\tTypeProtoP\001\240\001\001\242\002\003GP" + "B\252\002\036Google.Protobuf.WellKnownTypesb\006prot" + "o3", 1522); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/type.proto", &protobuf_RegisterTypes); Type::default_instance_ = new Type(); @@ -245,6 +255,20 @@ struct StaticDescriptorInitializer_google_2fprotobuf_2ftype_2eproto { protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); } } static_descriptor_initializer_google_2fprotobuf_2ftype_2eproto_; +const ::google::protobuf::EnumDescriptor* Syntax_descriptor() { + protobuf_AssignDescriptorsOnce(); + return Syntax_descriptor_; +} +bool Syntax_IsValid(int value) { + switch(value) { + case 0: + case 1: + return true; + default: + return false; + } +} + namespace { @@ -264,6 +288,7 @@ const int Type::kFieldsFieldNumber; const int Type::kOneofsFieldNumber; const int Type::kOptionsFieldNumber; const int Type::kSourceContextFieldNumber; +const int Type::kSyntaxFieldNumber; #endif // !_MSC_VER Type::Type() @@ -291,6 +316,7 @@ void Type::SharedCtor() { _cached_size_ = 0; name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Type::~Type() { @@ -334,6 +360,7 @@ void Type::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; + syntax_ = 0; fields_.Clear(); oneofs_.Clear(); options_.Clear(); @@ -354,10 +381,10 @@ bool Type::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Type.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Type.name")); } else { goto handle_unusual; } @@ -388,11 +415,11 @@ bool Type::MergePartialFromCodedStream( parse_oneofs: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->add_oneofs())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->oneofs(this->oneofs_size() - 1).data(), this->oneofs(this->oneofs_size() - 1).length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Type.oneofs"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Type.oneofs")); } else { goto handle_unusual; } @@ -427,6 +454,22 @@ bool Type::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(48)) goto parse_syntax; + break; + } + + // optional .google.protobuf.Syntax syntax = 6; + case 6: { + if (tag == 48) { + parse_syntax: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + set_syntax(static_cast< ::google::protobuf::Syntax >(value)); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -457,9 +500,9 @@ void Type::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Type) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Type.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -473,10 +516,10 @@ void Type::SerializeWithCachedSizes( // repeated string oneofs = 3; for (int i = 0; i < this->oneofs_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( - this->oneofs(i).data(), this->oneofs(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, - "google.protobuf.Type.oneofs"); + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->oneofs(i).data(), this->oneofs(i).length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Type.oneofs"); ::google::protobuf::internal::WireFormatLite::WriteString( 3, this->oneofs(i), output); } @@ -493,6 +536,12 @@ void Type::SerializeWithCachedSizes( 5, *this->source_context_, output); } + // optional .google.protobuf.Syntax syntax = 6; + if (this->syntax() != 0) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 6, this->syntax(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Type) } @@ -501,9 +550,9 @@ void Type::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Type.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -519,9 +568,9 @@ void Type::SerializeWithCachedSizes( // repeated string oneofs = 3; for (int i = 0; i < this->oneofs_size(); i++) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->oneofs(i).data(), this->oneofs(i).length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Type.oneofs"); target = ::google::protobuf::internal::WireFormatLite:: WriteStringToArray(3, this->oneofs(i), target); @@ -541,6 +590,12 @@ void Type::SerializeWithCachedSizes( 5, *this->source_context_, target); } + // optional .google.protobuf.Syntax syntax = 6; + if (this->syntax() != 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 6, this->syntax(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Type) return target; } @@ -562,6 +617,12 @@ int Type::ByteSize() const { *this->source_context_); } + // optional .google.protobuf.Syntax syntax = 6; + if (this->syntax() != 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax()); + } + // repeated .google.protobuf.Field fields = 2; total_size += 1 * this->fields_size(); for (int i = 0; i < this->fields_size(); i++) { @@ -615,6 +676,9 @@ void Type::MergeFrom(const Type& from) { if (from.has_source_context()) { mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context()); } + if (from.syntax() != 0) { + set_syntax(from.syntax()); + } } void Type::CopyFrom(const ::google::protobuf::Message& from) { @@ -644,6 +708,7 @@ void Type::InternalSwap(Type* other) { oneofs_.UnsafeArenaSwap(&other->oneofs_); options_.UnsafeArenaSwap(&other->options_); std::swap(source_context_, other->source_context_); + std::swap(syntax_, other->syntax_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -709,28 +774,28 @@ int Type::fields_size() const { void Type::clear_fields() { fields_.Clear(); } - const ::google::protobuf::Field& Type::fields(int index) const { +const ::google::protobuf::Field& Type::fields(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Type.fields) return fields_.Get(index); } - ::google::protobuf::Field* Type::mutable_fields(int index) { +::google::protobuf::Field* Type::mutable_fields(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Type.fields) return fields_.Mutable(index); } - ::google::protobuf::Field* Type::add_fields() { +::google::protobuf::Field* Type::add_fields() { // @@protoc_insertion_point(field_add:google.protobuf.Type.fields) return fields_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& -Type::fields() const { - // @@protoc_insertion_point(field_list:google.protobuf.Type.fields) - return fields_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >* Type::mutable_fields() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields) return &fields_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& +Type::fields() const { + // @@protoc_insertion_point(field_list:google.protobuf.Type.fields) + return fields_; +} // repeated string oneofs = 3; int Type::oneofs_size() const { @@ -793,28 +858,28 @@ int Type::options_size() const { void Type::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& Type::options(int index) const { +const ::google::protobuf::Option& Type::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Type.options) return options_.Get(index); } - ::google::protobuf::Option* Type::mutable_options(int index) { +::google::protobuf::Option* Type::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Type.options) return options_.Mutable(index); } - ::google::protobuf::Option* Type::add_options() { +::google::protobuf::Option* Type::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Type.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Type::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Type.options) - return options_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Type::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options) return &options_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Type::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Type.options) + return options_; +} // optional .google.protobuf.SourceContext source_context = 5; bool Type::has_source_context() const { @@ -824,11 +889,11 @@ void Type::clear_source_context() { if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } - const ::google::protobuf::SourceContext& Type::source_context() const { +const ::google::protobuf::SourceContext& Type::source_context() const { // @@protoc_insertion_point(field_get:google.protobuf.Type.source_context) return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_; } - ::google::protobuf::SourceContext* Type::mutable_source_context() { +::google::protobuf::SourceContext* Type::mutable_source_context() { if (source_context_ == NULL) { source_context_ = new ::google::protobuf::SourceContext; @@ -836,13 +901,13 @@ void Type::clear_source_context() { // @@protoc_insertion_point(field_mutable:google.protobuf.Type.source_context) return source_context_; } - ::google::protobuf::SourceContext* Type::release_source_context() { +::google::protobuf::SourceContext* Type::release_source_context() { ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; return temp; } - void Type::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { +void Type::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { delete source_context_; source_context_ = source_context; if (source_context) { @@ -853,6 +918,20 @@ void Type::clear_source_context() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context) } +// optional .google.protobuf.Syntax syntax = 6; +void Type::clear_syntax() { + syntax_ = 0; +} + ::google::protobuf::Syntax Type::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} + void Type::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax) +} + #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== @@ -873,6 +952,7 @@ bool Field_Kind_IsValid(int value) { case 7: case 8: case 9: + case 10: case 11: case 12: case 13: @@ -898,6 +978,7 @@ const Field_Kind Field::TYPE_FIXED64; const Field_Kind Field::TYPE_FIXED32; const Field_Kind Field::TYPE_BOOL; const Field_Kind Field::TYPE_STRING; +const Field_Kind Field::TYPE_GROUP; const Field_Kind Field::TYPE_MESSAGE; const Field_Kind Field::TYPE_BYTES; const Field_Kind Field::TYPE_UINT32; @@ -944,6 +1025,7 @@ const int Field::kTypeUrlFieldNumber; const int Field::kOneofIndexFieldNumber; const int Field::kPackedFieldNumber; const int Field::kOptionsFieldNumber; +const int Field::kJsonNameFieldNumber; #endif // !_MSC_VER Field::Field() @@ -975,6 +1057,7 @@ void Field::SharedCtor() { type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); oneof_index_ = 0; packed_ = false; + json_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } Field::~Field() { @@ -985,6 +1068,7 @@ Field::~Field() { void Field::SharedDtor() { name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); type_url_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + json_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (this != default_instance_) { } } @@ -1028,6 +1112,7 @@ void Field::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); packed_ = false; + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); #undef ZR_HELPER_ #undef ZR_ @@ -1097,10 +1182,10 @@ bool Field::MergePartialFromCodedStream( parse_name: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Field.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Field.name")); } else { goto handle_unusual; } @@ -1114,10 +1199,10 @@ bool Field::MergePartialFromCodedStream( parse_type_url: DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_type_url())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Field.type_url"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Field.type_url")); } else { goto handle_unusual; } @@ -1168,6 +1253,23 @@ bool Field::MergePartialFromCodedStream( } if (input->ExpectTag(74)) goto parse_loop_options; input->UnsafeDecrementRecursionDepth(); + if (input->ExpectTag(82)) goto parse_json_name; + break; + } + + // optional string json_name = 10; + case 10: { + if (tag == 82) { + parse_json_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_json_name())); + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Field.json_name")); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1215,9 +1317,9 @@ void Field::SerializeWithCachedSizes( // optional string name = 4; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Field.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 4, this->name(), output); @@ -1225,9 +1327,9 @@ void Field::SerializeWithCachedSizes( // optional string type_url = 6; if (this->type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Field.type_url"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 6, this->type_url(), output); @@ -1249,6 +1351,16 @@ void Field::SerializeWithCachedSizes( 9, this->options(i), output); } + // optional string json_name = 10; + if (this->json_name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Field.json_name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 10, this->json_name(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Field) } @@ -1274,9 +1386,9 @@ void Field::SerializeWithCachedSizes( // optional string name = 4; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Field.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1285,9 +1397,9 @@ void Field::SerializeWithCachedSizes( // optional string type_url = 6; if (this->type_url().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->type_url().data(), this->type_url().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Field.type_url"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1311,6 +1423,17 @@ void Field::SerializeWithCachedSizes( 9, this->options(i), target); } + // optional string json_name = 10; + if (this->json_name().size() > 0) { + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormatLite::SERIALIZE, + "google.protobuf.Field.json_name"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 10, this->json_name(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Field) return target; } @@ -1363,6 +1486,13 @@ int Field::ByteSize() const { total_size += 1 + 1; } + // optional string json_name = 10; + if (this->json_name().size() > 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->json_name()); + } + // repeated .google.protobuf.Option options = 9; total_size += 1 * this->options_size(); for (int i = 0; i < this->options_size(); i++) { @@ -1415,6 +1545,10 @@ void Field::MergeFrom(const Field& from) { if (from.packed() != 0) { set_packed(from.packed()); } + if (from.json_name().size() > 0) { + + json_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.json_name_); + } } void Field::CopyFrom(const ::google::protobuf::Message& from) { @@ -1447,6 +1581,7 @@ void Field::InternalSwap(Field* other) { std::swap(oneof_index_, other->oneof_index_); std::swap(packed_, other->packed_); options_.UnsafeArenaSwap(&other->options_); + json_name_.Swap(&other->json_name_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -1625,27 +1760,70 @@ int Field::options_size() const { void Field::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& Field::options(int index) const { +const ::google::protobuf::Option& Field::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Field.options) return options_.Get(index); } - ::google::protobuf::Option* Field::mutable_options(int index) { +::google::protobuf::Option* Field::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Field.options) return options_.Mutable(index); } - ::google::protobuf::Option* Field::add_options() { +::google::protobuf::Option* Field::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Field.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +Field::mutable_options() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options) + return &options_; +} +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& Field::options() const { // @@protoc_insertion_point(field_list:google.protobuf.Field.options) return options_; } - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* -Field::mutable_options() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options) - return &options_; + +// optional string json_name = 10; +void Field::clear_json_name() { + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + const ::std::string& Field::json_name() const { + // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name) + return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Field::set_json_name(const ::std::string& value) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name) +} + void Field::set_json_name(const char* value) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Field.json_name) +} + void Field::set_json_name(const char* value, size_t size) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.json_name) +} + ::std::string* Field::mutable_json_name() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name) + return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + ::std::string* Field::release_json_name() { + + return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void Field::set_allocated_json_name(::std::string* json_name) { + if (json_name != NULL) { + + } else { + + } + json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -1657,6 +1835,7 @@ const int Enum::kNameFieldNumber; const int Enum::kEnumvalueFieldNumber; const int Enum::kOptionsFieldNumber; const int Enum::kSourceContextFieldNumber; +const int Enum::kSyntaxFieldNumber; #endif // !_MSC_VER Enum::Enum() @@ -1684,6 +1863,7 @@ void Enum::SharedCtor() { _cached_size_ = 0; name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Enum::~Enum() { @@ -1727,6 +1907,7 @@ void Enum::Clear() { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; + syntax_ = 0; enumvalue_.Clear(); options_.Clear(); } @@ -1746,10 +1927,10 @@ bool Enum::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Enum.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Enum.name")); } else { goto handle_unusual; } @@ -1799,6 +1980,22 @@ bool Enum::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(40)) goto parse_syntax; + break; + } + + // optional .google.protobuf.Syntax syntax = 5; + case 5: { + if (tag == 40) { + parse_syntax: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + set_syntax(static_cast< ::google::protobuf::Syntax >(value)); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1829,9 +2026,9 @@ void Enum::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Enum) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Enum.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -1855,6 +2052,12 @@ void Enum::SerializeWithCachedSizes( 4, *this->source_context_, output); } + // optional .google.protobuf.Syntax syntax = 5; + if (this->syntax() != 0) { + ::google::protobuf::internal::WireFormatLite::WriteEnum( + 5, this->syntax(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Enum) } @@ -1863,9 +2066,9 @@ void Enum::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Enum.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -1893,6 +2096,12 @@ void Enum::SerializeWithCachedSizes( 4, *this->source_context_, target); } + // optional .google.protobuf.Syntax syntax = 5; + if (this->syntax() != 0) { + target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( + 5, this->syntax(), target); + } + // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Enum) return target; } @@ -1914,6 +2123,12 @@ int Enum::ByteSize() const { *this->source_context_); } + // optional .google.protobuf.Syntax syntax = 5; + if (this->syntax() != 0) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::EnumSize(this->syntax()); + } + // repeated .google.protobuf.EnumValue enumvalue = 2; total_size += 1 * this->enumvalue_size(); for (int i = 0; i < this->enumvalue_size(); i++) { @@ -1959,6 +2174,9 @@ void Enum::MergeFrom(const Enum& from) { if (from.has_source_context()) { mutable_source_context()->::google::protobuf::SourceContext::MergeFrom(from.source_context()); } + if (from.syntax() != 0) { + set_syntax(from.syntax()); + } } void Enum::CopyFrom(const ::google::protobuf::Message& from) { @@ -1987,6 +2205,7 @@ void Enum::InternalSwap(Enum* other) { enumvalue_.UnsafeArenaSwap(&other->enumvalue_); options_.UnsafeArenaSwap(&other->options_); std::swap(source_context_, other->source_context_); + std::swap(syntax_, other->syntax_); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); } @@ -2052,28 +2271,28 @@ int Enum::enumvalue_size() const { void Enum::clear_enumvalue() { enumvalue_.Clear(); } - const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const { +const ::google::protobuf::EnumValue& Enum::enumvalue(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Enum.enumvalue) return enumvalue_.Get(index); } - ::google::protobuf::EnumValue* Enum::mutable_enumvalue(int index) { +::google::protobuf::EnumValue* Enum::mutable_enumvalue(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.enumvalue) return enumvalue_.Mutable(index); } - ::google::protobuf::EnumValue* Enum::add_enumvalue() { +::google::protobuf::EnumValue* Enum::add_enumvalue() { // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue) return enumvalue_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& -Enum::enumvalue() const { - // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue) - return enumvalue_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >* Enum::mutable_enumvalue() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue) return &enumvalue_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& +Enum::enumvalue() const { + // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue) + return enumvalue_; +} // repeated .google.protobuf.Option options = 3; int Enum::options_size() const { @@ -2082,28 +2301,28 @@ int Enum::options_size() const { void Enum::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& Enum::options(int index) const { +const ::google::protobuf::Option& Enum::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.Enum.options) return options_.Get(index); } - ::google::protobuf::Option* Enum::mutable_options(int index) { +::google::protobuf::Option* Enum::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.options) return options_.Mutable(index); } - ::google::protobuf::Option* Enum::add_options() { +::google::protobuf::Option* Enum::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Enum.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Enum::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Enum.options) - return options_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Enum::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options) return &options_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Enum::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Enum.options) + return options_; +} // optional .google.protobuf.SourceContext source_context = 4; bool Enum::has_source_context() const { @@ -2113,11 +2332,11 @@ void Enum::clear_source_context() { if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; } - const ::google::protobuf::SourceContext& Enum::source_context() const { +const ::google::protobuf::SourceContext& Enum::source_context() const { // @@protoc_insertion_point(field_get:google.protobuf.Enum.source_context) return source_context_ != NULL ? *source_context_ : *default_instance_->source_context_; } - ::google::protobuf::SourceContext* Enum::mutable_source_context() { +::google::protobuf::SourceContext* Enum::mutable_source_context() { if (source_context_ == NULL) { source_context_ = new ::google::protobuf::SourceContext; @@ -2125,13 +2344,13 @@ void Enum::clear_source_context() { // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.source_context) return source_context_; } - ::google::protobuf::SourceContext* Enum::release_source_context() { +::google::protobuf::SourceContext* Enum::release_source_context() { ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; return temp; } - void Enum::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { +void Enum::set_allocated_source_context(::google::protobuf::SourceContext* source_context) { delete source_context_; source_context_ = source_context; if (source_context) { @@ -2142,6 +2361,20 @@ void Enum::clear_source_context() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context) } +// optional .google.protobuf.Syntax syntax = 5; +void Enum::clear_syntax() { + syntax_ = 0; +} + ::google::protobuf::Syntax Enum::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} + void Enum::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax) +} + #endif // PROTOBUF_INLINE_NOT_IN_HEADERS // =================================================================== @@ -2235,10 +2468,10 @@ bool EnumValue::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.EnumValue.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.EnumValue.name")); } else { goto handle_unusual; } @@ -2304,9 +2537,9 @@ void EnumValue::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.EnumValue) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.EnumValue.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -2331,9 +2564,9 @@ void EnumValue::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.EnumValue.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -2515,28 +2748,28 @@ int EnumValue::options_size() const { void EnumValue::clear_options() { options_.Clear(); } - const ::google::protobuf::Option& EnumValue::options(int index) const { +const ::google::protobuf::Option& EnumValue::options(int index) const { // @@protoc_insertion_point(field_get:google.protobuf.EnumValue.options) return options_.Get(index); } - ::google::protobuf::Option* EnumValue::mutable_options(int index) { +::google::protobuf::Option* EnumValue::mutable_options(int index) { // @@protoc_insertion_point(field_mutable:google.protobuf.EnumValue.options) return options_.Mutable(index); } - ::google::protobuf::Option* EnumValue::add_options() { +::google::protobuf::Option* EnumValue::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options) return options_.Add(); } - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -EnumValue::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options) - return options_; -} - ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* EnumValue::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options) return &options_; } +const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +EnumValue::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options) + return options_; +} #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -2632,10 +2865,10 @@ bool Option::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.Option.name"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.Option.name")); } else { goto handle_unusual; } @@ -2682,9 +2915,9 @@ void Option::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.Option) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Option.name"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->name(), output); @@ -2704,9 +2937,9 @@ void Option::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option) // optional string name = 1; if (this->name().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.Option.name"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( @@ -2860,11 +3093,11 @@ void Option::clear_value() { if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; } - const ::google::protobuf::Any& Option::value() const { +const ::google::protobuf::Any& Option::value() const { // @@protoc_insertion_point(field_get:google.protobuf.Option.value) return value_ != NULL ? *value_ : *default_instance_->value_; } - ::google::protobuf::Any* Option::mutable_value() { +::google::protobuf::Any* Option::mutable_value() { if (value_ == NULL) { value_ = new ::google::protobuf::Any; @@ -2872,13 +3105,13 @@ void Option::clear_value() { // @@protoc_insertion_point(field_mutable:google.protobuf.Option.value) return value_; } - ::google::protobuf::Any* Option::release_value() { +::google::protobuf::Any* Option::release_value() { ::google::protobuf::Any* temp = value_; value_ = NULL; return temp; } - void Option::set_allocated_value(::google::protobuf::Any* value) { +void Option::set_allocated_value(::google::protobuf::Any* value) { delete value_; value_ = value; if (value) { diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index c9952efa..deda9213 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -40,11 +40,11 @@ void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2ftype_2eproto(); -class Type; -class Field; class Enum; class EnumValue; +class Field; class Option; +class Type; enum Field_Kind { Field_Kind_TYPE_UNKNOWN = 0, @@ -57,6 +57,7 @@ enum Field_Kind { Field_Kind_TYPE_FIXED32 = 7, Field_Kind_TYPE_BOOL = 8, Field_Kind_TYPE_STRING = 9, + Field_Kind_TYPE_GROUP = 10, Field_Kind_TYPE_MESSAGE = 11, Field_Kind_TYPE_BYTES = 12, Field_Kind_TYPE_UINT32 = 13, @@ -106,6 +107,27 @@ inline bool Field_Cardinality_Parse( return ::google::protobuf::internal::ParseNamedEnum<Field_Cardinality>( Field_Cardinality_descriptor(), name, value); } +enum Syntax { + SYNTAX_PROTO2 = 0, + SYNTAX_PROTO3 = 1, + Syntax_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min, + Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max +}; +LIBPROTOBUF_EXPORT bool Syntax_IsValid(int value); +const Syntax Syntax_MIN = SYNTAX_PROTO2; +const Syntax Syntax_MAX = SYNTAX_PROTO3; +const int Syntax_ARRAYSIZE = Syntax_MAX + 1; + +LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* Syntax_descriptor(); +inline const ::std::string& Syntax_Name(Syntax value) { + return ::google::protobuf::internal::NameOfEnum( + Syntax_descriptor(), value); +} +inline bool Syntax_Parse( + const ::std::string& name, Syntax* value) { + return ::google::protobuf::internal::ParseNamedEnum<Syntax>( + Syntax_descriptor(), name, value); +} // =================================================================== class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { @@ -182,10 +204,10 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { const ::google::protobuf::Field& fields(int index) const; ::google::protobuf::Field* mutable_fields(int index); ::google::protobuf::Field* add_fields(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& - fields() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >* mutable_fields(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& + fields() const; // repeated string oneofs = 3; int oneofs_size() const; @@ -210,10 +232,10 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; // optional .google.protobuf.SourceContext source_context = 5; bool has_source_context() const; @@ -224,6 +246,12 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { ::google::protobuf::SourceContext* release_source_context(); void set_allocated_source_context(::google::protobuf::SourceContext* source_context); + // optional .google.protobuf.Syntax syntax = 6; + void clear_syntax(); + static const int kSyntaxFieldNumber = 6; + ::google::protobuf::Syntax syntax() const; + void set_syntax(::google::protobuf::Syntax value); + // @@protoc_insertion_point(class_scope:google.protobuf.Type) private: @@ -234,6 +262,7 @@ class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::std::string> oneofs_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; ::google::protobuf::SourceContext* source_context_; + int syntax_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto(); @@ -309,6 +338,7 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { static const Kind TYPE_FIXED32 = Field_Kind_TYPE_FIXED32; static const Kind TYPE_BOOL = Field_Kind_TYPE_BOOL; static const Kind TYPE_STRING = Field_Kind_TYPE_STRING; + static const Kind TYPE_GROUP = Field_Kind_TYPE_GROUP; static const Kind TYPE_MESSAGE = Field_Kind_TYPE_MESSAGE; static const Kind TYPE_BYTES = Field_Kind_TYPE_BYTES; static const Kind TYPE_UINT32 = Field_Kind_TYPE_UINT32; @@ -425,10 +455,21 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; + + // optional string json_name = 10; + void clear_json_name(); + static const int kJsonNameFieldNumber = 10; + const ::std::string& json_name() const; + void set_json_name(const ::std::string& value); + void set_json_name(const char* value); + void set_json_name(const char* value, size_t size); + ::std::string* mutable_json_name(); + ::std::string* release_json_name(); + void set_allocated_json_name(::std::string* json_name); // @@protoc_insertion_point(class_scope:google.protobuf.Field) private: @@ -442,6 +483,7 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { ::google::protobuf::int32 oneof_index_; ::google::protobuf::internal::ArenaStringPtr type_url_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; + ::google::protobuf::internal::ArenaStringPtr json_name_; bool packed_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); @@ -527,10 +569,10 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message { const ::google::protobuf::EnumValue& enumvalue(int index) const; ::google::protobuf::EnumValue* mutable_enumvalue(int index); ::google::protobuf::EnumValue* add_enumvalue(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& - enumvalue() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >* mutable_enumvalue(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& + enumvalue() const; // repeated .google.protobuf.Option options = 3; int options_size() const; @@ -539,10 +581,10 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; // optional .google.protobuf.SourceContext source_context = 4; bool has_source_context() const; @@ -553,6 +595,12 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message { ::google::protobuf::SourceContext* release_source_context(); void set_allocated_source_context(::google::protobuf::SourceContext* source_context); + // optional .google.protobuf.Syntax syntax = 5; + void clear_syntax(); + static const int kSyntaxFieldNumber = 5; + ::google::protobuf::Syntax syntax() const; + void set_syntax(::google::protobuf::Syntax value); + // @@protoc_insertion_point(class_scope:google.protobuf.Enum) private: @@ -562,6 +610,7 @@ class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue > enumvalue_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option > options_; ::google::protobuf::SourceContext* source_context_; + int syntax_; mutable int _cached_size_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2ftype_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2ftype_2eproto(); @@ -652,10 +701,10 @@ class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message { const ::google::protobuf::Option& options(int index) const; ::google::protobuf::Option* mutable_options(int index); ::google::protobuf::Option* add_options(); - const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& - options() const; ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& + options() const; // @@protoc_insertion_point(class_scope:google.protobuf.EnumValue) private: @@ -836,16 +885,16 @@ inline ::google::protobuf::Field* Type::add_fields() { // @@protoc_insertion_point(field_add:google.protobuf.Type.fields) return fields_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& -Type::fields() const { - // @@protoc_insertion_point(field_list:google.protobuf.Type.fields) - return fields_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >* Type::mutable_fields() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.fields) return &fields_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Field >& +Type::fields() const { + // @@protoc_insertion_point(field_list:google.protobuf.Type.fields) + return fields_; +} // repeated string oneofs = 3; inline int Type::oneofs_size() const { @@ -920,16 +969,16 @@ inline ::google::protobuf::Option* Type::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Type.options) return options_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Type::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Type.options) - return options_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Type::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Type.options) return &options_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Type::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Type.options) + return options_; +} // optional .google.protobuf.SourceContext source_context = 5; inline bool Type::has_source_context() const { @@ -968,6 +1017,20 @@ inline void Type::set_allocated_source_context(::google::protobuf::SourceContext // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.source_context) } +// optional .google.protobuf.Syntax syntax = 6; +inline void Type::clear_syntax() { + syntax_ = 0; +} +inline ::google::protobuf::Syntax Type::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Type.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} +inline void Type::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Type.syntax) +} + // ------------------------------------------------------------------- // Field @@ -1147,15 +1210,58 @@ inline ::google::protobuf::Option* Field::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Field.options) return options_.Add(); } +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* +Field::mutable_options() { + // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options) + return &options_; +} inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& Field::options() const { // @@protoc_insertion_point(field_list:google.protobuf.Field.options) return options_; } -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* -Field::mutable_options() { - // @@protoc_insertion_point(field_mutable_list:google.protobuf.Field.options) - return &options_; + +// optional string json_name = 10; +inline void Field::clear_json_name() { + json_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline const ::std::string& Field::json_name() const { + // @@protoc_insertion_point(field_get:google.protobuf.Field.json_name) + return json_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Field::set_json_name(const ::std::string& value) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.Field.json_name) +} +inline void Field::set_json_name(const char* value) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.Field.json_name) +} +inline void Field::set_json_name(const char* value, size_t size) { + + json_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.Field.json_name) +} +inline ::std::string* Field::mutable_json_name() { + + // @@protoc_insertion_point(field_mutable:google.protobuf.Field.json_name) + return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* Field::release_json_name() { + + return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void Field::set_allocated_json_name(::std::string* json_name) { + if (json_name != NULL) { + + } else { + + } + json_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), json_name); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.Field.json_name) } // ------------------------------------------------------------------- @@ -1224,16 +1330,16 @@ inline ::google::protobuf::EnumValue* Enum::add_enumvalue() { // @@protoc_insertion_point(field_add:google.protobuf.Enum.enumvalue) return enumvalue_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& -Enum::enumvalue() const { - // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue) - return enumvalue_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >* Enum::mutable_enumvalue() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.enumvalue) return &enumvalue_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValue >& +Enum::enumvalue() const { + // @@protoc_insertion_point(field_list:google.protobuf.Enum.enumvalue) + return enumvalue_; +} // repeated .google.protobuf.Option options = 3; inline int Enum::options_size() const { @@ -1254,16 +1360,16 @@ inline ::google::protobuf::Option* Enum::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.Enum.options) return options_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -Enum::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.Enum.options) - return options_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* Enum::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.Enum.options) return &options_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +Enum::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.Enum.options) + return options_; +} // optional .google.protobuf.SourceContext source_context = 4; inline bool Enum::has_source_context() const { @@ -1302,6 +1408,20 @@ inline void Enum::set_allocated_source_context(::google::protobuf::SourceContext // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.source_context) } +// optional .google.protobuf.Syntax syntax = 5; +inline void Enum::clear_syntax() { + syntax_ = 0; +} +inline ::google::protobuf::Syntax Enum::syntax() const { + // @@protoc_insertion_point(field_get:google.protobuf.Enum.syntax) + return static_cast< ::google::protobuf::Syntax >(syntax_); +} +inline void Enum::set_syntax(::google::protobuf::Syntax value) { + + syntax_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.Enum.syntax) +} + // ------------------------------------------------------------------- // EnumValue @@ -1382,16 +1502,16 @@ inline ::google::protobuf::Option* EnumValue::add_options() { // @@protoc_insertion_point(field_add:google.protobuf.EnumValue.options) return options_.Add(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& -EnumValue::options() const { - // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options) - return options_; -} inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* EnumValue::mutable_options() { // @@protoc_insertion_point(field_mutable_list:google.protobuf.EnumValue.options) return &options_; } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >& +EnumValue::options() const { + // @@protoc_insertion_point(field_list:google.protobuf.EnumValue.options) + return options_; +} // ------------------------------------------------------------------- @@ -1506,6 +1626,11 @@ template <> inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::Field_Cardinality>() { return ::google::protobuf::Field_Cardinality_descriptor(); } +template <> struct is_proto_enum< ::google::protobuf::Syntax> : ::google::protobuf::internal::true_type {}; +template <> +inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::Syntax>() { + return ::google::protobuf::Syntax_descriptor(); +} } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto index ce22d33d..4df95762 100644 --- a/src/google/protobuf/type.proto +++ b/src/google/protobuf/type.proto @@ -34,30 +34,27 @@ package google.protobuf; import "google/protobuf/any.proto"; import "google/protobuf/source_context.proto"; -option java_multiple_files = true; -option java_outer_classname = "TypeProto"; option java_package = "com.google.protobuf"; +option java_outer_classname = "TypeProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - // A light-weight descriptor for a proto message type. message Type { // The fully qualified message name. string name = 1; - // The list of fields. repeated Field fields = 2; - // The list of oneof definitions. - // The list of oneofs declared in this Type - repeated string oneofs = 3; - + repeated string oneofs = 3; // The list of oneofs declared in this Type // The proto options. repeated Option options = 4; - // The source context. SourceContext source_context = 5; + // The source syntax. + Syntax syntax = 6; } // Field represents a single field of a message type. @@ -65,125 +62,99 @@ message Field { // Kind represents a basic field type. enum Kind { // Field type unknown. - TYPE_UNKNOWN = 0; - + TYPE_UNKNOWN = 0; // Field type double. - TYPE_DOUBLE = 1; - + TYPE_DOUBLE = 1; // Field type float. - TYPE_FLOAT = 2; - + TYPE_FLOAT = 2; // Field type int64. - TYPE_INT64 = 3; - + TYPE_INT64 = 3; // Field type uint64. - TYPE_UINT64 = 4; - + TYPE_UINT64 = 4; // Field type int32. - TYPE_INT32 = 5; - + TYPE_INT32 = 5; // Field type fixed64. - TYPE_FIXED64 = 6; - + TYPE_FIXED64 = 6; // Field type fixed32. - TYPE_FIXED32 = 7; - + TYPE_FIXED32 = 7; // Field type bool. - TYPE_BOOL = 8; - + TYPE_BOOL = 8; // Field type string. - TYPE_STRING = 9; - + TYPE_STRING = 9; + // Field type group (deprecated proto2 type) + TYPE_GROUP = 10; // Field type message. - TYPE_MESSAGE = 11; - + TYPE_MESSAGE = 11; // Field type bytes. - TYPE_BYTES = 12; - + TYPE_BYTES = 12; // Field type uint32. - TYPE_UINT32 = 13; - + TYPE_UINT32 = 13; // Field type enum. - TYPE_ENUM = 14; - + TYPE_ENUM = 14; // Field type sfixed32. - TYPE_SFIXED32 = 15; - + TYPE_SFIXED32 = 15; // Field type sfixed64. - TYPE_SFIXED64 = 16; - + TYPE_SFIXED64 = 16; // Field type sint32. - TYPE_SINT32 = 17; - + TYPE_SINT32 = 17; // Field type sint64. - TYPE_SINT64 = 18; - } + TYPE_SINT64 = 18; + }; // Cardinality represents whether a field is optional, required, or // repeated. enum Cardinality { // The field cardinality is unknown. Typically an error condition. CARDINALITY_UNKNOWN = 0; - // For optional fields. CARDINALITY_OPTIONAL = 1; - // For required fields. Not used for proto3. CARDINALITY_REQUIRED = 2; - // For repeated fields. CARDINALITY_REPEATED = 3; - } + }; // The field kind. Kind kind = 1; - // The field cardinality, i.e. optional/required/repeated. Cardinality cardinality = 2; - // The proto field number. int32 number = 3; - // The field name. string name = 4; - // The type URL (without the scheme) when the type is MESSAGE or ENUM, // such as `type.googleapis.com/google.protobuf.Empty`. string type_url = 6; - // Index in Type.oneofs. Starts at 1. Zero means no oneof mapping. int32 oneof_index = 7; - // Whether to use alternative packed wire representation. bool packed = 8; - // The proto options. repeated Option options = 9; + // The JSON name for this field. + string json_name = 10; } // Enum type definition. message Enum { // Enum type name. string name = 1; - // Enum value definitions. repeated EnumValue enumvalue = 2; - // Proto options for the enum type. repeated Option options = 3; - // The source context. SourceContext source_context = 4; + // The source syntax. + Syntax syntax = 5; } // Enum value definition. message EnumValue { // Enum value name. string name = 1; - // Enum value number. int32 number = 2; - // Proto options for the enum value. repeated Option options = 3; } @@ -192,7 +163,14 @@ message EnumValue { message Option { // Proto option name. string name = 1; - // Proto option value. Any value = 2; } + +// Syntax specifies the syntax in which a service element was defined. +enum Syntax { + // Syntax "proto2" + SYNTAX_PROTO2 = 0; + // Syntax "proto3" + SYNTAX_PROTO3 = 1; +} diff --git a/src/google/protobuf/unittest_mset.proto b/src/google/protobuf/unittest_mset.proto index 3aa31fa9..49d9adad 100644 --- a/src/google/protobuf/unittest_mset.proto +++ b/src/google/protobuf/unittest_mset.proto @@ -32,33 +32,31 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. // -// This file contains messages for testing message_set_wire_format. +// This file is similar to unittest_mset_wire_format.proto, but does not +// have a TestMessageSet, so it can be downgraded to proto1. syntax = "proto2"; + +import "google/protobuf/unittest_mset_wire_format.proto"; + package protobuf_unittest; option cc_enable_arenas = true; option optimize_for = SPEED; -// A message with message_set_wire_format. -message TestMessageSet { - option message_set_wire_format = true; - extensions 4 to max; -} - message TestMessageSetContainer { - optional TestMessageSet message_set = 1; + optional proto2_wireformat_unittest.TestMessageSet message_set = 1; } message TestMessageSetExtension1 { - extend TestMessageSet { + extend proto2_wireformat_unittest.TestMessageSet { optional TestMessageSetExtension1 message_set_extension = 1545008; } optional int32 i = 15; } message TestMessageSetExtension2 { - extend TestMessageSet { + extend proto2_wireformat_unittest.TestMessageSet { optional TestMessageSetExtension2 message_set_extension = 1547769; } optional string str = 25; @@ -82,4 +80,3 @@ message RawMessageSet { required bytes message = 3; } } - diff --git a/src/google/protobuf/unittest_mset_wire_format.proto b/src/google/protobuf/unittest_mset_wire_format.proto new file mode 100644 index 00000000..04e4352e --- /dev/null +++ b/src/google/protobuf/unittest_mset_wire_format.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: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// This file contains messages for testing message_set_wire_format. + +syntax = "proto2"; +package proto2_wireformat_unittest; + +option cc_enable_arenas = true; +option optimize_for = SPEED; +option csharp_namespace = "Google.ProtocolBuffers.TestProtos"; + +// A message with message_set_wire_format. +message TestMessageSet { + option message_set_wire_format = true; + extensions 4 to max; +} + +message TestMessageSetWireFormatContainer { + optional TestMessageSet message_set = 1; +} diff --git a/src/google/protobuf/unittest_no_arena_lite.proto b/src/google/protobuf/unittest_no_arena_lite.proto new file mode 100644 index 00000000..34c7b7ce --- /dev/null +++ b/src/google/protobuf/unittest_no_arena_lite.proto @@ -0,0 +1,42 @@ +// 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 optimize_for = LITE_RUNTIME; + +// 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; + +message ForeignMessageLite { + optional int32 c = 1; +} diff --git a/src/google/protobuf/unknown_enum_impl.h b/src/google/protobuf/unknown_enum_impl.h index 39c10cbc..7c68ad6c 100644 --- a/src/google/protobuf/unknown_enum_impl.h +++ b/src/google/protobuf/unknown_enum_impl.h @@ -34,7 +34,6 @@ #include <stdlib.h> #include <google/protobuf/stubs/common.h> -#include "net/proto/tagmapper.h" #include <google/protobuf/bridge/compatibility_mode_support.h> namespace google { @@ -59,10 +58,10 @@ namespace util { // 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); + int32* unknown_value = NULL); // Same as above, but returns all unknown enums. bool GetRepeatedEnumUnknowns(const Message& message, int32 field_number, - vector<int32>* unknown_values = nullptr); + vector<int32>* unknown_values = NULL); // 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. @@ -75,7 +74,7 @@ bool GetRepeatedEnumUnknownsProto1(const Message& message, int32 field_number, // or proto2. template <typename T> bool HasUnknownEnum_Template(const T& message, int32 field_number, - int32* unknown_value = nullptr) { + int32* unknown_value = NULL) { if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value || !internal::is_base_of<ProtocolMessage, T>::value) { return HasUnknownEnum(message, field_number, unknown_value); @@ -88,7 +87,7 @@ bool HasUnknownEnum_Template(const T& message, int32 field_number, template <typename T> bool GetRepeatedEnumUnknowns_Template( const T& message, int32 field_number, - vector<int32>* unknown_values = nullptr) { + vector<int32>* unknown_values = NULL) { if (internal::is_base_of<bridge::internal::Proto1CompatibleMessage, T>::value || !internal::is_base_of<ProtocolMessage, T>::value) { return GetRepeatedEnumUnknowns(message, field_number, unknown_values); diff --git a/src/google/protobuf/unknown_enum_test.proto b/src/google/protobuf/unknown_enum_test.proto index 0ea1ede3..3c549cc7 100644 --- a/src/google/protobuf/unknown_enum_test.proto +++ b/src/google/protobuf/unknown_enum_test.proto @@ -36,6 +36,8 @@ syntax = "proto2"; package google.protobuf.util; +option csharp_namespace = "Google.ProtocolBuffers.TestProtos"; + message DownRevision { enum Enum { DEFAULT_VALUE = 2; diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 93f0f206..d4e383da 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -34,6 +34,7 @@ #include <google/protobuf/unknown_field_set.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream.h> diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 6781cd0f..612a942a 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -42,6 +42,7 @@ #include <string> #include <vector> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc index 9b02f0b0..5de72630 100644 --- a/src/google/protobuf/unknown_field_set_unittest.cc +++ b/src/google/protobuf/unknown_field_set_unittest.cc @@ -43,7 +43,10 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/test_util.h> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> +#include <google/protobuf/stubs/mutex.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> #include <google/protobuf/stubs/stl_util.h> diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc index 748c7d11..845839ac 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -34,8 +34,8 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/descriptor.h> -#include <gtest/gtest.h> #include <google/protobuf/stubs/mathutil.h> +#include <gtest/gtest.h> namespace google { namespace protobuf { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc new file mode 100644 index 00000000..82034bd4 --- /dev/null +++ b/src/google/protobuf/util/field_mask_util.cc @@ -0,0 +1,418 @@ +// 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/field_mask_util.h> + +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/map_util.h> + +namespace google { +namespace protobuf { +namespace util { + +using google::protobuf::FieldMask; + +string FieldMaskUtil::ToString(const FieldMask& mask) { + return Join(mask.paths(), ","); +} + +void FieldMaskUtil::FromString(const string& str, FieldMask* out) { + out->Clear(); + vector<string> paths = Split(str, ","); + for (int i = 0; i < paths.size(); ++i) { + if (paths[i].empty()) continue; + out->add_paths(paths[i]); + } +} + +bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, + const string& path) { + vector<string> parts = Split(path, "."); + for (int i = 0; i < parts.size(); ++i) { + const string& field_name = parts[i]; + if (descriptor == NULL) { + return false; + } + const FieldDescriptor* field = descriptor->FindFieldByName(field_name); + if (field == NULL) { + return false; + } + if (!field->is_repeated() && + field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + descriptor = field->message_type(); + } else { + descriptor = NULL; + } + } + return true; +} + +void FieldMaskUtil::InternalGetFieldMaskForAllFields( + const Descriptor* descriptor, FieldMask* out) { + for (int i = 0; i < descriptor->field_count(); ++i) { + out->add_paths(descriptor->field(i)->name()); + } +} + +namespace { +// A FieldMaskTree represents a FieldMask in a tree structure. For example, +// given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be: +// +// [root] -+- foo -+- bar +// | | +// | +- baz +// | +// +- bar --- baz +// +// In the tree, each leaf node represents a field path. +class FieldMaskTree { + public: + FieldMaskTree(); + ~FieldMaskTree(); + + void MergeFromFieldMask(const FieldMask& mask); + void MergeToFieldMask(FieldMask* mask); + + // Add a field path into the tree. In a FieldMask, each field path matches + // the specified field and also all its sub-fields. If the field path to + // add is a sub-path of an existing field path in the tree (i.e., a leaf + // node), it means the tree already matchesthe the given path so nothing will + // be added to the tree. If the path matches an existing non-leaf node in the + // tree, that non-leaf node will be turned into a leaf node with all its + // children removed because the path matches all the node's children. + void AddPath(const string& path); + + // Calculate the intersection part of a field path with this tree and add + // the intersection field path into out. + void IntersectPath(const string& path, FieldMaskTree* out); + + // Merge all fields specified by this tree from one message to another. + void MergeMessage(const Message& source, + const FieldMaskUtil::MergeOptions& options, + Message* destination) { + // Do nothing if the tree is empty. + if (root_.children.empty()) { + return; + } + MergeMessage(&root_, source, options, destination); + } + + private: + struct Node { + Node() {} + + ~Node() { ClearChildren(); } + + void ClearChildren() { + for (map<string, Node*>::iterator it = children.begin(); + it != children.end(); ++it) { + delete it->second; + } + children.clear(); + } + + map<string, Node*> children; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node); + }; + + // Merge a sub-tree to mask. This method adds the field paths represented + // by all leaf nodes descended from "node" to mask. + void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out); + + // Merge all leaf nodes of a sub-tree to another tree. + void MergeLeafNodesToTree(const string& prefix, const Node* node, + FieldMaskTree* out); + + // Merge all fields specified by a sub-tree from one message to another. + void MergeMessage(const Node* node, const Message& source, + const FieldMaskUtil::MergeOptions& options, + Message* destination); + + Node root_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree); +}; + +FieldMaskTree::FieldMaskTree() {} + +FieldMaskTree::~FieldMaskTree() {} + +void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) { + for (int i = 0; i < mask.paths_size(); ++i) { + AddPath(mask.paths(i)); + } +} + +void FieldMaskTree::MergeToFieldMask(FieldMask* mask) { + MergeToFieldMask("", &root_, mask); +} + +void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node, + FieldMask* out) { + if (node->children.empty()) { + if (prefix.empty()) { + // This is the root node. + return; + } + out->add_paths(prefix); + return; + } + for (map<string, Node*>::const_iterator it = node->children.begin(); + it != node->children.end(); ++it) { + string current_path = prefix.empty() ? it->first : prefix + "." + it->first; + MergeToFieldMask(current_path, it->second, out); + } +} + +void FieldMaskTree::AddPath(const string& path) { + vector<string> parts = Split(path, "."); + if (parts.empty()) { + return; + } + bool new_branch = false; + Node* node = &root_; + for (int i = 0; i < parts.size(); ++i) { + if (!new_branch && node != &root_ && node->children.empty()) { + // Path matches an existing leaf node. This means the path is already + // coverred by this tree (for example, adding "foo.bar.baz" to a tree + // which already contains "foo.bar"). + return; + } + const string& node_name = parts[i]; + Node*& child = node->children[node_name]; + if (child == NULL) { + new_branch = true; + child = new Node(); + } + node = child; + } + if (!node->children.empty()) { + node->ClearChildren(); + } +} + +void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) { + vector<string> parts = Split(path, "."); + if (parts.empty()) { + return; + } + const Node* node = &root_; + for (int i = 0; i < parts.size(); ++i) { + if (node->children.empty()) { + if (node != &root_) { + out->AddPath(path); + } + return; + } + const string& node_name = parts[i]; + const Node* result = FindPtrOrNull(node->children, node_name); + if (result == NULL) { + // No intersection found. + return; + } + node = result; + } + // Now we found a matching node with the given path. Add all leaf nodes + // to out. + MergeLeafNodesToTree(path, node, out); +} + +void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node, + FieldMaskTree* out) { + if (node->children.empty()) { + out->AddPath(prefix); + } + for (map<string, Node*>::const_iterator it = node->children.begin(); + it != node->children.end(); ++it) { + string current_path = prefix.empty() ? it->first : prefix + "." + it->first; + MergeLeafNodesToTree(current_path, it->second, out); + } +} + +void FieldMaskTree::MergeMessage(const Node* node, const Message& source, + const FieldMaskUtil::MergeOptions& options, + Message* destination) { + GOOGLE_DCHECK(!node->children.empty()); + const Reflection* source_reflection = source.GetReflection(); + const Reflection* destination_reflection = destination->GetReflection(); + const Descriptor* descriptor = source.GetDescriptor(); + for (map<string, Node*>::const_iterator it = node->children.begin(); + it != node->children.end(); ++it) { + const string& field_name = it->first; + const Node* child = it->second; + const FieldDescriptor* field = descriptor->FindFieldByName(field_name); + if (field == NULL) { + GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message " + << descriptor->full_name(); + continue; + } + if (!child->children.empty()) { + // Sub-paths are only allowed for singular message fields. + if (field->is_repeated() || + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message " + << descriptor->full_name() + << " is not a singular message field and cannot " + << "have sub-fields."; + continue; + } + MergeMessage(child, source_reflection->GetMessage(source, field), options, + destination_reflection->MutableMessage(destination, field)); + continue; + } + if (!field->is_repeated()) { + switch (field->cpp_type()) { +#define COPY_VALUE(TYPE, Name) \ + case FieldDescriptor::CPPTYPE_##TYPE: { \ + destination_reflection->Set##Name( \ + destination, field, source_reflection->Get##Name(source, field)); \ + break; \ + } + COPY_VALUE(BOOL, Bool) + COPY_VALUE(INT32, Int32) + COPY_VALUE(INT64, Int64) + COPY_VALUE(UINT32, UInt32) + COPY_VALUE(UINT64, UInt64) + COPY_VALUE(FLOAT, Float) + COPY_VALUE(DOUBLE, Double) + COPY_VALUE(ENUM, Enum) + COPY_VALUE(STRING, String) +#undef COPY_VALUE + case FieldDescriptor::CPPTYPE_MESSAGE: { + if (options.replace_message_fields()) { + destination_reflection->ClearField(destination, field); + } + if (source_reflection->HasField(source, field)) { + destination_reflection->MutableMessage(destination, field) + ->MergeFrom(source_reflection->GetMessage(source, field)); + } + break; + } + } + } else { + if (options.replace_repeated_fields()) { + destination_reflection->ClearField(destination, field); + } + switch (field->cpp_type()) { +#define COPY_REPEATED_VALUE(TYPE, Name) \ + case FieldDescriptor::CPPTYPE_##TYPE: { \ + int size = source_reflection->FieldSize(source, field); \ + for (int i = 0; i < size; ++i) { \ + destination_reflection->Add##Name( \ + destination, field, \ + source_reflection->GetRepeated##Name(source, field, i)); \ + } \ + break; \ + } + COPY_REPEATED_VALUE(BOOL, Bool) + COPY_REPEATED_VALUE(INT32, Int32) + COPY_REPEATED_VALUE(INT64, Int64) + COPY_REPEATED_VALUE(UINT32, UInt32) + COPY_REPEATED_VALUE(UINT64, UInt64) + COPY_REPEATED_VALUE(FLOAT, Float) + COPY_REPEATED_VALUE(DOUBLE, Double) + COPY_REPEATED_VALUE(ENUM, Enum) + COPY_REPEATED_VALUE(STRING, String) +#undef COPY_REPEATED_VALUE + case FieldDescriptor::CPPTYPE_MESSAGE: { + int size = source_reflection->FieldSize(source, field); + for (int i = 0; i < size; ++i) { + destination_reflection->AddMessage(destination, field) + ->MergeFrom( + source_reflection->GetRepeatedMessage(source, field, i)); + } + break; + } + } + } + } +} + +} // namespace + +void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) { + FieldMaskTree tree; + tree.MergeFromFieldMask(mask); + out->Clear(); + tree.MergeToFieldMask(out); +} + +void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2, + FieldMask* out) { + FieldMaskTree tree; + tree.MergeFromFieldMask(mask1); + tree.MergeFromFieldMask(mask2); + out->Clear(); + tree.MergeToFieldMask(out); +} + +void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2, + FieldMask* out) { + FieldMaskTree tree, intersection; + tree.MergeFromFieldMask(mask1); + for (int i = 0; i < mask2.paths_size(); ++i) { + tree.IntersectPath(mask2.paths(i), &intersection); + } + out->Clear(); + intersection.MergeToFieldMask(out); +} + +bool FieldMaskUtil::IsPathInFieldMask(const string& path, + const FieldMask& mask) { + for (int i = 0; i < mask.paths_size(); ++i) { + const string& mask_path = mask.paths(i); + if (path == mask_path) { + return true; + } else if (mask_path.length() < path.length()) { + // Also check whether mask.paths(i) is a prefix of path. + if (path.compare(0, mask_path.length() + 1, mask_path + ".") == 0) { + return true; + } + } + } + return false; +} + +void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask, + const MergeOptions& options, + Message* destination) { + GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor()); + // Build a FieldMaskTree and walk through the tree to merge all specified + // fields. + FieldMaskTree tree; + tree.MergeFromFieldMask(mask); + tree.MergeMessage(source, options, destination); +} + +} // namespace util +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h new file mode 100644 index 00000000..c99c34f8 --- /dev/null +++ b/src/google/protobuf/util/field_mask_util.h @@ -0,0 +1,146 @@ +// 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_FIELD_MASK_UTIL_H__ +#define GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__ + +#include <string> + +#include <google/protobuf/descriptor.h> +#include <google/protobuf/field_mask.pb.h> + +namespace google { +namespace protobuf { +namespace util { + +class LIBPROTOBUF_EXPORT FieldMaskUtil { + typedef google::protobuf::FieldMask FieldMask; + + public: + // Converts FieldMask to/from string, formatted according to proto3 JSON + // spec for FieldMask (e.g., "foo,bar,baz.quz"). + static string ToString(const FieldMask& mask); + static void FromString(const string& str, FieldMask* out); + + // Checks whether the given path is valid for type T. + template <typename T> + static bool IsValidPath(const string& path) { + return InternalIsValidPath(T::descriptor(), path); + } + + // Checks whether the given FieldMask is valid for type T. + template <typename T> + static bool IsValidFieldMask(const FieldMask& mask) { + for (int i = 0; i < mask.paths_size(); ++i) { + if (!InternalIsValidPath(T::descriptor(), mask.paths(i))) return false; + } + return true; + } + + // Adds a path to FieldMask after checking whether the given path is valid. + // This method check-fails if the path is not a valid path for type T. + template <typename T> + static void AddPathToFieldMask(const string& path, FieldMask* mask) { + GOOGLE_CHECK(IsValidPath<T>(path)); + mask->add_paths(path); + } + + // Creates a FieldMask with all fields of type T. This FieldMask only + // contains fields of T but not any sub-message fields. + template <typename T> + static void GetFieldMaskForAllFields(FieldMask* out) { + InternalGetFieldMaskForAllFields(T::descriptor(), out); + } + + // Converts a FieldMask to the canonical form. It will: + // 1. Remove paths that are covered by another path. For example, + // "foo.bar" is covered by "foo" and will be removed if "foo" + // is also in the FieldMask. + // 2. Sort all paths in alphabetical order. + static void ToCanonicalForm(const FieldMask& mask, FieldMask* out); + + // Creates an union of two FieldMasks. + static void Union(const FieldMask& mask1, const FieldMask& mask2, + FieldMask* out); + + // Creates an intersection of two FieldMasks. + static void Intersect(const FieldMask& mask1, const FieldMask& mask2, + FieldMask* out); + + // Returns true if path is covered by the given FieldMask. Note that path + // "foo.bar" covers all paths like "foo.bar.baz", "foo.bar.quz.x", etc. + static bool IsPathInFieldMask(const string& path, const FieldMask& mask); + + class MergeOptions; + // Merges fields specified in a FieldMask into another message. + static void MergeMessageTo(const Message& source, const FieldMask& mask, + const MergeOptions& options, Message* destination); + + private: + static bool InternalIsValidPath(const Descriptor* descriptor, + const string& path); + + static void InternalGetFieldMaskForAllFields(const Descriptor* descriptor, + FieldMask* out); +}; + +class LIBPROTOBUF_EXPORT FieldMaskUtil::MergeOptions { + public: + MergeOptions() + : replace_message_fields_(false), replace_repeated_fields_(false) {} + // When merging message fields, the default behavior is to merge the + // content of two message fields together. If you instead want to use + // the field from the source message to replace the corresponding field + // in the destination message, set this flag to true. When this flag is set, + // specified submessage fields that are missing in source will be cleared in + // destination. + void set_replace_message_fields(bool value) { + replace_message_fields_ = value; + } + bool replace_message_fields() const { return replace_message_fields_; } + // The default merging behavior will append entries from the source + // repeated field to the destination repeated field. If you only want + // to keep the entries from the source repeated field, set this flag + // to true. + void set_replace_repeated_fields(bool value) { + replace_repeated_fields_ = value; + } + bool replace_repeated_fields() const { return replace_repeated_fields_; } + + private: + bool replace_message_fields_; + bool replace_repeated_fields_; +}; + +} // namespace util +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_FIELD_MASK_UTIL_H__ diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc new file mode 100644 index 00000000..a9523250 --- /dev/null +++ b/src/google/protobuf/util/field_mask_util_test.cc @@ -0,0 +1,395 @@ +// 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/field_mask_util.h> + +#include <google/protobuf/field_mask.pb.h> +#include <google/protobuf/unittest.pb.h> +#include <google/protobuf/test_util.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace util { +namespace { + +using protobuf_unittest::TestAllTypes; +using protobuf_unittest::NestedTestAllTypes; +using google::protobuf::FieldMask; + +TEST(FieldMaskUtilTest, StringFormat) { + FieldMask mask; + EXPECT_EQ("", FieldMaskUtil::ToString(mask)); + mask.add_paths("foo"); + EXPECT_EQ("foo", FieldMaskUtil::ToString(mask)); + mask.add_paths("bar"); + EXPECT_EQ("foo,bar", FieldMaskUtil::ToString(mask)); + + FieldMaskUtil::FromString("", &mask); + EXPECT_EQ(0, mask.paths_size()); + FieldMaskUtil::FromString("foo", &mask); + EXPECT_EQ(1, mask.paths_size()); + EXPECT_EQ("foo", mask.paths(0)); + FieldMaskUtil::FromString("foo,bar", &mask); + EXPECT_EQ(2, mask.paths_size()); + EXPECT_EQ("foo", mask.paths(0)); + EXPECT_EQ("bar", mask.paths(1)); +} + +TEST(FieldMaskUtilTest, TestIsVaildPath) { + EXPECT_TRUE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_int32")); + EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nonexist")); + EXPECT_TRUE( + FieldMaskUtil::IsValidPath<TestAllTypes>("optional_nested_message.bb")); + EXPECT_FALSE(FieldMaskUtil::IsValidPath<TestAllTypes>( + "optional_nested_message.nonexist")); + // FieldMask cannot be used to specify sub-fields of a repeated message. + EXPECT_FALSE( + FieldMaskUtil::IsValidPath<TestAllTypes>("repeated_nested_message.bb")); +} + +TEST(FieldMaskUtilTest, TestIsValidFieldMask) { + FieldMask mask; + FieldMaskUtil::FromString("optional_int32,optional_nested_message.bb", &mask); + EXPECT_TRUE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask)); + + FieldMaskUtil::FromString( + "optional_int32,optional_nested_message.bb,optional_nonexist", &mask); + EXPECT_FALSE(FieldMaskUtil::IsValidFieldMask<TestAllTypes>(mask)); +} + +TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) { + FieldMask mask; + FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes::NestedMessage>(&mask); + EXPECT_EQ(1, mask.paths_size()); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); + + FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(&mask); + EXPECT_EQ(76, mask.paths_size()); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sint64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_fixed64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_sfixed64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_float", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_double", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bool", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_string", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_bytes", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("optional_nested_message", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("optional_foreign_message", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("optional_import_message", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_nested_enum", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_foreign_enum", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_import_enum", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_int64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_uint64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sint64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_fixed64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed32", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_sfixed64", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_float", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_double", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bool", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_string", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_bytes", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("repeated_nested_message", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("repeated_foreign_message", mask)); + EXPECT_TRUE( + FieldMaskUtil::IsPathInFieldMask("repeated_import_message", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_nested_enum", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_foreign_enum", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("repeated_import_enum", mask)); +} + +TEST(FieldMaskUtilTest, TestToCanonicalForm) { + FieldMask in, out; + // Paths will be sorted. + FieldMaskUtil::FromString("baz.quz,bar,foo", &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("bar,baz.quz,foo", FieldMaskUtil::ToString(out)); + // Duplicated paths will be removed. + FieldMaskUtil::FromString("foo,bar,foo", &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("bar,foo", FieldMaskUtil::ToString(out)); + // Sub-paths of other paths will be removed. + FieldMaskUtil::FromString("foo.b1,bar.b1,foo.b2,bar", &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("bar,foo.b1,foo.b2", FieldMaskUtil::ToString(out)); + + // Test more deeply nested cases. + FieldMaskUtil::FromString( + "foo.bar.baz1," + "foo.bar.baz2.quz," + "foo.bar.baz2", + &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out)); + FieldMaskUtil::FromString( + "foo.bar.baz1," + "foo.bar.baz2," + "foo.bar.baz2.quz", + &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("foo.bar.baz1,foo.bar.baz2", FieldMaskUtil::ToString(out)); + FieldMaskUtil::FromString( + "foo.bar.baz1," + "foo.bar.baz2," + "foo.bar.baz2.quz," + "foo.bar", + &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("foo.bar", FieldMaskUtil::ToString(out)); + FieldMaskUtil::FromString( + "foo.bar.baz1," + "foo.bar.baz2," + "foo.bar.baz2.quz," + "foo", + &in); + FieldMaskUtil::ToCanonicalForm(in, &out); + EXPECT_EQ("foo", FieldMaskUtil::ToString(out)); +} + +TEST(FieldMaskUtilTest, TestUnion) { + FieldMask mask1, mask2, out; + // Test cases without overlapping. + FieldMaskUtil::FromString("foo,baz", &mask1); + FieldMaskUtil::FromString("bar,quz", &mask2); + FieldMaskUtil::Union(mask1, mask2, &out); + EXPECT_EQ("bar,baz,foo,quz", FieldMaskUtil::ToString(out)); + // Overlap with duplicated paths. + FieldMaskUtil::FromString("foo,baz.bb", &mask1); + FieldMaskUtil::FromString("baz.bb,quz", &mask2); + FieldMaskUtil::Union(mask1, mask2, &out); + EXPECT_EQ("baz.bb,foo,quz", FieldMaskUtil::ToString(out)); + // Overlap with paths covering some other paths. + FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1); + FieldMaskUtil::FromString("foo.bar,bar", &mask2); + FieldMaskUtil::Union(mask1, mask2, &out); + EXPECT_EQ("bar,foo.bar,quz", FieldMaskUtil::ToString(out)); +} + +TEST(FieldMaskUtilTest, TestIntersect) { + FieldMask mask1, mask2, out; + // Test cases without overlapping. + FieldMaskUtil::FromString("foo,baz", &mask1); + FieldMaskUtil::FromString("bar,quz", &mask2); + FieldMaskUtil::Intersect(mask1, mask2, &out); + EXPECT_EQ("", FieldMaskUtil::ToString(out)); + // Overlap with duplicated paths. + FieldMaskUtil::FromString("foo,baz.bb", &mask1); + FieldMaskUtil::FromString("baz.bb,quz", &mask2); + FieldMaskUtil::Intersect(mask1, mask2, &out); + EXPECT_EQ("baz.bb", FieldMaskUtil::ToString(out)); + // Overlap with paths covering some other paths. + FieldMaskUtil::FromString("foo.bar.baz,quz", &mask1); + FieldMaskUtil::FromString("foo.bar,bar", &mask2); + FieldMaskUtil::Intersect(mask1, mask2, &out); + EXPECT_EQ("foo.bar.baz", FieldMaskUtil::ToString(out)); +} + +TEST(FieldMaskUtilTest, TestIspathInFieldMask) { + FieldMask mask; + FieldMaskUtil::FromString("foo.bar", &mask); + EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("", mask)); + EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar", mask)); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("foo.bar.baz", mask)); + EXPECT_FALSE(FieldMaskUtil::IsPathInFieldMask("foo.bar0.baz", mask)); +} + +TEST(FieldMaskUtilTest, MergeMessage) { + TestAllTypes src, dst; + TestUtil::SetAllFields(&src); + FieldMaskUtil::MergeOptions options; + +#define TEST_MERGE_ONE_PRIMITIVE_FIELD(field_name) \ + { \ + TestAllTypes tmp; \ + tmp.set_##field_name(src.field_name()); \ + FieldMask mask; \ + mask.add_paths(#field_name); \ + dst.Clear(); \ + FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \ + EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \ + } + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int32) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int64) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint32) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_uint64) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint32) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sint64) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed32) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_fixed64) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed32) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_sfixed64) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_float) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_double) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bool) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_string) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_bytes) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_nested_enum) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_foreign_enum) + TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_import_enum) +#undef TEST_MERGE_ONE_PRIMITIVE_FIELD + +#define TEST_MERGE_ONE_FIELD(field_name) \ + { \ + TestAllTypes tmp; \ + *tmp.mutable_##field_name() = src.field_name(); \ + FieldMask mask; \ + mask.add_paths(#field_name); \ + dst.Clear(); \ + FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \ + EXPECT_EQ(tmp.DebugString(), dst.DebugString()); \ + } + TEST_MERGE_ONE_FIELD(optional_nested_message) + TEST_MERGE_ONE_FIELD(optional_foreign_message) + TEST_MERGE_ONE_FIELD(optional_import_message) + + TEST_MERGE_ONE_FIELD(repeated_int32) + TEST_MERGE_ONE_FIELD(repeated_int64) + TEST_MERGE_ONE_FIELD(repeated_uint32) + TEST_MERGE_ONE_FIELD(repeated_uint64) + TEST_MERGE_ONE_FIELD(repeated_sint32) + TEST_MERGE_ONE_FIELD(repeated_sint64) + TEST_MERGE_ONE_FIELD(repeated_fixed32) + TEST_MERGE_ONE_FIELD(repeated_fixed64) + TEST_MERGE_ONE_FIELD(repeated_sfixed32) + TEST_MERGE_ONE_FIELD(repeated_sfixed64) + TEST_MERGE_ONE_FIELD(repeated_float) + TEST_MERGE_ONE_FIELD(repeated_double) + TEST_MERGE_ONE_FIELD(repeated_bool) + TEST_MERGE_ONE_FIELD(repeated_string) + TEST_MERGE_ONE_FIELD(repeated_bytes) + TEST_MERGE_ONE_FIELD(repeated_nested_message) + TEST_MERGE_ONE_FIELD(repeated_foreign_message) + TEST_MERGE_ONE_FIELD(repeated_import_message) + TEST_MERGE_ONE_FIELD(repeated_nested_enum) + TEST_MERGE_ONE_FIELD(repeated_foreign_enum) + TEST_MERGE_ONE_FIELD(repeated_import_enum) +#undef TEST_MERGE_ONE_FIELD + + // Test merge nested fields. + NestedTestAllTypes nested_src, nested_dst; + nested_src.mutable_child()->mutable_payload()->set_optional_int32(1234); + nested_src.mutable_child() + ->mutable_child() + ->mutable_payload() + ->set_optional_int32(5678); + FieldMask mask; + FieldMaskUtil::FromString("child.payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(0, nested_dst.child().child().payload().optional_int32()); + + FieldMaskUtil::FromString("child.child.payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); + + nested_dst.Clear(); + FieldMaskUtil::FromString("child.child.payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(0, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); + + nested_dst.Clear(); + FieldMaskUtil::FromString("child", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(5678, nested_dst.child().child().payload().optional_int32()); + + // Test MergeOptions. + + nested_dst.Clear(); + nested_dst.mutable_child()->mutable_payload()->set_optional_int64(4321); + // Message fields will be merged by default. + FieldMaskUtil::FromString("child.payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(4321, nested_dst.child().payload().optional_int64()); + // Change the behavior to replace message fields. + options.set_replace_message_fields(true); + FieldMaskUtil::FromString("child.payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_EQ(1234, nested_dst.child().payload().optional_int32()); + EXPECT_EQ(0, nested_dst.child().payload().optional_int64()); + + // By default, fields missing in source are not cleared in destination. + options.set_replace_message_fields(false); + nested_dst.mutable_payload(); + EXPECT_TRUE(nested_dst.has_payload()); + FieldMaskUtil::FromString("payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_TRUE(nested_dst.has_payload()); + // But they are cleared when replacing message fields. + options.set_replace_message_fields(true); + nested_dst.Clear(); + nested_dst.mutable_payload(); + FieldMaskUtil::FromString("payload", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + EXPECT_FALSE(nested_dst.has_payload()); + + nested_src.mutable_payload()->add_repeated_int32(1234); + nested_dst.mutable_payload()->add_repeated_int32(5678); + // Repeated fields will be appended by default. + FieldMaskUtil::FromString("payload.repeated_int32", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + ASSERT_EQ(2, nested_dst.payload().repeated_int32_size()); + EXPECT_EQ(5678, nested_dst.payload().repeated_int32(0)); + EXPECT_EQ(1234, nested_dst.payload().repeated_int32(1)); + // Change the behavior to replace repeated fields. + options.set_replace_repeated_fields(true); + FieldMaskUtil::FromString("payload.repeated_int32", &mask); + FieldMaskUtil::MergeMessageTo(nested_src, mask, options, &nested_dst); + ASSERT_EQ(1, nested_dst.payload().repeated_int32_size()); + EXPECT_EQ(1234, nested_dst.payload().repeated_int32(0)); +} + + +} // namespace +} // namespace util +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index 944fb2e3..ea360798 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -79,7 +79,9 @@ StatusOr<To> NumberConvertAndCheck(From before) { // For conversion between double and float only. template <typename To, typename From> StatusOr<To> FloatingPointConvertAndCheck(From before) { - if (MathLimits<From>::IsNaN(before)) return std::numeric_limits<To>::quiet_NaN(); + if (MathLimits<From>::IsNaN(before)) { + return std::numeric_limits<To>::quiet_NaN(); + } To after = static_cast<To>(before); if (MathUtil::AlmostEquals<To>(after, before)) { @@ -167,7 +169,7 @@ StatusOr<string> DataPiece::ToString() const { return str_.ToString(); case TYPE_BYTES: { string base64; - WebSafeBase64Escape(str_, &base64); + Base64Escape(str_, &base64); return base64; } default: diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h index 30947252..2ab3fa88 100644 --- a/src/google/protobuf/util/internal/datapiece.h +++ b/src/google/protobuf/util/internal/datapiece.h @@ -193,13 +193,13 @@ class LIBPROTOBUF_EXPORT DataPiece { // Stored piece of data. union { - const int32 i32_; - const int64 i64_; - const uint32 u32_; - const uint64 u64_; - const double double_; - const float float_; - const bool bool_; + int32 i32_; + int64 i64_; + uint32 u32_; + uint64 u64_; + double double_; + float float_; + bool bool_; StringPiecePod str_; }; }; diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index 267e2cd3..97b248ff 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -46,6 +46,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, ObjectWriter* ow) : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), + own_typeinfo_(true), type_(type), disable_normalize_(false), current_(NULL), @@ -56,6 +57,9 @@ DefaultValueObjectWriter::~DefaultValueObjectWriter() { for (int i = 0; i < string_values_.size(); ++i) { delete string_values_[i]; } + if (own_typeinfo_) { + delete typeinfo_; + } } DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(StringPiece name, @@ -197,33 +201,47 @@ void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) { if (disable_normalize_) { ow->DisableCaseNormalizationForNextKey(); } + if (kind_ == PRIMITIVE) { ObjectWriter::RenderDataPieceTo(data_, name_, ow); return; } - if (is_placeholder_) { - // If is_placeholder_ = true, we didn't see this node in the response, so - // skip output. + + // Render maps. Empty maps are rendered as "{}". + if (kind_ == MAP) { + ow->StartObject(name_); + WriteChildren(ow); + ow->EndObject(); return; } + + // Write out lists. If we didn't have any list in response, write out empty + // list. if (kind_ == LIST) { ow->StartList(name_); - } else { - ow->StartObject(name_); + WriteChildren(ow); + ow->EndList(); + return; } + + // If is_placeholder_ = true, we didn't see this node in the response, so + // skip output. + if (is_placeholder_) return; + + ow->StartObject(name_); + WriteChildren(ow); + ow->EndObject(); +} + +void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) { for (int i = 0; i < children_.size(); ++i) { Node* child = children_[i]; child->WriteTo(ow); } - if (kind_ == LIST) { - ow->EndList(); - } else { - ow->EndObject(); - } } const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( - const google::protobuf::Type& found_type, TypeInfo* typeinfo) { + const google::protobuf::Type& found_type, const TypeInfo* typeinfo) { // If this field is a map, we should use the type of its "Value" as // the type of the child node. for (int i = 0; i < found_type.fields_size(); ++i) { @@ -248,7 +266,8 @@ const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType( return NULL; } -void DefaultValueObjectWriter::Node::PopulateChildren(TypeInfo* typeinfo) { +void DefaultValueObjectWriter::Node::PopulateChildren( + const TypeInfo* typeinfo) { // Ignores well known types that don't require automatically populating their // primitive children. For type "Any", we only populate its children when the // "@type" field is set. @@ -310,15 +329,17 @@ void DefaultValueObjectWriter::Node::PopulateChildren(TypeInfo* typeinfo) { google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) { kind = LIST; } - // If the child field is of primitive type, sets its data to the default - // value of its type. + // If oneof_index() != 0, the child field is part of a "oneof", which means // the child field is optional and we shouldn't populate its default value. + if (field.oneof_index() != 0) continue; + + // If the child field is of primitive type, sets its data to the default + // value of its type. google::protobuf::scoped_ptr<Node> child( - new Node(field.name(), field_type, kind, - ((kind == PRIMITIVE && field.oneof_index() == 0) - ? CreateDefaultDataPieceForField(field) - : DataPiece::NullData()), + new Node(field.json_name(), field_type, kind, + kind == PRIMITIVE ? CreateDefaultDataPieceForField(field) + : DataPiece::NullData(), true)); new_children.push_back(child.release()); } @@ -338,7 +359,7 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { // have been added, populates its children. if (node != NULL && node->is_any() && node->type() != NULL && node->type()->name() != kAnyType && node->number_of_children() == 1) { - node->PopulateChildren(typeinfo_.get()); + node->PopulateChildren(typeinfo_); } } @@ -388,7 +409,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), false)); root_->set_disable_normalize(GetAndResetDisableNormalize()); - root_->PopulateChildren(typeinfo_.get()); + root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; } @@ -409,7 +430,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( child->set_is_placeholder(false); child->set_disable_normalize(GetAndResetDisableNormalize()); if (child->kind() == OBJECT && child->number_of_children() == 0) { - child->PopulateChildren(typeinfo_.get()); + child->PopulateChildren(typeinfo_); } stack_.push(current_); @@ -492,12 +513,11 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, // first value field is rendered before we populate the children, because // the "value" field of a Any message could be omitted. if (current_->number_of_children() > 1 && current_->type() != NULL) { - current_->PopulateChildren(typeinfo_.get()); + current_->PopulateChildren(typeinfo_); } } Node* child = current_->FindChild(name); if (child == NULL || child->kind() != PRIMITIVE) { - GOOGLE_LOG(WARNING) << "Cannot find primitive field '" << name << "'."; // No children are found, creates a new child. google::protobuf::scoped_ptr<Node> node( new Node(name.ToString(), NULL, PRIMITIVE, data, false)); diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 759ba91b..d4547601 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -129,7 +129,7 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Populates children of this Node based on its type. If there are already // children created, they will be merged to the result. Caller should pass // in TypeInfo for looking up types of the children. - void PopulateChildren(TypeInfo* typeinfo); + void PopulateChildren(const TypeInfo* typeinfo); // If this node is a leaf (has data), writes the current node to the // ObjectWriter; if not, then recursively writes the children to the @@ -165,7 +165,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Returns the Value Type of a map given the Type of the map entry and a // TypeInfo instance. const google::protobuf::Type* GetMapValueType( - const google::protobuf::Type& entry_type, TypeInfo* typeinfo); + const google::protobuf::Type& entry_type, const TypeInfo* typeinfo); + + // Calls WriteTo() on every child in children_. + void WriteChildren(ObjectWriter* ow); // The name of this node. string name_; @@ -210,7 +213,9 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. - google::protobuf::scoped_ptr<TypeInfo> typeinfo_; + const TypeInfo* typeinfo_; + // Whether the TypeInfo object is owned by this class. + bool own_typeinfo_; // google::protobuf::Type of the root message type. const google::protobuf::Type& type_; // Holds copies of strings passed to RenderString. diff --git a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc index 593c7105..237d0722 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter_test.cc @@ -73,15 +73,15 @@ INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, TEST_P(DefaultValueObjectWriterTest, Empty) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 0.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") - ->RenderBytes("bytes_value", "") + ->RenderDouble("doubleValue", 0.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") + ->RenderBytes("bytesValue", "") ->EndObject(); // Actual testing @@ -91,42 +91,42 @@ TEST_P(DefaultValueObjectWriterTest, Empty) { TEST_P(DefaultValueObjectWriterTest, NonDefaultDouble) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 1.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") + ->RenderDouble("doubleValue", 1.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") ->EndObject(); // Actual testing - testing_->StartObject("")->RenderDouble("double_value", 1.0)->EndObject(); + testing_->StartObject("")->RenderDouble("doubleValue", 1.0)->EndObject(); } TEST_P(DefaultValueObjectWriterTest, ShouldRetainUnknownField) { // Set expectation expects_.StartObject("") - ->RenderDouble("double_value", 1.0) - ->RenderFloat("float_value", 0.0) - ->RenderInt64("int64_value", 0) - ->RenderUint64("uint64_value", 0) - ->RenderInt32("int32_value", 0) - ->RenderUint32("uint32_value", 0) - ->RenderBool("bool_value", false) - ->RenderString("string_value", "") + ->RenderDouble("doubleValue", 1.0) + ->RenderFloat("floatValue", 0.0) + ->RenderInt64("int64Value", 0) + ->RenderUint64("uint64Value", 0) + ->RenderInt32("int32Value", 0) + ->RenderUint32("uint32Value", 0) + ->RenderBool("boolValue", false) + ->RenderString("stringValue", "") ->RenderString("unknown", "abc") - ->StartObject("unknown_object") + ->StartObject("unknownObject") ->RenderString("unknown", "def") ->EndObject() ->EndObject(); // Actual testing testing_->StartObject("") - ->RenderDouble("double_value", 1.0) + ->RenderDouble("doubleValue", 1.0) ->RenderString("unknown", "abc") - ->StartObject("unknown_object") + ->StartObject("unknownObject") ->RenderString("unknown", "def") ->EndObject() ->EndObject(); diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h index 9b907df5..2699684d 100644 --- a/src/google/protobuf/util/internal/error_listener.h +++ b/src/google/protobuf/util/internal/error_listener.h @@ -37,7 +37,9 @@ #endif #include <string> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/util/internal/location_tracker.h> #include <google/protobuf/stubs/stringpiece.h> diff --git a/src/google/protobuf/util/internal/field_mask_utility.cc b/src/google/protobuf/util/internal/field_mask_utility.cc index 92468959..f0e8fc88 100644 --- a/src/google/protobuf/util/internal/field_mask_utility.cc +++ b/src/google/protobuf/util/internal/field_mask_utility.cc @@ -34,7 +34,6 @@ #include <google/protobuf/stubs/status_macros.h> namespace google { - namespace protobuf { namespace util { namespace converter { @@ -138,7 +137,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, } // Un-escaped '"' must be followed with a ']'. if (i >= length - 1 || paths[i + 1] != ']') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be represented as [\"some_key\"].")); @@ -150,7 +149,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // Checks whether the key ends at the end of a path segment. if (i < length - 1 && paths[i + 1] != '.' && paths[i + 1] != ',' && paths[i + 1] != ')' && paths[i + 1] != '(') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be at the end of a path segment.")); @@ -162,7 +161,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // We are not in a map key, look for the start of one. if (paths[i] == '[') { if (i >= length - 1 || paths[i + 1] != '\"') { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Map keys should be represented as [\"some_key\"].")); @@ -198,7 +197,7 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, // Removes the last prefix after seeing a ')'. if (i < length && paths[i] == ')') { if (prefix.empty()) { - return CreatePublicError( + return util::Status( util::error::INVALID_ARGUMENT, StrCat("Invalid FieldMask '", paths, "'. Cannot find matching '(' for all ')'.")); @@ -208,16 +207,14 @@ util::Status DecodeCompactFieldMaskPaths(StringPiece paths, previous_position = i + 1; } if (in_map_key) { - return CreatePublicError( - util::error::INVALID_ARGUMENT, - StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ']' for all '['.")); + return util::Status(util::error::INVALID_ARGUMENT, + StrCat("Invalid FieldMask '", paths, + "'. Cannot find matching ']' for all '['.")); } if (!prefix.empty()) { - return CreatePublicError( - util::error::INVALID_ARGUMENT, - StrCat("Invalid FieldMask '", paths, - "'. Cannot find matching ')' for all '('.")); + return util::Status(util::error::INVALID_ARGUMENT, + StrCat("Invalid FieldMask '", paths, + "'. Cannot find matching ')' for all '('.")); } return util::Status::OK; } diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc index 5ac23421..36dc8ef9 100644 --- a/src/google/protobuf/util/internal/json_escaping.cc +++ b/src/google/protobuf/util/internal/json_escaping.cc @@ -30,6 +30,7 @@ #include <google/protobuf/util/internal/json_escaping.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> namespace google { diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index 0c41515f..f81e3306 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -33,9 +33,11 @@ #include <math.h> #include <google/protobuf/stubs/casts.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/util/internal/utility.h> #include <google/protobuf/util/internal/json_escaping.h> +#include <google/protobuf/stubs/mathlimits.h> #include <google/protobuf/stubs/strutil.h> namespace google { @@ -114,7 +116,9 @@ JsonObjectWriter* JsonObjectWriter::RenderUint64(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, double value) { - if (isfinite(value)) return RenderSimple(name, SimpleDtoa(value)); + if (google::protobuf::MathLimits<double>::IsFinite(value)) { + return RenderSimple(name, SimpleDtoa(value)); + } // Render quoted with NaN/Infinity-aware DoubleAsString. return RenderString(name, DoubleAsString(value)); @@ -122,7 +126,9 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) { - if (isfinite(value)) return RenderSimple(name, SimpleFtoa(value)); + if (google::protobuf::MathLimits<float>::IsFinite(value)) { + return RenderSimple(name, SimpleFtoa(value)); + } // Render quoted with NaN/Infinity-aware FloatAsString. return RenderString(name, FloatAsString(value)); @@ -142,7 +148,7 @@ JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name, StringPiece value) { WritePrefix(name); string base64; - WebSafeBase64EscapeWithPadding(value, &base64); + Base64Escape(value, &base64); WriteChar('"'); // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes // directly to the stream, rather than first putting them diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index df9a133e..dcd60601 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -47,7 +47,8 @@ class JsonObjectWriterTest : public ::testing::Test { JsonObjectWriterTest() : str_stream_(new StringOutputStream(&output_)), out_stream_(new CodedOutputStream(str_stream_)), - ow_(NULL) {} + ow_(NULL) { + } virtual ~JsonObjectWriterTest() { delete ow_; @@ -63,34 +64,36 @@ class JsonObjectWriterTest : public ::testing::Test { TEST_F(JsonObjectWriterTest, EmptyRootObject) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->EndObject(); + ow_->StartObject("") + ->EndObject(); EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartObject("empty") - ->EndObject() - ->EndObject(); + ->RenderString("test", "value") + ->StartObject("empty") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyRootList) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartList("")->EndList(); + ow_->StartList("") + ->EndList(); EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderString("test", "value") - ->StartList("empty") - ->EndList() - ->EndObject(); + ->RenderString("test", "value") + ->StartList("empty") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", output_.substr(0, out_stream_->ByteCount())); } @@ -98,10 +101,10 @@ TEST_F(JsonObjectWriterTest, EmptyList) { TEST_F(JsonObjectWriterTest, ObjectInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartObject("nested") - ->RenderString("field", "value") - ->EndObject() - ->EndObject(); + ->StartObject("nested") + ->RenderString("field", "value") + ->EndObject() + ->EndObject(); EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", output_.substr(0, out_stream_->ByteCount())); } @@ -109,10 +112,10 @@ TEST_F(JsonObjectWriterTest, ObjectInObject) { TEST_F(JsonObjectWriterTest, ListInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->StartList("nested") - ->RenderString("", "value") - ->EndList() - ->EndObject(); + ->StartList("nested") + ->RenderString("", "value") + ->EndList() + ->EndObject(); EXPECT_EQ("{\"nested\":[\"value\"]}", output_.substr(0, out_stream_->ByteCount())); } @@ -120,10 +123,10 @@ TEST_F(JsonObjectWriterTest, ListInObject) { TEST_F(JsonObjectWriterTest, ObjectInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartObject("") - ->RenderString("field", "value") - ->EndObject() - ->EndList(); + ->StartObject("") + ->RenderString("field", "value") + ->EndObject() + ->EndList(); EXPECT_EQ("[{\"field\":\"value\"}]", output_.substr(0, out_stream_->ByteCount())); } @@ -131,10 +134,10 @@ TEST_F(JsonObjectWriterTest, ObjectInList) { TEST_F(JsonObjectWriterTest, ListInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") - ->StartList("") - ->RenderString("", "value") - ->EndList() - ->EndList(); + ->StartList("") + ->RenderString("", "value") + ->EndList() + ->EndList(); EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount())); } @@ -164,97 +167,95 @@ TEST_F(JsonObjectWriterTest, RenderPrimitives) { output_.substr(0, out_stream_->ByteCount())); } -TEST_F(JsonObjectWriterTest, BytesEncodesAsWebSafeBase64) { +TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { string s; s.push_back('\377'); s.push_back('\357'); ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("")->RenderBytes("bytes", s)->EndObject(); // Non-web-safe would encode this as "/+8=" - EXPECT_EQ("{\"bytes\":\"_-8=\"}", + EXPECT_EQ("{\"bytes\":\"/+8=\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("items") - ->RenderString("", "item1") - ->RenderString("", "item2") - ->RenderString("", "item3") - ->EndList() - ->StartList("empty") - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": [\n" - " \"item1\",\n" - " \"item2\",\n" - " \"item3\"\n" - " ],\n" - " \"empty\": []\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("items") + ->RenderString("", "item1") + ->RenderString("", "item2") + ->RenderString("", "item3") + ->EndList() + ->StartList("empty") + ->EndList() + ->EndObject(); + EXPECT_EQ("{\n" + " \"items\": [\n" + " \"item1\",\n" + " \"item2\",\n" + " \"item3\"\n" + " ],\n" + " \"empty\": []\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintObject) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartObject("items") - ->RenderString("key1", "item1") - ->RenderString("key2", "item2") - ->RenderString("key3", "item3") - ->EndObject() - ->StartObject("empty") - ->EndObject() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"items\": {\n" - " \"key1\": \"item1\",\n" - " \"key2\": \"item2\",\n" - " \"key3\": \"item3\"\n" - " },\n" - " \"empty\": {}\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartObject("items") + ->RenderString("key1", "item1") + ->RenderString("key2", "item2") + ->RenderString("key3", "item3") + ->EndObject() + ->StartObject("empty") + ->EndObject() + ->EndObject(); + EXPECT_EQ("{\n" + " \"items\": {\n" + " \"key1\": \"item1\",\n" + " \"key2\": \"item2\",\n" + " \"key3\": \"item3\"\n" + " },\n" + " \"empty\": {}\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->StartList("list") - ->StartObject("") - ->EndObject() - ->EndList() - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"list\": [\n" - " {}\n" - " ]\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->StartList("list") + ->StartObject("") + ->EndObject() + ->EndList() + ->EndObject(); + EXPECT_EQ("{\n" + " \"list\": [\n" + " {}\n" + " ]\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") - ->RenderBool("bool", true) - ->RenderInt32("int", 42) - ->EndObject(); - EXPECT_EQ( - "{\n" - " \"bool\": true,\n" - " \"int\": 42\n" - "}\n", - output_.substr(0, out_stream_->ByteCount())); + ->RenderBool("bool", true) + ->RenderInt32("int", 42) + ->EndObject(); + EXPECT_EQ("{\n" + " \"bool\": true,\n" + " \"int\": 42\n" + "}\n", + output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { ow_ = new JsonObjectWriter("", out_stream_); - ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); + ow_->StartObject("") + ->RenderString("string", "'<>&\\\"\r\n") + ->EndObject(); EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", output_.substr(0, out_stream_->ByteCount())); } @@ -262,13 +263,13 @@ TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { TEST_F(JsonObjectWriterTest, Stringification) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") - ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN()) - ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN()) - ->RenderDouble("double_pos", std::numeric_limits<double>::infinity()) - ->RenderFloat("float_pos", std::numeric_limits<float>::infinity()) - ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity()) - ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity()) - ->EndObject(); + ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN()) + ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN()) + ->RenderDouble("double_pos", std::numeric_limits<double>::infinity()) + ->RenderFloat("float_pos", std::numeric_limits<float>::infinity()) + ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity()) + ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity()) + ->EndObject(); EXPECT_EQ( "{\"double_nan\":\"NaN\"," "\"float_nan\":\"NaN\"," diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index d439a221..a7ef7fe2 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -40,6 +40,7 @@ #include <google/protobuf/stubs/shared_ptr.h> #endif +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/util/internal/object_writer.h> @@ -104,16 +105,42 @@ JsonStreamParser::JsonStreamParser(ObjectWriter* ow) parsed_(), parsed_storage_(), string_open_(0), - utf8_storage_(), - utf8_length_(0) { + chunk_storage_(), + coerce_to_utf8_(false) { // Initialize the stack with a single value to be parsed. stack_.push(VALUE); } JsonStreamParser::~JsonStreamParser() {} + util::Status JsonStreamParser::Parse(StringPiece json) { - return ParseChunk(json); + StringPiece chunk = json; + // If we have leftovers from a previous chunk, append the new chunk to it + // and create a new StringPiece pointing at the string's data. This could + // be large but we rely on the chunks to be small, assuming they are + // fragments of a Cord. + if (!leftover_.empty()) { + // Don't point chunk to leftover_ because leftover_ will be updated in + // ParseChunk(chunk). + chunk_storage_.swap(leftover_); + json.AppendToString(&chunk_storage_); + chunk = StringPiece(chunk_storage_); + } + + // Find the structurally valid UTF8 prefix and parse only that. + int n = internal::UTF8SpnStructurallyValid(chunk); + if (n > 0) { + util::Status status = ParseChunk(chunk.substr(0, n)); + + // Any leftover characters are stashed in leftover_ for later parsing when + // there is more data available. + chunk.substr(n).AppendToString(&leftover_); + return status; + } else { + chunk.CopyToString(&leftover_); + return util::Status::OK; + } } util::Status JsonStreamParser::FinishParse() { @@ -122,9 +149,22 @@ util::Status JsonStreamParser::FinishParse() { if (stack_.empty() && leftover_.empty()) { return util::Status::OK; } + + // Storage for UTF8-coerced string. + google::protobuf::scoped_array<char> utf8; + if (coerce_to_utf8_) { + utf8.reset(new char[leftover_.size()]); + char* coerced = internal::UTF8CoerceToStructurallyValid(leftover_, utf8.get(), ' '); + p_ = json_ = StringPiece(coerced, leftover_.size()); + } else { + if (!internal::IsStructurallyValidUTF8(leftover_)) { + return ReportFailure("Encountered non UTF-8 code points."); + } + p_ = json_ = leftover_; + } + // Parse the remainder in finishing mode, which reports errors for things like // unterminated strings or unknown tokens that would normally be retried. - p_ = json_ = StringPiece(leftover_); finishing_ = true; util::Status result = RunParser(); if (result.ok()) { @@ -137,16 +177,10 @@ util::Status JsonStreamParser::FinishParse() { } util::Status JsonStreamParser::ParseChunk(StringPiece chunk) { - // If we have leftovers from a previous chunk, append the new chunk to it and - // create a new StringPiece pointing at the string's data. This could be - // large but we rely on the chunks to be small, assuming they are fragments - // of a Cord. - if (!leftover_.empty()) { - chunk.AppendToString(&leftover_); - p_ = json_ = StringPiece(leftover_); - } else { - p_ = json_ = chunk; - } + // Do not do any work if the chunk is empty. + if (chunk.empty()) return util::Status::OK; + + p_ = json_ = chunk; finishing_ = false; util::Status result = RunParser(); diff --git a/src/google/protobuf/util/internal/json_stream_parser.h b/src/google/protobuf/util/internal/json_stream_parser.h index 17b094ae..0278c28f 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.h +++ b/src/google/protobuf/util/internal/json_stream_parser.h @@ -75,12 +75,14 @@ class LIBPROTOBUF_EXPORT JsonStreamParser { explicit JsonStreamParser(ObjectWriter* ow); virtual ~JsonStreamParser(); - // Parse a JSON string (UTF-8 encoded). + // Parses a UTF-8 encoded JSON string from a StringPiece. util::Status Parse(StringPiece json); + // Finish parsing the JSON string. util::Status FinishParse(); + private: enum TokenType { BEGIN_STRING, // " or ' @@ -239,11 +241,11 @@ class LIBPROTOBUF_EXPORT JsonStreamParser { // A value of 0 indicates that string parsing is not in process. char string_open_; - // Storage for utf8-coerced bytes. - google::protobuf::scoped_array<char> utf8_storage_; + // Storage for the chunk that are being parsed in ParseChunk(). + string chunk_storage_; - // Length of the storage for utf8-coerced bytes. - int utf8_length_; + // Whether to allow non UTF-8 encoded input and replace invalid code points. + bool coerce_to_utf8_; GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonStreamParser); }; diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc index b0775a2f..c833ed1f 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -30,6 +30,7 @@ #include <google/protobuf/util/internal/json_stream_parser.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/time.h> #include <google/protobuf/util/internal/expecting_objectwriter.h> @@ -85,7 +86,7 @@ class JsonStreamParserTest : public ::testing::Test { JsonStreamParserTest() : mock_(), ow_(&mock_) {} virtual ~JsonStreamParserTest() {} - util::Status RunTest(StringPiece json, int split) { + util::Status RunTest(StringPiece json, int split, bool coerce_utf8 = false) { JsonStreamParser parser(&mock_); // Special case for split == length, test parsing one character at a time. @@ -115,8 +116,8 @@ class JsonStreamParserTest : public ::testing::Test { return result; } - void DoTest(StringPiece json, int split) { - util::Status result = RunTest(json, split); + void DoTest(StringPiece json, int split, bool coerce_utf8 = false) { + util::Status result = RunTest(json, split, coerce_utf8); if (!result.ok()) { GOOGLE_LOG(WARNING) << result; } @@ -337,14 +338,26 @@ TEST_F(JsonStreamParserTest, ObjectValues) { } } + +TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { + StringPiece json = "{\"address\":\xFF\"חרושת 23, רעננה, ישראל\"}"; + for (int i = 0; i <= json.length(); ++i) { + DoErrorTest(json, i, "Encountered non UTF-8 code points."); + } + json = "{\"address\": \"חרושת 23,\xFFרעננה, ישראל\"}"; + for (int i = 0; i <= json.length(); ++i) { + DoErrorTest(json, i, "Encountered non UTF-8 code points."); + } +} + #ifndef _MSC_VER // - unicode handling in strings TEST_F(JsonStreamParserTest, UnicodeEscaping) { StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; for (int i = 0; i <= str.length(); ++i) { // TODO(xiaofeng): Figure out what default encoding to use for JSON strings. - // In protobuf we use UTF-8 for strings, but for JSON we probably should allow - // different encodings? + // In protobuf we use UTF-8 for strings, but for JSON we probably should + // allow different encodings? ow_.StartList("")->RenderString("", "\u0639\u0631\u0628\u0649")->EndList(); DoTest(str, i); } diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 53a0e47a..18bb2772 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -33,6 +33,7 @@ #include <utility> #include <google/protobuf/stubs/casts.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/stubs/time.h> @@ -96,7 +97,7 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( } ProtoStreamObjectSource::ProtoStreamObjectSource( - google::protobuf::io::CodedInputStream* stream, TypeInfo* typeinfo, + google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, const google::protobuf::Type& type) : stream_(stream), typeinfo_(typeinfo), own_typeinfo_(false), type_(type) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; @@ -156,7 +157,7 @@ Status ProtoStreamObjectSource::WriteMessage(const google::protobuf::Type& type, last_tag = tag; field = FindAndVerifyField(type, tag); if (field != NULL) { - field_name = field->name(); + field_name = field->json_name(); } } if (field == NULL) { @@ -214,7 +215,7 @@ StatusOr<uint32> ProtoStreamObjectSource::RenderMap( const google::protobuf::Field* field, StringPiece name, uint32 list_tag, ObjectWriter* ow) const { const google::protobuf::Type* field_type = - typeinfo_->GetType(field->type_url()); + typeinfo_->GetTypeByTypeUrl(field->type_url()); uint32 tag_to_return = 0; if (IsPackable(*field) && list_tag == @@ -784,7 +785,8 @@ Status ProtoStreamObjectSource::RenderField( // Get the nested enum type for this field. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this // up. - const google::protobuf::Enum* en = typeinfo_->GetEnum(field->type_url()); + const google::protobuf::Enum* en = + typeinfo_->GetEnumByTypeUrl(field->type_url()); // Lookup the name of the enum, and render that. Skips unknown enums. if (en != NULL) { const google::protobuf::EnumValue* enum_value = @@ -819,7 +821,7 @@ Status ProtoStreamObjectSource::RenderField( int old_limit = stream_->PushLimit(buffer32); // Get the nested message type for this field. const google::protobuf::Type* type = - typeinfo_->GetType(field->type_url()); + typeinfo_->GetTypeByTypeUrl(field->type_url()); if (type == NULL) { return Status(util::error::INTERNAL, StrCat("Invalid configuration. Could not find the type: ", @@ -928,7 +930,8 @@ const string ProtoStreamObjectSource::ReadFieldValueAsString( // Get the nested enum type for this field. // TODO(skarvaje): Avoid string manipulation. Find ways to speed this // up. - const google::protobuf::Enum* en = typeinfo_->GetEnum(field.type_url()); + const google::protobuf::Enum* en = + typeinfo_->GetEnumByTypeUrl(field.type_url()); // Lookup the name of the enum, and render that. Skips unknown enums. if (en != NULL) { const google::protobuf::EnumValue* enum_value = @@ -962,7 +965,7 @@ const string ProtoStreamObjectSource::ReadFieldValueAsString( bool ProtoStreamObjectSource::IsMap( const google::protobuf::Field& field) const { const google::protobuf::Type* field_type = - typeinfo_->GetType(field.type_url()); + typeinfo_->GetTypeByTypeUrl(field.type_url()); // TODO(xiaofeng): Unify option names. return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE && diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 4a4e6bbf..845437f5 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -46,7 +46,6 @@ #include <google/protobuf/stubs/statusor.h> - namespace google { namespace protobuf { class Field; @@ -61,7 +60,10 @@ namespace converter { class TypeInfo; // An ObjectSource that can parse a stream of bytes as a protocol buffer. -// This implementation uses a tech Type for tag lookup. +// Its WriteTo() method can be given an ObjectWriter. +// This implementation uses a google.protobuf.Type for tag and name lookup. +// The field names are converted into lower camel-case when writing to the +// ObjectWriter. // // Sample usage: (suppose input is: string proto) // ArrayInputStream arr_stream(proto.data(), proto.size()); @@ -93,7 +95,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { private: ProtoStreamObjectSource(google::protobuf::io::CodedInputStream* stream, - TypeInfo* typeinfo, + const TypeInfo* typeinfo, const google::protobuf::Type& type); // Function that renders a well known type with a modified behavior. typedef util::Status (*TypeRenderer)(const ProtoStreamObjectSource*, @@ -226,7 +228,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // Type information for all the types used in the descriptor. Used to find // google::protobuf::Type of nested messages/enums. - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Whether this class owns the typeinfo_ object. If true the typeinfo_ object // should be deleted in the destructor. bool own_typeinfo_; diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 4cc62410..f6e5ee7a 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -117,61 +117,61 @@ class ProtostreamObjectSourceTest void PrepareExpectingObjectWriterForRepeatedPrimitive() { ow_.StartObject("") - ->StartList("rep_fix32") + ->StartList("repFix32") ->RenderUint32("", bit_cast<uint32>(3201)) ->RenderUint32("", bit_cast<uint32>(0)) ->RenderUint32("", bit_cast<uint32>(3202)) ->EndList() - ->StartList("rep_u32") + ->StartList("repU32") ->RenderUint32("", bit_cast<uint32>(3203)) ->RenderUint32("", bit_cast<uint32>(0)) ->EndList() - ->StartList("rep_i32") + ->StartList("repI32") ->RenderInt32("", 0) ->RenderInt32("", 3204) ->RenderInt32("", 3205) ->EndList() - ->StartList("rep_sf32") + ->StartList("repSf32") ->RenderInt32("", 3206) ->RenderInt32("", 0) ->EndList() - ->StartList("rep_s32") + ->StartList("repS32") ->RenderInt32("", 0) ->RenderInt32("", 3207) ->RenderInt32("", 3208) ->EndList() - ->StartList("rep_fix64") + ->StartList("repFix64") ->RenderUint64("", bit_cast<uint64>(6401LL)) ->RenderUint64("", bit_cast<uint64>(0LL)) ->EndList() - ->StartList("rep_u64") + ->StartList("repU64") ->RenderUint64("", bit_cast<uint64>(0LL)) ->RenderUint64("", bit_cast<uint64>(6402LL)) ->RenderUint64("", bit_cast<uint64>(6403LL)) ->EndList() - ->StartList("rep_i64") + ->StartList("repI64") ->RenderInt64("", 6404L) ->RenderInt64("", 0L) ->EndList() - ->StartList("rep_sf64") + ->StartList("repSf64") ->RenderInt64("", 0L) ->RenderInt64("", 6405L) ->RenderInt64("", 6406L) ->EndList() - ->StartList("rep_s64") + ->StartList("repS64") ->RenderInt64("", 6407L) ->RenderInt64("", 0L) ->EndList() - ->StartList("rep_float") + ->StartList("repFloat") ->RenderFloat("", 0.0f) ->RenderFloat("", 32.1f) ->RenderFloat("", 32.2f) ->EndList() - ->StartList("rep_double") + ->StartList("repDouble") ->RenderDouble("", 64.1L) ->RenderDouble("", 0.0L) ->EndList() - ->StartList("rep_bool") + ->StartList("repBool") ->RenderBool("", true) ->RenderBool("", false) ->EndList() @@ -317,11 +317,11 @@ TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) { primitive.add_rep_str("String Two"); primitive.add_rep_bytes("Some Bytes"); - ow_.StartList("rep_str") + ow_.StartList("repStr") ->RenderString("", "String One") ->RenderString("", "String Two") ->EndList() - ->StartList("rep_bytes") + ->StartList("repBytes") ->RenderBytes("", "Some Bytes") ->EndList(); DoTest(primitive, Primitive::descriptor()); @@ -794,16 +794,16 @@ TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { ow_.StartObject("") ->RenderString("id", "1") - ->RenderString("single_mask", "path1,snakeCasePath2") - ->StartList("repeated_mask") + ->RenderString("singleMask", "path1,snakeCasePath2") + ->StartList("repeatedMask") ->RenderString("", "path3") ->RenderString("", "snakeCasePath4,path5") ->EndList() - ->StartList("nested_mask") + ->StartList("nestedMask") ->StartObject("") ->RenderString("data", "data") - ->RenderString("single_mask", "nested.path1,nestedField.snakeCasePath2") - ->StartList("repeated_mask") + ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2") + ->StartList("repeatedMask") ->RenderString("", "nestedField.path3,nested.snakeCasePath4") ->RenderString("", "nested.path5") ->RenderString("", diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index f9ddbf32..87f504e0 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -74,7 +74,7 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( tracker_(new ObjectLocationTracker()) {} ProtoStreamObjectWriter::ProtoStreamObjectWriter( - TypeInfo* typeinfo, const google::protobuf::Type& type, + const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener) : master_type_(type), typeinfo_(typeinfo), @@ -91,14 +91,19 @@ ProtoStreamObjectWriter::ProtoStreamObjectWriter( tracker_(new ObjectLocationTracker()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { - // Cleanup explicitly in order to avoid destructor stack overflow when input - // is deeply nested. - while (element_ != NULL) { - element_.reset(element_->pop()); - } if (own_typeinfo_) { delete typeinfo_; } + if (element_ == NULL) return; + // Cleanup explicitly in order to avoid destructor stack overflow when input + // is deeply nested. + // Cast to BaseElement to avoid doing additional checks (like missing fields) + // during pop(). + google::protobuf::scoped_ptr<BaseElement> element( + static_cast<BaseElement*>(element_.get())->pop<BaseElement>()); + while (element != NULL) { + element.reset(element->pop<BaseElement>()); + } } namespace { @@ -454,7 +459,7 @@ void ProtoStreamObjectWriter::AnyWriter::WriteAny() { } ProtoStreamObjectWriter::ProtoElement::ProtoElement( - TypeInfo* typeinfo, const google::protobuf::Type& type, + const TypeInfo* typeinfo, const google::protobuf::Type& type, ProtoStreamObjectWriter* enclosing) : BaseElement(NULL), ow_(enclosing), @@ -586,6 +591,14 @@ string ProtoStreamObjectWriter::ProtoElement::ToString() const { return loc.empty() ? "." : loc; } +bool ProtoStreamObjectWriter::ProtoElement::OneofIndexTaken(int32 index) { + return ContainsKey(oneof_indices_, index); +} + +void ProtoStreamObjectWriter::ProtoElement::TakeOneofIndex(int32 index) { + InsertIfNotPresent(&oneof_indices_, index); +} + inline void ProtoStreamObjectWriter::InvalidName(StringPiece unknown_name, StringPiece message) { listener_->InvalidName(location(), ToSnakeCase(unknown_name), message); @@ -655,6 +668,13 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( return this; } + // Check to see if this field is a oneof and that no oneof in that group has + // already been set. + if (!ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + if (field->type_url() == GetFullTypeWithUrl(kStructType)) { // Start a struct object. StartStruct(field); @@ -932,6 +952,14 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Also we ignore if the field is not found here as it is caught later. field = typeinfo_->FindField(&element_->type(), name); + // Only check for oneof collisions on the first StartList call. We identify + // the first call with !name.empty() check. Subsequent list element calls + // will not have the name filled. + if (!name.empty() && field && !ValidOneof(*field, name)) { + ++invalid_depth_; + return this; + } + // It is an error to try to bind to map, which behind the scenes is a list. if (field && IsMap(*field)) { // Push field to stack for error location tracking & reporting. @@ -1080,9 +1108,9 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, data.ValueAsStringOrDefault(""))); } - // TODO(tsun): figure out how to do proto descriptor based snake case - // conversions as much as possible. Because ToSnakeCase sometimes returns the - // wrong value. +// TODO(tsun): figure out how to do proto descriptor based snake case +// conversions as much as possible. Because ToSnakeCase sometimes returns the +// wrong value. google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback( NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); @@ -1154,6 +1182,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( const google::protobuf::Field* field = NULL; string type_url; bool is_map_entry = false; + // We are at the root when element_ == NULL. if (element_ == NULL) { type_url = GetFullTypeWithUrl(master_type_.name()); } else { @@ -1166,6 +1195,11 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( if (field == NULL) { return this; } + + // Check to see if this field is a oneof and that no oneof in that group has + // already been set. + if (!ValidOneof(*field, name)) return this; + type_url = field->type_url(); } @@ -1314,7 +1348,8 @@ void ProtoStreamObjectWriter::RenderSimpleDataPiece( } case google::protobuf::Field_Kind_TYPE_ENUM: { status = WriteEnum(field.number(), data, - typeinfo_->GetEnum(field.type_url()), stream_.get()); + typeinfo_->GetEnumByTypeUrl(field.type_url()), + stream_.get()); break; } default: // TYPE_GROUP or TYPE_MESSAGE @@ -1401,6 +1436,24 @@ ProtoStreamObjectWriter::GetElementType(const google::protobuf::Type& type) { } } +bool ProtoStreamObjectWriter::ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name) { + if (element_ == NULL) return true; + + if (field.oneof_index() > 0) { + if (element_->OneofIndexTaken(field.oneof_index())) { + InvalidValue( + "oneof", + StrCat("oneof field '", + element_->type().oneofs(field.oneof_index() - 1), + "' is already set. Cannot set '", unnormalized_name, "'")); + return false; + } + element_->TakeOneofIndex(field.oneof_index()); + } + return true; +} + const google::protobuf::Field* ProtoStreamObjectWriter::BeginNamed( StringPiece name, bool is_list) { if (invalid_depth_ > 0) { @@ -1450,7 +1503,7 @@ const google::protobuf::Field* ProtoStreamObjectWriter::Lookup( const google::protobuf::Type* ProtoStreamObjectWriter::LookupType( const google::protobuf::Field* field) { return (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE - ? typeinfo_->GetType(field->type_url()) + ? typeinfo_->GetTypeByTypeUrl(field->type_url()) : &element_->type()); } @@ -1539,7 +1592,7 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) { return false; } const google::protobuf::Type* field_type = - typeinfo_->GetType(field.type_url()); + typeinfo_->GetTypeByTypeUrl(field.type_url()); return GetBoolOptionOrDefault(field_type->options(), "google.protobuf.MessageOptions.map_entry", false); diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index eb4a59f9..f11c47c0 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -71,7 +71,7 @@ class ObjectLocationTracker; // It also supports streaming. class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter { public: - // Constructor. Does not take ownership of any parameter passed in. +// Constructor. Does not take ownership of any parameter passed in. ProtoStreamObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); @@ -82,20 +82,17 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter virtual ProtoStreamObjectWriter* EndObject(); virtual ProtoStreamObjectWriter* StartList(StringPiece name); virtual ProtoStreamObjectWriter* EndList(); - virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, - bool value) { + virtual ProtoStreamObjectWriter* RenderBool(StringPiece name, bool value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, - int32 value) { + virtual ProtoStreamObjectWriter* RenderInt32(StringPiece name, int32 value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderUint32(StringPiece name, uint32 value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, - int64 value) { + virtual ProtoStreamObjectWriter* RenderInt64(StringPiece name, int64 value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderUint64(StringPiece name, @@ -106,8 +103,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter double value) { return RenderDataPiece(name, DataPiece(value)); } - virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, - float value) { + virtual ProtoStreamObjectWriter* RenderFloat(StringPiece name, float value) { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoStreamObjectWriter* RenderString(StringPiece name, @@ -217,7 +213,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter }; // Constructor for the root element. No parent nor field. - ProtoElement(TypeInfo* typeinfo, const google::protobuf::Type& type, + ProtoElement(const TypeInfo* typeinfo, const google::protobuf::Type& type, ProtoStreamObjectWriter* enclosing); // Constructor for a field of an element. @@ -256,6 +252,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter return static_cast<ProtoElement*>(BaseElement::parent()); } + // Returns true if the index is already taken by a preceeding oneof input. + bool OneofIndexTaken(int32 index); + + // Marks the oneof 'index' as taken. Future inputs to this oneof will + // generate an error. + void TakeOneofIndex(int32 index); + private: // Used for access to variables of the enclosing instance of // ProtoStreamObjectWriter. @@ -269,7 +272,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter const google::protobuf::Field* field_; // TypeInfo to lookup types. - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Additional variables if this element is a message: // (Root element is always a message). @@ -289,6 +292,10 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter // The type of this element, see enum for permissible types. ElementType element_type_; + // Set of oneof indices already seen for the type_. Used to validate + // incoming messages so no more than one oneof is set. + hash_set<int32> oneof_indices_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoElement); }; @@ -298,7 +305,7 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter int size; }; - ProtoStreamObjectWriter(TypeInfo* typeinfo, + ProtoStreamObjectWriter(const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener); @@ -407,11 +414,19 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public StructuredObjectWriter static ProtoElement::ElementType GetElementType( const google::protobuf::Type& type); + // Returns true if the field for type_ can be set as a oneof. If field is not + // a oneof type, this function does nothing and returns true. + // If another field for this oneof is already set, this function returns + // false. It also calls the appropriate error callback. + // unnormalized_name is used for error string. + bool ValidOneof(const google::protobuf::Field& field, + StringPiece unnormalized_name); + // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. // typeinfo_ : the TypeInfo object to lookup types. const google::protobuf::Type& master_type_; - TypeInfo* typeinfo_; + const TypeInfo* typeinfo_; // Whether we own the typeinfo_ object. bool own_typeinfo_; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index bd4f29f5..96e5ccfb 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -49,6 +49,7 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/util/internal/testdata/anys.pb.h> #include <google/protobuf/util/internal/testdata/maps.pb.h> +#include <google/protobuf/util/internal/testdata/oneofs.pb.h> #include <google/protobuf/util/internal/testdata/struct.pb.h> #include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h> #include <gtest/gtest.h> @@ -75,6 +76,7 @@ using ::testing::_; using ::testing::Args; using google::protobuf::testing::anys::AnyM; using google::protobuf::testing::anys::AnyOut; +using google::protobuf::testing::oneofs::OneOfsRequest; using google::protobuf::testing::FieldMaskTest; using google::protobuf::testing::maps::MapIn; using google::protobuf::testing::structs::StructType; @@ -143,7 +145,7 @@ class BaseProtoStreamObjectWriterTest void CheckOutput(const Message& expected) { CheckOutput(expected, -1); } const google::protobuf::Type* GetType(const Descriptor* descriptor) { - return helper_.GetTypeInfo()->GetType(GetTypeUrl(descriptor)); + return helper_.GetTypeInfo()->GetTypeByTypeUrl(GetTypeUrl(descriptor)); } testing::TypeInfoTestHelper helper_; @@ -854,11 +856,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece( - "Field 'ts', Illegal timestamp format; timestamps " - "must end with 'Z'"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Illegal timestamp format; timestamps " + "must end with 'Z'"))); ow_->StartObject("")->RenderString("ts", "")->EndObject(); CheckOutput(timestamp); @@ -883,11 +884,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError3) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Timestamp"), - StringPiece( - "Field 'ts', Invalid time format, failed to parse nano " - "seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format, failed to parse nano " + "seconds"))); ow_->StartObject("") ->RenderString("ts", "1970-01-01T00:00:00.ABZ") @@ -919,11 +919,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError1) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Illegal duration format; duration must " - "end with 's'"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Illegal duration format; duration must " + "end with 's'"))); ow_->StartObject("")->RenderString("dur", "")->EndObject(); CheckOutput(duration); @@ -934,11 +933,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError2) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Invalid duration format, failed to parse " - "seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Invalid duration format, failed to parse " + "seconds"))); ow_->StartObject("")->RenderString("dur", "s")->EndObject(); CheckOutput(duration); @@ -949,11 +947,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidDurationError3) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.Duration"), - StringPiece( - "Field 'dur', Invalid duration format, failed to " - "parse nanos seconds"))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.Duration"), + StringPiece("Field 'dur', Invalid duration format, failed to " + "parse nanos seconds"))); ow_->StartObject("")->RenderString("dur", "123.DEFs")->EndObject(); CheckOutput(duration); @@ -1174,10 +1171,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, EmptyAnyFromEmptyObject) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1192,10 +1189,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails1) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1210,10 +1207,10 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails2) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { AnyOut any; - EXPECT_CALL(listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Missing or invalid @type for any field in " + EXPECT_CALL( + listener_, + InvalidValue(_, StringPiece("Any"), + StringPiece("Missing or invalid @type for any field in " "google.protobuf.testing.anys.AnyOut"))); ow_->StartObject("") @@ -1227,13 +1224,12 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithoutTypeUrlFails3) { TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithInvalidTypeUrlFails) { AnyOut any; - EXPECT_CALL( - listener_, - InvalidValue(_, StringPiece("Any"), - StringPiece( - "Invalid type URL, type URLs must be of the form " - "'type.googleapis.com/<typename>', got: " - "type.other.com/some.Type"))); + EXPECT_CALL(listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Invalid type URL, type URLs must be of the form " + "'type.googleapis.com/<typename>', got: " + "type.other.com/some.Type"))); ow_->StartObject("") ->StartObject("any") @@ -1401,11 +1397,10 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MaskUsingApiaryStyleShouldWork) { TEST_P(ProtoStreamObjectWriterFieldMaskTest, MoreCloseThanOpenParentheses) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask 'a(b,c))'. " - "Cannot find matching '(' for all ')'."))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), + StringPiece("Field 'single_mask', Invalid FieldMask 'a(b,c))'. " + "Cannot find matching '(' for all ')'."))); ow_->StartObject(""); ow_->RenderString("id", "1"); @@ -1448,12 +1443,11 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeAtTheEndOfAPathSegment) { EXPECT_CALL( listener_, - InvalidValue(_, - StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " - "Map keys should be at the end of a path segment."))); + InvalidValue( + _, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"key1\"]a,path.to.map[\"key2\"]'. " + "Map keys should be at the end of a path segment."))); ow_->StartObject(""); ow_->RenderString("single_mask", @@ -1466,10 +1460,9 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustEnd) { listener_, InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"key1\"'. Map keys should be " - "represented as [\"some_key\"]."))); + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"key1\"'. Map keys should be " + "represented as [\"some_key\"]."))); ow_->StartObject(""); ow_->RenderString("single_mask", "path.to.map[\"key1\""); @@ -1481,10 +1474,9 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyMustBeEscapedCorrectly) { listener_, InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.FieldMask"), - StringPiece( - "Field 'single_mask', Invalid FieldMask " - "'path.to.map[\"ke\"y1\"]'. Map keys should be " - "represented as [\"some_key\"]."))); + StringPiece("Field 'single_mask', Invalid FieldMask " + "'path.to.map[\"ke\"y1\"]'. Map keys should be " + "represented as [\"some_key\"]."))); ow_->StartObject(""); ow_->RenderString("single_mask", "path.to.map[\"ke\"y1\"]"); @@ -1507,6 +1499,192 @@ TEST_P(ProtoStreamObjectWriterFieldMaskTest, MapKeyCanContainAnyChars) { CheckOutput(expected); } +class ProtoStreamObjectWriterOneOfsTest + : public BaseProtoStreamObjectWriterTest { + protected: + ProtoStreamObjectWriterOneOfsTest() { + vector<const Descriptor*> descriptors; + descriptors.push_back(OneOfsRequest::descriptor()); + descriptors.push_back(google::protobuf::Struct::descriptor()); + ResetTypeInfo(descriptors); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtoStreamObjectWriterOneOfsTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForPrimitiveTypesTest) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("oneof"), + StringPiece( + "oneof field 'data' is already set. Cannot set 'intData'"))); + + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->RenderString("intData", "123"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForMessageTypesPrimitiveFirstTest) { + // Test for setting primitive oneof field first and then message field. + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'messageData'"))); + + // JSON: { "strData": "blah", "messageData": { "dataValue": 123 } } + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForMessageTypesMessageFirstTest) { + // Test for setting message oneof field first and then primitive field. + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'strData'"))); + + // JSON: { "messageData": { "dataValue": 123 }, "strData": "blah" } + ow_->StartObject(""); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->RenderString("strData", "blah"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructTypesPrimitiveFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'structData'"))); + + // JSON: { "strData": "blah", "structData": { "a": "b" } } + ow_->StartObject(""); + ow_->RenderString("strData", "blah"); + ow_->StartObject("structData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructTypesStructFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'strData'"))); + + // JSON: { "structData": { "a": "b" }, "strData": "blah" } + ow_->StartObject(""); + ow_->StartObject("structData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->RenderString("strData", "blah"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForStructValueTypesTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'valueData'"))); + + // JSON: { "messageData": { "dataValue": 123 }, "valueData": { "a": "b" } } + ow_->StartObject(""); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->StartObject("valueData"); + ow_->RenderString("a", "b"); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesPrimitiveFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'tsData'"))); + + // JSON: { "intData": 123, "tsData": "1970-01-02T01:00:00.000Z" } + ow_->StartObject(""); + ow_->RenderInt32("intData", 123); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesWktFirstTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'intData'"))); + + // JSON: { "tsData": "1970-01-02T01:00:00.000Z", "intData": 123 } + ow_->StartObject(""); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->RenderInt32("intData", 123); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForWellKnownTypesAndMessageTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'messageData'"))); + + // JSON: { "tsData": "1970-01-02T01:00:00.000Z", + // "messageData": { "dataValue": 123 } } + ow_->StartObject(""); + ow_->RenderString("tsData", "1970-01-02T01:00:00.000Z"); + ow_->StartObject("messageData"); + ow_->RenderInt32("dataValue", 123); + ow_->EndObject(); + ow_->EndObject(); +} + +TEST_P(ProtoStreamObjectWriterOneOfsTest, + MultipleOneofsFailForOneofWithinAnyTest) { + EXPECT_CALL(listener_, + InvalidValue(_, StringPiece("oneof"), + StringPiece("oneof field 'data' is already set. " + "Cannot set 'intData'"))); + + using google::protobuf::testing::oneofs::OneOfsRequest; + // JSON: + // { "anyData": + // { "@type": + // "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest", + // "strData": "blah", + // "intData": 123 + // } + // } + ow_->StartObject(""); + ow_->StartObject("anyData"); + ow_->RenderString( + "@type", + "type.googleapis.com/google.protobuf.testing.oneofs.OneOfsRequest"); + ow_->RenderString("strData", "blah"); + ow_->RenderInt32("intData", 123); + ow_->EndObject(); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter.h b/src/google/protobuf/util/internal/snake2camel_objectwriter.h index 1a32bc56..9b4ab8a3 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter.h +++ b/src/google/protobuf/util/internal/snake2camel_objectwriter.h @@ -58,9 +58,7 @@ class Snake2CamelObjectWriter : public ObjectWriter { // ObjectWriter methods. virtual Snake2CamelObjectWriter* StartObject(StringPiece name) { - ow_->StartObject(ShouldNormalizeCase(name) - ? StringPiece(StringPiece(ToCamelCase(name))) - : name); + ow_->StartObject(name); return this; } @@ -70,8 +68,7 @@ class Snake2CamelObjectWriter : public ObjectWriter { } virtual Snake2CamelObjectWriter* StartList(StringPiece name) { - ow_->StartList(ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) - : name); + ow_->StartList(name); return this; } @@ -81,76 +78,57 @@ class Snake2CamelObjectWriter : public ObjectWriter { } virtual Snake2CamelObjectWriter* RenderBool(StringPiece name, bool value) { - ow_->RenderBool( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderBool(name, value); return this; } virtual Snake2CamelObjectWriter* RenderInt32(StringPiece name, int32 value) { - ow_->RenderInt32( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderInt32(name, value); return this; } virtual Snake2CamelObjectWriter* RenderUint32(StringPiece name, uint32 value) { - ow_->RenderUint32( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderUint32(name, value); return this; } virtual Snake2CamelObjectWriter* RenderInt64(StringPiece name, int64 value) { - ow_->RenderInt64( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderInt64(name, value); return this; } virtual Snake2CamelObjectWriter* RenderUint64(StringPiece name, uint64 value) { - ow_->RenderUint64( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderUint64(name, value); return this; } virtual Snake2CamelObjectWriter* RenderDouble(StringPiece name, double value) { - ow_->RenderDouble( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderDouble(name, value); return this; } virtual Snake2CamelObjectWriter* RenderFloat(StringPiece name, float value) { - ow_->RenderFloat( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderFloat(name, value); return this; } virtual Snake2CamelObjectWriter* RenderString(StringPiece name, StringPiece value) { - ow_->RenderString( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderString(name, value); return this; } virtual Snake2CamelObjectWriter* RenderBytes(StringPiece name, StringPiece value) { - ow_->RenderBytes( - ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) : name, - value); + ow_->RenderBytes(name, value); return this; } virtual Snake2CamelObjectWriter* RenderNull(StringPiece name) { - ow_->RenderNull(ShouldNormalizeCase(name) ? StringPiece(ToCamelCase(name)) - : name); + ow_->RenderNull(name); return this; } diff --git a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc b/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc index 67388c3b..e5db844c 100644 --- a/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/snake2camel_objectwriter_test.cc @@ -47,263 +47,9 @@ class Snake2CamelObjectWriterTest : public ::testing::Test { Snake2CamelObjectWriter testing_; }; -TEST_F(Snake2CamelObjectWriterTest, Empty) { - // Set expectation - expects_.StartObject("")->EndObject(); - - // Actual testing - testing_.StartObject("")->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, UnderscoresOnly) { - // Set expectation - expects_.StartObject("") - ->RenderInt32("", 1) - ->RenderInt32("", 2) - ->RenderInt32("", 3) - ->RenderInt32("", 4) - ->RenderInt32("", 5) - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderInt32("_", 1) - ->RenderInt32("__", 2) - ->RenderInt32("___", 3) - ->RenderInt32("____", 4) - ->RenderInt32("_____", 5) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LowercaseOnly) { - // Set expectation - expects_.StartObject("") - ->RenderString("key", "value") - ->RenderString("abracadabra", "magic") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("key", "value") - ->RenderString("abracadabra", "magic") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, UppercaseOnly) { - // Set expectation - expects_.StartObject("") - ->RenderString("key", "VALUE") - ->RenderString("abracadabra", "MAGIC") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("KEY", "VALUE") - ->RenderString("ABRACADABRA", "MAGIC") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, CamelCase) { - // Set expectation - expects_.StartObject("") - ->RenderString("camelCase", "camelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "theQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("camelCase", "camelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "theQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, FirstCapCamelCase) { - // Sets expectation - expects_.StartObject("camel") - ->RenderString("camelCase", "CamelCase") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "TheQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); - - // Actual testing - testing_.StartObject("Camel") - ->RenderString("CamelCase", "CamelCase") - ->RenderString("TheQuickBrownFoxJumpsOverTheLazyDog", - "TheQuickBrownFoxJumpsOverTheLazyDog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LastCapCamelCase) { - // Sets expectation - expects_.StartObject("lastCapCamelCasE")->EndObject(); - - // Actual testing - testing_.StartObject("lastCapCamelCasE")->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, MixedCapCamelCase) { - // Sets expectation - expects_.StartObject("googleIsTheBest") - ->RenderFloat("iLoveGOOGLE", 1.61803f) - ->RenderFloat("goGoogleGO", 2.71828f) - ->RenderFloat("gBikeISCool", 3.14159f) - ->EndObject(); - - // Actual testing - testing_.StartObject("GOOGLEIsTheBest") - ->RenderFloat("ILoveGOOGLE", 1.61803f) - ->RenderFloat("GOGoogleGO", 2.71828f) - ->RenderFloat("GBikeISCool", 3.14159f) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, MixedCase) { - // Sets expectation - expects_.StartObject("snakeCaseCamelCase") - ->RenderBool("camelCaseSnakeCase", false) - ->RenderBool("mixedCamelAndUnderScores", false) - ->RenderBool("goGOOGLEGo", true) - ->EndObject(); - - // Actual testing - testing_.StartObject("snake_case_camelCase") - ->RenderBool("camelCase_snake_case", false) - ->RenderBool("MixedCamel_And_UnderScores", false) - ->RenderBool("Go_GOOGLEGo", true) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, SnakeCase) { - // Sets expectation - expects_.StartObject("") - ->RenderString("snakeCase", "snake_case") - ->RenderString("theQuickBrownFoxJumpsOverTheLazyDog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("snake_case", "snake_case") - ->RenderString("the_quick_brown_fox_jumps_over_the_lazy_dog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, FirstCapSnakeCase) { - // Sets expectation - expects_.StartObject("firstCapSnakeCase") - ->RenderBool("helloWorld", true) - ->EndObject(); - - // Actual testing - testing_.StartObject("First_Cap_Snake_Case") - ->RenderBool("Hello_World", true) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, AllCapSnakeCase) { - // Sets expectation - expects_.StartObject("allCAPSNAKECASE") - ->RenderDouble("nyseGOOGL", 600.0L) - ->RenderDouble("aBCDE", 1.0L) - ->RenderDouble("klMNOP", 2.0L) - ->RenderDouble("abcIJKPQRXYZ", 3.0L) - ->EndObject(); - - // Actual testing - testing_.StartObject("ALL_CAP_SNAKE_CASE") - ->RenderDouble("NYSE_GOOGL", 600.0L) - ->RenderDouble("A_B_C_D_E", 1.0L) - ->RenderDouble("KL_MN_OP", 2.0L) - ->RenderDouble("ABC_IJK_PQR_XYZ", 3.0L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, RepeatedUnderScoreSnakeCase) { - // Sets expectation - expects_.StartObject("") - ->RenderInt32("doubleUnderscoreSnakeCase", 2) - ->RenderInt32("tripleUnderscoreFirstCap", 3) - ->RenderInt32("quadrupleUNDERSCOREALLCAP", 4) - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderInt32("double__underscore__snake__case", 2) - ->RenderInt32("Triple___Underscore___First___Cap", 3) - ->RenderInt32("QUADRUPLE____UNDERSCORE____ALL____CAP", 4) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, LeadingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("leadingUnderscoreSnakeCase") - ->RenderUint32("leadingDoubleUnderscore", 2) - ->RenderUint32("leadingTripleUnderscoreFirstCap", 3) - ->RenderUint32("leadingQUADRUPLEUNDERSCOREALLCAP", 4) - ->EndObject(); - - // Actual testing - testing_.StartObject("_leading_underscore_snake_case") - ->RenderUint32("__leading_double_underscore", 2) - ->RenderUint32("___Leading_Triple_Underscore_First_Cap", 3) - ->RenderUint32("____LEADING_QUADRUPLE_UNDERSCORE_ALL_CAP", 4) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, TrailingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("trailingUnderscoreSnakeCase") - ->RenderInt64("trailingDoubleUnderscore", 2L) - ->RenderInt64("trailingTripleUnderscoreFirstCap", 3L) - ->RenderInt64("trailingQUADRUPLEUNDERSCOREALLCAP", 4L) - ->EndObject(); - - // Actual testing - testing_.StartObject("trailing_underscore_snake_case") - ->RenderInt64("trailing_double_underscore__", 2L) - ->RenderInt64("Trailing_Triple_Underscore_First_Cap___", 3L) - ->RenderInt64("TRAILING_QUADRUPLE_UNDERSCORE_ALL_CAP____", 4L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, EnclosingUnderscoreSnakeCase) { - // Sets expectation - expects_.StartObject("enclosingUnderscoreSnakeCase") - ->RenderUint64("enclosingDoubleUnderscore", 2L) - ->RenderUint64("enclosingTripleUnderscoreFirstCap", 3L) - ->RenderUint64("enclosingQUADRUPLEUNDERSCOREALLCAP", 4L) - ->EndObject(); - - // Actual testing - testing_.StartObject("_enclosing_underscore_snake_case_") - ->RenderUint64("__enclosing_double_underscore__", 2L) - ->RenderUint64("___Enclosing_Triple_Underscore_First_Cap___", 3L) - ->RenderUint64("____ENCLOSING_QUADRUPLE_UNDERSCORE_ALL_CAP____", 4L) - ->EndObject(); -} - -TEST_F(Snake2CamelObjectWriterTest, DisableCaseNormalizationOnlyDisablesFirst) { - // Sets expectation - expects_.StartObject("") - ->RenderString("snakeCase", "snake_case") - ->RenderString( - "the_quick_brown_fox_jumps_over_the_lazy_dog", // case retained - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->RenderBool("theSlowFox", true) // disable case not in effect - ->EndObject(); - - // Actual testing - testing_.StartObject("") - ->RenderString("snake_case", "snake_case") - ->DisableCaseNormalizationForNextKey() - ->RenderString("the_quick_brown_fox_jumps_over_the_lazy_dog", - "the_quick_brown_fox_jumps_over_the_lazy_dog") - ->RenderBool("the_slow_fox", true) - ->EndObject(); -} +// All tests are deleted as they are no longer needed. This file will be removed +// after the component dependecies are cleaned up. +// TODO(skarvaje): Remove this file. } // namespace converter } // namespace util diff --git a/src/google/protobuf/util/internal/testdata/default_value.proto b/src/google/protobuf/util/internal/testdata/default_value.proto index ecfc8119..ebbdf6ab 100644 --- a/src/google/protobuf/util/internal/testdata/default_value.proto +++ b/src/google/protobuf/util/internal/testdata/default_value.proto @@ -43,6 +43,7 @@ message DefaultValueTestCases { DoubleMessage repeated_double = 4; DoubleMessage nested_message = 5; DoubleMessage repeated_nested_message = 6; + DoubleMessage double_message_with_oneof = 7; StructMessage empty_struct = 201; StructMessage empty_struct2 = 202; StructMessage struct_with_null_value = 203; @@ -75,6 +76,8 @@ message DefaultValueTestCases { MixedMap mixed1 = 404; MixedMap2 mixed2 = 405; MessageMap map_of_objects = 406; + MixedMap mixed_empty = 407; + MessageMap message_map_empty = 408; DoubleValueMessage double_value = 501; DoubleValueMessage double_value_default = 502; } @@ -85,6 +88,10 @@ message DoubleMessage { DoubleMessage nested_message = 3; repeated DoubleMessage repeated_nested_message = 4; google.protobuf.DoubleValue double_wrapper = 100; + oneof value { + string str_value = 112; + int64 num_value = 113; + } } message StructMessage { diff --git a/src/google/protobuf/util/internal/testdata/oneofs.proto b/src/google/protobuf/util/internal/testdata/oneofs.proto new file mode 100644 index 00000000..5bc9fa08 --- /dev/null +++ b/src/google/protobuf/util/internal/testdata/oneofs.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. + +// Proto to test oneofs. +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; + +package google.protobuf.testing.oneofs; +option java_package = "com.google.protobuf.testing.oneofs"; + +message OneOfsRequest { + string value = 1; + oneof data { + string str_data = 2; + int32 int_data = 3; + // Simple message + Data message_data = 4; + // Well known types + google.protobuf.Struct struct_data = 5; + google.protobuf.Value value_data = 6; + google.protobuf.ListValue list_value_data = 7; + google.protobuf.Timestamp ts_data = 8; + } + google.protobuf.Any any_data = 19; +} + +message Data { + int32 data_value = 1; +} + +message Response { + string value = 1; +} + +service TestService { + // Test call. + rpc Call(OneOfsRequest) returns (Response); +} diff --git a/src/google/protobuf/util/internal/type_info.cc b/src/google/protobuf/util/internal/type_info.cc index 6392e18c..a45a76e3 100644 --- a/src/google/protobuf/util/internal/type_info.cc +++ b/src/google/protobuf/util/internal/type_info.cc @@ -35,11 +35,11 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/type.pb.h> +#include <google/protobuf/util/internal/utility.h> #include <google/protobuf/stubs/stringpiece.h> #include <google/protobuf/stubs/map_util.h> #include <google/protobuf/stubs/status.h> #include <google/protobuf/stubs/statusor.h> -#include <google/protobuf/util/internal/utility.h> namespace google { namespace protobuf { @@ -47,7 +47,6 @@ namespace util { namespace converter { namespace { - // A TypeInfo that looks up information provided by a TypeResolver. class TypeInfoForTypeResolver : public TypeInfo { public: @@ -60,7 +59,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl( - StringPiece type_url) { + StringPiece type_url) const { map<StringPiece, StatusOrType>::iterator it = cached_types_.find(type_url); if (it != cached_types_.end()) { return it->second; @@ -78,12 +77,14 @@ class TypeInfoForTypeResolver : public TypeInfo { return result; } - virtual const google::protobuf::Type* GetType(StringPiece type_url) { + virtual const google::protobuf::Type* GetTypeByTypeUrl( + StringPiece type_url) const { StatusOrType result = ResolveTypeUrl(type_url); return result.ok() ? result.ValueOrDie() : NULL; } - virtual const google::protobuf::Enum* GetEnum(StringPiece type_url) { + virtual const google::protobuf::Enum* GetEnumByTypeUrl( + StringPiece type_url) const { map<StringPiece, StatusOrEnum>::iterator it = cached_enums_.find(type_url); if (it != cached_enums_.end()) { return it->second.ok() ? it->second.ValueOrDie() : NULL; @@ -103,7 +104,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, StringPiece camel_case_name) { + const google::protobuf::Type* type, StringPiece camel_case_name) const { if (indexed_types_.find(type) == indexed_types_.end()) { PopulateNameLookupTable(type); indexed_types_.insert(type); @@ -131,7 +132,7 @@ class TypeInfoForTypeResolver : public TypeInfo { } } - void PopulateNameLookupTable(const google::protobuf::Type* type) { + void PopulateNameLookupTable(const google::protobuf::Type* type) const { for (int i = 0; i < type->fields_size(); ++i) { const google::protobuf::Field& field = type->fields(i); StringPiece name = field.name(); @@ -151,13 +152,13 @@ class TypeInfoForTypeResolver : public TypeInfo { // Stores string values that will be referenced by StringPieces in // cached_types_, cached_enums_ and camel_case_name_table_. - set<string> string_storage_; + mutable set<string> string_storage_; - map<StringPiece, StatusOrType> cached_types_; - map<StringPiece, StatusOrEnum> cached_enums_; + mutable map<StringPiece, StatusOrType> cached_types_; + mutable map<StringPiece, StatusOrEnum> cached_enums_; - set<const google::protobuf::Type*> indexed_types_; - map<StringPiece, StringPiece> camel_case_name_table_; + mutable set<const google::protobuf::Type*> indexed_types_; + mutable map<StringPiece, StringPiece> camel_case_name_table_; }; } // namespace diff --git a/src/google/protobuf/util/internal/type_info.h b/src/google/protobuf/util/internal/type_info.h index 67403fff..d8133176 100644 --- a/src/google/protobuf/util/internal/type_info.h +++ b/src/google/protobuf/util/internal/type_info.h @@ -55,24 +55,29 @@ class LIBPROTOBUF_EXPORT TypeInfo { // // This TypeInfo class retains the ownership of the returned pointer. virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl( - StringPiece type_url) = 0; + StringPiece type_url) const = 0; // Resolves a type url into a Type. Like ResolveTypeUrl() but returns // NULL if the type url is invalid or the type cannot be found. // // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Type* GetType(StringPiece type_url) = 0; + virtual const google::protobuf::Type* GetTypeByTypeUrl( + StringPiece type_url) const = 0; // Resolves a type url for an enum. Returns NULL if the type url is // invalid or the type cannot be found. // // This TypeInfo class retains the ownership of the returned pointer. - virtual const google::protobuf::Enum* GetEnum(StringPiece type_url) = 0; + virtual const google::protobuf::Enum* GetEnumByTypeUrl( + StringPiece type_url) const = 0; // Looks up a field in the specified type given a CamelCase name. virtual const google::protobuf::Field* FindField( - const google::protobuf::Type* type, StringPiece camel_case_name) = 0; + const google::protobuf::Type* type, + StringPiece camel_case_name) const = 0; + // Creates a TypeInfo object that looks up type information from a + // TypeResolver. Caller takes ownership of the returned pointer. static TypeInfo* NewTypeInfo(TypeResolver* type_resolver); private: diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc index 177b96e2..1b9c5154 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ b/src/google/protobuf/util/internal/type_info_test_helper.cc @@ -36,6 +36,7 @@ #endif #include <vector> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/util/internal/default_value_objectwriter.h> @@ -89,7 +90,7 @@ TypeInfo* TypeInfoTestHelper::GetTypeInfo() { return typeinfo_.get(); } ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( io::CodedInputStream* coded_input, const string& type_url) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectSource(coded_input, type_resolver_.get(), @@ -103,7 +104,7 @@ ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( const string& type_url, strings::ByteSink* output, ErrorListener* listener) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output, @@ -116,7 +117,7 @@ ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( DefaultValueObjectWriter* TypeInfoTestHelper::NewDefaultValueWriter( const string& type_url, ObjectWriter* writer) { - const google::protobuf::Type* type = typeinfo_->GetType(type_url); + const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new DefaultValueObjectWriter(type_resolver_.get(), *type, writer); diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 794777d4..5d7dcc87 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -30,11 +30,9 @@ #include <google/protobuf/util/internal/utility.h> -#include <cmath> -#include <algorithm> -#include <utility> - +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/wrappers.pb.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> @@ -301,15 +299,15 @@ bool IsMap(const google::protobuf::Field& field, } string DoubleAsString(double value) { - if (value == std::numeric_limits<double>::infinity()) return "Infinity"; - if (value == -std::numeric_limits<double>::infinity()) return "-Infinity"; + if (google::protobuf::MathLimits<double>::IsPosInf(value)) return "Infinity"; + if (google::protobuf::MathLimits<double>::IsNegInf(value)) return "-Infinity"; if (google::protobuf::MathLimits<double>::IsNaN(value)) return "NaN"; return SimpleDtoa(value); } string FloatAsString(float value) { - if (isfinite(value)) return SimpleFtoa(value); + if (google::protobuf::MathLimits<float>::IsFinite(value)) return SimpleFtoa(value); return DoubleAsString(value); } @@ -320,8 +318,7 @@ bool SafeStrToFloat(StringPiece str, float *value) { } *value = static_cast<float>(double_value); - if ((*value == numeric_limits<float>::infinity()) || - (*value == -numeric_limits<float>::infinity())) { + if (google::protobuf::MathLimits<float>::IsInf(*value)) { return false; } return true; diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h index d0d88c19..87f7602a 100644 --- a/src/google/protobuf/util/internal/utility.h +++ b/src/google/protobuf/util/internal/utility.h @@ -39,6 +39,7 @@ #include <utility> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/type.pb.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/stubs/stringpiece.h> @@ -117,23 +118,23 @@ LIBPROTOBUF_EXPORT const string GetFullTypeWithUrl(StringPiece simple_type); // Finds and returns option identified by name and option_name within the // provided map. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::Option* FindOptionOrNull( +const google::protobuf::Option* FindOptionOrNull( const google::protobuf::RepeatedPtrField<google::protobuf::Option>& options, const string& option_name); // Finds and returns the field identified by field_name in the passed tech Type // object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::Field* FindFieldInTypeOrNull( +const google::protobuf::Field* FindFieldInTypeOrNull( const google::protobuf::Type* type, StringPiece field_name); // Finds and returns the EnumValue identified by enum_name in the passed tech // Enum object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::EnumValue* FindEnumValueByNameOrNull( +const google::protobuf::EnumValue* FindEnumValueByNameOrNull( const google::protobuf::Enum* enum_type, StringPiece enum_name); // Finds and returns the EnumValue identified by value in the passed tech // Enum object. Returns NULL if none found. -LIBPROTOBUF_EXPORT const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( +const google::protobuf::EnumValue* FindEnumValueByNumberOrNull( const google::protobuf::Enum* enum_type, int32 value); // Converts input to camel-case and returns it. @@ -153,7 +154,7 @@ LIBPROTOBUF_EXPORT bool IsWellKnownType(const string& type_name); LIBPROTOBUF_EXPORT bool IsValidBoolString(const string& bool_string); // Returns true if "field" is a protobuf map field based on its type. -bool IsMap(const google::protobuf::Field& field, +LIBPROTOBUF_EXPORT bool IsMap(const google::protobuf::Field& field, const google::protobuf::Type& type); // Infinity/NaN-aware conversion to string. diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h index 6796ea08..1718bfb5 100644 --- a/src/google/protobuf/util/json_util.h +++ b/src/google/protobuf/util/json_util.h @@ -44,7 +44,7 @@ class ZeroCopyOutputStream; } // namespace io namespace util { -struct LIBPROTOBUF_EXPORT JsonOptions { +struct JsonOptions { // Whether to add spaces, line breaks and indentation to make the JSON output // easy to read. bool add_whitespace; @@ -65,7 +65,7 @@ struct LIBPROTOBUF_EXPORT JsonOptions { // 2. input is not valid protobuf wire format, or conflicts with the type // information returned by TypeResolver. // Note that unknown fields will be discarded silently. -LIBPROTOBUF_EXPORT util::Status BinaryToJsonStream( +util::Status BinaryToJsonStream( TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* binary_input, @@ -101,7 +101,7 @@ inline util::Status BinaryToJsonString(TypeResolver* resolver, // 2. input is not valid JSON format, or conflicts with the type // information returned by TypeResolver. // 3. input has unknown fields. -LIBPROTOBUF_EXPORT util::Status JsonToBinaryStream( +util::Status JsonToBinaryStream( TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* json_input, diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index 8399b408..7f88e672 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -98,27 +98,28 @@ TEST_F(JsonUtilTest, TestWhitespaces) { ToJson(m, options)); } -TEST_F(JsonUtilTest, TestDefaultValues) { - TestMessage m; - JsonOptions options; - EXPECT_EQ("{}", ToJson(m, options)); - options.always_print_primitive_fields = true; - EXPECT_EQ( - "{\"boolValue\":false," - "\"int32Value\":0," - "\"int64Value\":\"0\"," - "\"uint32Value\":0," - "\"uint64Value\":\"0\"," - "\"floatValue\":0," - "\"doubleValue\":0," - "\"stringValue\":\"\"," - "\"bytesValue\":\"\"," - // TODO(xiaofeng): The default enum value should be FOO. I believe - // this is a bug in DefaultValueObjectWriter. - "\"enumValue\":null" - "}", - ToJson(m, options)); -} +// TODO(skarvaje): Uncomment after cl/96232915 is submitted. +// TEST_F(JsonUtilTest, TestDefaultValues) { + // TestMessage m; + // JsonOptions options; + // EXPECT_EQ("{}", ToJson(m, options)); + // options.always_print_primitive_fields = true; + // EXPECT_EQ( + // "{\"boolValue\":false," + // "\"int32Value\":0," + // "\"int64Value\":\"0\"," + // "\"uint32Value\":0," + // "\"uint64Value\":\"0\"," + // "\"floatValue\":0," + // "\"doubleValue\":0," + // "\"stringValue\":\"\"," + // "\"bytesValue\":\"\"," + // // TODO(xiaofeng): The default enum value should be FOO. I believe + // // this is a bug in DefaultValueObjectWriter. + // "\"enumValue\":null" + // "}", + // ToJson(m, options)); +// } TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 057b414a..d709da57 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -45,6 +45,7 @@ #endif #include <utility> +#include <google/protobuf/stubs/callback.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/any.h> diff --git a/src/google/protobuf/util/message_differencer_unittest.cc b/src/google/protobuf/util/message_differencer_unittest.cc index bd19f695..701b94ae 100755 --- a/src/google/protobuf/util/message_differencer_unittest.cc +++ b/src/google/protobuf/util/message_differencer_unittest.cc @@ -52,6 +52,7 @@ #include <google/protobuf/map_test_util.h> #include <google/protobuf/test_util.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/testing/googletest.h> @@ -131,7 +132,7 @@ TEST(MessageDifferencerTest, MapFieldEqualityTest) { unittest::TestMap msg1; unittest::TestMap msg2; - MapTestUtil::MapReflectionTester tester(unittest::TestMap::descriptor()); + MapReflectionTester tester(unittest::TestMap::descriptor()); tester.SetMapFieldsViaReflection(&msg1); tester.SetMapFieldsViaReflection(&msg2); tester.SwapMapsViaReflection(&msg1); diff --git a/src/google/protobuf/util/time_util.cc b/src/google/protobuf/util/time_util.cc new file mode 100644 index 00000000..c782d691 --- /dev/null +++ b/src/google/protobuf/util/time_util.cc @@ -0,0 +1,525 @@ +// 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/time_util.h> + +#include <google/protobuf/stubs/time.h> +#include <google/protobuf/stubs/int128.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/stringprintf.h> +#include <google/protobuf/duration.pb.h> +#include <google/protobuf/timestamp.pb.h> + +namespace google { +namespace protobuf { +namespace util { + +using google::protobuf::Timestamp; +using google::protobuf::Duration; + +namespace { +static const int kNanosPerSecond = 1000000000; +static const int kMicrosPerSecond = 1000000; +static const int kMillisPerSecond = 1000; +static const int kNanosPerMillisecond = 1000000; +static const int kMicrosPerMillisecond = 1000; +static const int kNanosPerMicrosecond = 1000; +static const int kSecondsPerMinute = 60; // Note that we ignore leap seconds. +static const int kSecondsPerHour = 3600; +static const char kTimestampFormat[] = "%E4Y-%m-%dT%H:%M:%S"; + +template <typename T> +T CreateNormalized(int64 seconds, int64 nanos); + +template <> +Timestamp CreateNormalized(int64 seconds, int64 nanos) { + // Make sure nanos is in the range. + if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { + seconds += nanos / kNanosPerSecond; + nanos = nanos % kNanosPerSecond; + } + // For Timestamp nanos should be in the range [0, 999999999] + if (nanos < 0) { + seconds -= 1; + nanos += kNanosPerSecond; + } + GOOGLE_DCHECK(seconds >= TimeUtil::kTimestampMinSeconds && + seconds <= TimeUtil::kTimestampMaxSeconds); + Timestamp result; + result.set_seconds(seconds); + result.set_nanos(static_cast<int32>(nanos)); + return result; +} + +template <> +Duration CreateNormalized(int64 seconds, int64 nanos) { + // Make sure nanos is in the range. + if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { + seconds += nanos / kNanosPerSecond; + nanos = nanos % kNanosPerSecond; + } + // nanos should have the same sign as seconds. + if (seconds < 0 && nanos > 0) { + seconds += 1; + nanos -= kNanosPerSecond; + } else if (seconds > 0 && nanos < 0) { + seconds -= 1; + nanos += kNanosPerSecond; + } + GOOGLE_DCHECK(seconds >= TimeUtil::kDurationMinSeconds && + seconds <= TimeUtil::kDurationMaxSeconds); + Duration result; + result.set_seconds(seconds); + result.set_nanos(static_cast<int32>(nanos)); + return result; +} + +// Format nanoseconds with either 3, 6, or 9 digits depending on the required +// precision to represent the exact value. +string FormatNanos(int32 nanos) { + if (nanos % kNanosPerMillisecond == 0) { + return StringPrintf("%03d", nanos / kNanosPerMillisecond); + } else if (nanos % kNanosPerMicrosecond == 0) { + return StringPrintf("%06d", nanos / kNanosPerMicrosecond); + } else { + return StringPrintf("%09d", nanos); + } +} + +string FormatTime(int64 seconds, int32 nanos) { + return ::google::protobuf::internal::FormatTime(seconds, nanos); +} + +bool ParseTime(const string& value, int64* seconds, int32* nanos) { + return ::google::protobuf::internal::ParseTime(value, seconds, nanos); +} + +void CurrentTime(int64* seconds, int32* nanos) { + return ::google::protobuf::internal::GetCurrentTime(seconds, nanos); +} + +// Truncates the remainder part after division. +int64 RoundTowardZero(int64 value, int64 divider) { + int64 result = value / divider; + int64 remainder = value % divider; + // Before C++11, the sign of the remainder is implementation dependent if + // any of the operands is negative. Here we try to enforce C++11's "rounded + // toward zero" semantics. For example, for (-5) / 2 an implementation may + // give -3 as the result with the remainder being 1. This function ensures + // we always return -2 (closer to zero) regardless of the implementation. + if (result < 0 && remainder > 0) { + return result + 1; + } else { + return result; + } +} +} // namespace + +string TimeUtil::ToString(const Timestamp& timestamp) { + return FormatTime(timestamp.seconds(), timestamp.nanos()); +} + +bool TimeUtil::FromString(const string& value, Timestamp* timestamp) { + int64 seconds; + int32 nanos; + if (!ParseTime(value, &seconds, &nanos)) { + return false; + } + *timestamp = CreateNormalized<Timestamp>(seconds, nanos); + return true; +} + +Timestamp TimeUtil::GetCurrentTime() { + int64 seconds; + int32 nanos; + CurrentTime(&seconds, &nanos); + return CreateNormalized<Timestamp>(seconds, nanos); +} + +Timestamp TimeUtil::GetEpoch() { return Timestamp(); } + +string TimeUtil::ToString(const Duration& duration) { + string result; + int64 seconds = duration.seconds(); + int32 nanos = duration.nanos(); + if (seconds < 0 || nanos < 0) { + result += "-"; + seconds = -seconds; + nanos = -nanos; + } + result += StringPrintf("%" GOOGLE_LL_FORMAT "d", seconds); + if (nanos != 0) { + result += "." + FormatNanos(nanos); + } + result += "s"; + return result; +} + +static int64 Pow(int64 x, int y) { + int64 result = 1; + for (int i = 0; i < y; ++i) { + result *= x; + } + return result; +} + +bool TimeUtil::FromString(const string& value, Duration* duration) { + if (value.length() <= 1 || value[value.length() - 1] != 's') { + return false; + } + bool negative = (value[0] == '-'); + int sign_length = (negative ? 1 : 0); + // Parse the duration value as two integers rather than a float value + // to avoid precision loss. + string seconds_part, nanos_part; + size_t pos = value.find_last_of("."); + if (pos == string::npos) { + seconds_part = value.substr(sign_length, value.length() - 1 - sign_length); + nanos_part = "0"; + } else { + seconds_part = value.substr(sign_length, pos - sign_length); + nanos_part = value.substr(pos + 1, value.length() - pos - 2); + } + char* end; + int64 seconds = strto64(seconds_part.c_str(), &end, 10); + if (end != seconds_part.c_str() + seconds_part.length()) { + return false; + } + int64 nanos = strto64(nanos_part.c_str(), &end, 10); + if (end != nanos_part.c_str() + nanos_part.length()) { + return false; + } + nanos = nanos * Pow(10, 9 - nanos_part.length()); + if (negative) { + // If a Duration is negative, both seconds and nanos should be negative. + seconds = -seconds; + nanos = -nanos; + } + duration->set_seconds(seconds); + duration->set_nanos(static_cast<int32>(nanos)); + return true; +} + +Duration TimeUtil::NanosecondsToDuration(int64 nanos) { + return CreateNormalized<Duration>(nanos / kNanosPerSecond, + nanos % kNanosPerSecond); +} + +Duration TimeUtil::MicrosecondsToDuration(int64 micros) { + return CreateNormalized<Duration>( + micros / kMicrosPerSecond, + (micros % kMicrosPerSecond) * kNanosPerMicrosecond); +} + +Duration TimeUtil::MillisecondsToDuration(int64 millis) { + return CreateNormalized<Duration>( + millis / kMillisPerSecond, + (millis % kMillisPerSecond) * kNanosPerMillisecond); +} + +Duration TimeUtil::SecondsToDuration(int64 seconds) { + return CreateNormalized<Duration>(seconds, 0); +} + +Duration TimeUtil::MinutesToDuration(int64 minutes) { + return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0); +} + +Duration TimeUtil::HoursToDuration(int64 hours) { + return CreateNormalized<Duration>(hours * kSecondsPerHour, 0); +} + +int64 TimeUtil::DurationToNanoseconds(const Duration& duration) { + return duration.seconds() * kNanosPerSecond + duration.nanos(); +} + +int64 TimeUtil::DurationToMicroseconds(const Duration& duration) { + return duration.seconds() * kMicrosPerSecond + + RoundTowardZero(duration.nanos(), kNanosPerMicrosecond); +} + +int64 TimeUtil::DurationToMilliseconds(const Duration& duration) { + return duration.seconds() * kMillisPerSecond + + RoundTowardZero(duration.nanos(), kNanosPerMillisecond); +} + +int64 TimeUtil::DurationToSeconds(const Duration& duration) { + return duration.seconds(); +} + +int64 TimeUtil::DurationToMinutes(const Duration& duration) { + return RoundTowardZero(duration.seconds(), kSecondsPerMinute); +} + +int64 TimeUtil::DurationToHours(const Duration& duration) { + return RoundTowardZero(duration.seconds(), kSecondsPerHour); +} + +Timestamp TimeUtil::NanosecondsToTimestamp(int64 nanos) { + return CreateNormalized<Timestamp>(nanos / kNanosPerSecond, + nanos % kNanosPerSecond); +} + +Timestamp TimeUtil::MicrosecondsToTimestamp(int64 micros) { + return CreateNormalized<Timestamp>( + micros / kMicrosPerSecond, + micros % kMicrosPerSecond * kNanosPerMicrosecond); +} + +Timestamp TimeUtil::MillisecondsToTimestamp(int64 millis) { + return CreateNormalized<Timestamp>( + millis / kMillisPerSecond, + millis % kMillisPerSecond * kNanosPerMillisecond); +} + +Timestamp TimeUtil::SecondsToTimestamp(int64 seconds) { + return CreateNormalized<Timestamp>(seconds, 0); +} + +int64 TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) { + return timestamp.seconds() * kNanosPerSecond + timestamp.nanos(); +} + +int64 TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) { + return timestamp.seconds() * kMicrosPerSecond + + RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond); +} + +int64 TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) { + return timestamp.seconds() * kMillisPerSecond + + RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond); +} + +int64 TimeUtil::TimestampToSeconds(const Timestamp& timestamp) { + return timestamp.seconds(); +} + +Timestamp TimeUtil::TimeTToTimestamp(time_t value) { + return CreateNormalized<Timestamp>(static_cast<int64>(value), 0); +} + +time_t TimeUtil::TimestampToTimeT(const Timestamp& value) { + return static_cast<time_t>(value.seconds()); +} + +Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) { + return CreateNormalized<Timestamp>(value.tv_sec, + value.tv_usec * kNanosPerMicrosecond); +} + +timeval TimeUtil::TimestampToTimeval(const Timestamp& value) { + timeval result; + result.tv_sec = value.seconds(); + result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond); + return result; +} + +Duration TimeUtil::TimevalToDuration(const timeval& value) { + return CreateNormalized<Duration>(value.tv_sec, + value.tv_usec * kNanosPerMicrosecond); +} + +timeval TimeUtil::DurationToTimeval(const Duration& value) { + timeval result; + result.tv_sec = value.seconds(); + result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond); + // timeval.tv_usec's range is [0, 1000000) + if (result.tv_usec < 0) { + result.tv_sec -= 1; + result.tv_usec += kMicrosPerSecond; + } + return result; +} + +} // namespace util +} // namespace protobuf + + +namespace protobuf { +namespace { +using google::protobuf::util::kNanosPerSecond; +using google::protobuf::util::CreateNormalized; + +// Convert a Timestamp to uint128. +void ToUint128(const Timestamp& value, uint128* result, bool* negative) { + if (value.seconds() < 0) { + *negative = true; + *result = static_cast<uint64>(-value.seconds()); + *result = *result * kNanosPerSecond - static_cast<uint32>(value.nanos()); + } else { + *negative = false; + *result = static_cast<uint64>(value.seconds()); + *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos()); + } +} + +// Convert a Duration to uint128. +void ToUint128(const Duration& value, uint128* result, bool* negative) { + if (value.seconds() < 0 || value.nanos() < 0) { + *negative = true; + *result = static_cast<uint64>(-value.seconds()); + *result = *result * kNanosPerSecond + static_cast<uint32>(-value.nanos()); + } else { + *negative = false; + *result = static_cast<uint64>(value.seconds()); + *result = *result * kNanosPerSecond + static_cast<uint32>(value.nanos()); + } +} + +void ToTimestamp(const uint128& value, bool negative, Timestamp* timestamp) { + int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond)); + int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond)); + if (negative) { + seconds = -seconds; + nanos = -nanos; + if (nanos < 0) { + nanos += kNanosPerSecond; + seconds -= 1; + } + } + timestamp->set_seconds(seconds); + timestamp->set_nanos(nanos); +} + +void ToDuration(const uint128& value, bool negative, Duration* duration) { + int64 seconds = static_cast<int64>(Uint128Low64(value / kNanosPerSecond)); + int32 nanos = static_cast<int32>(Uint128Low64(value % kNanosPerSecond)); + if (negative) { + seconds = -seconds; + nanos = -nanos; + } + duration->set_seconds(seconds); + duration->set_nanos(nanos); +} +} // namespace + +Duration& operator+=(Duration& d1, const Duration& d2) { + d1 = CreateNormalized<Duration>(d1.seconds() + d2.seconds(), + d1.nanos() + d2.nanos()); + return d1; +} + +Duration& operator-=(Duration& d1, const Duration& d2) { // NOLINT + d1 = CreateNormalized<Duration>(d1.seconds() - d2.seconds(), + d1.nanos() - d2.nanos()); + return d1; +} + +Duration& operator*=(Duration& d, int64 r) { // NOLINT + bool negative; + uint128 value; + ToUint128(d, &value, &negative); + if (r > 0) { + value *= static_cast<uint64>(r); + } else { + negative = !negative; + value *= static_cast<uint64>(-r); + } + ToDuration(value, negative, &d); + return d; +} + +Duration& operator*=(Duration& d, double r) { // NOLINT + double result = (d.seconds() * 1.0 + 1.0 * d.nanos() / kNanosPerSecond) * r; + int64 seconds = static_cast<int64>(result); + int32 nanos = static_cast<int32>((result - seconds) * kNanosPerSecond); + // Note that we normalize here not just because nanos can have a different + // sign from seconds but also that nanos can be any arbitrary value when + // overflow happens (i.e., the result is a much larger value than what + // int64 can represent). + d = CreateNormalized<Duration>(seconds, nanos); + return d; +} + +Duration& operator/=(Duration& d, int64 r) { // NOLINT + bool negative; + uint128 value; + ToUint128(d, &value, &negative); + if (r > 0) { + value /= static_cast<uint64>(r); + } else { + negative = !negative; + value /= static_cast<uint64>(-r); + } + ToDuration(value, negative, &d); + return d; +} + +Duration& operator/=(Duration& d, double r) { // NOLINT + return d *= 1.0 / r; +} + +Duration& operator%=(Duration& d1, const Duration& d2) { // NOLINT + bool negative1, negative2; + uint128 value1, value2; + ToUint128(d1, &value1, &negative1); + ToUint128(d2, &value2, &negative2); + uint128 result = value1 % value2; + // When negative values are involved in division, we round the division + // result towards zero. With this semantics, sign of the remainder is the + // same as the dividend. For example: + // -5 / 10 = 0, -5 % 10 = -5 + // -5 / (-10) = 0, -5 % (-10) = -5 + // 5 / (-10) = 0, 5 % (-10) = 5 + ToDuration(result, negative1, &d1); + return d1; +} + +int64 operator/(const Duration& d1, const Duration& d2) { + bool negative1, negative2; + uint128 value1, value2; + ToUint128(d1, &value1, &negative1); + ToUint128(d2, &value2, &negative2); + int64 result = Uint128Low64(value1 / value2); + if (negative1 != negative2) { + result = -result; + } + return result; +} + +Timestamp& operator+=(Timestamp& t, const Duration& d) { // NOLINT + t = CreateNormalized<Timestamp>(t.seconds() + d.seconds(), + t.nanos() + d.nanos()); + return t; +} + +Timestamp& operator-=(Timestamp& t, const Duration& d) { // NOLINT + t = CreateNormalized<Timestamp>(t.seconds() - d.seconds(), + t.nanos() - d.nanos()); + return t; +} + +Duration operator-(const Timestamp& t1, const Timestamp& t2) { + return CreateNormalized<Duration>(t1.seconds() - t2.seconds(), + t1.nanos() - t2.nanos()); +} +} // namespace protobuf + +} // namespace google diff --git a/src/google/protobuf/util/time_util.h b/src/google/protobuf/util/time_util.h new file mode 100644 index 00000000..58dbf8e6 --- /dev/null +++ b/src/google/protobuf/util/time_util.h @@ -0,0 +1,296 @@ +// 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_TIME_UTIL_H__ +#define GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__ + +#include <ctime> +#include <ostream> +#include <string> +#ifdef _MSC_VER +#include <winsock2.h> +#else +#include <sys/time.h> +#endif + +#include <google/protobuf/duration.pb.h> +#include <google/protobuf/stubs/port.h> +#include <google/protobuf/timestamp.pb.h> + +namespace google { +namespace protobuf { +namespace util { + +class LIBPROTOBUF_EXPORT TimeUtil { + typedef google::protobuf::Timestamp Timestamp; + typedef google::protobuf::Duration Duration; + + public: + // The min/max Timestamp/Duration values we support. + // + // For "0001-01-01T00:00:00Z". + static const int64 kTimestampMinSeconds = -62135596800LL; + // For "9999-12-31T23:59:59.999999999Z". + static const int64 kTimestampMaxSeconds = 253402300799LL; + static const int64 kDurationMinSeconds = -315576000000LL; + static const int64 kDurationMaxSeconds = 315576000000LL; + + // Converts Timestamp to/from RFC 3339 date string format. + // Generated output will always be Z-normalized and uses 3, 6 or 9 + // fractional digits as required to represent the exact time. When + // parsing, any fractional digits (or none) and any offset are + // accepted as long as they fit into nano-seconds precision. + // Note that Timestamp can only represent time from + // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. Converting + // a Timestamp outside of this range is undefined behavior. + // See https://www.ietf.org/rfc/rfc3339.txt + // + // Example of generated format: + // "1972-01-01T10:00:20.021Z" + // + // Example of accepted format: + // "1972-01-01T10:00:20.021-05:00" + static string ToString(const Timestamp& timestamp); + static bool FromString(const string& value, Timestamp* timestamp); + + // Converts Duration to/from string format. The string format will contains + // 3, 6, or 9 fractional digits depending on the precision required to + // represent the exact Duration value. For example: + // "1s", "1.010s", "1.000000100s", "-3.100s" + // The range that can be represented by Duration is from -315,576,000,000 + // to +315,576,000,000 inclusive (in seconds). + static string ToString(const Duration& duration); + static bool FromString(const string& value, Duration* timestamp); + +#ifdef GetCurrentTime +#undef GetCurrentTime // Visual Studio has macro GetCurrentTime +#endif + // Gets the current UTC time. + static Timestamp GetCurrentTime(); + // Returns the Time representing "1970-01-01 00:00:00". + static Timestamp GetEpoch(); + + // Converts between Duration and integer types. The behavior is undefined if + // the input value is not in the valid range of Duration. + static Duration NanosecondsToDuration(int64 nanos); + static Duration MicrosecondsToDuration(int64 micros); + static Duration MillisecondsToDuration(int64 millis); + static Duration SecondsToDuration(int64 seconds); + static Duration MinutesToDuration(int64 minutes); + static Duration HoursToDuration(int64 hours); + // Result will be truncated towards zero. For example, "-1.5s" will be + // truncated to "-1s", and "1.5s" to "1s" when converting to seconds. + // It's undefined behavior if the input duration is not valid or the result + // exceeds the range of int64. A duration is not valid if it's not in the + // valid range of Duration, or have an invalid nanos value (i.e., larger + // than 999999999, less than -999999999, or have a different sign from the + // seconds part). + static int64 DurationToNanoseconds(const Duration& duration); + static int64 DurationToMicroseconds(const Duration& duration); + static int64 DurationToMilliseconds(const Duration& duration); + static int64 DurationToSeconds(const Duration& duration); + static int64 DurationToMinutes(const Duration& duration); + static int64 DurationToHours(const Duration& duration); + // Creates Timestamp from integer types. The integer value indicates the + // time elapsed from Epoch time. The behavior is undefined if the input + // value is not in the valid range of Timestamp. + static Timestamp NanosecondsToTimestamp(int64 nanos); + static Timestamp MicrosecondsToTimestamp(int64 micros); + static Timestamp MillisecondsToTimestamp(int64 millis); + static Timestamp SecondsToTimestamp(int64 seconds); + // Result will be truncated down to the nearest integer value. For example, + // with "1969-12-31T23:59:59.9Z", TimestampToMilliseconds() returns -100 + // and TimestampToSeconds() returns -1. It's undefined behavior if the input + // Timestamp is not valid (i.e., its seconds part or nanos part does not fall + // in the valid range) or the return value doesn't fit into int64. + static int64 TimestampToNanoseconds(const Timestamp& timestamp); + static int64 TimestampToMicroseconds(const Timestamp& timestamp); + static int64 TimestampToMilliseconds(const Timestamp& timestamp); + static int64 TimestampToSeconds(const Timestamp& timestamp); + + // Conversion to/from other time/date types. Note that these types may + // have a different precision and time range from Timestamp/Duration. + // When converting to a lower precision type, the value will be truncated + // to the nearest value that can be represented. If the value is + // out of the range of the result type, the return value is undefined. + // + // Conversion to/from time_t + static Timestamp TimeTToTimestamp(time_t value); + static time_t TimestampToTimeT(const Timestamp& value); + + // Conversion to/from timeval + static Timestamp TimevalToTimestamp(const timeval& value); + static timeval TimestampToTimeval(const Timestamp& value); + static Duration TimevalToDuration(const timeval& value); + static timeval DurationToTimeval(const Duration& value); +}; + +} // namespace util +} // namespace protobuf + + +namespace protobuf { +// Overloaded operators for Duration. +// +// Assignment operators. +LIBPROTOBUF_EXPORT Duration& operator+=(Duration& d1, const Duration& d2); // NOLINT +LIBPROTOBUF_EXPORT Duration& operator-=(Duration& d1, const Duration& d2); // NOLINT +LIBPROTOBUF_EXPORT Duration& operator*=(Duration& d, int64 r); // NOLINT +LIBPROTOBUF_EXPORT Duration& operator*=(Duration& d, double r); // NOLINT +LIBPROTOBUF_EXPORT Duration& operator/=(Duration& d, int64 r); // NOLINT +LIBPROTOBUF_EXPORT Duration& operator/=(Duration& d, double r); // NOLINT +// Overload for other integer types. +template <typename T> +Duration& operator*=(Duration& d, T r) { // NOLINT + int64 x = r; + return d *= x; +} +template <typename T> +Duration& operator/=(Duration& d, T r) { // NOLINT + int64 x = r; + return d /= x; +} +LIBPROTOBUF_EXPORT Duration& operator%=(Duration& d1, const Duration& d2); // NOLINT +// Relational operators. +inline bool operator<(const Duration& d1, const Duration& d2) { + if (d1.seconds() == d2.seconds()) { + return d1.nanos() < d2.nanos(); + } + return d1.seconds() < d2.seconds(); +} +inline bool operator>(const Duration& d1, const Duration& d2) { + return d2 < d1; +} +inline bool operator>=(const Duration& d1, const Duration& d2) { + return !(d1 < d2); +} +inline bool operator<=(const Duration& d1, const Duration& d2) { + return !(d2 < d1); +} +inline bool operator==(const Duration& d1, const Duration& d2) { + return d1.seconds() == d2.seconds() && d1.nanos() == d2.nanos(); +} +inline bool operator!=(const Duration& d1, const Duration& d2) { + return !(d1 == d2); +} +// Additive operators +inline Duration operator-(const Duration& d) { + Duration result; + result.set_seconds(-d.seconds()); + result.set_nanos(-d.nanos()); + return result; +} +inline Duration operator+(const Duration& d1, const Duration& d2) { + Duration result = d1; + return result += d2; +} +inline Duration operator-(const Duration& d1, const Duration& d2) { + Duration result = d1; + return result -= d2; +} +// Multiplicative operators +template<typename T> +inline Duration operator*(Duration d, T r) { + return d *= r; +} +template<typename T> +inline Duration operator*(T r, Duration d) { + return d *= r; +} +template<typename T> +inline Duration operator/(Duration d, T r) { + return d /= r; +} +LIBPROTOBUF_EXPORT int64 operator/(const Duration& d1, const Duration& d2); + +inline Duration operator%(const Duration& d1, const Duration& d2) { + Duration result = d1; + return result %= d2; +} + +inline ostream& operator<<(ostream& out, const Duration& d) { + out << google::protobuf::util::TimeUtil::ToString(d); + return out; +} + +// Overloaded operators for Timestamp +// +// Assignement operators. +LIBPROTOBUF_EXPORT +Timestamp& operator+=(Timestamp& t, const Duration& d); // NOLINT +LIBPROTOBUF_EXPORT +Timestamp& operator-=(Timestamp& t, const Duration& d); // NOLINT +// Relational operators. +inline bool operator<(const Timestamp& t1, const Timestamp& t2) { + if (t1.seconds() == t2.seconds()) { + return t1.nanos() < t2.nanos(); + } + return t1.seconds() < t2.seconds(); +} +inline bool operator>(const Timestamp& t1, const Timestamp& t2) { + return t2 < t1; +} +inline bool operator>=(const Timestamp& t1, const Timestamp& t2) { + return !(t1 < t2); +} +inline bool operator<=(const Timestamp& t1, const Timestamp& t2) { + return !(t2 < t1); +} +inline bool operator==(const Timestamp& t1, const Timestamp& t2) { + return t1.seconds() == t2.seconds() && t1.nanos() == t2.nanos(); +} +inline bool operator!=(const Timestamp& t1, const Timestamp& t2) { + return !(t1 == t2); +} +// Additive operators. +inline Timestamp operator+(const Timestamp& t, const Duration& d) { + Timestamp result = t; + return result += d; +} +inline Timestamp operator+(const Duration& d, const Timestamp& t) { + Timestamp result = t; + return result += d; +} +inline Timestamp operator-(const Timestamp& t, const Duration& d) { + Timestamp result = t; + return result -= d; +} +LIBPROTOBUF_EXPORT Duration operator-(const Timestamp& t1, const Timestamp& t2); + +inline ostream& operator<<(ostream& out, const Timestamp& t) { + out << google::protobuf::util::TimeUtil::ToString(t); + return out; +} + +} // namespace protobuf + + +} // namespace google +#endif // GOOGLE_PROTOBUF_UTIL_TIME_UTIL_H__ diff --git a/src/google/protobuf/util/time_util_test.cc b/src/google/protobuf/util/time_util_test.cc new file mode 100644 index 00000000..285740ab --- /dev/null +++ b/src/google/protobuf/util/time_util_test.cc @@ -0,0 +1,380 @@ +// 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/time_util.h> + +#include <ctime> + +#include <google/protobuf/timestamp.pb.h> +#include <google/protobuf/duration.pb.h> +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace util { + +using google::protobuf::Timestamp; +using google::protobuf::Duration; + +namespace { + +TEST(TimeUtilTest, TimestampStringFormat) { + Timestamp begin, end; + EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin)); + EXPECT_EQ(TimeUtil::kTimestampMinSeconds, begin.seconds()); + EXPECT_EQ(0, begin.nanos()); + EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end)); + EXPECT_EQ(TimeUtil::kTimestampMaxSeconds, end.seconds()); + EXPECT_EQ(999999999, end.nanos()); + EXPECT_EQ("0001-01-01T00:00:00Z", TimeUtil::ToString(begin)); + EXPECT_EQ("9999-12-31T23:59:59.999999999Z", TimeUtil::ToString(end)); + + // Test negative timestamps. + Timestamp time = TimeUtil::NanosecondsToTimestamp(-1); + EXPECT_EQ(-1, time.seconds()); + // Timestamp's nano part is always non-negative. + EXPECT_EQ(999999999, time.nanos()); + EXPECT_EQ("1969-12-31T23:59:59.999999999Z", TimeUtil::ToString(time)); + + // Generated output should contain 3, 6, or 9 fractional digits. + EXPECT_EQ("1970-01-01T00:00:00Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(0))); + EXPECT_EQ("1970-01-01T00:00:00.010Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10000000))); + EXPECT_EQ("1970-01-01T00:00:00.000010Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10000))); + EXPECT_EQ("1970-01-01T00:00:00.000000010Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(10))); + + // Parsing accepts an fractional digits as long as they fit into nano + // precision. + EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.1Z", &time)); + EXPECT_EQ(100000000, TimeUtil::TimestampToNanoseconds(time)); + EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.0001Z", &time)); + EXPECT_EQ(100000, TimeUtil::TimestampToNanoseconds(time)); + EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00.0000001Z", &time)); + EXPECT_EQ(100, TimeUtil::TimestampToNanoseconds(time)); + + // Also accpets offsets. + EXPECT_TRUE(TimeUtil::FromString("1970-01-01T00:00:00-08:00", &time)); + EXPECT_EQ(8 * 3600, TimeUtil::TimestampToSeconds(time)); +} + +TEST(TimeUtilTest, DurationStringFormat) { + Timestamp begin, end; + EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin)); + EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end)); + + EXPECT_EQ("315537897599.999999999s", TimeUtil::ToString(end - begin)); + EXPECT_EQ(999999999, (end - begin).nanos()); + EXPECT_EQ("-315537897599.999999999s", TimeUtil::ToString(begin - end)); + EXPECT_EQ(-999999999, (begin - end).nanos()); + + // Generated output should contain 3, 6, or 9 fractional digits. + EXPECT_EQ("1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(1))); + EXPECT_EQ("0.010s", TimeUtil::ToString(TimeUtil::MillisecondsToDuration(10))); + EXPECT_EQ("0.000010s", + TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(10))); + EXPECT_EQ("0.000000010s", + TimeUtil::ToString(TimeUtil::NanosecondsToDuration(10))); + + // Parsing accepts an fractional digits as long as they fit into nano + // precision. + Duration d; + EXPECT_TRUE(TimeUtil::FromString("0.1s", &d)); + EXPECT_EQ(100, TimeUtil::DurationToMilliseconds(d)); + EXPECT_TRUE(TimeUtil::FromString("0.0001s", &d)); + EXPECT_EQ(100, TimeUtil::DurationToMicroseconds(d)); + EXPECT_TRUE(TimeUtil::FromString("0.0000001s", &d)); + EXPECT_EQ(100, TimeUtil::DurationToNanoseconds(d)); + + // Duration must support range from -315,576,000,000s to +315576000000s + // which includes negative values. + EXPECT_TRUE(TimeUtil::FromString("315576000000.999999999s", &d)); + EXPECT_EQ(315576000000LL, d.seconds()); + EXPECT_EQ(999999999, d.nanos()); + EXPECT_TRUE(TimeUtil::FromString("-315576000000.999999999s", &d)); + EXPECT_EQ(-315576000000LL, d.seconds()); + EXPECT_EQ(-999999999, d.nanos()); +} + +TEST(TimeUtilTest, GetEpoch) { + EXPECT_EQ(0, TimeUtil::TimestampToNanoseconds(TimeUtil::GetEpoch())); +} + +TEST(TimeUtilTest, DurationIntegerConversion) { + EXPECT_EQ("0.000000001s", + TimeUtil::ToString(TimeUtil::NanosecondsToDuration(1))); + EXPECT_EQ("-0.000000001s", + TimeUtil::ToString(TimeUtil::NanosecondsToDuration(-1))); + EXPECT_EQ("0.000001s", + TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(1))); + EXPECT_EQ("-0.000001s", + TimeUtil::ToString(TimeUtil::MicrosecondsToDuration(-1))); + EXPECT_EQ("0.001s", TimeUtil::ToString(TimeUtil::MillisecondsToDuration(1))); + EXPECT_EQ("-0.001s", + TimeUtil::ToString(TimeUtil::MillisecondsToDuration(-1))); + EXPECT_EQ("1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(1))); + EXPECT_EQ("-1s", TimeUtil::ToString(TimeUtil::SecondsToDuration(-1))); + EXPECT_EQ("60s", TimeUtil::ToString(TimeUtil::MinutesToDuration(1))); + EXPECT_EQ("-60s", TimeUtil::ToString(TimeUtil::MinutesToDuration(-1))); + EXPECT_EQ("3600s", TimeUtil::ToString(TimeUtil::HoursToDuration(1))); + EXPECT_EQ("-3600s", TimeUtil::ToString(TimeUtil::HoursToDuration(-1))); + + EXPECT_EQ( + 1, TimeUtil::DurationToNanoseconds(TimeUtil::NanosecondsToDuration(1))); + EXPECT_EQ( + -1, TimeUtil::DurationToNanoseconds(TimeUtil::NanosecondsToDuration(-1))); + EXPECT_EQ( + 1, TimeUtil::DurationToMicroseconds(TimeUtil::MicrosecondsToDuration(1))); + EXPECT_EQ(-1, TimeUtil::DurationToMicroseconds( + TimeUtil::MicrosecondsToDuration(-1))); + EXPECT_EQ( + 1, TimeUtil::DurationToMilliseconds(TimeUtil::MillisecondsToDuration(1))); + EXPECT_EQ(-1, TimeUtil::DurationToMilliseconds( + TimeUtil::MillisecondsToDuration(-1))); + EXPECT_EQ(1, TimeUtil::DurationToSeconds(TimeUtil::SecondsToDuration(1))); + EXPECT_EQ(-1, TimeUtil::DurationToSeconds(TimeUtil::SecondsToDuration(-1))); + EXPECT_EQ(1, TimeUtil::DurationToMinutes(TimeUtil::MinutesToDuration(1))); + EXPECT_EQ(-1, TimeUtil::DurationToMinutes(TimeUtil::MinutesToDuration(-1))); + EXPECT_EQ(1, TimeUtil::DurationToHours(TimeUtil::HoursToDuration(1))); + EXPECT_EQ(-1, TimeUtil::DurationToHours(TimeUtil::HoursToDuration(-1))); + + // Test truncation behavior. + EXPECT_EQ(1, TimeUtil::DurationToMicroseconds( + TimeUtil::NanosecondsToDuration(1999))); + // For negative values, Duration will be rounded towards 0. + EXPECT_EQ(-1, TimeUtil::DurationToMicroseconds( + TimeUtil::NanosecondsToDuration(-1999))); +} + +TEST(TestUtilTest, TimestampIntegerConversion) { + EXPECT_EQ("1970-01-01T00:00:00.000000001Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(1))); + EXPECT_EQ("1969-12-31T23:59:59.999999999Z", + TimeUtil::ToString(TimeUtil::NanosecondsToTimestamp(-1))); + EXPECT_EQ("1970-01-01T00:00:00.000001Z", + TimeUtil::ToString(TimeUtil::MicrosecondsToTimestamp(1))); + EXPECT_EQ("1969-12-31T23:59:59.999999Z", + TimeUtil::ToString(TimeUtil::MicrosecondsToTimestamp(-1))); + EXPECT_EQ("1970-01-01T00:00:00.001Z", + TimeUtil::ToString(TimeUtil::MillisecondsToTimestamp(1))); + EXPECT_EQ("1969-12-31T23:59:59.999Z", + TimeUtil::ToString(TimeUtil::MillisecondsToTimestamp(-1))); + EXPECT_EQ("1970-01-01T00:00:01Z", + TimeUtil::ToString(TimeUtil::SecondsToTimestamp(1))); + EXPECT_EQ("1969-12-31T23:59:59Z", + TimeUtil::ToString(TimeUtil::SecondsToTimestamp(-1))); + + EXPECT_EQ( + 1, TimeUtil::TimestampToNanoseconds(TimeUtil::NanosecondsToTimestamp(1))); + EXPECT_EQ(-1, TimeUtil::TimestampToNanoseconds( + TimeUtil::NanosecondsToTimestamp(-1))); + EXPECT_EQ(1, TimeUtil::TimestampToMicroseconds( + TimeUtil::MicrosecondsToTimestamp(1))); + EXPECT_EQ(-1, TimeUtil::TimestampToMicroseconds( + TimeUtil::MicrosecondsToTimestamp(-1))); + EXPECT_EQ(1, TimeUtil::TimestampToMilliseconds( + TimeUtil::MillisecondsToTimestamp(1))); + EXPECT_EQ(-1, TimeUtil::TimestampToMilliseconds( + TimeUtil::MillisecondsToTimestamp(-1))); + EXPECT_EQ(1, TimeUtil::TimestampToSeconds(TimeUtil::SecondsToTimestamp(1))); + EXPECT_EQ(-1, TimeUtil::TimestampToSeconds(TimeUtil::SecondsToTimestamp(-1))); + + // Test truncation behavior. + EXPECT_EQ(1, TimeUtil::TimestampToMicroseconds( + TimeUtil::NanosecondsToTimestamp(1999))); + // For negative values, Timestamp will be rounded down. + // For example, "1969-12-31T23:59:59.5Z" (i.e., -0.5s) rounded to seconds + // will be "1969-12-31T23:59:59Z" (i.e., -1s) rather than + // "1970-01-01T00:00:00Z" (i.e., 0s). + EXPECT_EQ(-2, TimeUtil::TimestampToMicroseconds( + TimeUtil::NanosecondsToTimestamp(-1999))); +} + +TEST(TimeUtilTest, TimeTConversion) { + time_t value = time(NULL); + EXPECT_EQ(value, + TimeUtil::TimestampToTimeT(TimeUtil::TimeTToTimestamp(value))); + EXPECT_EQ( + 1, TimeUtil::TimestampToTimeT(TimeUtil::MillisecondsToTimestamp(1999))); +} + +TEST(TimeUtilTest, TimevalConversion) { + timeval value = TimeUtil::TimestampToTimeval( + TimeUtil::NanosecondsToTimestamp(1999999999)); + EXPECT_EQ(1, value.tv_sec); + EXPECT_EQ(999999, value.tv_usec); + value = TimeUtil::TimestampToTimeval( + TimeUtil::NanosecondsToTimestamp(-1999999999)); + EXPECT_EQ(-2, value.tv_sec); + EXPECT_EQ(0, value.tv_usec); + + value = + TimeUtil::DurationToTimeval(TimeUtil::NanosecondsToDuration(1999999999)); + EXPECT_EQ(1, value.tv_sec); + EXPECT_EQ(999999, value.tv_usec); + value = + TimeUtil::DurationToTimeval(TimeUtil::NanosecondsToDuration(-1999999999)); + EXPECT_EQ(-2, value.tv_sec); + EXPECT_EQ(1, value.tv_usec); +} + +TEST(TimeUtilTest, DurationOperators) { + Duration one_second = TimeUtil::SecondsToDuration(1); + Duration one_nano = TimeUtil::NanosecondsToDuration(1); + + // Test +/- + Duration a = one_second; + a += one_second; + a -= one_nano; + EXPECT_EQ("1.999999999s", TimeUtil::ToString(a)); + Duration b = -a; + EXPECT_EQ("-1.999999999s", TimeUtil::ToString(b)); + EXPECT_EQ("3.999999998s", TimeUtil::ToString(a + a)); + EXPECT_EQ("0s", TimeUtil::ToString(a + b)); + EXPECT_EQ("0s", TimeUtil::ToString(b + a)); + EXPECT_EQ("-3.999999998s", TimeUtil::ToString(b + b)); + EXPECT_EQ("3.999999998s", TimeUtil::ToString(a - b)); + EXPECT_EQ("0s", TimeUtil::ToString(a - a)); + EXPECT_EQ("0s", TimeUtil::ToString(b - b)); + EXPECT_EQ("-3.999999998s", TimeUtil::ToString(b - a)); + + // Test * + EXPECT_EQ(a + a, a * 2); + EXPECT_EQ(b + b, a * (-2)); + EXPECT_EQ(b + b, b * 2); + EXPECT_EQ(a + a, b * (-2)); + EXPECT_EQ("0.999999999s", TimeUtil::ToString(a * 0.5)); + EXPECT_EQ("-0.999999999s", TimeUtil::ToString(b * 0.5)); + // Multiplication should not overflow if the result fits into the supported + // range of Duration (intermediate result may be larger than int64). + EXPECT_EQ("315575999684.424s", + TimeUtil::ToString((one_second - one_nano) * 315576000000LL)); + EXPECT_EQ("-315575999684.424s", + TimeUtil::ToString((one_nano - one_second) * 315576000000LL)); + EXPECT_EQ("-315575999684.424s", + TimeUtil::ToString((one_second - one_nano) * (-315576000000LL))); + + // Test / and % + EXPECT_EQ("0.999999999s", TimeUtil::ToString(a / 2)); + EXPECT_EQ("-0.999999999s", TimeUtil::ToString(b / 2)); + Duration large = TimeUtil::SecondsToDuration(315576000000LL) - one_nano; + // We have to handle division with values beyond 64 bits. + EXPECT_EQ("0.999999999s", TimeUtil::ToString(large / 315576000000LL)); + EXPECT_EQ("-0.999999999s", TimeUtil::ToString((-large) / 315576000000LL)); + EXPECT_EQ("-0.999999999s", TimeUtil::ToString(large / (-315576000000LL))); + Duration large2 = large + one_nano; + EXPECT_EQ(large, large % large2); + EXPECT_EQ(-large, (-large) % large2); + EXPECT_EQ(large, large % (-large2)); + EXPECT_EQ(one_nano, large2 % large); + EXPECT_EQ(-one_nano, (-large2) % large); + EXPECT_EQ(one_nano, large2 % (-large)); + // Some corner cases about negative values. + // + // (-5) / 2 = -2, remainder = -1 + // (-5) / (-2) = 2, remainder = -1 + a = TimeUtil::NanosecondsToDuration(-5); + EXPECT_EQ(TimeUtil::NanosecondsToDuration(-2), a / 2); + EXPECT_EQ(TimeUtil::NanosecondsToDuration(2), a / (-2)); + b = TimeUtil::NanosecondsToDuration(2); + EXPECT_EQ(-2, a / b); + EXPECT_EQ(TimeUtil::NanosecondsToDuration(-1), a % b); + EXPECT_EQ(2, a / (-b)); + EXPECT_EQ(TimeUtil::NanosecondsToDuration(-1), a % (-b)); + + // Test relational operators. + EXPECT_TRUE(one_nano < one_second); + EXPECT_FALSE(one_second < one_second); + EXPECT_FALSE(one_second < one_nano); + EXPECT_FALSE(-one_nano < -one_second); + EXPECT_FALSE(-one_second < -one_second); + EXPECT_TRUE(-one_second < -one_nano); + EXPECT_TRUE(-one_nano < one_nano); + EXPECT_FALSE(one_nano < -one_nano); + + EXPECT_FALSE(one_nano > one_second); + EXPECT_FALSE(one_nano > one_nano); + EXPECT_TRUE(one_second > one_nano); + + EXPECT_FALSE(one_nano >= one_second); + EXPECT_TRUE(one_nano >= one_nano); + EXPECT_TRUE(one_second >= one_nano); + + EXPECT_TRUE(one_nano <= one_second); + EXPECT_TRUE(one_nano <= one_nano); + EXPECT_FALSE(one_second <= one_nano); + + EXPECT_TRUE(one_nano == one_nano); + EXPECT_FALSE(one_nano == one_second); + + EXPECT_FALSE(one_nano != one_nano); + EXPECT_TRUE(one_nano != one_second); +} + +TEST(TimeUtilTest, TimestampOperators) { + Timestamp begin, end; + EXPECT_TRUE(TimeUtil::FromString("0001-01-01T00:00:00Z", &begin)); + EXPECT_TRUE(TimeUtil::FromString("9999-12-31T23:59:59.999999999Z", &end)); + Duration d = end - begin; + EXPECT_TRUE(end == begin + d); + EXPECT_TRUE(end == d + begin); + EXPECT_TRUE(begin == end - d); + + // Test relational operators + Timestamp t1 = begin + d / 4; + Timestamp t2 = end - d / 4; + EXPECT_TRUE(t1 < t2); + EXPECT_FALSE(t1 < t1); + EXPECT_FALSE(t2 < t1); + EXPECT_FALSE(t1 > t2); + EXPECT_FALSE(t1 > t1); + EXPECT_TRUE(t2 > t1); + EXPECT_FALSE(t1 >= t2); + EXPECT_TRUE(t1 >= t1); + EXPECT_TRUE(t2 >= t1); + EXPECT_TRUE(t1 <= t2); + EXPECT_TRUE(t1 <= t1); + EXPECT_FALSE(t2 <= t1); + + EXPECT_FALSE(t1 == t2); + EXPECT_TRUE(t1 == t1); + EXPECT_FALSE(t2 == t1); + EXPECT_TRUE(t1 != t2); + EXPECT_FALSE(t1 != t1); + EXPECT_TRUE(t2 != t1); +} + +} // namespace +} // namespace util +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc index 053a4ed7..908634eb 100644 --- a/src/google/protobuf/util/type_resolver_util.cc +++ b/src/google/protobuf/util/type_resolver_util.cc @@ -35,6 +35,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/util/type_resolver.h> +#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/status.h> namespace google { @@ -64,6 +65,47 @@ bool SplitTypeUrl(const string& type_url, return true; } +// This code is originally defined in +// //google/protobuf/util/converter/utility.h. Copied here due to component +// dependency. +// TODO(xiaofeng): Remove this when converter code is in components. +string ToCamelCase(const StringPiece input) { + bool capitalize_next = false; + bool was_cap = true; + bool is_cap = false; + bool first_word = true; + string result; + result.reserve(input.size()); + + for (size_t i = 0; i < input.size(); ++i, was_cap = is_cap) { + is_cap = ascii_isupper(input[i]); + if (input[i] == '_') { + capitalize_next = true; + if (!result.empty()) first_word = false; + continue; + } else if (first_word) { + // Consider when the current character B is capitalized, + // first word ends when: + // 1) following a lowercase: "...aB..." + // 2) followed by a lowercase: "...ABc..." + if (!result.empty() && is_cap && + (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { + first_word = false; + } else { + result.push_back(ascii_tolower(input[i])); + continue; + } + } else if (capitalize_next) { + capitalize_next = false; + if (ascii_islower(input[i])) { + result.push_back(ascii_toupper(input[i])); + continue; + } + } + result.push_back(input[i]); + } + return result; +} class DescriptorPoolTypeResolver : public TypeResolver { public: @@ -155,6 +197,7 @@ class DescriptorPoolTypeResolver : public TypeResolver { } field->set_number(descriptor->number()); field->set_name(descriptor->name()); + field->set_json_name(ToCamelCase(descriptor->name())); if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) { field->set_type_url(GetTypeUrl(descriptor->message_type())); } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) { diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index c5db963b..5ee4e25d 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -38,6 +38,7 @@ #include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/descriptor.h> @@ -460,6 +461,10 @@ bool WireFormat::ParseAndMergeMessageSetField(uint32 field_number, } } +static bool StrictUtf8Check(const FieldDescriptor* field) { + return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + bool WireFormat::ParseAndMergeField( uint32 tag, const FieldDescriptor* field, // May be NULL for unknown @@ -632,10 +637,19 @@ bool WireFormat::ParseAndMergeField( // Handle strings separately so that we can optimize the ctype=CORD case. case FieldDescriptor::TYPE_STRING: { + bool strict_utf8_check = StrictUtf8Check(field); string value; if (!WireFormatLite::ReadString(input, &value)) return false; - VerifyUTF8StringNamedField(value.data(), value.length(), PARSE, - field->name().c_str()); + if (strict_utf8_check) { + if (!WireFormatLite::VerifyUtf8String( + value.data(), value.length(), WireFormatLite::PARSE, + field->full_name().c_str())) { + return false; + } + } else { + VerifyUTF8StringNamedField(value.data(), value.length(), PARSE, + field->full_name().c_str()); + } if (field->is_repeated()) { message_reflection->AddString(message, field, value); } else { @@ -893,13 +907,20 @@ void WireFormat::SerializeFieldWithCachedSizes( // Handle strings separately so that we can get string references // instead of copying. case FieldDescriptor::TYPE_STRING: { + bool strict_utf8_check = StrictUtf8Check(field); string scratch; const string& value = field->is_repeated() ? message_reflection->GetRepeatedStringReference( message, field, j, &scratch) : message_reflection->GetStringReference(message, field, &scratch); - VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE, - field->name().c_str()); + if (strict_utf8_check) { + WireFormatLite::VerifyUtf8String(value.data(), value.length(), + WireFormatLite::SERIALIZE, + field->full_name().c_str()); + } else { + VerifyUTF8StringNamedField(value.data(), value.length(), SERIALIZE, + field->full_name().c_str()); + } WireFormatLite::WriteString(field->number(), value, output); break; } @@ -1107,34 +1128,6 @@ int WireFormat::MessageSetItemByteSize( return our_size; } -void WireFormat::VerifyUTF8StringFallback(const char* data, - int size, - Operation op, - const char* field_name) { - if (!IsStructurallyValidUTF8(data, size)) { - const char* operation_str = NULL; - switch (op) { - case PARSE: - operation_str = "parsing"; - break; - case SERIALIZE: - operation_str = "serializing"; - break; - // no default case: have the compiler warn if a case is not covered. - } - 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. "; - } -} - - } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h index 84270fee..941be75b 100644 --- a/src/google/protobuf/wire_format.h +++ b/src/google/protobuf/wire_format.h @@ -231,8 +231,8 @@ class LIBPROTOBUF_EXPORT WireFormat { const Message& message); enum Operation { - PARSE, - SERIALIZE, + PARSE = 0, + SERIALIZE = 1, }; // Verifies that a string field is valid UTF8, logging an error if not. @@ -247,13 +247,6 @@ class LIBPROTOBUF_EXPORT WireFormat { 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, - const char* field_name); - // Skip a MessageSet field. static bool SkipMessageSetField(io::CodedInputStream* input, uint32 field_number, @@ -265,8 +258,6 @@ class LIBPROTOBUF_EXPORT WireFormat { Message* message, io::CodedInputStream* input); - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat); }; @@ -321,7 +312,8 @@ 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, NULL); + WireFormatLite::VerifyUtf8String( + data, size, static_cast<WireFormatLite::Operation>(op), NULL); #else // Avoid the compiler warning about unsued variables. (void)data; (void)size; (void)op; @@ -332,7 +324,8 @@ 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); + WireFormatLite::VerifyUtf8String( + data, size, static_cast<WireFormatLite::Operation>(op), field_name); #endif } diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 2ce4920c..847e3500 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -37,11 +37,14 @@ #include <stack> #include <string> #include <vector> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/stringprintf.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_lite.h> + namespace google { namespace protobuf { namespace internal { @@ -484,9 +487,9 @@ void WireFormatLite::WriteMessageMaybeToArray(int field_number, } } -static inline bool ReadBytesToString(io::CodedInputStream* input, - string* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; -static inline bool ReadBytesToString(io::CodedInputStream* input, +GOOGLE_ATTRIBUTE_ALWAYS_INLINE static bool ReadBytesToString( + io::CodedInputStream* input, string* value); +inline static bool ReadBytesToString(io::CodedInputStream* input, string* value) { uint32 length; return input->ReadVarint32(&length) && @@ -504,6 +507,35 @@ bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string** p) { return ReadBytesToString(input, *p); } +bool WireFormatLite::VerifyUtf8String(const char* data, + int size, + Operation op, + const char* field_name) { + if (!IsStructurallyValidUTF8(data, size)) { + const char* operation_str = NULL; + switch (op) { + case PARSE: + operation_str = "parsing"; + break; + case SERIALIZE: + operation_str = "serializing"; + break; + // no default case: have the compiler warn if a case is not covered. + } + 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. "; + return false; + } + return true; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index ac83abdc..55fc7ecd 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -250,17 +250,17 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // For primitive fields, we just use a templatized routine parameterized by // the represented type and the FieldType. These are specialized with the // appropriate definition for each declared type. - template <typename CType, enum FieldType DeclaredType> - static inline bool ReadPrimitive(input, CType* value) INL; + template <typename CType, enum FieldType DeclaredType> INL + static bool ReadPrimitive(input, CType* value); // Reads repeated primitive values, with optimizations for repeats. // tag_size and tag should both be compile-time constants provided by the // protocol compiler. - template <typename CType, enum FieldType DeclaredType> - static inline bool ReadRepeatedPrimitive(int tag_size, - uint32 tag, - input, - RepeatedField<CType>* value) INL; + template <typename CType, enum FieldType DeclaredType> INL + static bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField<CType>* value); // Identical to ReadRepeatedPrimitive, except will not inline the // implementation. @@ -275,16 +275,14 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // // This is only implemented for the types with fixed wire size, e.g. // float, double, and the (s)fixed* types. - template <typename CType, enum FieldType DeclaredType> - static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, - CType* value) INL; + template <typename CType, enum FieldType DeclaredType> INL + static const uint8* ReadPrimitiveFromArray(const uint8* buffer, CType* value); // Reads a primitive packed field. // // This is only implemented for packable types. - template <typename CType, enum FieldType DeclaredType> - static inline bool ReadPackedPrimitive(input, - RepeatedField<CType>* value) INL; + template <typename CType, enum FieldType DeclaredType> INL + static bool ReadPackedPrimitive(input, RepeatedField<CType>* value); // Identical to ReadPackedPrimitive, except will not inline the // implementation. @@ -318,6 +316,16 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static bool ReadBytes(input, string** p); + enum Operation { + PARSE = 0, + SERIALIZE = 1, + }; + + // Returns true if the data is valid UTF-8. + static bool VerifyUtf8String(const char* data, int size, + Operation op, + const char* field_name); + static inline bool ReadGroup (field_number, input, MessageLite* value); static inline bool ReadMessage(input, MessageLite* value); @@ -344,23 +352,23 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // Write a tag. The Write*() functions typically include the tag, so // normally there's no need to call this unless using the Write*NoTag() // variants. - static inline void WriteTag(field_number, WireType type, output) INL; + INL static void WriteTag(field_number, WireType type, output); // Write fields, without tags. - static inline void WriteInt32NoTag (int32 value, output) INL; - static inline void WriteInt64NoTag (int64 value, output) INL; - static inline void WriteUInt32NoTag (uint32 value, output) INL; - static inline void WriteUInt64NoTag (uint64 value, output) INL; - static inline void WriteSInt32NoTag (int32 value, output) INL; - static inline void WriteSInt64NoTag (int64 value, output) INL; - static inline void WriteFixed32NoTag (uint32 value, output) INL; - static inline void WriteFixed64NoTag (uint64 value, output) INL; - static inline void WriteSFixed32NoTag(int32 value, output) INL; - static inline void WriteSFixed64NoTag(int64 value, output) INL; - static inline void WriteFloatNoTag (float value, output) INL; - static inline void WriteDoubleNoTag (double value, output) INL; - static inline void WriteBoolNoTag (bool value, output) INL; - static inline void WriteEnumNoTag (int value, output) INL; + INL static void WriteInt32NoTag (int32 value, output); + INL static void WriteInt64NoTag (int64 value, output); + INL static void WriteUInt32NoTag (uint32 value, output); + INL static void WriteUInt64NoTag (uint64 value, output); + INL static void WriteSInt32NoTag (int32 value, output); + INL static void WriteSInt64NoTag (int64 value, output); + INL static void WriteFixed32NoTag (uint32 value, output); + INL static void WriteFixed64NoTag (uint64 value, output); + INL static void WriteSFixed32NoTag(int32 value, output); + INL static void WriteSFixed64NoTag(int64 value, output); + INL static void WriteFloatNoTag (float value, output); + INL static void WriteDoubleNoTag (double value, output); + INL static void WriteBoolNoTag (bool value, output); + INL static void WriteEnumNoTag (int value, output); // Write fields, including tags. static void WriteInt32 (field_number, int32 value, output); @@ -410,73 +418,59 @@ class LIBPROTOBUF_EXPORT WireFormatLite { #define output uint8* target // Like above, but use only *ToArray methods of CodedOutputStream. - static inline uint8* WriteTagToArray(field_number, WireType type, output) INL; + INL static uint8* WriteTagToArray(field_number, WireType type, output); // Write fields, without tags. - static inline uint8* WriteInt32NoTagToArray (int32 value, output) INL; - static inline uint8* WriteInt64NoTagToArray (int64 value, output) INL; - static inline uint8* WriteUInt32NoTagToArray (uint32 value, output) INL; - static inline uint8* WriteUInt64NoTagToArray (uint64 value, output) INL; - static inline uint8* WriteSInt32NoTagToArray (int32 value, output) INL; - static inline uint8* WriteSInt64NoTagToArray (int64 value, output) INL; - static inline uint8* WriteFixed32NoTagToArray (uint32 value, output) INL; - static inline uint8* WriteFixed64NoTagToArray (uint64 value, output) INL; - static inline uint8* WriteSFixed32NoTagToArray(int32 value, output) INL; - static inline uint8* WriteSFixed64NoTagToArray(int64 value, output) INL; - static inline uint8* WriteFloatNoTagToArray (float value, output) INL; - static inline uint8* WriteDoubleNoTagToArray (double value, output) INL; - static inline uint8* WriteBoolNoTagToArray (bool value, output) INL; - static inline uint8* WriteEnumNoTagToArray (int value, output) INL; + INL static uint8* WriteInt32NoTagToArray (int32 value, output); + INL static uint8* WriteInt64NoTagToArray (int64 value, output); + INL static uint8* WriteUInt32NoTagToArray (uint32 value, output); + INL static uint8* WriteUInt64NoTagToArray (uint64 value, output); + INL static uint8* WriteSInt32NoTagToArray (int32 value, output); + INL static uint8* WriteSInt64NoTagToArray (int64 value, output); + INL static uint8* WriteFixed32NoTagToArray (uint32 value, output); + INL static uint8* WriteFixed64NoTagToArray (uint64 value, output); + INL static uint8* WriteSFixed32NoTagToArray(int32 value, output); + INL static uint8* WriteSFixed64NoTagToArray(int64 value, output); + INL static uint8* WriteFloatNoTagToArray (float value, output); + INL static uint8* WriteDoubleNoTagToArray (double value, output); + INL static uint8* WriteBoolNoTagToArray (bool value, output); + INL static uint8* WriteEnumNoTagToArray (int value, output); // Write fields, including tags. - static inline uint8* WriteInt32ToArray( - field_number, int32 value, output) INL; - static inline uint8* WriteInt64ToArray( - field_number, int64 value, output) INL; - static inline uint8* WriteUInt32ToArray( - field_number, uint32 value, output) INL; - static inline uint8* WriteUInt64ToArray( - field_number, uint64 value, output) INL; - static inline uint8* WriteSInt32ToArray( - field_number, int32 value, output) INL; - static inline uint8* WriteSInt64ToArray( - field_number, int64 value, output) INL; - static inline uint8* WriteFixed32ToArray( - field_number, uint32 value, output) INL; - static inline uint8* WriteFixed64ToArray( - field_number, uint64 value, output) INL; - static inline uint8* WriteSFixed32ToArray( - field_number, int32 value, output) INL; - static inline uint8* WriteSFixed64ToArray( - field_number, int64 value, output) INL; - static inline uint8* WriteFloatToArray( - field_number, float value, output) INL; - static inline uint8* WriteDoubleToArray( - field_number, double value, output) INL; - static inline uint8* WriteBoolToArray( - field_number, bool value, output) INL; - static inline uint8* WriteEnumToArray( - field_number, int value, output) INL; - - static inline uint8* WriteStringToArray( - field_number, const string& value, output) INL; - static inline uint8* WriteBytesToArray( - field_number, const string& value, output) INL; - - static inline uint8* WriteGroupToArray( - field_number, const MessageLite& value, output) INL; - static inline uint8* WriteMessageToArray( - field_number, const MessageLite& value, output) INL; + INL static uint8* WriteInt32ToArray(field_number, int32 value, output); + INL static uint8* WriteInt64ToArray(field_number, int64 value, output); + INL static uint8* WriteUInt32ToArray(field_number, uint32 value, output); + INL static uint8* WriteUInt64ToArray(field_number, uint64 value, output); + INL static uint8* WriteSInt32ToArray(field_number, int32 value, output); + INL static uint8* WriteSInt64ToArray(field_number, int64 value, output); + INL static uint8* WriteFixed32ToArray(field_number, uint32 value, output); + INL static uint8* WriteFixed64ToArray(field_number, uint64 value, output); + INL static uint8* WriteSFixed32ToArray(field_number, int32 value, output); + INL static uint8* WriteSFixed64ToArray(field_number, int64 value, output); + INL static uint8* WriteFloatToArray(field_number, float value, output); + INL static uint8* WriteDoubleToArray(field_number, double value, output); + INL static uint8* WriteBoolToArray(field_number, bool value, output); + INL static uint8* WriteEnumToArray(field_number, int value, output); + + INL static uint8* WriteStringToArray( + field_number, const string& value, output); + INL static uint8* WriteBytesToArray( + field_number, const string& value, output); + + INL static uint8* WriteGroupToArray( + field_number, const MessageLite& value, output); + INL static uint8* WriteMessageToArray( + field_number, const MessageLite& value, output); // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The // pointer must point at an instance of MessageType, *not* a subclass (or // the subclass must not override SerializeWithCachedSizes()). template<typename MessageType> - static inline uint8* WriteGroupNoVirtualToArray( - field_number, const MessageType& value, output) INL; + INL static uint8* WriteGroupNoVirtualToArray( + field_number, const MessageType& value, output); template<typename MessageType> - static inline uint8* WriteMessageNoVirtualToArray( - field_number, const MessageType& value, output) INL; + INL static uint8* WriteMessageNoVirtualToArray( + field_number, const MessageType& value, output); #undef output #undef input @@ -527,18 +521,17 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // A helper method for the repeated primitive reader. This method has // optimizations for primitive types that have fixed size on the wire, and // can be read using potentially faster paths. - template <typename CType, enum FieldType DeclaredType> - static inline bool ReadRepeatedFixedSizePrimitive( + template <typename CType, enum FieldType DeclaredType> GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static bool ReadRepeatedFixedSizePrimitive( int tag_size, uint32 tag, google::protobuf::io::CodedInputStream* input, - RepeatedField<CType>* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + RepeatedField<CType>* value); // 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; + template <typename CType, enum FieldType DeclaredType> GOOGLE_ATTRIBUTE_ALWAYS_INLINE + static bool ReadPackedFixedSizePrimitive(google::protobuf::io::CodedInputStream* input, + RepeatedField<CType>* value); static const CppType kFieldTypeToCppTypeMap[]; static const WireFormatLite::WireType kWireTypeForFieldType[]; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index d073ff92..991c3d04 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -43,6 +43,7 @@ #include <string> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/message_lite.h> #include <google/protobuf/repeated_field.h> #include <google/protobuf/wire_format_lite.h> diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index aef22b29..15c37556 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -40,8 +40,10 @@ #include <google/protobuf/unittest.pb.h> #include <google/protobuf/unittest_proto3_arena.pb.h> #include <google/protobuf/unittest_mset.pb.h> +#include <google/protobuf/unittest_mset_wire_format.pb.h> #include <google/protobuf/test_util.h> +#include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -419,7 +421,7 @@ const int kUnknownTypeId = 1550055; TEST(WireFormatTest, SerializeMessageSet) { // Set up a TestMessageSet with two known messages and an unknown one. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; message_set.MutableExtension( unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); message_set.MutableExtension( @@ -462,7 +464,7 @@ TEST(WireFormatTest, SerializeMessageSetVariousWaysAreEqual) { // Set up a TestMessageSet with two known messages and an unknown one, as // above. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; message_set.MutableExtension( unittest::TestMessageSetExtension1::message_set_extension)->set_i(123); message_set.MutableExtension( @@ -539,7 +541,7 @@ TEST(WireFormatTest, ParseMessageSet) { ASSERT_TRUE(raw.SerializeToString(&data)); // Parse as a TestMessageSet and check the contents. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; ASSERT_TRUE(message_set.ParseFromString(data)); EXPECT_EQ(123, message_set.GetExtension( @@ -553,7 +555,7 @@ TEST(WireFormatTest, ParseMessageSet) { EXPECT_EQ("bar", message_set.unknown_fields().field(0).length_delimited()); // Also parse using WireFormat. - unittest::TestMessageSet dynamic_message_set; + proto2_wireformat_unittest::TestMessageSet dynamic_message_set; io::CodedInputStream input(reinterpret_cast<const uint8*>(data.data()), data.size()); ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &dynamic_message_set)); @@ -583,7 +585,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { coded_output.WriteTag(WireFormatLite::kMessageSetItemEndTag); } { - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; ASSERT_TRUE(message_set.ParseFromString(data)); EXPECT_EQ(123, message_set.GetExtension( @@ -591,7 +593,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { } { // Test parse the message via Reflection. - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; io::CodedInputStream input( reinterpret_cast<const uint8*>(data.data()), data.size()); EXPECT_TRUE(WireFormat::ParseAndMergePartial(&input, &message_set)); @@ -603,7 +605,7 @@ TEST(WireFormatTest, ParseMessageSetWithReverseTagOrder) { } TEST(WireFormatTest, ParseBrokenMessageSet) { - unittest::TestMessageSet message_set; + proto2_wireformat_unittest::TestMessageSet message_set; string input("goodbye"); // Invalid wire format data. EXPECT_FALSE(message_set.ParseFromString(input)); } diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index db75db15..b2a7e970 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -262,9 +262,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() { "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013" "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022" "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001" - " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BM\n\023com" - ".google.protobufB\rWrappersProtoP\001\242\002\003GPB\252" - "\002\036Google.Protobuf.WellKnownTypesb\006proto3", 400); + " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BP\n\023com" + ".google.protobufB\rWrappersProtoP\001\240\001\001\242\002\003G" + "PB\252\002\036Google.Protobuf.WellKnownTypesb\006pro" + "to3", 403); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/wrappers.proto", &protobuf_RegisterTypes); DoubleValue::default_instance_ = new DoubleValue(); @@ -1967,10 +1968,10 @@ bool StringValue::MergePartialFromCodedStream( if (tag == 10) { DO_(::google::protobuf::internal::WireFormatLite::ReadString( input, this->mutable_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->value().data(), this->value().length(), - ::google::protobuf::internal::WireFormat::PARSE, - "google.protobuf.StringValue.value"); + ::google::protobuf::internal::WireFormatLite::PARSE, + "google.protobuf.StringValue.value")); } else { goto handle_unusual; } @@ -2004,9 +2005,9 @@ void StringValue::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_start:google.protobuf.StringValue) // optional string value = 1; if (this->value().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->value().data(), this->value().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.StringValue.value"); ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 1, this->value(), output); @@ -2020,9 +2021,9 @@ void StringValue::SerializeWithCachedSizes( // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue) // optional string value = 1; if (this->value().size() > 0) { - ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( this->value().data(), this->value().length(), - ::google::protobuf::internal::WireFormat::SERIALIZE, + ::google::protobuf::internal::WireFormatLite::SERIALIZE, "google.protobuf.StringValue.value"); target = ::google::protobuf::internal::WireFormatLite::WriteStringToArray( diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index 387ebd7c..15bcc7a2 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -37,15 +37,15 @@ void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto(); void protobuf_AssignDesc_google_2fprotobuf_2fwrappers_2eproto(); void protobuf_ShutdownFile_google_2fprotobuf_2fwrappers_2eproto(); +class BoolValue; +class BytesValue; class DoubleValue; class FloatValue; -class Int64Value; -class UInt64Value; class Int32Value; -class UInt32Value; -class BoolValue; +class Int64Value; class StringValue; -class BytesValue; +class UInt32Value; +class UInt64Value; // =================================================================== diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index 6d3181bf..a1d6e446 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -37,62 +37,80 @@ syntax = "proto3"; package google.protobuf; +option java_generate_equals_and_hash = true; option java_multiple_files = true; option java_outer_classname = "WrappersProto"; option java_package = "com.google.protobuf"; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option objc_class_prefix = "GPB"; - -// Wrapper message for double. +// Wrapper message for `double`. +// +// The JSON representation for `DoubleValue` is JSON number. message DoubleValue { // The double value. double value = 1; } -// Wrapper message for float. +// Wrapper message for `float`. +// +// The JSON representation for `FloatValue` is JSON number. message FloatValue { // The float value. float value = 1; } -// Wrapper message for int64. +// Wrapper message for `int64`. +// +// The JSON representation for `Int64Value` is JSON string. message Int64Value { // The int64 value. int64 value = 1; } -// Wrapper message for uint64. +// Wrapper message for `uint64`. +// +// The JSON representation for `UInt64Value` is JSON string. message UInt64Value { // The uint64 value. uint64 value = 1; } -// Wrapper message for int32. +// Wrapper message for `int32`. +// +// The JSON representation for `Int32Value` is JSON number. message Int32Value { // The int32 value. int32 value = 1; } -// Wrapper message for uint32. +// Wrapper message for `uint32`. +// +// The JSON representation for `UInt32Value` is JSON number. message UInt32Value { // The uint32 value. uint32 value = 1; } -// Wrapper message for bool. +// Wrapper message for `bool`. +// +// The JSON representation for `BoolValue` is JSON `true` and `false`. message BoolValue { // The bool value. bool value = 1; } -// Wrapper message for string. +// Wrapper message for `string`. +// +// The JSON representation for `StringValue` is JSON string. message StringValue { // The string value. string value = 1; } -// Wrapper message for bytes. +// Wrapper message for `bytes`. +// +// The JSON representation for `BytesValue` is JSON string. message BytesValue { // The bytes value. bytes value = 1; |