From b0f661181d10bddc08e380992590a1cdd92be92b Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 21 Aug 2015 11:18:45 -0700 Subject: [PATCH] Down-integrate from internal branch. Change-Id: Ieb7a2c2fbf35bc2a8fa65b915a5ecb68c83863e4 --- appveyor.yml | 68 +- cmake/extract_includes.bat.in | 2 + cmake/libprotobuf-lite.cmake | 1 + cmake/libprotobuf.cmake | 2 + cmake/libprotoc.cmake | 1 + cmake/tests.cmake | 6 + java/pom.xml | 1 + .../internal/message_set_extensions.proto | 66 ++ .../protobuf/internal/packed_field_test.proto | 0 python/setup.py | 6 + src/Makefile.am | 31 +- src/google/protobuf/any.proto | 10 +- src/google/protobuf/api.pb.cc | 601 +++++++++++++++++- src/google/protobuf/api.pb.h | 275 +++++++- src/google/protobuf/api.proto | 107 +++- .../protobuf/compiler/java/java_enum_lite.cc | 0 .../protobuf/compiler/java/java_enum_lite.h | 0 src/google/protobuf/duration.proto | 1 + src/google/protobuf/empty.pb.cc | 4 +- src/google/protobuf/empty.proto | 11 +- src/google/protobuf/field_mask.pb.cc | 5 +- src/google/protobuf/field_mask.proto | 8 +- src/google/protobuf/source_context.pb.cc | 4 +- src/google/protobuf/source_context.proto | 6 +- src/google/protobuf/struct.proto | 28 +- src/google/protobuf/stubs/common.cc | 63 +- src/google/protobuf/stubs/common.h | 24 + src/google/protobuf/stubs/hash.h | 15 + src/google/protobuf/stubs/int128.cc | 200 ++++++ src/google/protobuf/stubs/int128.h | 381 +++++++++++ src/google/protobuf/stubs/int128_unittest.cc | 513 +++++++++++++++ src/google/protobuf/stubs/logging.h | 4 +- src/google/protobuf/stubs/port.h | 12 +- .../protobuf/stubs/structurally_valid.cc | 52 ++ src/google/protobuf/timestamp.proto | 11 +- src/google/protobuf/type.pb.cc | 294 ++++++++- src/google/protobuf/type.pb.h | 125 ++++ src/google/protobuf/type.proto | 102 ++- .../protobuf/unittest_mset_wire_format.proto | 52 ++ .../protobuf/unittest_no_arena_lite.proto | 42 ++ src/google/protobuf/util/field_mask_util.cc | 418 ++++++++++++ src/google/protobuf/util/field_mask_util.h | 146 +++++ .../protobuf/util/field_mask_util_test.cc | 395 ++++++++++++ .../util/internal/testdata/oneofs.proto | 68 ++ src/google/protobuf/util/time_util.cc | 525 +++++++++++++++ src/google/protobuf/util/time_util.h | 287 +++++++++ src/google/protobuf/util/time_util_test.cc | 380 +++++++++++ src/google/protobuf/wrappers.pb.cc | 6 +- src/google/protobuf/wrappers.proto | 40 +- update_file_lists.sh | 28 +- 50 files changed, 5186 insertions(+), 241 deletions(-) create mode 100644 python/google/protobuf/internal/message_set_extensions.proto create mode 100644 python/google/protobuf/internal/packed_field_test.proto create mode 100644 src/google/protobuf/compiler/java/java_enum_lite.cc create mode 100644 src/google/protobuf/compiler/java/java_enum_lite.h create mode 100644 src/google/protobuf/stubs/int128.cc create mode 100644 src/google/protobuf/stubs/int128.h create mode 100644 src/google/protobuf/stubs/int128_unittest.cc create mode 100644 src/google/protobuf/unittest_mset_wire_format.proto create mode 100644 src/google/protobuf/unittest_no_arena_lite.proto create mode 100644 src/google/protobuf/util/field_mask_util.cc create mode 100644 src/google/protobuf/util/field_mask_util.h create mode 100644 src/google/protobuf/util/field_mask_util_test.cc create mode 100644 src/google/protobuf/util/internal/testdata/oneofs.proto create mode 100644 src/google/protobuf/util/time_util.cc create mode 100644 src/google/protobuf/util/time_util.h create mode 100644 src/google/protobuf/util/time_util_test.cc diff --git a/appveyor.yml b/appveyor.yml index 476a11790fcee..d49086544d0bd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,34 +1,34 @@ -# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can -# test more combinations but AppVeyor just takes too long to finish (each -# combination takes ~15mins). -platform: - - Win64 - -configuration: - - Debug - -environment: - matrix: - - BUILD_DLL: ON - -install: - - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip - - 7z x gmock-1.7.0.zip - - rename gmock-1.7.0 gmock - -before_build: - - if %platform%==Win32 set generator=Visual Studio 12 - - if %platform%==Win64 set generator=Visual Studio 12 Win64 - - if %platform%==Win32 set vcplatform=Win32 - - if %platform%==Win64 set vcplatform=x64 - -build_script: - - mkdir build_msvc - - cd build_msvc - - cmake -G "%generator%" -DBUILD_SHARED_LIBS=%BUILD_DLL% ../cmake - - msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" - - cd %configuration% - - tests.exe - -skip_commits: - message: /.*\[skip appveyor\].*/ +# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can +# test more combinations but AppVeyor just takes too long to finish (each +# combination takes ~15mins). +platform: + - Win64 + +configuration: + - Debug + +environment: + matrix: + - BUILD_DLL: ON + +install: + - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip + - 7z x gmock-1.7.0.zip + - rename gmock-1.7.0 gmock + +before_build: + - if %platform%==Win32 set generator=Visual Studio 12 + - if %platform%==Win64 set generator=Visual Studio 12 Win64 + - if %platform%==Win32 set vcplatform=Win32 + - if %platform%==Win64 set vcplatform=x64 + +build_script: + - mkdir build_msvc + - cd build_msvc + - cmake -G "%generator%" -DBUILD_SHARED_LIBS=%BUILD_DLL% ../cmake + - msbuild protobuf.sln /p:Platform=%vcplatform% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + - cd %configuration% + - tests.exe + +skip_commits: + message: /.*\[skip appveyor\].*/ diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in index 99ab50a94a812..25c60b17f1435 100644 --- a/cmake/extract_includes.bat.in +++ b/cmake/extract_includes.bat.in @@ -109,8 +109,10 @@ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.pb.h include copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.pb.h include\google\protobuf\type.pb.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\unknown_field_set.h include\google\protobuf\unknown_field_set.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_comparator.h include\google\protobuf\util\field_comparator.h +copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_mask_util.h include\google\protobuf\util\field_mask_util.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\json_util.h include\google\protobuf\util\json_util.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\message_differencer.h include\google\protobuf\util\message_differencer.h +copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\time_util.h include\google\protobuf\util\time_util.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver.h include\google\protobuf\util\type_resolver.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\type_resolver_util.h include\google\protobuf\util\type_resolver_util.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\wire_format.h include\google\protobuf\wire_format.h diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake index db55ea92fd10e..9b14d4ccef581 100644 --- a/cmake/libprotobuf-lite.cmake +++ b/cmake/libprotobuf-lite.cmake @@ -12,6 +12,7 @@ set(libprotobuf_lite_files ${protobuf_source_dir}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc ${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.cc ${protobuf_source_dir}/src/google/protobuf/stubs/common.cc + ${protobuf_source_dir}/src/google/protobuf/stubs/int128.cc ${protobuf_source_dir}/src/google/protobuf/stubs/once.cc ${protobuf_source_dir}/src/google/protobuf/stubs/status.cc ${protobuf_source_dir}/src/google/protobuf/stubs/statusor.cc diff --git a/cmake/libprotobuf.cmake b/cmake/libprotobuf.cmake index 53ba3d3effa99..49a12f7d211e4 100644 --- a/cmake/libprotobuf.cmake +++ b/cmake/libprotobuf.cmake @@ -32,6 +32,7 @@ set(libprotobuf_files ${protobuf_source_dir}/src/google/protobuf/type.pb.cc ${protobuf_source_dir}/src/google/protobuf/unknown_field_set.cc ${protobuf_source_dir}/src/google/protobuf/util/field_comparator.cc + ${protobuf_source_dir}/src/google/protobuf/util/field_mask_util.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/datapiece.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/default_value_objectwriter.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/error_listener.cc @@ -47,6 +48,7 @@ set(libprotobuf_files ${protobuf_source_dir}/src/google/protobuf/util/internal/utility.cc ${protobuf_source_dir}/src/google/protobuf/util/json_util.cc ${protobuf_source_dir}/src/google/protobuf/util/message_differencer.cc + ${protobuf_source_dir}/src/google/protobuf/util/time_util.cc ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util.cc ${protobuf_source_dir}/src/google/protobuf/wire_format.cc ${protobuf_source_dir}/src/google/protobuf/wrappers.pb.cc diff --git a/cmake/libprotoc.cmake b/cmake/libprotoc.cmake index 8caa9e9e83ba9..aaed4863382bb 100644 --- a/cmake/libprotoc.cmake +++ b/cmake/libprotoc.cmake @@ -34,6 +34,7 @@ set(libprotoc_files ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_field_lite.cc + ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum_lite.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_extension.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_field.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_file.cc diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 16c94933f8a13..921510873734e 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -21,6 +21,7 @@ set(lite_test_protos google/protobuf/unittest_import_lite.proto google/protobuf/unittest_import_public_lite.proto google/protobuf/unittest_lite.proto + google/protobuf/unittest_no_arena_lite.proto ) set(tests_protos @@ -40,6 +41,7 @@ set(tests_protos google/protobuf/unittest_import_public.proto google/protobuf/unittest_lite_imports_nonlite.proto google/protobuf/unittest_mset.proto + google/protobuf/unittest_mset_wire_format.proto google/protobuf/unittest_no_arena.proto google/protobuf/unittest_no_arena_import.proto google/protobuf/unittest_no_field_presence.proto @@ -55,6 +57,7 @@ set(tests_protos 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 @@ -134,6 +137,7 @@ set(tests_files ${protobuf_source_dir}/src/google/protobuf/repeated_field_unittest.cc ${protobuf_source_dir}/src/google/protobuf/stubs/bytestream_unittest.cc ${protobuf_source_dir}/src/google/protobuf/stubs/common_unittest.cc + ${protobuf_source_dir}/src/google/protobuf/stubs/int128_unittest.cc ${protobuf_source_dir}/src/google/protobuf/stubs/once_unittest.cc ${protobuf_source_dir}/src/google/protobuf/stubs/status_test.cc ${protobuf_source_dir}/src/google/protobuf/stubs/statusor_test.cc @@ -147,6 +151,7 @@ set(tests_files ${protobuf_source_dir}/src/google/protobuf/text_format_unittest.cc ${protobuf_source_dir}/src/google/protobuf/unknown_field_set_unittest.cc ${protobuf_source_dir}/src/google/protobuf/util/field_comparator_test.cc + ${protobuf_source_dir}/src/google/protobuf/util/field_mask_util_test.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/default_value_objectwriter_test.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/json_objectwriter_test.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -154,6 +159,7 @@ set(tests_files ${protobuf_source_dir}/src/google/protobuf/util/internal/protostream_objectwriter_test.cc ${protobuf_source_dir}/src/google/protobuf/util/internal/type_info_test_helper.cc ${protobuf_source_dir}/src/google/protobuf/util/json_util_test.cc + ${protobuf_source_dir}/src/google/protobuf/util/time_util_test.cc ${protobuf_source_dir}/src/google/protobuf/util/type_resolver_util_test.cc ${protobuf_source_dir}/src/google/protobuf/well_known_types_unittest.cc ${protobuf_source_dir}/src/google/protobuf/wire_format_unittest.cc diff --git a/java/pom.xml b/java/pom.xml index 6877ac27ec329..fb7e4168e95f7 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -114,6 +114,7 @@ + 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,23 +140,29 @@ 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.OptionB\'\n\023com.google.p" - "rotobufB\010ApiProtoP\001\242\002\003GPBb\006proto3", 513); + "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(\tB*\n\023com.google.pr" + "otobufB\010ApiProtoP\001\240\001\001\242\002\003GPBb\006proto3", 675); ::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); } @@ -159,6 +191,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() @@ -187,6 +221,7 @@ void Api::SharedCtor() { name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); version_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Api::~Api() { @@ -232,8 +267,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( @@ -321,6 +358,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; } @@ -387,6 +457,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) } @@ -436,6 +518,19 @@ ::google::protobuf::uint8* Api::SerializeWithCachedSizesToArray( 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; } @@ -464,6 +559,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++) { @@ -480,6 +581,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(); @@ -502,6 +611,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_); @@ -513,6 +623,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) { @@ -542,6 +655,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_); } @@ -740,6 +855,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(); +} + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& +Api::mixins() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins) + return mixins_; +} + ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* +Api::mutable_mixins() { + // @@protoc_insertion_point(field_mutable_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 // =================================================================== @@ -751,6 +910,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() @@ -780,6 +940,7 @@ void Method::SharedCtor() { request_streaming_ = false; response_type_url_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); response_streaming_ = false; + syntax_ = 0; } Method::~Method() { @@ -829,7 +990,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()); @@ -943,6 +1104,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; } @@ -1017,6 +1194,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) } @@ -1073,6 +1256,12 @@ ::google::protobuf::uint8* Method::SerializeWithCachedSizesToArray( 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; } @@ -1111,6 +1300,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++) { @@ -1158,6 +1353,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) { @@ -1188,6 +1386,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_); } @@ -1390,6 +1589,388 @@ Method::mutable_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())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::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())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormat::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::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::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::WireFormat::VerifyUTF8StringNamedField( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormat::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::WireFormat::VerifyUTF8StringNamedField( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::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::WireFormat::VerifyUTF8StringNamedField( + this->root().data(), this->root().length(), + ::google::protobuf::internal::WireFormat::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( + &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(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(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 // @@protoc_insertion_point(namespace_scope) diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 985adc5d5ddd8..414734a91fcba 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; // =================================================================== @@ -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(); + const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& + mixins() const; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* + mutable_mixins(); + + // 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(); @@ -288,6 +309,12 @@ class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + // 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_; +}; // =================================================================== @@ -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 const ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >& +Api::mixins() const { + // @@protoc_insertion_point(field_list:google.protobuf.Api.mixins) + return mixins_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::Mixin >* +Api::mutable_mixins() { + // @@protoc_insertion_point(field_mutable_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 @@ -689,9 +856,115 @@ Method::mutable_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(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(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 f368c24d0a906..41cd5131b2bcd 100644 --- a/src/google/protobuf/api.proto +++ b/src/google/protobuf/api.proto @@ -34,14 +34,15 @@ 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 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; @@ -73,18 +74,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; @@ -102,4 +107,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/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc new file mode 100644 index 0000000000000..e69de29bb2d1d 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 0000000000000..e69de29bb2d1d diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index e466341aed3f6..e2662abca9db0 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/empty.pb.cc b/src/google/protobuf/empty.pb.cc index 1a9a6661a1d67..319279c9149aa 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -79,8 +79,8 @@ void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\033google/protobuf/empty.proto\022\017google.pr" - "otobuf\"\007\n\005EmptyB)\n\023com.google.protobufB\n" - "EmptyProtoP\001\242\002\003GPBb\006proto3", 106); + "otobuf\"\007\n\005EmptyB,\n\023com.google.protobufB\n" + "EmptyProtoP\001\240\001\001\242\002\003GPBb\006proto3", 109); ::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 94df0397145d6..e0ff94b6465be 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -31,12 +31,12 @@ syntax = "proto3"; package google.protobuf; -option java_multiple_files = true; -option java_outer_classname = "EmptyProto"; option java_package = "com.google.protobuf"; +option java_outer_classname = "EmptyProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; 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: @@ -45,6 +45,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/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index 68314fd3161a2..8a6de0fa2d15e 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -81,8 +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" - "F\n\023com.google.protobufB\016FieldMaskProtoP\001" - "\242\002\003GPB\252\002\026Google.ProtocolBuffersb\006proto3", 159); + "I\n\023com.google.protobufB\016FieldMaskProtoP\001" + "\240\001\001\242\002\003GPB\252\002\026Google.ProtocolBuffersb\006prot" + "o3", 162); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/field_mask.proto", &protobuf_RegisterTypes); FieldMask::default_instance_ = new FieldMask(); diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index 35b1acc341852..4d06fef6968ac 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 csharp_namespace = "Google.ProtocolBuffers"; +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.ProtocolBuffers"; 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/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index 3b3799a9d507d..6d89845b182de 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -81,8 +81,8 @@ 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(\tB1\n\023com.google.protobufB\022Sour" - "ceContextProtoP\001\242\002\003GPBb\006proto3", 150); + "_name\030\001 \001(\tB4\n\023com.google.protobufB\022Sour" + "ceContextProtoP\001\240\001\001\242\002\003GPBb\006proto3", 153); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/source_context.proto", &protobuf_RegisterTypes); SourceContext::default_instance_ = new SourceContext(); diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto index 2c8a17a868aa1..5d46ebdaf59de 100644 --- a/src/google/protobuf/source_context.proto +++ b/src/google/protobuf/source_context.proto @@ -31,12 +31,12 @@ syntax = "proto3"; package google.protobuf; -option java_multiple_files = true; -option java_outer_classname = "SourceContextProto"; option java_package = "com.google.protobuf"; +option java_outer_classname = "SourceContextProto"; +option java_multiple_files = true; +option java_generate_equals_and_hash = true; 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.proto b/src/google/protobuf/struct.proto index cd10273192915..87783feac690f 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 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 d470fc7265c11..54dbafab5dcac 100644 --- a/src/google/protobuf/stubs/common.cc +++ b/src/google/protobuf/stubs/common.cc @@ -35,8 +35,10 @@ #include #include #include -#include +#include #include +#include +#include #include #ifdef _WIN32 @@ -48,6 +50,9 @@ #else #error "No suitable threading library available." #endif +#if defined(__ANDROID__) +#include +#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 de866e149f9ea..88e7084fcdeda 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 #include #include @@ -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 9a6b217adbfaf..0d94ad80d2206 100755 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -143,6 +143,21 @@ # define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set #endif +#ifndef GOOGLE_PROTOBUF_HASH_NAMESPACE +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END +#elif !defined(GOOGLE_PROTOBUF_HAS_CXX11_HASH) && \ + defined(GOOGLE_PROTOBUF_HAS_TR1) +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ + namespace std { \ + namespace tr1 { +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END }} +#else +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_START \ + namespace GOOGLE_PROTOBUF_HASH_NAMESPACE { +# define GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END } +#endif + #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 0000000000000..9f4fb82489f67 --- /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 + +#include +#include // NOLINT(readability/streams) +#include + +namespace google { +namespace protobuf { + +const uint128_pod kuint128max = { + static_cast(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)), + static_cast(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(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 0000000000000..1e63037f0a67e --- /dev/null +++ b/src/google/protobuf/stubs/int128.h @@ -0,0 +1,381 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifndef GOOGLE_PROTOBUF_STUBS_INT128_H_ +#define GOOGLE_PROTOBUF_STUBS_INT128_H_ + +#include + +#include + +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 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. + 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; +}; + +extern const uint128_pod kuint128max; + +// allow uint128 to be logged +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((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 0000000000000..5d33292ccc89e --- /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 + +#include +#include +#include + +#include +#include + +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(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:. + 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::value); + EXPECT_TRUE(std::is_trivially_copy_assignable::value); + EXPECT_TRUE(std::is_trivially_destructible::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 330d33d2fda62..3108db8c89922 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/port.h b/src/google/protobuf/stubs/port.h index c86cf35be2f2a..7d84b92fe6fb1 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/structurally_valid.cc b/src/google/protobuf/stubs/structurally_valid.cc index 0f6afe6dc8e11..d79a6ee45007c 100644 --- a/src/google/protobuf/stubs/structurally_valid.cc +++ b/src/google/protobuf/stubs/structurally_valid.cc @@ -3,6 +3,8 @@ #include +#include + 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(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/timestamp.proto b/src/google/protobuf/timestamp.proto index 381ff997ec53e..ac2a482512c27 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.ProtocolBuffers"; 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 8b08909e75cdf..7e8ffa9eb8d8a 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,42 @@ 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.AnyB(\n\023com.g" - "oogle.protobufB\tTypeProtoP\001\242\002\003GPBb\006proto" - "3", 1321); + "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\001B+\n\023" + "com.google.protobufB\tTypeProtoP\001\240\001\001\242\002\003GP" + "Bb\006proto3", 1489); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/type.proto", &protobuf_RegisterTypes); Type::default_instance_ = new Type(); @@ -245,6 +254,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 +287,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 +315,7 @@ void Type::SharedCtor() { _cached_size_ = 0; name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Type::~Type() { @@ -334,6 +359,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(); @@ -427,6 +453,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; } @@ -493,6 +535,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) } @@ -541,6 +589,12 @@ ::google::protobuf::uint8* Type::SerializeWithCachedSizesToArray( 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 +616,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 +675,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 +707,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_); } @@ -853,6 +917,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 +951,7 @@ bool Field_Kind_IsValid(int value) { case 7: case 8: case 9: + case 10: case 11: case 12: case 13: @@ -898,6 +977,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 +1024,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 +1056,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 +1067,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 +1111,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_ @@ -1168,6 +1252,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())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.Field.json_name"); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -1249,6 +1350,16 @@ void Field::SerializeWithCachedSizes( 9, this->options(i), output); } + // optional string json_name = 10; + if (this->json_name().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.Field.json_name"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 10, this->json_name(), output); + } + // @@protoc_insertion_point(serialize_end:google.protobuf.Field) } @@ -1311,6 +1422,17 @@ ::google::protobuf::uint8* Field::SerializeWithCachedSizesToArray( 9, this->options(i), target); } + // optional string json_name = 10; + if (this->json_name().size() > 0) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->json_name().data(), this->json_name().length(), + ::google::protobuf::internal::WireFormat::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 +1485,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 +1544,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 +1580,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_); } @@ -1648,6 +1782,49 @@ Field::mutable_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(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 +1834,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 +1862,7 @@ void Enum::SharedCtor() { _cached_size_ = 0; name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); source_context_ = NULL; + syntax_ = 0; } Enum::~Enum() { @@ -1727,6 +1906,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(); } @@ -1799,6 +1979,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; } @@ -1855,6 +2051,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) } @@ -1893,6 +2095,12 @@ ::google::protobuf::uint8* Enum::SerializeWithCachedSizesToArray( 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 +2122,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 +2173,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 +2204,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_); } @@ -2142,6 +2360,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 // =================================================================== diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index c9952efa8e251..0d0aa2fc369d9 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -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_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_descriptor(), name, value); +} // =================================================================== class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message { @@ -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; @@ -430,6 +460,17 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { ::google::protobuf::RepeatedPtrField< ::google::protobuf::Option >* mutable_options(); + // 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(); @@ -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(); @@ -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 @@ -1158,6 +1221,49 @@ Field::mutable_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(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) +} + // ------------------------------------------------------------------- // Enum @@ -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 @@ -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 ace5d995a4b48..d6b018254df97 100644 --- a/src/google/protobuf/type.proto +++ b/src/google/protobuf/type.proto @@ -34,29 +34,26 @@ 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 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. @@ -64,125 +61,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; } @@ -191,7 +162,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_wire_format.proto b/src/google/protobuf/unittest_mset_wire_format.proto new file mode 100644 index 0000000000000..04e4352e06d3e --- /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 0000000000000..34c7b7ce99a95 --- /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/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc new file mode 100644 index 0000000000000..82034bd412275 --- /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 + +#include +#include + +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 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 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::iterator it = children.begin(); + it != children.end(); ++it) { + delete it->second; + } + children.clear(); + } + + map 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::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 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 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::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::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 0000000000000..c99c34f87fa65 --- /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 + +#include +#include + +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 + static bool IsValidPath(const string& path) { + return InternalIsValidPath(T::descriptor(), path); + } + + // Checks whether the given FieldMask is valid for type T. + template + 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 + static void AddPathToFieldMask(const string& path, FieldMask* mask) { + GOOGLE_CHECK(IsValidPath(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 + 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 0000000000000..a9523250bdd60 --- /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 + +#include +#include +#include +#include + +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("optional_int32")); + EXPECT_FALSE(FieldMaskUtil::IsValidPath("optional_nonexist")); + EXPECT_TRUE( + FieldMaskUtil::IsValidPath("optional_nested_message.bb")); + EXPECT_FALSE(FieldMaskUtil::IsValidPath( + "optional_nested_message.nonexist")); + // FieldMask cannot be used to specify sub-fields of a repeated message. + EXPECT_FALSE( + FieldMaskUtil::IsValidPath("repeated_nested_message.bb")); +} + +TEST(FieldMaskUtilTest, TestIsValidFieldMask) { + FieldMask mask; + FieldMaskUtil::FromString("optional_int32,optional_nested_message.bb", &mask); + EXPECT_TRUE(FieldMaskUtil::IsValidFieldMask(mask)); + + FieldMaskUtil::FromString( + "optional_int32,optional_nested_message.bb,optional_nonexist", &mask); + EXPECT_FALSE(FieldMaskUtil::IsValidFieldMask(mask)); +} + +TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) { + FieldMask mask; + FieldMaskUtil::GetFieldMaskForAllFields(&mask); + EXPECT_EQ(1, mask.paths_size()); + EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); + + FieldMaskUtil::GetFieldMaskForAllFields(&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/testdata/oneofs.proto b/src/google/protobuf/util/internal/testdata/oneofs.proto new file mode 100644 index 0000000000000..5bc9fa084d1d1 --- /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/time_util.cc b/src/google/protobuf/util/time_util.cc new file mode 100644 index 0000000000000..c782d691a874b --- /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 + +#include +#include +#include +#include +#include +#include + +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 +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(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(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(seconds, nanos); + return true; +} + +Timestamp TimeUtil::GetCurrentTime() { + int64 seconds; + int32 nanos; + CurrentTime(&seconds, &nanos); + return CreateNormalized(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(nanos)); + return true; +} + +Duration TimeUtil::NanosecondsToDuration(int64 nanos) { + return CreateNormalized(nanos / kNanosPerSecond, + nanos % kNanosPerSecond); +} + +Duration TimeUtil::MicrosecondsToDuration(int64 micros) { + return CreateNormalized( + micros / kMicrosPerSecond, + (micros % kMicrosPerSecond) * kNanosPerMicrosecond); +} + +Duration TimeUtil::MillisecondsToDuration(int64 millis) { + return CreateNormalized( + millis / kMillisPerSecond, + (millis % kMillisPerSecond) * kNanosPerMillisecond); +} + +Duration TimeUtil::SecondsToDuration(int64 seconds) { + return CreateNormalized(seconds, 0); +} + +Duration TimeUtil::MinutesToDuration(int64 minutes) { + return CreateNormalized(minutes * kSecondsPerMinute, 0); +} + +Duration TimeUtil::HoursToDuration(int64 hours) { + return CreateNormalized(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(nanos / kNanosPerSecond, + nanos % kNanosPerSecond); +} + +Timestamp TimeUtil::MicrosecondsToTimestamp(int64 micros) { + return CreateNormalized( + micros / kMicrosPerSecond, + micros % kMicrosPerSecond * kNanosPerMicrosecond); +} + +Timestamp TimeUtil::MillisecondsToTimestamp(int64 millis) { + return CreateNormalized( + millis / kMillisPerSecond, + millis % kMillisPerSecond * kNanosPerMillisecond); +} + +Timestamp TimeUtil::SecondsToTimestamp(int64 seconds) { + return CreateNormalized(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(static_cast(value), 0); +} + +time_t TimeUtil::TimestampToTimeT(const Timestamp& value) { + return static_cast(value.seconds()); +} + +Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) { + return CreateNormalized(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(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(-value.seconds()); + *result = *result * kNanosPerSecond - static_cast(value.nanos()); + } else { + *negative = false; + *result = static_cast(value.seconds()); + *result = *result * kNanosPerSecond + static_cast(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(-value.seconds()); + *result = *result * kNanosPerSecond + static_cast(-value.nanos()); + } else { + *negative = false; + *result = static_cast(value.seconds()); + *result = *result * kNanosPerSecond + static_cast(value.nanos()); + } +} + +void ToTimestamp(const uint128& value, bool negative, Timestamp* timestamp) { + int64 seconds = static_cast(Uint128Low64(value / kNanosPerSecond)); + int32 nanos = static_cast(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(Uint128Low64(value / kNanosPerSecond)); + int32 nanos = static_cast(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(d1.seconds() + d2.seconds(), + d1.nanos() + d2.nanos()); + return d1; +} + +Duration& operator-=(Duration& d1, const Duration& d2) { // NOLINT + d1 = CreateNormalized(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(r); + } else { + negative = !negative; + value *= static_cast(-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(result); + int32 nanos = static_cast((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(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(r); + } else { + negative = !negative; + value /= static_cast(-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(t.seconds() + d.seconds(), + t.nanos() + d.nanos()); + return t; +} + +Timestamp& operator-=(Timestamp& t, const Duration& d) { // NOLINT + t = CreateNormalized(t.seconds() - d.seconds(), + t.nanos() - d.nanos()); + return t; +} + +Duration operator-(const Timestamp& t1, const Timestamp& t2) { + return CreateNormalized(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 0000000000000..112681572810d --- /dev/null +++ b/src/google/protobuf/util/time_util.h @@ -0,0 +1,287 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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 + +#include +#include +#include + +#include +#include + +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); + + // 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. +Duration& operator+=(Duration& d1, const Duration& d2); // NOLINT +Duration& operator-=(Duration& d1, const Duration& d2); // NOLINT +Duration& operator*=(Duration& d, int64 r); // NOLINT +Duration& operator*=(Duration& d, double r); // NOLINT +Duration& operator/=(Duration& d, int64 r); // NOLINT +Duration& operator/=(Duration& d, double r); // NOLINT +// Overload for other integer types. +template +Duration& operator*=(Duration& d, T r) { // NOLINT + int64 x = r; + return d *= x; +} +template +Duration& operator/=(Duration& d, T r) { // NOLINT + int64 x = r; + return d /= x; +} +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 +inline Duration operator*(Duration d, T r) { + return d *= r; +} +template +inline Duration operator*(T r, Duration d) { + return d *= r; +} +template +inline Duration operator/(Duration d, T r) { + return d /= r; +} +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. +Timestamp& operator+=(Timestamp& t, const Duration& d); // NOLINT +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; +} +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 0000000000000..285740abe1e6e --- /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 + +#include + +#include +#include +#include +#include + +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/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index ffc77f1c2f056..69e031a3b7d2b 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -262,9 +262,9 @@ 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(\014BE\n\023com" - ".google.protobufB\rWrappersProtoP\001\242\002\003GPB\252" - "\002\026Google.ProtocolBuffersb\006proto3", 392); + " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BH\n\023com" + ".google.protobufB\rWrappersProtoP\001\240\001\001\242\002\003G" + "PB\252\002\026Google.ProtocolBuffersb\006proto3", 395); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/wrappers.proto", &protobuf_RegisterTypes); DoubleValue::default_instance_ = new DoubleValue(); diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index a13e6edbc1b24..f313a8a89c117 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -37,62 +37,80 @@ syntax = "proto3"; package google.protobuf; +option csharp_namespace = "Google.ProtocolBuffers"; +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.ProtocolBuffers"; 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; diff --git a/update_file_lists.sh b/update_file_lists.sh index 34443456f03df..206be4399c534 100755 --- a/update_file_lists.sh +++ b/update_file_lists.sh @@ -133,11 +133,6 @@ done # Update bazel BUILD files. ################################################################################ -BAZEL_BUILD=./BUILD -[ -f "$BAZEL_BUILD" ] || { - echo "Cannot find: $BAZEL_BUILD" - exit 1 -} set_bazel_value() { local FILENAME=$1 local VARNAME=$2 @@ -169,14 +164,19 @@ set_bazel_value() { } +BAZEL_BUILD=./BUILD BAZEL_PREFIX="src/" -set_bazel_value $BAZEL_BUILD protobuf_lite_srcs $BAZEL_PREFIX $LIBPROTOBUF_LITE_SOURCES -set_bazel_value $BAZEL_BUILD protobuf_srcs $BAZEL_PREFIX $LIBPROTOBUF_SOURCES -set_bazel_value $BAZEL_BUILD protoc_lib_srcs $BAZEL_PREFIX $LIBPROTOC_SOURCES -set_bazel_value $BAZEL_BUILD lite_test_protos "" $LITE_PROTOS -set_bazel_value $BAZEL_BUILD well_known_protos "" $WKT_PROTOS -set_bazel_value $BAZEL_BUILD test_protos "" $PROTOS -set_bazel_value $BAZEL_BUILD common_test_srcs $BAZEL_PREFIX $COMMON_TEST_SOURCES -set_bazel_value $BAZEL_BUILD test_srcs $BAZEL_PREFIX $TEST_SOURCES -set_bazel_value $BAZEL_BUILD test_plugin_srcs $BAZEL_PREFIX $TEST_PLUGIN_SOURCES +if [ -f "$BAZEL_BUILD" ]; then + set_bazel_value $BAZEL_BUILD protobuf_lite_srcs $BAZEL_PREFIX $LIBPROTOBUF_LITE_SOURCES + set_bazel_value $BAZEL_BUILD protobuf_srcs $BAZEL_PREFIX $LIBPROTOBUF_SOURCES + set_bazel_value $BAZEL_BUILD protoc_lib_srcs $BAZEL_PREFIX $LIBPROTOC_SOURCES + set_bazel_value $BAZEL_BUILD lite_test_protos "" $LITE_PROTOS + set_bazel_value $BAZEL_BUILD well_known_protos "" $WKT_PROTOS + set_bazel_value $BAZEL_BUILD test_protos "" $PROTOS + set_bazel_value $BAZEL_BUILD common_test_srcs $BAZEL_PREFIX $COMMON_TEST_SOURCES + set_bazel_value $BAZEL_BUILD test_srcs $BAZEL_PREFIX $TEST_SOURCES + set_bazel_value $BAZEL_BUILD test_plugin_srcs $BAZEL_PREFIX $TEST_PLUGIN_SOURCES +else + echo "Skipped BUILD file update." +fi