diff --git a/BUILD b/BUILD index 9fbf69dfca96..a9ed429f10ac 100644 --- a/BUILD +++ b/BUILD @@ -147,6 +147,7 @@ cc_library( "src/google/protobuf/message_lite.cc", "src/google/protobuf/parse_context.cc", "src/google/protobuf/repeated_field.cc", + "src/google/protobuf/repeated_ptr_field.cc", "src/google/protobuf/stubs/bytestream.cc", "src/google/protobuf/stubs/common.cc", "src/google/protobuf/stubs/int128.cc", diff --git a/CHANGES.txt b/CHANGES.txt index 7682fbdd1970..66f1bc0f4c5f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,19 @@ Unreleased Changes (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) - Protocol Compiler + + Python + * Proto2 DecodeError now includes message name in error message + + C++ * Make proto2::Message::DiscardUnknownFields() non-virtual + * Separate RepeatedPtrField into its own header file + * For default floating point values of 0, consider all bits significant + + Java + * For default floating point values of 0, consider all bits significant + * Annotate `//java/com/google/protobuf/util/...` with nullness annotations + + Kotlin + * Switch Kotlin proto DSLs to be implemented with inline value classes 2021-10-04 version 3.18.1 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript) diff --git a/WORKSPACE b/WORKSPACE index 2174cabf8c8f..c88d242db2be 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -38,13 +38,15 @@ bind( load("@rules_jvm_external//:defs.bzl", "maven_install") maven_install( artifacts = [ + "com.google.code.findbugs:jsr305:3.0.2", "com.google.code.gson:gson:2.8.6", "com.google.errorprone:error_prone_annotations:2.3.2", - "com.google.j2objc:j2obj_annotations:1.3", + "com.google.j2objc:j2objc-annotations:1.3", "com.google.guava:guava:30.1.1-jre", "com.google.truth:truth:1.1.2", "junit:junit:4.12", "org.easymock:easymock:3.2", + ], repositories = [ "https://repo1.maven.org/maven2", @@ -78,6 +80,11 @@ bind( actual = "@maven//:com_google_j2objc_j2objc_annotations", ) +bind( + name = "jsr305", + actual = "@maven//:com_google_code_findbugs_jsr305", +) + bind( name = "junit", actual = "@maven//:junit_junit", @@ -88,11 +95,6 @@ bind( actual = "@maven//:org_easymock_easymock", ) -bind( - name = "easymock_classextension", - actual = "@maven//:org_easymock_easymockclassextension", -) - bind( name = "truth", actual = "@maven//:com_google_truth_truth", diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in index dd96c6ae3196..605c5f966ba3 100644 --- a/cmake/extract_includes.bat.in +++ b/cmake/extract_includes.bat.in @@ -93,6 +93,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\port_undef.inc" inclu copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection.h" include\google\protobuf\reflection.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\reflection_ops.h" include\google\protobuf\reflection_ops.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_field.h" include\google\protobuf\repeated_field.h +copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\repeated_ptr_field.h" include\google\protobuf\repeated_ptr_field.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\service.h" include\google\protobuf\service.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\source_context.pb.h" include\google\protobuf\source_context.pb.h copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\struct.pb.h" include\google\protobuf\struct.pb.h diff --git a/cmake/libprotobuf-lite.cmake b/cmake/libprotobuf-lite.cmake index 024a4ee39e39..f36a7acf6c04 100644 --- a/cmake/libprotobuf-lite.cmake +++ b/cmake/libprotobuf-lite.cmake @@ -19,6 +19,7 @@ set(libprotobuf_lite_files ${protobuf_source_dir}/src/google/protobuf/message_lite.cc ${protobuf_source_dir}/src/google/protobuf/parse_context.cc ${protobuf_source_dir}/src/google/protobuf/repeated_field.cc + ${protobuf_source_dir}/src/google/protobuf/repeated_ptr_field.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 @@ -65,6 +66,7 @@ set(libprotobuf_lite_includes ${protobuf_source_dir}/src/google/protobuf/parse_context.h ${protobuf_source_dir}/src/google/protobuf/port.h ${protobuf_source_dir}/src/google/protobuf/repeated_field.h + ${protobuf_source_dir}/src/google/protobuf/repeated_ptr_field.h ${protobuf_source_dir}/src/google/protobuf/stubs/bytestream.h ${protobuf_source_dir}/src/google/protobuf/stubs/callback.h ${protobuf_source_dir}/src/google/protobuf/stubs/casts.h diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs index 8a522090fdee..d2db53d06ae6 100644 --- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs +++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.cs @@ -25,7 +25,7 @@ static TestMessagesProto2Reflection() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Cipnb29nbGUvcHJvdG9idWYvdGVzdF9tZXNzYWdlc19wcm90bzIucHJvdG8S", - "HXByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yIv45ChJUZXN0QWxsVHlw", + "HXByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yIqQ+ChJUZXN0QWxsVHlw", "ZXNQcm90bzISFgoOb3B0aW9uYWxfaW50MzIYASABKAUSFgoOb3B0aW9uYWxf", "aW50NjQYAiABKAMSFwoPb3B0aW9uYWxfdWludDMyGAMgASgNEhcKD29wdGlv", "bmFsX3VpbnQ2NBgEIAEoBBIXCg9vcHRpb25hbF9zaW50MzIYBSABKBESFwoP", @@ -135,80 +135,92 @@ static TestMessagesProto2Reflection() { "b25lb2ZfZG91YmxlGHYgASgBSAASUgoKb25lb2ZfZW51bRh3IAEoDjI8LnBy", "b3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1Byb3Rv", "Mi5OZXN0ZWRFbnVtSAASRQoEZGF0YRjJASABKAoyNi5wcm90b2J1Zl90ZXN0", - "X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIuRGF0YRITCgpm", - "aWVsZG5hbWUxGJEDIAEoBRIUCgtmaWVsZF9uYW1lMhiSAyABKAUSFQoMX2Zp", - "ZWxkX25hbWUzGJMDIAEoBRIWCg1maWVsZF9fbmFtZTRfGJQDIAEoBRIUCgtm", - "aWVsZDBuYW1lNRiVAyABKAUSFgoNZmllbGRfMF9uYW1lNhiWAyABKAUSEwoK", - "ZmllbGROYW1lNxiXAyABKAUSEwoKRmllbGROYW1lOBiYAyABKAUSFAoLZmll", - "bGRfTmFtZTkYmQMgASgFEhUKDEZpZWxkX05hbWUxMBiaAyABKAUSFQoMRklF", - "TERfTkFNRTExGJsDIAEoBRIVCgxGSUVMRF9uYW1lMTIYnAMgASgFEhcKDl9f", - "ZmllbGRfbmFtZTEzGJ0DIAEoBRIXCg5fX0ZpZWxkX25hbWUxNBieAyABKAUS", - "FgoNZmllbGRfX25hbWUxNRifAyABKAUSFgoNZmllbGRfX05hbWUxNhigAyAB", - "KAUSFwoOZmllbGRfbmFtZTE3X18YoQMgASgFEhcKDkZpZWxkX25hbWUxOF9f", - "GKIDIAEoBRpiCg1OZXN0ZWRNZXNzYWdlEgkKAWEYASABKAUSRgoLY29yZWN1", - "cnNpdmUYAiABKAsyMS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5U", - "ZXN0QWxsVHlwZXNQcm90bzIaNAoSTWFwSW50MzJJbnQzMkVudHJ5EgsKA2tl", - "eRgBIAEoBRINCgV2YWx1ZRgCIAEoBToCOAEaNAoSTWFwSW50NjRJbnQ2NEVu", - "dHJ5EgsKA2tleRgBIAEoAxINCgV2YWx1ZRgCIAEoAzoCOAEaNgoUTWFwVWlu", - "dDMyVWludDMyRW50cnkSCwoDa2V5GAEgASgNEg0KBXZhbHVlGAIgASgNOgI4", - "ARo2ChRNYXBVaW50NjRVaW50NjRFbnRyeRILCgNrZXkYASABKAQSDQoFdmFs", - "dWUYAiABKAQ6AjgBGjYKFE1hcFNpbnQzMlNpbnQzMkVudHJ5EgsKA2tleRgB", - "IAEoERINCgV2YWx1ZRgCIAEoEToCOAEaNgoUTWFwU2ludDY0U2ludDY0RW50", - "cnkSCwoDa2V5GAEgASgSEg0KBXZhbHVlGAIgASgSOgI4ARo4ChZNYXBGaXhl", - "ZDMyRml4ZWQzMkVudHJ5EgsKA2tleRgBIAEoBxINCgV2YWx1ZRgCIAEoBzoC", - "OAEaOAoWTWFwRml4ZWQ2NEZpeGVkNjRFbnRyeRILCgNrZXkYASABKAYSDQoF", - "dmFsdWUYAiABKAY6AjgBGjoKGE1hcFNmaXhlZDMyU2ZpeGVkMzJFbnRyeRIL", - "CgNrZXkYASABKA8SDQoFdmFsdWUYAiABKA86AjgBGjoKGE1hcFNmaXhlZDY0", - "U2ZpeGVkNjRFbnRyeRILCgNrZXkYASABKBASDQoFdmFsdWUYAiABKBA6AjgB", - "GjQKEk1hcEludDMyRmxvYXRFbnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUY", - "AiABKAI6AjgBGjUKE01hcEludDMyRG91YmxlRW50cnkSCwoDa2V5GAEgASgF", - "Eg0KBXZhbHVlGAIgASgBOgI4ARoyChBNYXBCb29sQm9vbEVudHJ5EgsKA2tl", - "eRgBIAEoCBINCgV2YWx1ZRgCIAEoCDoCOAEaNgoUTWFwU3RyaW5nU3RyaW5n", - "RW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ARo1ChNNYXBT", - "dHJpbmdCeXRlc0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoDDoC", - "OAEafgobTWFwU3RyaW5nTmVzdGVkTWVzc2FnZUVudHJ5EgsKA2tleRgBIAEo", - "CRJOCgV2YWx1ZRgCIAEoCzI/LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJv", - "dG8yLlRlc3RBbGxUeXBlc1Byb3RvMi5OZXN0ZWRNZXNzYWdlOgI4ARpzChxN", - "YXBTdHJpbmdGb3JlaWduTWVzc2FnZUVudHJ5EgsKA2tleRgBIAEoCRJCCgV2", - "YWx1ZRgCIAEoCzIzLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLkZv", - "cmVpZ25NZXNzYWdlUHJvdG8yOgI4ARp4ChhNYXBTdHJpbmdOZXN0ZWRFbnVt", - "RW50cnkSCwoDa2V5GAEgASgJEksKBXZhbHVlGAIgASgOMjwucHJvdG9idWZf", - "dGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8yLk5lc3Rl", - "ZEVudW06AjgBGm0KGU1hcFN0cmluZ0ZvcmVpZ25FbnVtRW50cnkSCwoDa2V5", - "GAEgASgJEj8KBXZhbHVlGAIgASgOMjAucHJvdG9idWZfdGVzdF9tZXNzYWdl", - "cy5wcm90bzIuRm9yZWlnbkVudW1Qcm90bzI6AjgBGjMKBERhdGESFAoLZ3Jv", - "dXBfaW50MzIYygEgASgFEhUKDGdyb3VwX3VpbnQzMhjLASABKA0aIQoRTWVz", - "c2FnZVNldENvcnJlY3QqCAgEEP////8HOgIIARrgAQobTWVzc2FnZVNldENv", - "cnJlY3RFeHRlbnNpb24xEgsKA3N0chgZIAEoCTKzAQoVbWVzc2FnZV9zZXRf", - "ZXh0ZW5zaW9uEkMucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVz", - "dEFsbFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0GPm7XiABKAsyTS5w", - "cm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90", - "bzIuTWVzc2FnZVNldENvcnJlY3RFeHRlbnNpb24xGt8BChtNZXNzYWdlU2V0", - "Q29ycmVjdEV4dGVuc2lvbjISCQoBaRgJIAEoBTK0AQoVbWVzc2FnZV9zZXRf", - "ZXh0ZW5zaW9uEkMucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVz", - "dEFsbFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0GJCz/AEgASgLMk0u", - "cHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFR5cGVzUHJv", - "dG8yLk1lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMiI5CgpOZXN0ZWRFbnVt", - "EgcKA0ZPTxAAEgcKA0JBUhABEgcKA0JBWhACEhAKA05FRxD///////////8B", - "KgUIeBDJAUINCgtvbmVvZl9maWVsZEoGCOgHEJBOIiEKFEZvcmVpZ25NZXNz", - "YWdlUHJvdG8yEgkKAWMYASABKAUiwQIKFVVua25vd25Ub1Rlc3RBbGxUeXBl", - "cxIXCg5vcHRpb25hbF9pbnQzMhjpByABKAUSGAoPb3B0aW9uYWxfc3RyaW5n", - "GOoHIAEoCRJMCg5uZXN0ZWRfbWVzc2FnZRjrByABKAsyMy5wcm90b2J1Zl90", - "ZXN0X21lc3NhZ2VzLnByb3RvMi5Gb3JlaWduTWVzc2FnZVByb3RvMhJaCg1v", - "cHRpb25hbGdyb3VwGOwHIAEoCjJCLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu", - "cHJvdG8yLlVua25vd25Ub1Rlc3RBbGxUeXBlcy5PcHRpb25hbEdyb3VwEhYK", - "DW9wdGlvbmFsX2Jvb2wY7gcgASgIEhcKDnJlcGVhdGVkX2ludDMyGPMHIAMo", - "BRoaCg1PcHRpb25hbEdyb3VwEgkKAWEYASABKAUiFgoUTnVsbEh5cG90aGVz", - "aXNQcm90bzIiLwoORW51bU9ubHlQcm90bzIiHQoEQm9vbBIKCgZrRmFsc2UQ", - "ABIJCgVrVHJ1ZRABKkYKEUZvcmVpZ25FbnVtUHJvdG8yEg8KC0ZPUkVJR05f", - "Rk9PEAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdOX0JBWhACOkoKD2V4", - "dGVuc2lvbl9pbnQzMhIxLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8y", - "LlRlc3RBbGxUeXBlc1Byb3RvMhh4IAEoBUIvCihjb20uZ29vZ2xlLnByb3Rv", - "YnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8ySAH4AQE=")); + "X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIuRGF0YRIiCg1k", + "ZWZhdWx0X2ludDMyGPEBIAEoBToKLTEyMzQ1Njc4ORIsCg1kZWZhdWx0X2lu", + "dDY0GPIBIAEoAzoULTkxMjM0NTY3ODkxMjM0NTY3ODkSIwoOZGVmYXVsdF91", + "aW50MzIY8wEgASgNOgoyMTIzNDU2Nzg5Ei0KDmRlZmF1bHRfdWludDY0GPQB", + "IAEoBDoUMTAxMjM0NTY3ODkxMjM0NTY3ODkSIwoOZGVmYXVsdF9zaW50MzIY", + "9QEgASgROgotMTIzNDU2Nzg5Ei0KDmRlZmF1bHRfc2ludDY0GPYBIAEoEjoU", + "LTkxMjM0NTY3ODkxMjM0NTY3ODkSJAoPZGVmYXVsdF9maXhlZDMyGPcBIAEo", + "BzoKMjEyMzQ1Njc4ORIuCg9kZWZhdWx0X2ZpeGVkNjQY+AEgASgGOhQxMDEy", + "MzQ1Njc4OTEyMzQ1Njc4ORIlChBkZWZhdWx0X3NmaXhlZDMyGPkBIAEoDzoK", + "LTEyMzQ1Njc4ORIvChBkZWZhdWx0X3NmaXhlZDY0GPoBIAEoEDoULTkxMjM0", + "NTY3ODkxMjM0NTY3ODkSHQoNZGVmYXVsdF9mbG9hdBj7ASABKAI6BTllKzA5", + "Eh4KDmRlZmF1bHRfZG91YmxlGPwBIAEoAToFN2UrMjISGwoMZGVmYXVsdF9i", + "b29sGP0BIAEoCDoEdHJ1ZRIgCg5kZWZhdWx0X3N0cmluZxj+ASABKAk6B1Jv", + "c2VidWQSEwoKZmllbGRuYW1lMRiRAyABKAUSFAoLZmllbGRfbmFtZTIYkgMg", + "ASgFEhUKDF9maWVsZF9uYW1lMxiTAyABKAUSFgoNZmllbGRfX25hbWU0XxiU", + "AyABKAUSFAoLZmllbGQwbmFtZTUYlQMgASgFEhYKDWZpZWxkXzBfbmFtZTYY", + "lgMgASgFEhMKCmZpZWxkTmFtZTcYlwMgASgFEhMKCkZpZWxkTmFtZTgYmAMg", + "ASgFEhQKC2ZpZWxkX05hbWU5GJkDIAEoBRIVCgxGaWVsZF9OYW1lMTAYmgMg", + "ASgFEhUKDEZJRUxEX05BTUUxMRibAyABKAUSFQoMRklFTERfbmFtZTEyGJwD", + "IAEoBRIXCg5fX2ZpZWxkX25hbWUxMxidAyABKAUSFwoOX19GaWVsZF9uYW1l", + "MTQYngMgASgFEhYKDWZpZWxkX19uYW1lMTUYnwMgASgFEhYKDWZpZWxkX19O", + "YW1lMTYYoAMgASgFEhcKDmZpZWxkX25hbWUxN19fGKEDIAEoBRIXCg5GaWVs", + "ZF9uYW1lMThfXxiiAyABKAUaYgoNTmVzdGVkTWVzc2FnZRIJCgFhGAEgASgF", + "EkYKC2NvcmVjdXJzaXZlGAIgASgLMjEucHJvdG9idWZfdGVzdF9tZXNzYWdl", + "cy5wcm90bzIuVGVzdEFsbFR5cGVzUHJvdG8yGjQKEk1hcEludDMySW50MzJF", + "bnRyeRILCgNrZXkYASABKAUSDQoFdmFsdWUYAiABKAU6AjgBGjQKEk1hcElu", + "dDY0SW50NjRFbnRyeRILCgNrZXkYASABKAMSDQoFdmFsdWUYAiABKAM6AjgB", + "GjYKFE1hcFVpbnQzMlVpbnQzMkVudHJ5EgsKA2tleRgBIAEoDRINCgV2YWx1", + "ZRgCIAEoDToCOAEaNgoUTWFwVWludDY0VWludDY0RW50cnkSCwoDa2V5GAEg", + "ASgEEg0KBXZhbHVlGAIgASgEOgI4ARo2ChRNYXBTaW50MzJTaW50MzJFbnRy", + "eRILCgNrZXkYASABKBESDQoFdmFsdWUYAiABKBE6AjgBGjYKFE1hcFNpbnQ2", + "NFNpbnQ2NEVudHJ5EgsKA2tleRgBIAEoEhINCgV2YWx1ZRgCIAEoEjoCOAEa", + "OAoWTWFwRml4ZWQzMkZpeGVkMzJFbnRyeRILCgNrZXkYASABKAcSDQoFdmFs", + "dWUYAiABKAc6AjgBGjgKFk1hcEZpeGVkNjRGaXhlZDY0RW50cnkSCwoDa2V5", + "GAEgASgGEg0KBXZhbHVlGAIgASgGOgI4ARo6ChhNYXBTZml4ZWQzMlNmaXhl", + "ZDMyRW50cnkSCwoDa2V5GAEgASgPEg0KBXZhbHVlGAIgASgPOgI4ARo6ChhN", + "YXBTZml4ZWQ2NFNmaXhlZDY0RW50cnkSCwoDa2V5GAEgASgQEg0KBXZhbHVl", + "GAIgASgQOgI4ARo0ChJNYXBJbnQzMkZsb2F0RW50cnkSCwoDa2V5GAEgASgF", + "Eg0KBXZhbHVlGAIgASgCOgI4ARo1ChNNYXBJbnQzMkRvdWJsZUVudHJ5EgsK", + "A2tleRgBIAEoBRINCgV2YWx1ZRgCIAEoAToCOAEaMgoQTWFwQm9vbEJvb2xF", + "bnRyeRILCgNrZXkYASABKAgSDQoFdmFsdWUYAiABKAg6AjgBGjYKFE1hcFN0", + "cmluZ1N0cmluZ0VudHJ5EgsKA2tleRgBIAEoCRINCgV2YWx1ZRgCIAEoCToC", + "OAEaNQoTTWFwU3RyaW5nQnl0ZXNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFs", + "dWUYAiABKAw6AjgBGn4KG01hcFN0cmluZ05lc3RlZE1lc3NhZ2VFbnRyeRIL", + "CgNrZXkYASABKAkSTgoFdmFsdWUYAiABKAsyPy5wcm90b2J1Zl90ZXN0X21l", + "c3NhZ2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIuTmVzdGVkTWVzc2Fn", + "ZToCOAEacwocTWFwU3RyaW5nRm9yZWlnbk1lc3NhZ2VFbnRyeRILCgNrZXkY", + "ASABKAkSQgoFdmFsdWUYAiABKAsyMy5wcm90b2J1Zl90ZXN0X21lc3NhZ2Vz", + "LnByb3RvMi5Gb3JlaWduTWVzc2FnZVByb3RvMjoCOAEaeAoYTWFwU3RyaW5n", + "TmVzdGVkRW51bUVudHJ5EgsKA2tleRgBIAEoCRJLCgV2YWx1ZRgCIAEoDjI8", + "LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1By", + "b3RvMi5OZXN0ZWRFbnVtOgI4ARptChlNYXBTdHJpbmdGb3JlaWduRW51bUVu", + "dHJ5EgsKA2tleRgBIAEoCRI/CgV2YWx1ZRgCIAEoDjIwLnByb3RvYnVmX3Rl", + "c3RfbWVzc2FnZXMucHJvdG8yLkZvcmVpZ25FbnVtUHJvdG8yOgI4ARozCgRE", + "YXRhEhQKC2dyb3VwX2ludDMyGMoBIAEoBRIVCgxncm91cF91aW50MzIYywEg", + "ASgNGiEKEU1lc3NhZ2VTZXRDb3JyZWN0KggIBBD/////BzoCCAEa4AEKG01l", + "c3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMRILCgNzdHIYGSABKAkyswEKFW1l", + "c3NhZ2Vfc2V0X2V4dGVuc2lvbhJDLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu", + "cHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdBj5", + "u14gASgLMk0ucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFs", + "bFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9uMRrfAQob", + "TWVzc2FnZVNldENvcnJlY3RFeHRlbnNpb24yEgkKAWkYCSABKAUytAEKFW1l", + "c3NhZ2Vfc2V0X2V4dGVuc2lvbhJDLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMu", + "cHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdBiQ", + "s/wBIAEoCzJNLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RB", + "bGxUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdEV4dGVuc2lvbjIiOQoK", + "TmVzdGVkRW51bRIHCgNGT08QABIHCgNCQVIQARIHCgNCQVoQAhIQCgNORUcQ", + "////////////ASoFCHgQyQFCDQoLb25lb2ZfZmllbGRKBgjoBxCQTiIhChRG", + "b3JlaWduTWVzc2FnZVByb3RvMhIJCgFjGAEgASgFIsECChVVbmtub3duVG9U", + "ZXN0QWxsVHlwZXMSFwoOb3B0aW9uYWxfaW50MzIY6QcgASgFEhgKD29wdGlv", + "bmFsX3N0cmluZxjqByABKAkSTAoObmVzdGVkX21lc3NhZ2UY6wcgASgLMjMu", + "cHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuRm9yZWlnbk1lc3NhZ2VQ", + "cm90bzISWgoNb3B0aW9uYWxncm91cBjsByABKAoyQi5wcm90b2J1Zl90ZXN0", + "X21lc3NhZ2VzLnByb3RvMi5Vbmtub3duVG9UZXN0QWxsVHlwZXMuT3B0aW9u", + "YWxHcm91cBIWCg1vcHRpb25hbF9ib29sGO4HIAEoCBIXCg5yZXBlYXRlZF9p", + "bnQzMhjzByADKAUaGgoNT3B0aW9uYWxHcm91cBIJCgFhGAEgASgFIhYKFE51", + "bGxIeXBvdGhlc2lzUHJvdG8yIi8KDkVudW1Pbmx5UHJvdG8yIh0KBEJvb2wS", + "CgoGa0ZhbHNlEAASCQoFa1RydWUQASpGChFGb3JlaWduRW51bVByb3RvMhIP", + "CgtGT1JFSUdOX0ZPTxAAEg8KC0ZPUkVJR05fQkFSEAESDwoLRk9SRUlHTl9C", + "QVoQAjpKCg9leHRlbnNpb25faW50MzISMS5wcm90b2J1Zl90ZXN0X21lc3Nh", + "Z2VzLnByb3RvMi5UZXN0QWxsVHlwZXNQcm90bzIYeCABKAVCLwooY29tLmdv", + "b2dsZS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMkgB+AEB")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto2.ForeignEnumProto2), }, new pb::Extension[] { TestMessagesProto2Extensions.ExtensionInt32 }, new pbr::GeneratedClrTypeInfo[] { - new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedNestedEnum", "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedNestedEnum", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "Data", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser, new[]{ "OptionalInt32", "OptionalInt64", "OptionalUint32", "OptionalUint64", "OptionalSint32", "OptionalSint64", "OptionalFixed32", "OptionalFixed64", "OptionalSfixed32", "OptionalSfixed64", "OptionalFloat", "OptionalDouble", "OptionalBool", "OptionalString", "OptionalBytes", "OptionalNestedMessage", "OptionalForeignMessage", "OptionalNestedEnum", "OptionalForeignEnum", "OptionalStringPiece", "OptionalCord", "RecursiveMessage", "RepeatedInt32", "RepeatedInt64", "RepeatedUint32", "RepeatedUint64", "RepeatedSint32", "RepeatedSint64", "RepeatedFixed32", "RepeatedFixed64", "RepeatedSfixed32", "RepeatedSfixed64", "RepeatedFloat", "RepeatedDouble", "RepeatedBool", "RepeatedString", "RepeatedBytes", "RepeatedNestedMessage", "RepeatedForeignMessage", "RepeatedNestedEnum", "RepeatedForeignEnum", "RepeatedStringPiece", "RepeatedCord", "PackedInt32", "PackedInt64", "PackedUint32", "PackedUint64", "PackedSint32", "PackedSint64", "PackedFixed32", "PackedFixed64", "PackedSfixed32", "PackedSfixed64", "PackedFloat", "PackedDouble", "PackedBool", "PackedNestedEnum", "UnpackedInt32", "UnpackedInt64", "UnpackedUint32", "UnpackedUint64", "UnpackedSint32", "UnpackedSint64", "UnpackedFixed32", "UnpackedFixed64", "UnpackedSfixed32", "UnpackedSfixed64", "UnpackedFloat", "UnpackedDouble", "UnpackedBool", "UnpackedNestedEnum", "MapInt32Int32", "MapInt64Int64", "MapUint32Uint32", "MapUint64Uint64", "MapSint32Sint32", "MapSint64Sint64", "MapFixed32Fixed32", "MapFixed64Fixed64", "MapSfixed32Sfixed32", "MapSfixed64Sfixed64", "MapInt32Float", "MapInt32Double", "MapBoolBool", "MapStringString", "MapStringBytes", "MapStringNestedMessage", "MapStringForeignMessage", "MapStringNestedEnum", "MapStringForeignEnum", "OneofUint32", "OneofNestedMessage", "OneofString", "OneofBytes", "OneofBool", "OneofUint64", "OneofFloat", "OneofDouble", "OneofEnum", "Data", "DefaultInt32", "DefaultInt64", "DefaultUint32", "DefaultUint64", "DefaultSint32", "DefaultSint64", "DefaultFixed32", "DefaultFixed64", "DefaultSfixed32", "DefaultSfixed64", "DefaultFloat", "DefaultDouble", "DefaultBool", "DefaultString", "Fieldname1", "FieldName2", "FieldName3", "FieldName4", "Field0Name5", "Field0Name6", "FieldName7", "FieldName8", "FieldName9", "FieldName10", "FIELDNAME11", "FIELDName12", "FieldName13", "FieldName14", "FieldName15", "FieldName16", "FieldName17", "FieldName18" }, new[]{ "OneofField" }, new[]{ typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.NestedMessage.Parser, new[]{ "A", "Corecursive" }, null, null, null, null), null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data.Parser, new[]{ "GroupInt32", "GroupUint32" }, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrect), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrect.Parser, null, null, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1), global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Parser, new[]{ "Str" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.MessageSetCorrectExtension1.Extensions.MessageSetExtension }, null), @@ -378,6 +390,20 @@ public TestAllTypesProto2(TestAllTypesProto2 other) : this() { mapStringNestedEnum_ = other.mapStringNestedEnum_.Clone(); mapStringForeignEnum_ = other.mapStringForeignEnum_.Clone(); data_ = other.HasData ? other.data_.Clone() : null; + defaultInt32_ = other.defaultInt32_; + defaultInt64_ = other.defaultInt64_; + defaultUint32_ = other.defaultUint32_; + defaultUint64_ = other.defaultUint64_; + defaultSint32_ = other.defaultSint32_; + defaultSint64_ = other.defaultSint64_; + defaultFixed32_ = other.defaultFixed32_; + defaultFixed64_ = other.defaultFixed64_; + defaultSfixed32_ = other.defaultSfixed32_; + defaultSfixed64_ = other.defaultSfixed64_; + defaultFloat_ = other.defaultFloat_; + defaultDouble_ = other.defaultDouble_; + defaultBool_ = other.defaultBool_; + defaultString_ = other.defaultString_; fieldname1_ = other.fieldname1_; fieldName2_ = other.fieldName2_; FieldName3_ = other.FieldName3_; @@ -1988,6 +2014,386 @@ public void ClearData() { data_ = null; } + /// Field number for the "default_int32" field. + public const int DefaultInt32FieldNumber = 241; + private readonly static int DefaultInt32DefaultValue = -123456789; + + private int defaultInt32_; + /// + /// default values + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int DefaultInt32 { + get { if ((_hasBits0 & 32768) != 0) { return defaultInt32_; } else { return DefaultInt32DefaultValue; } } + set { + _hasBits0 |= 32768; + defaultInt32_ = value; + } + } + /// Gets whether the "default_int32" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultInt32 { + get { return (_hasBits0 & 32768) != 0; } + } + /// Clears the value of the "default_int32" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultInt32() { + _hasBits0 &= ~32768; + } + + /// Field number for the "default_int64" field. + public const int DefaultInt64FieldNumber = 242; + private readonly static long DefaultInt64DefaultValue = -9123456789123456789L; + + private long defaultInt64_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long DefaultInt64 { + get { if ((_hasBits0 & 65536) != 0) { return defaultInt64_; } else { return DefaultInt64DefaultValue; } } + set { + _hasBits0 |= 65536; + defaultInt64_ = value; + } + } + /// Gets whether the "default_int64" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultInt64 { + get { return (_hasBits0 & 65536) != 0; } + } + /// Clears the value of the "default_int64" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultInt64() { + _hasBits0 &= ~65536; + } + + /// Field number for the "default_uint32" field. + public const int DefaultUint32FieldNumber = 243; + private readonly static uint DefaultUint32DefaultValue = 2123456789; + + private uint defaultUint32_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint DefaultUint32 { + get { if ((_hasBits0 & 131072) != 0) { return defaultUint32_; } else { return DefaultUint32DefaultValue; } } + set { + _hasBits0 |= 131072; + defaultUint32_ = value; + } + } + /// Gets whether the "default_uint32" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultUint32 { + get { return (_hasBits0 & 131072) != 0; } + } + /// Clears the value of the "default_uint32" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultUint32() { + _hasBits0 &= ~131072; + } + + /// Field number for the "default_uint64" field. + public const int DefaultUint64FieldNumber = 244; + private readonly static ulong DefaultUint64DefaultValue = 10123456789123456789UL; + + private ulong defaultUint64_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ulong DefaultUint64 { + get { if ((_hasBits0 & 262144) != 0) { return defaultUint64_; } else { return DefaultUint64DefaultValue; } } + set { + _hasBits0 |= 262144; + defaultUint64_ = value; + } + } + /// Gets whether the "default_uint64" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultUint64 { + get { return (_hasBits0 & 262144) != 0; } + } + /// Clears the value of the "default_uint64" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultUint64() { + _hasBits0 &= ~262144; + } + + /// Field number for the "default_sint32" field. + public const int DefaultSint32FieldNumber = 245; + private readonly static int DefaultSint32DefaultValue = -123456789; + + private int defaultSint32_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int DefaultSint32 { + get { if ((_hasBits0 & 524288) != 0) { return defaultSint32_; } else { return DefaultSint32DefaultValue; } } + set { + _hasBits0 |= 524288; + defaultSint32_ = value; + } + } + /// Gets whether the "default_sint32" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultSint32 { + get { return (_hasBits0 & 524288) != 0; } + } + /// Clears the value of the "default_sint32" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultSint32() { + _hasBits0 &= ~524288; + } + + /// Field number for the "default_sint64" field. + public const int DefaultSint64FieldNumber = 246; + private readonly static long DefaultSint64DefaultValue = -9123456789123456789L; + + private long defaultSint64_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long DefaultSint64 { + get { if ((_hasBits0 & 1048576) != 0) { return defaultSint64_; } else { return DefaultSint64DefaultValue; } } + set { + _hasBits0 |= 1048576; + defaultSint64_ = value; + } + } + /// Gets whether the "default_sint64" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultSint64 { + get { return (_hasBits0 & 1048576) != 0; } + } + /// Clears the value of the "default_sint64" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultSint64() { + _hasBits0 &= ~1048576; + } + + /// Field number for the "default_fixed32" field. + public const int DefaultFixed32FieldNumber = 247; + private readonly static uint DefaultFixed32DefaultValue = 2123456789; + + private uint defaultFixed32_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint DefaultFixed32 { + get { if ((_hasBits0 & 2097152) != 0) { return defaultFixed32_; } else { return DefaultFixed32DefaultValue; } } + set { + _hasBits0 |= 2097152; + defaultFixed32_ = value; + } + } + /// Gets whether the "default_fixed32" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultFixed32 { + get { return (_hasBits0 & 2097152) != 0; } + } + /// Clears the value of the "default_fixed32" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultFixed32() { + _hasBits0 &= ~2097152; + } + + /// Field number for the "default_fixed64" field. + public const int DefaultFixed64FieldNumber = 248; + private readonly static ulong DefaultFixed64DefaultValue = 10123456789123456789UL; + + private ulong defaultFixed64_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public ulong DefaultFixed64 { + get { if ((_hasBits0 & 4194304) != 0) { return defaultFixed64_; } else { return DefaultFixed64DefaultValue; } } + set { + _hasBits0 |= 4194304; + defaultFixed64_ = value; + } + } + /// Gets whether the "default_fixed64" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultFixed64 { + get { return (_hasBits0 & 4194304) != 0; } + } + /// Clears the value of the "default_fixed64" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultFixed64() { + _hasBits0 &= ~4194304; + } + + /// Field number for the "default_sfixed32" field. + public const int DefaultSfixed32FieldNumber = 249; + private readonly static int DefaultSfixed32DefaultValue = -123456789; + + private int defaultSfixed32_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int DefaultSfixed32 { + get { if ((_hasBits0 & 8388608) != 0) { return defaultSfixed32_; } else { return DefaultSfixed32DefaultValue; } } + set { + _hasBits0 |= 8388608; + defaultSfixed32_ = value; + } + } + /// Gets whether the "default_sfixed32" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultSfixed32 { + get { return (_hasBits0 & 8388608) != 0; } + } + /// Clears the value of the "default_sfixed32" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultSfixed32() { + _hasBits0 &= ~8388608; + } + + /// Field number for the "default_sfixed64" field. + public const int DefaultSfixed64FieldNumber = 250; + private readonly static long DefaultSfixed64DefaultValue = -9123456789123456789L; + + private long defaultSfixed64_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public long DefaultSfixed64 { + get { if ((_hasBits0 & 16777216) != 0) { return defaultSfixed64_; } else { return DefaultSfixed64DefaultValue; } } + set { + _hasBits0 |= 16777216; + defaultSfixed64_ = value; + } + } + /// Gets whether the "default_sfixed64" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultSfixed64 { + get { return (_hasBits0 & 16777216) != 0; } + } + /// Clears the value of the "default_sfixed64" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultSfixed64() { + _hasBits0 &= ~16777216; + } + + /// Field number for the "default_float" field. + public const int DefaultFloatFieldNumber = 251; + private readonly static float DefaultFloatDefaultValue = 9e+09F; + + private float defaultFloat_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public float DefaultFloat { + get { if ((_hasBits0 & 33554432) != 0) { return defaultFloat_; } else { return DefaultFloatDefaultValue; } } + set { + _hasBits0 |= 33554432; + defaultFloat_ = value; + } + } + /// Gets whether the "default_float" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultFloat { + get { return (_hasBits0 & 33554432) != 0; } + } + /// Clears the value of the "default_float" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultFloat() { + _hasBits0 &= ~33554432; + } + + /// Field number for the "default_double" field. + public const int DefaultDoubleFieldNumber = 252; + private readonly static double DefaultDoubleDefaultValue = 7e+22D; + + private double defaultDouble_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public double DefaultDouble { + get { if ((_hasBits0 & 67108864) != 0) { return defaultDouble_; } else { return DefaultDoubleDefaultValue; } } + set { + _hasBits0 |= 67108864; + defaultDouble_ = value; + } + } + /// Gets whether the "default_double" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultDouble { + get { return (_hasBits0 & 67108864) != 0; } + } + /// Clears the value of the "default_double" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultDouble() { + _hasBits0 &= ~67108864; + } + + /// Field number for the "default_bool" field. + public const int DefaultBoolFieldNumber = 253; + private readonly static bool DefaultBoolDefaultValue = true; + + private bool defaultBool_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool DefaultBool { + get { if ((_hasBits0 & 134217728) != 0) { return defaultBool_; } else { return DefaultBoolDefaultValue; } } + set { + _hasBits0 |= 134217728; + defaultBool_ = value; + } + } + /// Gets whether the "default_bool" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultBool { + get { return (_hasBits0 & 134217728) != 0; } + } + /// Clears the value of the "default_bool" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultBool() { + _hasBits0 &= ~134217728; + } + + /// Field number for the "default_string" field. + public const int DefaultStringFieldNumber = 254; + private readonly static string DefaultStringDefaultValue = global::System.Text.Encoding.UTF8.GetString(global::System.Convert.FromBase64String("Um9zZWJ1ZA=="), 0, 7); + + private string defaultString_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public string DefaultString { + get { return defaultString_ ?? DefaultStringDefaultValue; } + set { + defaultString_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + /// Gets whether the "default_string" field is set + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool HasDefaultString { + get { return defaultString_ != null; } + } + /// Clears the value of the "default_string" field + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void ClearDefaultString() { + defaultString_ = null; + } + /// Field number for the "fieldname1" field. public const int Fieldname1FieldNumber = 401; private readonly static int Fieldname1DefaultValue = 0; @@ -2000,9 +2406,9 @@ public void ClearData() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int Fieldname1 { - get { if ((_hasBits0 & 32768) != 0) { return fieldname1_; } else { return Fieldname1DefaultValue; } } + get { if ((_hasBits0 & 268435456) != 0) { return fieldname1_; } else { return Fieldname1DefaultValue; } } set { - _hasBits0 |= 32768; + _hasBits0 |= 268435456; fieldname1_ = value; } } @@ -2010,13 +2416,13 @@ public int Fieldname1 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldname1 { - get { return (_hasBits0 & 32768) != 0; } + get { return (_hasBits0 & 268435456) != 0; } } /// Clears the value of the "fieldname1" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldname1() { - _hasBits0 &= ~32768; + _hasBits0 &= ~268435456; } /// Field number for the "field_name2" field. @@ -2027,9 +2433,9 @@ public void ClearFieldname1() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName2 { - get { if ((_hasBits0 & 65536) != 0) { return fieldName2_; } else { return FieldName2DefaultValue; } } + get { if ((_hasBits0 & 536870912) != 0) { return fieldName2_; } else { return FieldName2DefaultValue; } } set { - _hasBits0 |= 65536; + _hasBits0 |= 536870912; fieldName2_ = value; } } @@ -2037,13 +2443,13 @@ public int FieldName2 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName2 { - get { return (_hasBits0 & 65536) != 0; } + get { return (_hasBits0 & 536870912) != 0; } } /// Clears the value of the "field_name2" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName2() { - _hasBits0 &= ~65536; + _hasBits0 &= ~536870912; } /// Field number for the "_field_name3" field. @@ -2054,9 +2460,9 @@ public void ClearFieldName2() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName3 { - get { if ((_hasBits0 & 131072) != 0) { return FieldName3_; } else { return FieldName3DefaultValue; } } + get { if ((_hasBits0 & 1073741824) != 0) { return FieldName3_; } else { return FieldName3DefaultValue; } } set { - _hasBits0 |= 131072; + _hasBits0 |= 1073741824; FieldName3_ = value; } } @@ -2064,13 +2470,13 @@ public int FieldName3 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName3 { - get { return (_hasBits0 & 131072) != 0; } + get { return (_hasBits0 & 1073741824) != 0; } } /// Clears the value of the "_field_name3" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName3() { - _hasBits0 &= ~131072; + _hasBits0 &= ~1073741824; } /// Field number for the "field__name4_" field. @@ -2081,9 +2487,9 @@ public void ClearFieldName3() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName4 { - get { if ((_hasBits0 & 262144) != 0) { return fieldName4_; } else { return FieldName4DefaultValue; } } + get { if ((_hasBits0 & -2147483648) != 0) { return fieldName4_; } else { return FieldName4DefaultValue; } } set { - _hasBits0 |= 262144; + _hasBits0 |= -2147483648; fieldName4_ = value; } } @@ -2091,13 +2497,13 @@ public int FieldName4 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName4 { - get { return (_hasBits0 & 262144) != 0; } + get { return (_hasBits0 & -2147483648) != 0; } } /// Clears the value of the "field__name4_" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName4() { - _hasBits0 &= ~262144; + _hasBits0 &= ~-2147483648; } /// Field number for the "field0name5" field. @@ -2108,9 +2514,9 @@ public void ClearFieldName4() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int Field0Name5 { - get { if ((_hasBits0 & 524288) != 0) { return field0Name5_; } else { return Field0Name5DefaultValue; } } + get { if ((_hasBits1 & 1) != 0) { return field0Name5_; } else { return Field0Name5DefaultValue; } } set { - _hasBits0 |= 524288; + _hasBits1 |= 1; field0Name5_ = value; } } @@ -2118,13 +2524,13 @@ public int Field0Name5 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasField0Name5 { - get { return (_hasBits0 & 524288) != 0; } + get { return (_hasBits1 & 1) != 0; } } /// Clears the value of the "field0name5" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearField0Name5() { - _hasBits0 &= ~524288; + _hasBits1 &= ~1; } /// Field number for the "field_0_name6" field. @@ -2135,9 +2541,9 @@ public void ClearField0Name5() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int Field0Name6 { - get { if ((_hasBits0 & 1048576) != 0) { return field0Name6_; } else { return Field0Name6DefaultValue; } } + get { if ((_hasBits1 & 2) != 0) { return field0Name6_; } else { return Field0Name6DefaultValue; } } set { - _hasBits0 |= 1048576; + _hasBits1 |= 2; field0Name6_ = value; } } @@ -2145,13 +2551,13 @@ public int Field0Name6 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasField0Name6 { - get { return (_hasBits0 & 1048576) != 0; } + get { return (_hasBits1 & 2) != 0; } } /// Clears the value of the "field_0_name6" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearField0Name6() { - _hasBits0 &= ~1048576; + _hasBits1 &= ~2; } /// Field number for the "fieldName7" field. @@ -2162,9 +2568,9 @@ public void ClearField0Name6() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName7 { - get { if ((_hasBits0 & 2097152) != 0) { return fieldName7_; } else { return FieldName7DefaultValue; } } + get { if ((_hasBits1 & 4) != 0) { return fieldName7_; } else { return FieldName7DefaultValue; } } set { - _hasBits0 |= 2097152; + _hasBits1 |= 4; fieldName7_ = value; } } @@ -2172,13 +2578,13 @@ public int FieldName7 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName7 { - get { return (_hasBits0 & 2097152) != 0; } + get { return (_hasBits1 & 4) != 0; } } /// Clears the value of the "fieldName7" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName7() { - _hasBits0 &= ~2097152; + _hasBits1 &= ~4; } /// Field number for the "FieldName8" field. @@ -2189,9 +2595,9 @@ public void ClearFieldName7() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName8 { - get { if ((_hasBits0 & 4194304) != 0) { return fieldName8_; } else { return FieldName8DefaultValue; } } + get { if ((_hasBits1 & 8) != 0) { return fieldName8_; } else { return FieldName8DefaultValue; } } set { - _hasBits0 |= 4194304; + _hasBits1 |= 8; fieldName8_ = value; } } @@ -2199,13 +2605,13 @@ public int FieldName8 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName8 { - get { return (_hasBits0 & 4194304) != 0; } + get { return (_hasBits1 & 8) != 0; } } /// Clears the value of the "FieldName8" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName8() { - _hasBits0 &= ~4194304; + _hasBits1 &= ~8; } /// Field number for the "field_Name9" field. @@ -2216,9 +2622,9 @@ public void ClearFieldName8() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName9 { - get { if ((_hasBits0 & 8388608) != 0) { return fieldName9_; } else { return FieldName9DefaultValue; } } + get { if ((_hasBits1 & 16) != 0) { return fieldName9_; } else { return FieldName9DefaultValue; } } set { - _hasBits0 |= 8388608; + _hasBits1 |= 16; fieldName9_ = value; } } @@ -2226,13 +2632,13 @@ public int FieldName9 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName9 { - get { return (_hasBits0 & 8388608) != 0; } + get { return (_hasBits1 & 16) != 0; } } /// Clears the value of the "field_Name9" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName9() { - _hasBits0 &= ~8388608; + _hasBits1 &= ~16; } /// Field number for the "Field_Name10" field. @@ -2243,9 +2649,9 @@ public void ClearFieldName9() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName10 { - get { if ((_hasBits0 & 16777216) != 0) { return fieldName10_; } else { return FieldName10DefaultValue; } } + get { if ((_hasBits1 & 32) != 0) { return fieldName10_; } else { return FieldName10DefaultValue; } } set { - _hasBits0 |= 16777216; + _hasBits1 |= 32; fieldName10_ = value; } } @@ -2253,13 +2659,13 @@ public int FieldName10 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName10 { - get { return (_hasBits0 & 16777216) != 0; } + get { return (_hasBits1 & 32) != 0; } } /// Clears the value of the "Field_Name10" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName10() { - _hasBits0 &= ~16777216; + _hasBits1 &= ~32; } /// Field number for the "FIELD_NAME11" field. @@ -2270,9 +2676,9 @@ public void ClearFieldName10() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FIELDNAME11 { - get { if ((_hasBits0 & 33554432) != 0) { return fIELDNAME11_; } else { return FIELDNAME11DefaultValue; } } + get { if ((_hasBits1 & 64) != 0) { return fIELDNAME11_; } else { return FIELDNAME11DefaultValue; } } set { - _hasBits0 |= 33554432; + _hasBits1 |= 64; fIELDNAME11_ = value; } } @@ -2280,13 +2686,13 @@ public int FIELDNAME11 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFIELDNAME11 { - get { return (_hasBits0 & 33554432) != 0; } + get { return (_hasBits1 & 64) != 0; } } /// Clears the value of the "FIELD_NAME11" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFIELDNAME11() { - _hasBits0 &= ~33554432; + _hasBits1 &= ~64; } /// Field number for the "FIELD_name12" field. @@ -2297,9 +2703,9 @@ public void ClearFIELDNAME11() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FIELDName12 { - get { if ((_hasBits0 & 67108864) != 0) { return fIELDName12_; } else { return FIELDName12DefaultValue; } } + get { if ((_hasBits1 & 128) != 0) { return fIELDName12_; } else { return FIELDName12DefaultValue; } } set { - _hasBits0 |= 67108864; + _hasBits1 |= 128; fIELDName12_ = value; } } @@ -2307,13 +2713,13 @@ public int FIELDName12 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFIELDName12 { - get { return (_hasBits0 & 67108864) != 0; } + get { return (_hasBits1 & 128) != 0; } } /// Clears the value of the "FIELD_name12" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFIELDName12() { - _hasBits0 &= ~67108864; + _hasBits1 &= ~128; } /// Field number for the "__field_name13" field. @@ -2324,9 +2730,9 @@ public void ClearFIELDName12() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName13 { - get { if ((_hasBits0 & 134217728) != 0) { return FieldName13_; } else { return FieldName13DefaultValue; } } + get { if ((_hasBits1 & 256) != 0) { return FieldName13_; } else { return FieldName13DefaultValue; } } set { - _hasBits0 |= 134217728; + _hasBits1 |= 256; FieldName13_ = value; } } @@ -2334,13 +2740,13 @@ public int FieldName13 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName13 { - get { return (_hasBits0 & 134217728) != 0; } + get { return (_hasBits1 & 256) != 0; } } /// Clears the value of the "__field_name13" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName13() { - _hasBits0 &= ~134217728; + _hasBits1 &= ~256; } /// Field number for the "__Field_name14" field. @@ -2351,9 +2757,9 @@ public void ClearFieldName13() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName14 { - get { if ((_hasBits0 & 268435456) != 0) { return FieldName14_; } else { return FieldName14DefaultValue; } } + get { if ((_hasBits1 & 512) != 0) { return FieldName14_; } else { return FieldName14DefaultValue; } } set { - _hasBits0 |= 268435456; + _hasBits1 |= 512; FieldName14_ = value; } } @@ -2361,13 +2767,13 @@ public int FieldName14 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName14 { - get { return (_hasBits0 & 268435456) != 0; } + get { return (_hasBits1 & 512) != 0; } } /// Clears the value of the "__Field_name14" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName14() { - _hasBits0 &= ~268435456; + _hasBits1 &= ~512; } /// Field number for the "field__name15" field. @@ -2378,9 +2784,9 @@ public void ClearFieldName14() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName15 { - get { if ((_hasBits0 & 536870912) != 0) { return fieldName15_; } else { return FieldName15DefaultValue; } } + get { if ((_hasBits1 & 1024) != 0) { return fieldName15_; } else { return FieldName15DefaultValue; } } set { - _hasBits0 |= 536870912; + _hasBits1 |= 1024; fieldName15_ = value; } } @@ -2388,13 +2794,13 @@ public int FieldName15 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName15 { - get { return (_hasBits0 & 536870912) != 0; } + get { return (_hasBits1 & 1024) != 0; } } /// Clears the value of the "field__name15" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName15() { - _hasBits0 &= ~536870912; + _hasBits1 &= ~1024; } /// Field number for the "field__Name16" field. @@ -2405,9 +2811,9 @@ public void ClearFieldName15() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName16 { - get { if ((_hasBits0 & 1073741824) != 0) { return fieldName16_; } else { return FieldName16DefaultValue; } } + get { if ((_hasBits1 & 2048) != 0) { return fieldName16_; } else { return FieldName16DefaultValue; } } set { - _hasBits0 |= 1073741824; + _hasBits1 |= 2048; fieldName16_ = value; } } @@ -2415,13 +2821,13 @@ public int FieldName16 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName16 { - get { return (_hasBits0 & 1073741824) != 0; } + get { return (_hasBits1 & 2048) != 0; } } /// Clears the value of the "field__Name16" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName16() { - _hasBits0 &= ~1073741824; + _hasBits1 &= ~2048; } /// Field number for the "field_name17__" field. @@ -2432,9 +2838,9 @@ public void ClearFieldName16() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName17 { - get { if ((_hasBits0 & -2147483648) != 0) { return fieldName17_; } else { return FieldName17DefaultValue; } } + get { if ((_hasBits1 & 4096) != 0) { return fieldName17_; } else { return FieldName17DefaultValue; } } set { - _hasBits0 |= -2147483648; + _hasBits1 |= 4096; fieldName17_ = value; } } @@ -2442,13 +2848,13 @@ public int FieldName17 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName17 { - get { return (_hasBits0 & -2147483648) != 0; } + get { return (_hasBits1 & 4096) != 0; } } /// Clears the value of the "field_name17__" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName17() { - _hasBits0 &= ~-2147483648; + _hasBits1 &= ~4096; } /// Field number for the "Field_name18__" field. @@ -2459,9 +2865,9 @@ public void ClearFieldName17() { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public int FieldName18 { - get { if ((_hasBits1 & 1) != 0) { return fieldName18_; } else { return FieldName18DefaultValue; } } + get { if ((_hasBits1 & 8192) != 0) { return fieldName18_; } else { return FieldName18DefaultValue; } } set { - _hasBits1 |= 1; + _hasBits1 |= 8192; fieldName18_ = value; } } @@ -2469,13 +2875,13 @@ public int FieldName18 { [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public bool HasFieldName18 { - get { return (_hasBits1 & 1) != 0; } + get { return (_hasBits1 & 8192) != 0; } } /// Clears the value of the "Field_name18__" field [global::System.Diagnostics.DebuggerNonUserCodeAttribute] [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] public void ClearFieldName18() { - _hasBits1 &= ~1; + _hasBits1 &= ~8192; } private object oneofField_; @@ -2621,6 +3027,20 @@ public bool Equals(TestAllTypesProto2 other) { if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(OneofDouble, other.OneofDouble)) return false; if (OneofEnum != other.OneofEnum) return false; if (!object.Equals(Data, other.Data)) return false; + if (DefaultInt32 != other.DefaultInt32) return false; + if (DefaultInt64 != other.DefaultInt64) return false; + if (DefaultUint32 != other.DefaultUint32) return false; + if (DefaultUint64 != other.DefaultUint64) return false; + if (DefaultSint32 != other.DefaultSint32) return false; + if (DefaultSint64 != other.DefaultSint64) return false; + if (DefaultFixed32 != other.DefaultFixed32) return false; + if (DefaultFixed64 != other.DefaultFixed64) return false; + if (DefaultSfixed32 != other.DefaultSfixed32) return false; + if (DefaultSfixed64 != other.DefaultSfixed64) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(DefaultFloat, other.DefaultFloat)) return false; + if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(DefaultDouble, other.DefaultDouble)) return false; + if (DefaultBool != other.DefaultBool) return false; + if (DefaultString != other.DefaultString) return false; if (Fieldname1 != other.Fieldname1) return false; if (FieldName2 != other.FieldName2) return false; if (FieldName3 != other.FieldName3) return false; @@ -2750,6 +3170,20 @@ public override int GetHashCode() { if (HasOneofDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(OneofDouble); if (HasOneofEnum) hash ^= OneofEnum.GetHashCode(); if (HasData) hash ^= Data.GetHashCode(); + if (HasDefaultInt32) hash ^= DefaultInt32.GetHashCode(); + if (HasDefaultInt64) hash ^= DefaultInt64.GetHashCode(); + if (HasDefaultUint32) hash ^= DefaultUint32.GetHashCode(); + if (HasDefaultUint64) hash ^= DefaultUint64.GetHashCode(); + if (HasDefaultSint32) hash ^= DefaultSint32.GetHashCode(); + if (HasDefaultSint64) hash ^= DefaultSint64.GetHashCode(); + if (HasDefaultFixed32) hash ^= DefaultFixed32.GetHashCode(); + if (HasDefaultFixed64) hash ^= DefaultFixed64.GetHashCode(); + if (HasDefaultSfixed32) hash ^= DefaultSfixed32.GetHashCode(); + if (HasDefaultSfixed64) hash ^= DefaultSfixed64.GetHashCode(); + if (HasDefaultFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(DefaultFloat); + if (HasDefaultDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(DefaultDouble); + if (HasDefaultBool) hash ^= DefaultBool.GetHashCode(); + if (HasDefaultString) hash ^= DefaultString.GetHashCode(); if (HasFieldname1) hash ^= Fieldname1.GetHashCode(); if (HasFieldName2) hash ^= FieldName2.GetHashCode(); if (HasFieldName3) hash ^= FieldName3.GetHashCode(); @@ -2987,6 +3421,62 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteGroup(Data); output.WriteRawTag(204, 12); } + if (HasDefaultInt32) { + output.WriteRawTag(136, 15); + output.WriteInt32(DefaultInt32); + } + if (HasDefaultInt64) { + output.WriteRawTag(144, 15); + output.WriteInt64(DefaultInt64); + } + if (HasDefaultUint32) { + output.WriteRawTag(152, 15); + output.WriteUInt32(DefaultUint32); + } + if (HasDefaultUint64) { + output.WriteRawTag(160, 15); + output.WriteUInt64(DefaultUint64); + } + if (HasDefaultSint32) { + output.WriteRawTag(168, 15); + output.WriteSInt32(DefaultSint32); + } + if (HasDefaultSint64) { + output.WriteRawTag(176, 15); + output.WriteSInt64(DefaultSint64); + } + if (HasDefaultFixed32) { + output.WriteRawTag(189, 15); + output.WriteFixed32(DefaultFixed32); + } + if (HasDefaultFixed64) { + output.WriteRawTag(193, 15); + output.WriteFixed64(DefaultFixed64); + } + if (HasDefaultSfixed32) { + output.WriteRawTag(205, 15); + output.WriteSFixed32(DefaultSfixed32); + } + if (HasDefaultSfixed64) { + output.WriteRawTag(209, 15); + output.WriteSFixed64(DefaultSfixed64); + } + if (HasDefaultFloat) { + output.WriteRawTag(221, 15); + output.WriteFloat(DefaultFloat); + } + if (HasDefaultDouble) { + output.WriteRawTag(225, 15); + output.WriteDouble(DefaultDouble); + } + if (HasDefaultBool) { + output.WriteRawTag(232, 15); + output.WriteBool(DefaultBool); + } + if (HasDefaultString) { + output.WriteRawTag(242, 15); + output.WriteString(DefaultString); + } if (HasFieldname1) { output.WriteRawTag(136, 25); output.WriteInt32(Fieldname1); @@ -3269,6 +3759,62 @@ public void WriteTo(pb::CodedOutputStream output) { output.WriteGroup(Data); output.WriteRawTag(204, 12); } + if (HasDefaultInt32) { + output.WriteRawTag(136, 15); + output.WriteInt32(DefaultInt32); + } + if (HasDefaultInt64) { + output.WriteRawTag(144, 15); + output.WriteInt64(DefaultInt64); + } + if (HasDefaultUint32) { + output.WriteRawTag(152, 15); + output.WriteUInt32(DefaultUint32); + } + if (HasDefaultUint64) { + output.WriteRawTag(160, 15); + output.WriteUInt64(DefaultUint64); + } + if (HasDefaultSint32) { + output.WriteRawTag(168, 15); + output.WriteSInt32(DefaultSint32); + } + if (HasDefaultSint64) { + output.WriteRawTag(176, 15); + output.WriteSInt64(DefaultSint64); + } + if (HasDefaultFixed32) { + output.WriteRawTag(189, 15); + output.WriteFixed32(DefaultFixed32); + } + if (HasDefaultFixed64) { + output.WriteRawTag(193, 15); + output.WriteFixed64(DefaultFixed64); + } + if (HasDefaultSfixed32) { + output.WriteRawTag(205, 15); + output.WriteSFixed32(DefaultSfixed32); + } + if (HasDefaultSfixed64) { + output.WriteRawTag(209, 15); + output.WriteSFixed64(DefaultSfixed64); + } + if (HasDefaultFloat) { + output.WriteRawTag(221, 15); + output.WriteFloat(DefaultFloat); + } + if (HasDefaultDouble) { + output.WriteRawTag(225, 15); + output.WriteDouble(DefaultDouble); + } + if (HasDefaultBool) { + output.WriteRawTag(232, 15); + output.WriteBool(DefaultBool); + } + if (HasDefaultString) { + output.WriteRawTag(242, 15); + output.WriteString(DefaultString); + } if (HasFieldname1) { output.WriteRawTag(136, 25); output.WriteInt32(Fieldname1); @@ -3518,6 +4064,48 @@ public int CalculateSize() { if (HasData) { size += 4 + pb::CodedOutputStream.ComputeGroupSize(Data); } + if (HasDefaultInt32) { + size += 2 + pb::CodedOutputStream.ComputeInt32Size(DefaultInt32); + } + if (HasDefaultInt64) { + size += 2 + pb::CodedOutputStream.ComputeInt64Size(DefaultInt64); + } + if (HasDefaultUint32) { + size += 2 + pb::CodedOutputStream.ComputeUInt32Size(DefaultUint32); + } + if (HasDefaultUint64) { + size += 2 + pb::CodedOutputStream.ComputeUInt64Size(DefaultUint64); + } + if (HasDefaultSint32) { + size += 2 + pb::CodedOutputStream.ComputeSInt32Size(DefaultSint32); + } + if (HasDefaultSint64) { + size += 2 + pb::CodedOutputStream.ComputeSInt64Size(DefaultSint64); + } + if (HasDefaultFixed32) { + size += 2 + 4; + } + if (HasDefaultFixed64) { + size += 2 + 8; + } + if (HasDefaultSfixed32) { + size += 2 + 4; + } + if (HasDefaultSfixed64) { + size += 2 + 8; + } + if (HasDefaultFloat) { + size += 2 + 4; + } + if (HasDefaultDouble) { + size += 2 + 8; + } + if (HasDefaultBool) { + size += 2 + 1; + } + if (HasDefaultString) { + size += 2 + pb::CodedOutputStream.ComputeStringSize(DefaultString); + } if (HasFieldname1) { size += 2 + pb::CodedOutputStream.ComputeInt32Size(Fieldname1); } @@ -3736,6 +4324,48 @@ public void MergeFrom(TestAllTypesProto2 other) { } Data.MergeFrom(other.Data); } + if (other.HasDefaultInt32) { + DefaultInt32 = other.DefaultInt32; + } + if (other.HasDefaultInt64) { + DefaultInt64 = other.DefaultInt64; + } + if (other.HasDefaultUint32) { + DefaultUint32 = other.DefaultUint32; + } + if (other.HasDefaultUint64) { + DefaultUint64 = other.DefaultUint64; + } + if (other.HasDefaultSint32) { + DefaultSint32 = other.DefaultSint32; + } + if (other.HasDefaultSint64) { + DefaultSint64 = other.DefaultSint64; + } + if (other.HasDefaultFixed32) { + DefaultFixed32 = other.DefaultFixed32; + } + if (other.HasDefaultFixed64) { + DefaultFixed64 = other.DefaultFixed64; + } + if (other.HasDefaultSfixed32) { + DefaultSfixed32 = other.DefaultSfixed32; + } + if (other.HasDefaultSfixed64) { + DefaultSfixed64 = other.DefaultSfixed64; + } + if (other.HasDefaultFloat) { + DefaultFloat = other.DefaultFloat; + } + if (other.HasDefaultDouble) { + DefaultDouble = other.DefaultDouble; + } + if (other.HasDefaultBool) { + DefaultBool = other.DefaultBool; + } + if (other.HasDefaultString) { + DefaultString = other.DefaultString; + } if (other.HasFieldname1) { Fieldname1 = other.Fieldname1; } @@ -4302,6 +4932,62 @@ public void MergeFrom(pb::CodedInputStream input) { input.ReadGroup(Data); break; } + case 1928: { + DefaultInt32 = input.ReadInt32(); + break; + } + case 1936: { + DefaultInt64 = input.ReadInt64(); + break; + } + case 1944: { + DefaultUint32 = input.ReadUInt32(); + break; + } + case 1952: { + DefaultUint64 = input.ReadUInt64(); + break; + } + case 1960: { + DefaultSint32 = input.ReadSInt32(); + break; + } + case 1968: { + DefaultSint64 = input.ReadSInt64(); + break; + } + case 1981: { + DefaultFixed32 = input.ReadFixed32(); + break; + } + case 1985: { + DefaultFixed64 = input.ReadFixed64(); + break; + } + case 1997: { + DefaultSfixed32 = input.ReadSFixed32(); + break; + } + case 2001: { + DefaultSfixed64 = input.ReadSFixed64(); + break; + } + case 2013: { + DefaultFloat = input.ReadFloat(); + break; + } + case 2017: { + DefaultDouble = input.ReadDouble(); + break; + } + case 2024: { + DefaultBool = input.ReadBool(); + break; + } + case 2034: { + DefaultString = input.ReadString(); + break; + } case 3208: { Fieldname1 = input.ReadInt32(); break; @@ -4852,6 +5538,62 @@ public void MergeFrom(pb::CodedInputStream input) { input.ReadGroup(Data); break; } + case 1928: { + DefaultInt32 = input.ReadInt32(); + break; + } + case 1936: { + DefaultInt64 = input.ReadInt64(); + break; + } + case 1944: { + DefaultUint32 = input.ReadUInt32(); + break; + } + case 1952: { + DefaultUint64 = input.ReadUInt64(); + break; + } + case 1960: { + DefaultSint32 = input.ReadSInt32(); + break; + } + case 1968: { + DefaultSint64 = input.ReadSInt64(); + break; + } + case 1981: { + DefaultFixed32 = input.ReadFixed32(); + break; + } + case 1985: { + DefaultFixed64 = input.ReadFixed64(); + break; + } + case 1997: { + DefaultSfixed32 = input.ReadSFixed32(); + break; + } + case 2001: { + DefaultSfixed64 = input.ReadSFixed64(); + break; + } + case 2013: { + DefaultFloat = input.ReadFloat(); + break; + } + case 2017: { + DefaultDouble = input.ReadDouble(); + break; + } + case 2024: { + DefaultBool = input.ReadBool(); + break; + } + case 2034: { + DefaultString = input.ReadString(); + break; + } case 3208: { Fieldname1 = input.ReadInt32(); break; diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb index da79db8ec462..f1f44f1c5467 100644 Binary files a/csharp/src/Google.Protobuf.Test/testprotos.pb and b/csharp/src/Google.Protobuf.Test/testprotos.pb differ diff --git a/java/core/BUILD b/java/core/BUILD index 42124bb4f011..c65f10a4e1a5 100644 --- a/java/core/BUILD +++ b/java/core/BUILD @@ -255,7 +255,6 @@ junit_tests( ":java_test_protos_java_proto", ":test_util", "//external:easymock", - "//external:easymock_classextension", "//external:guava", "//external:junit", "//external:truth", diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java index eb690b5a4370..f36d03332773 100644 --- a/java/core/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java @@ -49,6 +49,7 @@ import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto; import com.google.protobuf.DescriptorProtos.ServiceOptions; import com.google.protobuf.Descriptors.FileDescriptor.Syntax; +import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; @@ -59,7 +60,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.WeakHashMap; import java.util.logging.Logger; /** @@ -1816,6 +1816,15 @@ public EnumValueDescriptor findValueByNumber(final int number) { valuesSortedByNumber, distinctNumbers, EnumValueDescriptor.NUMBER_GETTER, number); } + private static class UnknownEnumValueReference extends WeakReference { + private final int number; + + private UnknownEnumValueReference(int number, EnumValueDescriptor descriptor) { + super(descriptor); + this.number = number; + } + } + /** * Get the enum value for a number. If no enum value has this number, construct an * EnumValueDescriptor for it. @@ -1827,43 +1836,28 @@ public EnumValueDescriptor findValueByNumberCreatingIfUnknown(final int number) } // The number represents an unknown enum value. synchronized (this) { - // Descriptors are compared by object identity so for the same number - // we need to return the same EnumValueDescriptor object. This means - // we have to store created EnumValueDescriptors. However, as there - // are potentially 2G unknown enum values, storing all of these - // objects persistently will consume lots of memory for long-running - // services and it's also unnecessary as not many EnumValueDescriptors - // will be used at the same time. - // - // To solve the problem we take advantage of Java's weak references and - // rely on gc to release unused descriptors. - // - // Here is how it works: - // * We store unknown EnumValueDescriptors in a WeakHashMap with the - // value being a weak reference to the descriptor. - // * The descriptor holds a strong reference to the key so as long - // as the EnumValueDescriptor is in use, the key will be there - // and the corresponding map entry will be there. Following-up - // queries with the same number will return the same descriptor. - // * If the user no longer uses an unknown EnumValueDescriptor, - // it will be gc-ed since we only hold a weak reference to it in - // the map. The key in the corresponding map entry will also be - // gc-ed as the only strong reference to it is in the descriptor - // which is just gc-ed. With the key being gone WeakHashMap will - // then remove the whole entry. This way unknown descriptors will - // be freed automatically and we don't need to do anything to - // clean-up unused map entries. - - // Note: We must use "new Integer(number)" here because we don't want - // these Integer objects to be cached. - Integer key = new Integer(number); - WeakReference reference = unknownValues.get(key); - if (reference != null) { - result = reference.get(); + if (cleanupQueue == null) { + cleanupQueue = new ReferenceQueue(); + unknownValues = new HashMap>(); + } else { + while (true) { + UnknownEnumValueReference toClean = (UnknownEnumValueReference) cleanupQueue.poll(); + if (toClean == null) { + break; + } + unknownValues.remove(toClean.number); + } } + + // There are two ways we can be missing a value: it wasn't in the map, or the reference + // has been GC'd. (It may even have been GC'd since we cleaned up the references a few + // lines of code ago.) So get out the reference, if it's still present... + WeakReference reference = unknownValues.get(number); + result = (reference == null) ? null : reference.get(); + if (result == null) { - result = new EnumValueDescriptor(this, key); - unknownValues.put(key, new WeakReference(result)); + result = new EnumValueDescriptor(this, number); + unknownValues.put(number, new UnknownEnumValueReference(number, result)); } } return result; @@ -1882,8 +1876,8 @@ int getUnknownEnumValueDescriptorCount() { private final EnumValueDescriptor[] values; private final EnumValueDescriptor[] valuesSortedByNumber; private final int distinctNumbers; - private final WeakHashMap> unknownValues = - new WeakHashMap<>(); + private Map> unknownValues = null; + private ReferenceQueue cleanupQueue = null; private EnumDescriptor( final EnumDescriptorProto proto, diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java index 90643b8abb99..07e8dd132257 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -54,6 +54,7 @@ public final class Internal { private Internal() {} + static final Charset US_ASCII = Charset.forName("US-ASCII"); static final Charset UTF_8 = Charset.forName("UTF-8"); static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); diff --git a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java index 4b4303374c83..118a1e8392b1 100644 --- a/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java +++ b/java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java @@ -134,7 +134,7 @@ static InvalidWireTypeException invalidWireType() { return new InvalidWireTypeException("Protocol message tag had invalid wire type."); } - /** Exception indicating that and unexpected wire type was encountered for a field. */ + /** Exception indicating that an unexpected wire type was encountered for a field. */ @ExperimentalApi public static class InvalidWireTypeException extends InvalidProtocolBufferException { private static final long serialVersionUID = 3283890091615336259L; diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java index 4aea9528ac01..9ad681679fbe 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java +++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java @@ -187,10 +187,10 @@ private static boolean isDefaultValue(Object o) { return ((Integer) o) == 0; } if (o instanceof Float) { - return ((Float) o) == 0f; + return Float.floatToRawIntBits((Float) o) == 0; } if (o instanceof Double) { - return ((Double) o) == 0d; + return Double.doubleToRawLongBits((Double) o) == 0; } if (o instanceof String) { return o.equals(""); diff --git a/java/core/src/main/java/com/google/protobuf/MessageSchema.java b/java/core/src/main/java/com/google/protobuf/MessageSchema.java index 33c8e914b24e..4170f4fbe499 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageSchema.java +++ b/java/core/src/main/java/com/google/protobuf/MessageSchema.java @@ -5808,9 +5808,9 @@ private boolean isFieldPresent(T message, int pos) { final long offset = offset(typeAndOffset); switch (type(typeAndOffset)) { case 0: // DOUBLE: - return UnsafeUtil.getDouble(message, offset) != 0D; + return Double.doubleToRawLongBits(UnsafeUtil.getDouble(message, offset)) != 0L; case 1: // FLOAT: - return UnsafeUtil.getFloat(message, offset) != 0F; + return Float.floatToRawIntBits(UnsafeUtil.getFloat(message, offset)) != 0; case 2: // INT64: return UnsafeUtil.getLong(message, offset) != 0L; case 3: // UINT64: diff --git a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java index a798599c8606..1d5e6ba69c17 100644 --- a/java/core/src/main/java/com/google/protobuf/SchemaUtil.java +++ b/java/core/src/main/java/com/google/protobuf/SchemaUtil.java @@ -68,13 +68,13 @@ public static void requireGeneratedMessage(Class messageType) { } public static void writeDouble(int fieldNumber, double value, Writer writer) throws IOException { - if (Double.compare(value, 0.0) != 0) { + if (Double.doubleToRawLongBits(value) != 0) { writer.writeDouble(fieldNumber, value); } } public static void writeFloat(int fieldNumber, float value, Writer writer) throws IOException { - if (Float.compare(value, 0.0f) != 0) { + if (Float.floatToRawIntBits(value) != 0) { writer.writeFloat(fieldNumber, value); } } diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java index 6ce9f783ac24..36232e9a5b57 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java @@ -90,7 +90,7 @@ private TextFormatParseInfoTree( /** * Retrieve all the locations of a field. * - * @param fieldDescriptor the @{link FieldDescriptor} of the desired field + * @param fieldDescriptor the {@link FieldDescriptor} of the desired field * @return a list of the locations of values of the field. If there are not values or the field * doesn't exist, an empty list is returned. */ @@ -105,7 +105,7 @@ public List getLocations(final FieldDescriptor fieldDes *

Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed * text. * - * @param fieldDescriptor the @{link FieldDescriptor} of the desired field + * @param fieldDescriptor the {@link FieldDescriptor} of the desired field * @param index the index of the value. * @return the {@link TextFormatParseLocation} of the value * @throws IllegalArgumentException index is out of range @@ -117,7 +117,7 @@ public TextFormatParseLocation getLocation(final FieldDescriptor fieldDescriptor /** * Retrieve a list of all the location information trees for a sub message field. * - * @param fieldDescriptor the @{link FieldDescriptor} of the desired field + * @param fieldDescriptor the {@link FieldDescriptor} of the desired field * @return A list of {@link TextFormatParseInfoTree} */ public List getNestedTrees(final FieldDescriptor fieldDescriptor) { @@ -128,7 +128,7 @@ public List getNestedTrees(final FieldDescriptor fieldD /** * Returns the parse info tree for the given field, which must be a message type. * - * @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message + * @param fieldDescriptor the {@link FieldDescriptor} of the desired sub message * @param index the index of message value. * @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field * doesn't exist or the index is out of range. diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java index 7d56ddd6e640..7c9133e16b32 100644 --- a/java/core/src/main/java/com/google/protobuf/Utf8.java +++ b/java/core/src/main/java/com/google/protobuf/Utf8.java @@ -1371,29 +1371,39 @@ String decodeUtf8(byte[] bytes, int index, int size) throws InvalidProtocolBuffe String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size)); } - int offset = index; - final int limit = offset + size; - - // The longest possible resulting String is the same as the number of input bytes, when it is - // all ASCII. For other cases, this over-allocates and we will truncate in the end. - char[] resultArr = new char[size]; - int resultPos = 0; + int offset = index + unsafeEstimateConsecutiveAscii(bytes, index, size); + final int limit = index + size; - // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this). - // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII). + // get an "exact" consecutive ASCII while (offset < limit) { byte b = UnsafeUtil.getByte(bytes, offset); - if (!DecodeUtil.isOneByte(b)) { + if (b < 0) { break; } offset++; - DecodeUtil.handleOneByte(b, resultArr, resultPos++); + } + + if (offset == limit) { + // The entire byte sequence is ASCII. Don't bother copying to a char[], JVMs using + // compact strings will just turn it back into the same byte[]. + return new String(bytes, index, size, Internal.US_ASCII); + } + + // It's not all ASCII, at this point. This may over-allocate, but we will truncate in the + // end. + char[] resultArr = new char[size]; + int resultPos = 0; + + // Copy over the initial run of ASCII. + for (int i = index; i < offset; i++) { + DecodeUtil.handleOneByte(UnsafeUtil.getByte(bytes, i), resultArr, resultPos++); } while (offset < limit) { byte byte1 = UnsafeUtil.getByte(bytes, offset++); if (DecodeUtil.isOneByte(byte1)) { DecodeUtil.handleOneByte(byte1, resultArr, resultPos++); + // It's common for there to be multiple ASCII characters in a run mixed in, so add an // extra optimized loop to take care of these runs. while (offset < limit) { @@ -1656,7 +1666,17 @@ private static int unsafeEstimateConsecutiveAscii( return 0; } - for (int i = 0; i < maxChars; i++) { + int i; + for (i = 0; i + 8 <= maxChars; i += 8) { + if ((UnsafeUtil.getLong(bytes, UnsafeUtil.BYTE_ARRAY_BASE_OFFSET + offset) + & ASCII_MASK_LONG) + != 0L) { + break; + } + offset += 8; + } + + for (; i < maxChars; i++) { if (UnsafeUtil.getByte(bytes, offset++) < 0) { return i; } diff --git a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java index 458529c4c318..800623ac741b 100644 --- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java +++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java @@ -49,7 +49,7 @@ @RunWith(JUnit4.class) public class CheckUtf8Test { - private static final String UTF8_BYTE_STRING_TEXT = "some text"; + private static final String UTF8_BYTE_STRING_TEXT = "some text π \uD83D\uDE00"; private static final ByteString UTF8_BYTE_STRING = ByteString.copyFromUtf8(UTF8_BYTE_STRING_TEXT); private static final ByteString NON_UTF8_BYTE_STRING = ByteString.copyFrom(new byte[] {(byte) 0x80}); // A lone continuation byte. diff --git a/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java index 359d4d74c02b..5a345aa173fd 100644 --- a/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java +++ b/java/core/src/test/java/com/google/protobuf/DecodeUtf8Test.java @@ -1,3 +1,33 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + package com.google.protobuf; import com.google.protobuf.Utf8.Processor; @@ -28,12 +58,13 @@ public void testRoundTripAllValidChars() throws Exception { public void testOneByte() throws Exception { int valid = 0; + ByteBuffer buffer = ByteBuffer.allocateDirect(1); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - ByteString bs = ByteString.copyFrom(new byte[] { (byte) i }); - if (!bs.isValidUtf8()) { - assertInvalid(bs.toByteArray()); - } else { + ByteString bs = ByteString.copyFrom(new byte[] {(byte) i}); + if (bs.isValidUtf8()) { valid++; + } else { + assertInvalid(bs.toByteArray(), buffer); } } assertEquals(IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, valid); @@ -41,13 +72,14 @@ public void testOneByte() throws Exception { public void testTwoBytes() throws Exception { int valid = 0; + ByteBuffer buffer = ByteBuffer.allocateDirect(2); for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) { - ByteString bs = ByteString.copyFrom(new byte[]{(byte) i, (byte) j}); - if (!bs.isValidUtf8()) { - assertInvalid(bs.toByteArray()); - } else { + ByteString bs = ByteString.copyFrom(new byte[] {(byte) i, (byte) j}); + if (bs.isValidUtf8()) { valid++; + } else { + assertInvalid(bs.toByteArray(), buffer); } } } @@ -55,34 +87,30 @@ public void testTwoBytes() throws Exception { } public void testThreeBytes() throws Exception { - // Travis' OOM killer doesn't like this test - if (System.getenv("TRAVIS") == null) { - int count = 0; - int valid = 0; - for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { - for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) { - for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) { - byte[] bytes = new byte[]{(byte) i, (byte) j, (byte) k}; - ByteString bs = ByteString.copyFrom(bytes); - if (!bs.isValidUtf8()) { - assertInvalid(bytes); - } else { - valid++; - } - count++; - if (count % 1000000L == 0) { - logger.info("Processed " + (count / 1000000L) + " million characters"); - } + int count = 0; + int valid = 0; + ByteBuffer buffer = ByteBuffer.allocateDirect(3); + for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) { + for (int j = Byte.MIN_VALUE; j <= Byte.MAX_VALUE; j++) { + for (int k = Byte.MIN_VALUE; k <= Byte.MAX_VALUE; k++) { + byte[] bytes = new byte[] {(byte) i, (byte) j, (byte) k}; + ByteString bs = ByteString.copyFrom(bytes); + if (bs.isValidUtf8()) { + valid++; + } else { + assertInvalid(bytes, buffer); + } + count++; + if (count % 1000000L == 0) { + logger.info("Processed " + (count / 1000000L) + " million characters"); } } } - assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid); } + assertEquals(IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT, valid); } - /** - * Tests that round tripping of a sample of four byte permutations work. - */ + /** Tests that round tripping of a sample of four byte permutations work. */ public void testInvalid_4BytesSamples() throws Exception { // Bad trailing bytes assertInvalid(0xF0, 0xA4, 0xAD, 0x7F); @@ -99,8 +127,7 @@ public void testRealStrings() throws Exception { // German assertRoundTrips("Quizdeltagerne spiste jordb\u00e6r med fl\u00f8de, mens cirkusklovnen"); // Japanese - assertRoundTrips( - "\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092"); + assertRoundTrips("\u3044\u308d\u306f\u306b\u307b\u3078\u3068\u3061\u308a\u306c\u308b\u3092"); // Hebrew assertRoundTrips( "\u05d3\u05d2 \u05e1\u05e7\u05e8\u05df \u05e9\u05d8 \u05d1\u05d9\u05dd " @@ -115,9 +142,10 @@ public void testRealStrings() throws Exception { assertRoundTrips( "\u8fd4\u56de\u94fe\u4e2d\u7684\u4e0b\u4e00\u4e2a\u4ee3\u7406\u9879\u9009\u62e9\u5668"); // Chinese with 4-byte chars - assertRoundTrips("\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78" - + "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F" - + "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2"); + assertRoundTrips( + "\uD841\uDF0E\uD841\uDF31\uD841\uDF79\uD843\uDC53\uD843\uDC78" + + "\uD843\uDC96\uD843\uDCCF\uD843\uDCD5\uD843\uDD15\uD843\uDD7C\uD843\uDD7F" + + "\uD843\uDE0E\uD843\uDE0F\uD843\uDE77\uD843\uDE9D\uD843\uDEA2"); // Mixed assertRoundTrips( "The quick brown \u3044\u308d\u306f\u306b\u307b\u3078\u8fd4\u56de\u94fe" @@ -132,7 +160,7 @@ public void testOverlong() throws Exception { // Max overlong assertInvalid(0xc1, 0xbf); assertInvalid(0xe0, 0x9f, 0xbf); - assertInvalid(0xf0 ,0x8f, 0xbf, 0xbf); + assertInvalid(0xf0, 0x8f, 0xbf, 0xbf); // null overlong assertInvalid(0xc0, 0x80); @@ -168,7 +196,7 @@ public void testBufferSlice() throws Exception { } public void testInvalidBufferSlice() throws Exception { - byte[] bytes = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8); + byte[] bytes = "The quick brown fox jumps over the lazy dog".getBytes(Internal.UTF_8); assertInvalidSlice(bytes, bytes.length - 3, 4); assertInvalidSlice(bytes, bytes.length, 1); assertInvalidSlice(bytes, bytes.length + 1, 0); @@ -180,10 +208,14 @@ private void assertInvalid(int... bytesAsInt) throws Exception { for (int i = 0; i < bytesAsInt.length; i++) { bytes[i] = (byte) bytesAsInt[i]; } - assertInvalid(bytes); + assertInvalid(bytes, null); } - private void assertInvalid(byte[] bytes) throws Exception { + // Attempts to decode the byte array in several ways and asserts that it always generates an + // exception. Allocating a direct ByteBuffer is slow, so the caller can optionally provide a + // buffer to reuse. If buffer is non-null, it must be a direct-allocated ByteBuffer of the + // appropriate size. + private void assertInvalid(byte[] bytes, ByteBuffer buffer) throws Exception { try { UNSAFE_PROCESSOR.decodeUtf8(bytes, 0, bytes.length); fail(); @@ -197,37 +229,24 @@ private void assertInvalid(byte[] bytes) throws Exception { // Expected. } - ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length); - direct.put(bytes); - direct.flip(); - try { - UNSAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. - } - try { - SAFE_PROCESSOR.decodeUtf8(direct, 0, bytes.length); - fail(); - } catch (InvalidProtocolBufferException e) { - // Expected. + if (buffer == null) { + buffer = ByteBuffer.allocateDirect(bytes.length); } - - ByteBuffer heap = ByteBuffer.allocate(bytes.length); - heap.put(bytes); - heap.flip(); + buffer.put(bytes); + buffer.flip(); try { - UNSAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length); + UNSAFE_PROCESSOR.decodeUtf8(buffer, 0, bytes.length); fail(); } catch (InvalidProtocolBufferException e) { // Expected. } try { - SAFE_PROCESSOR.decodeUtf8(heap, 0, bytes.length); + SAFE_PROCESSOR.decodeUtf8(buffer, 0, bytes.length); fail(); } catch (InvalidProtocolBufferException e) { // Expected. } + buffer.clear(); } private void assertInvalidSlice(byte[] bytes, int index, int size) throws Exception { @@ -286,25 +305,31 @@ private void assertRoundTrips(String str, int index, int size) throws Exception if (size == -1) { size = bytes.length; } - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), UNSAFE_PROCESSOR.decodeUtf8(bytes, index, size)); - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), SAFE_PROCESSOR.decodeUtf8(bytes, index, size)); ByteBuffer direct = ByteBuffer.allocateDirect(bytes.length); direct.put(bytes); direct.flip(); - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), UNSAFE_PROCESSOR.decodeUtf8(direct, index, size)); - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), SAFE_PROCESSOR.decodeUtf8(direct, index, size)); ByteBuffer heap = ByteBuffer.allocate(bytes.length); heap.put(bytes); heap.flip(); - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), UNSAFE_PROCESSOR.decodeUtf8(heap, index, size)); - assertDecode(new String(bytes, index, size, Internal.UTF_8), + assertDecode( + new String(bytes, index, size, Internal.UTF_8), SAFE_PROCESSOR.decodeUtf8(heap, index, size)); } @@ -321,5 +346,4 @@ private List codepoints(String str) { } return codepoints; } - } diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java index bbbe2cd2b392..46e56a9ccbbd 100644 --- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java +++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java @@ -36,6 +36,7 @@ import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT; import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY; import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY; +import static com.google.protobuf.IsValidUtf8TestUtil.ROPE_FACTORY; import static com.google.protobuf.IsValidUtf8TestUtil.testBytes; import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory; @@ -61,6 +62,7 @@ public void testIsValidUtf8_1Byte() { testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(ROPE_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); } /** Tests that round tripping of all two byte permutations work. */ @@ -69,17 +71,16 @@ public void testIsValidUtf8_2Bytes() { testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(ROPE_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); } /** Tests that round tripping of all three byte permutations work. */ @Test public void testIsValidUtf8_3Bytes() { - // Travis' OOM killer doesn't like this test - if (System.getenv("TRAVIS") == null) { - testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); - testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); - testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); - } + testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(ROPE_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); } /** @@ -168,12 +169,14 @@ private void assertValidUtf8(int... bytes) { assertValidUtf8(LITERAL_FACTORY, bytes, false); assertValidUtf8(HEAP_NIO_FACTORY, bytes, false); assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false); + assertValidUtf8(ROPE_FACTORY, bytes, false); } private void assertInvalidUtf8(int... bytes) { assertValidUtf8(LITERAL_FACTORY, bytes, true); assertValidUtf8(HEAP_NIO_FACTORY, bytes, true); assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true); + assertValidUtf8(ROPE_FACTORY, bytes, true); } private static ByteString asBytes(String s) { diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java index 94a9ffb5d26e..f1a671164d18 100644 --- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java +++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java @@ -35,16 +35,10 @@ import java.lang.ref.SoftReference; import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Random; -import java.util.logging.Logger; /** * Shared testing code for {@link IsValidUtf8Test} and {@link IsValidUtf8FourByteTest}. @@ -53,8 +47,6 @@ * @author martinrb@google.com (Martin Buchholz) */ final class IsValidUtf8TestUtil { - private static final Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName()); - private IsValidUtf8TestUtil() {} static interface ByteStringFactory { @@ -102,6 +94,29 @@ public ByteString newByteString(byte[] bytes) { } }; + static final ByteStringFactory ROPE_FACTORY = + new ByteStringFactory() { + // Seed the random number generator with 0 so that the tests are deterministic. + private final Random random = new Random(0); + + @Override + public ByteString newByteString(byte[] bytes) { + // We split the byte array into three pieces (some possibly empty) by choosing two random + // cut points i and j. + int i = random.nextInt(bytes.length); + int j = random.nextInt(bytes.length); + if (j < i) { + int tmp = i; + i = j; + j = tmp; + } + return RopeByteString.newInstanceForTest( + ByteString.wrap(bytes, 0, i), + RopeByteString.newInstanceForTest( + ByteString.wrap(bytes, i, j - i), ByteString.wrap(bytes, j, bytes.length - j))); + } + }; + // 128 - [chars 0x0000 to 0x007f] static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1; @@ -247,13 +262,11 @@ static void testBytes(ByteStringFactory factory, int numBytes, long expectedCoun */ static void testBytes( ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) { - Random rnd = new Random(); byte[] bytes = new byte[numBytes]; if (lim == -1) { lim = 1L << (numBytes * 8); } - long count = 0; long countRoundTripped = 0; for (long byteChar = start; byteChar < lim; byteChar++) { long tmpByteChar = byteChar; @@ -271,166 +284,13 @@ static void testBytes( outputFailure(byteChar, bytes, bytesReencoded); } - // Check agreement with static Utf8 methods. + // Check agreement with Utf8.isValidUtf8. assertThat(Utf8.isValidUtf8(bytes)).isEqualTo(isRoundTrippable); - assertThat(Utf8.isValidUtf8(bytes, 0, numBytes)).isEqualTo(isRoundTrippable); - - try { - assertThat(Utf8.decodeUtf8(bytes, 0, numBytes)).isEqualTo(s); - } catch (InvalidProtocolBufferException e) { - if (isRoundTrippable) { - System.out.println("Could not decode utf-8"); - outputFailure(byteChar, bytes, bytesReencoded); - } - } - - // Test partial sequences. - // Partition numBytes into three segments (not necessarily non-empty). - int i = rnd.nextInt(numBytes); - int j = rnd.nextInt(numBytes); - if (j < i) { - int tmp = i; - i = j; - j = tmp; - } - int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i); - int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j); - int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes); - if (isRoundTrippable != (state3 == Utf8.COMPLETE)) { - System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j); - outputFailure(byteChar, bytes, bytesReencoded); - } - assertThat((state3 == Utf8.COMPLETE)).isEqualTo(isRoundTrippable); - - // Test ropes built out of small partial sequences - ByteString rope = - RopeByteString.newInstanceForTest( - bs.substring(0, i), - RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes))); - assertThat(rope.getClass()).isSameInstanceAs(RopeByteString.class); - - ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope}; - for (ByteString x : byteStrings) { - assertThat(x.isValidUtf8()).isEqualTo(isRoundTrippable); - assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes)).isEqualTo(state3); - - assertThat(x.partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1); - assertThat(x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i)).isEqualTo(state1); - assertThat(x.partialIsValidUtf8(state1, i, j - i)).isEqualTo(state2); - assertThat(x.substring(i, j).partialIsValidUtf8(state1, 0, j - i)).isEqualTo(state2); - assertThat(x.partialIsValidUtf8(state2, j, numBytes - j)).isEqualTo(state3); - assertThat(x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j)) - .isEqualTo(state3); - } - - // ByteString reduplication should not affect its UTF-8 validity. - ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes)); - assertThat(ropeADope.isValidUtf8()).isEqualTo(isRoundTrippable); - - if (isRoundTrippable) { - countRoundTripped++; - } - count++; - if (byteChar != 0 && byteChar % 1000000L == 0) { - logger.info("Processed " + (byteChar / 1000000L) + " million characters"); - } - } - logger.info("Round tripped " + countRoundTripped + " of " + count); - assertThat(countRoundTripped).isEqualTo(expectedCount); - } - - /** - * Variation of {@link #testBytes} that does less allocation using the low-level encoders/decoders - * directly. Checked in because it's useful for debugging when trying to process bytes faster, but - * since it doesn't use the actual String class, it's possible for incompatibilities to develop - * (although unlikely). - * - * @param factory the factory for {@link ByteString} instances. - * @param numBytes the number of bytes in the byte array - * @param expectedCount the expected number of roundtrippable permutations - * @param start the starting bytes encoded as a long as big-endian - * @param lim the limit of bytes to process encoded as a long as big-endian, or -1 to mean the max - * limit for numBytes - */ - static void testBytesUsingByteBuffers( - ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) { - CharsetDecoder decoder = - Internal.UTF_8 - .newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - CharsetEncoder encoder = - Internal.UTF_8 - .newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - byte[] bytes = new byte[numBytes]; - int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1; - char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1]; - int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1; - byte[] bytesReencoded = new byte[maxBytes]; - - ByteBuffer bb = ByteBuffer.wrap(bytes); - CharBuffer cb = CharBuffer.wrap(charsDecoded); - ByteBuffer bbReencoded = ByteBuffer.wrap(bytesReencoded); - if (lim == -1) { - lim = 1L << (numBytes * 8); - } - long count = 0; - long countRoundTripped = 0; - for (long byteChar = start; byteChar < lim; byteChar++) { - bb.rewind(); - bb.limit(bytes.length); - cb.rewind(); - cb.limit(charsDecoded.length); - bbReencoded.rewind(); - bbReencoded.limit(bytesReencoded.length); - encoder.reset(); - decoder.reset(); - long tmpByteChar = byteChar; - for (int i = 0; i < bytes.length; i++) { - bytes[bytes.length - i - 1] = (byte) tmpByteChar; - tmpByteChar = tmpByteChar >> 8; - } - boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8(); - CoderResult result = decoder.decode(bb, cb, true); - assertThat(result.isError()).isFalse(); - result = decoder.flush(cb); - assertThat(result.isError()).isFalse(); - - int charLen = cb.position(); - cb.rewind(); - cb.limit(charLen); - result = encoder.encode(cb, bbReencoded, true); - assertThat(result.isError()).isFalse(); - result = encoder.flush(bbReencoded); - assertThat(result.isError()).isFalse(); - - boolean bytesEqual = true; - int bytesLen = bbReencoded.position(); - if (bytesLen != numBytes) { - bytesEqual = false; - } else { - for (int i = 0; i < numBytes; i++) { - if (bytes[i] != bytesReencoded[i]) { - bytesEqual = false; - break; - } - } - } - if (bytesEqual != isRoundTrippable) { - outputFailure(byteChar, bytes, bytesReencoded, bytesLen); - } - count++; if (isRoundTrippable) { countRoundTripped++; } - if (byteChar != 0 && byteChar % 1000000 == 0) { - logger.info("Processed " + (byteChar / 1000000) + " million characters"); - } } - logger.info("Round tripped " + countRoundTripped + " of " + count); assertThat(countRoundTripped).isEqualTo(expectedCount); } diff --git a/java/core/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java index 9c34161b6516..fa3643393ffc 100644 --- a/java/core/src/test/java/com/google/protobuf/MessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java @@ -380,4 +380,34 @@ public void testDynamicRepeatedMessageNotNull() throws Exception { result.getDescriptorForType().findFieldByName("repeated_foreign_message"))) .isEqualTo(2); } + + @Test + public void testPreservesFloatingPointNegative0() throws Exception { + proto3_unittest.UnittestProto3.TestAllTypes message = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(-0.0f) + .setOptionalDouble(-0.0) + .build(); + assertThat( + proto3_unittest.UnittestProto3.TestAllTypes.parseFrom( + message.toByteString(), ExtensionRegistry.getEmptyRegistry())) + .isEqualTo(message); + } + + @Test + public void testNegative0FloatingPointEquality() throws Exception { + // Like Double#equals and Float#equals, we treat -0.0 as not being equal to +0.0 even though + // IEEE 754 mandates that they are equivalent. This test asserts that behavior. + proto3_unittest.UnittestProto3.TestAllTypes message1 = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(-0.0f) + .setOptionalDouble(-0.0) + .build(); + proto3_unittest.UnittestProto3.TestAllTypes message2 = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(0.0f) + .setOptionalDouble(0.0) + .build(); + assertThat(message1).isNotEqualTo(message2); + } } diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java index d7996782f71b..33ce537a4aaf 100644 --- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java +++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java @@ -316,7 +316,6 @@ public WrapsCallback(MockCallback callback) { } @Override - @SuppressWarnings("unchecked") public boolean matches(Object actual) { if (!(actual instanceof RpcCallback)) { return false; diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java index 5d0eb62c5d52..b6241912a32f 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java @@ -41,7 +41,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Test @{link TextFormatParseInfoTree}. */ +/** Test {@link TextFormatParseInfoTree}. */ @RunWith(JUnit4.class) public class TextFormatParseInfoTreeTest { diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java index ed20df5cbe3a..f85ee6c5a1ba 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java @@ -37,7 +37,7 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Test @{link TextFormatParseLocation}. */ +/** Test {@link TextFormatParseLocation}. */ @RunWith(JUnit4.class) public class TextFormatParseLocationTest { diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java index e755111f0f9e..f9b7da46b7cd 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -1815,4 +1815,15 @@ public void testSortMapFields() throws Exception { + "}\n"; assertThat(TextFormat.printer().printToString(message)).isEqualTo(text); } + + @Test + public void testPreservesFloatingPointNegative0() throws Exception { + proto3_unittest.UnittestProto3.TestAllTypes message = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(-0.0f) + .setOptionalDouble(-0.0) + .build(); + assertThat(TextFormat.printer().printToString(message)) + .isEqualTo("optional_float: -0.0\noptional_double: -0.0\n"); + } } diff --git a/java/lite/src/test/java/com/google/protobuf/LiteTest.java b/java/lite/src/test/java/com/google/protobuf/LiteTest.java index 3680cc23bc07..b0972111acd8 100644 --- a/java/lite/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/lite/src/test/java/com/google/protobuf/LiteTest.java @@ -2752,6 +2752,36 @@ public void testUnpairedSurrogatesReplacedByQuestionMark() throws InvalidProtoco .isTrue(); } + @Test + public void testPreservesFloatingPointNegative0() throws Exception { + proto3_unittest.UnittestProto3.TestAllTypes message = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(-0.0f) + .setOptionalDouble(-0.0) + .build(); + assertThat( + proto3_unittest.UnittestProto3.TestAllTypes.parseFrom( + message.toByteString(), ExtensionRegistryLite.getEmptyRegistry())) + .isEqualTo(message); + } + + @Test + public void testNegative0FloatingPointEquality() throws Exception { + // Like Double#equals and Float#equals, we treat -0.0 as not being equal to +0.0 even though + // IEEE 754 mandates that they are equivalent. This test asserts that behavior. + proto3_unittest.UnittestProto3.TestAllTypes message1 = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(-0.0f) + .setOptionalDouble(-0.0) + .build(); + proto3_unittest.UnittestProto3.TestAllTypes message2 = + proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() + .setOptionalFloat(0.0f) + .setOptionalDouble(0.0) + .build(); + assertThat(message1).isNotEqualTo(message2); + } + private String encodeHex(ByteString bytes) { String hexDigits = "0123456789abcdef"; StringBuilder stringBuilder = new StringBuilder(bytes.size() * 2); diff --git a/java/util/BUILD b/java/util/BUILD index 02e55496897f..3855da96f01d 100644 --- a/java/util/BUILD +++ b/java/util/BUILD @@ -14,6 +14,7 @@ java_library( "//external:error_prone_annotations", "//external:j2objc_annotations", "//external:gson", + "//external:jsr305", "//external:guava", "//java/core", "//java/lite", diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java index a6cdcb995765..9f36494a710d 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.annotation.Nullable; /** * Utility helper functions to work with {@link com.google.protobuf.FieldMask}. @@ -230,10 +231,8 @@ public static boolean isValid(Class type, String path) { return isValid(descriptor, path); } - /** - * Checks whether paths in a given fields mask are valid. - */ - public static boolean isValid(Descriptor descriptor, String path) { + /** Checks whether paths in a given fields mask are valid. */ + public static boolean isValid(@Nullable Descriptor descriptor, String path) { String[] parts = path.split(FIELD_SEPARATOR_REGEX); if (parts.length == 0) { return false; diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java index d94fb3d85948..ddfbc9ed900e 100644 --- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java +++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java @@ -88,6 +88,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.logging.Logger; +import javax.annotation.Nullable; /** * Utility classes to convert protobuf messages to/from JSON format. The JSON @@ -521,10 +522,12 @@ public static Builder newBuilder() { * Find a type by its full name. Returns null if it cannot be found in this {@link * TypeRegistry}. */ + @Nullable public Descriptor find(String name) { return types.get(name); } + @Nullable Descriptor getDescriptorForTypeUrl(String typeUrl) throws InvalidProtocolBufferException { return find(getTypeName(typeUrl)); } @@ -546,7 +549,7 @@ private Builder() {} */ @CanIgnoreReturnValue public Builder add(Descriptor messageType) { - if (types == null) { + if (built) { throw new IllegalStateException("A TypeRegistry.Builder can only be used once."); } addFile(messageType.getFile()); @@ -559,7 +562,7 @@ public Builder add(Descriptor messageType) { */ @CanIgnoreReturnValue public Builder add(Iterable messageTypes) { - if (types == null) { + if (built) { throw new IllegalStateException("A TypeRegistry.Builder can only be used once."); } for (Descriptor type : messageTypes) { @@ -573,10 +576,8 @@ public Builder add(Iterable messageTypes) { * one Builder. */ public TypeRegistry build() { - TypeRegistry result = new TypeRegistry(types); - // Make sure the built {@link TypeRegistry} is immutable. - types = null; - return result; + built = true; + return new TypeRegistry(types); } private void addFile(FileDescriptor file) { @@ -607,6 +608,7 @@ private void addMessage(Descriptor message) { private final Set files = new HashSet(); private Map types = new HashMap(); + private boolean built = false; } } @@ -984,7 +986,7 @@ private void printListValue(MessageOrBuilder message) throws IOException { } /** Prints a regular message with an optional type URL. */ - private void print(MessageOrBuilder message, String typeUrl) throws IOException { + private void print(MessageOrBuilder message, @Nullable String typeUrl) throws IOException { generator.print("{" + blankOrNewLine); generator.indent(); @@ -1340,7 +1342,9 @@ void merge(String json, Message.Builder builder) throws InvalidProtocolBufferExc throw e; } catch (Exception e) { // We convert all exceptions from JSON parsing to our own exceptions. - throw new InvalidProtocolBufferException(e.getMessage()); + InvalidProtocolBufferException toThrow = new InvalidProtocolBufferException(e.getMessage()); + toThrow.initCause(e); + throw toThrow; } } @@ -1899,6 +1903,7 @@ private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferExce } } + @Nullable private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json) throws InvalidProtocolBufferException { String value = json.getAsString(); @@ -1926,6 +1931,7 @@ private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement return result; } + @Nullable private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder) throws InvalidProtocolBufferException { if (json instanceof JsonNull) { diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java index bd58cc9a8ea6..f00bbb1b4c9e 100644 --- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java @@ -1887,4 +1887,12 @@ public void testPrintingEnumsAsIntsChainedAfterIncludingDefaultValueFields() thr .print(message)) .isEqualTo("{\n" + " \"optionalBool\": false\n" + "}"); } + + @Test + public void testPreservesFloatingPointNegative0() throws Exception { + TestAllTypes message = + TestAllTypes.newBuilder().setOptionalFloat(-0.0f).setOptionalDouble(-0.0).build(); + assertThat(JsonFormat.printer().print(message)) + .isEqualTo("{\n \"optionalFloat\": -0.0,\n \"optionalDouble\": -0.0\n}"); + } } diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js index bc1707d9e3bd..70585db46e05 100644 --- a/js/binary/utils_test.js +++ b/js/binary/utils_test.js @@ -394,7 +394,7 @@ describe('binaryUtilsTest', function() { // corner cases test(0.9999999762949594, 0x3f800000); test(7.99999999999999, 0x41000000); - test(Math.sin(30 * Math.PI / 180), 0x3f000000); // sin(30 degrees) + test(Math.sin(30 * Math.PI / 180), 0x3f000000); // sin(30 degrees) // Various positive values. var cursor = f32_eps * 10; diff --git a/maven_install.json b/maven_install.json index f9342185c4e4..6168aa4af246 100644 --- a/maven_install.json +++ b/maven_install.json @@ -1,6 +1,8 @@ { "dependency_tree": { - "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 1033791982, + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": 1907885757, + "__RESOLVED_ARTIFACTS_HASH": 375457873, "conflict_resolution": { "com.google.errorprone:error_prone_annotations:2.3.2": "com.google.errorprone:error_prone_annotations:2.5.1", "junit:junit:4.12": "junit:junit:4.13.1" @@ -201,24 +203,6 @@ "sha256": "b3dd1cf5019f942d8cc2afad0aa6aef4b21532446fe90a6b68d567e3389763dd", "url": "https://repo1.maven.org/maven2/org/easymock/easymock/3.2/easymock-3.2.jar" }, - { - "coord": "org.easymock:easymockclassextension:3.2", - "dependencies": [ - "org.easymock:easymock:3.2", - "cglib:cglib-nodep:2.2.2", - "org.objenesis:objenesis:1.3" - ], - "directDependencies": [ - "org.easymock:easymock:3.2" - ], - "file": "v1/https/repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar", - "mirror_urls": [ - "https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar", - "https://repo.maven.apache.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar" - ], - "sha256": "e2aeb3ecec87d859b2f3072985d4b15873558bcf6410f422db0c0c5194c76c87", - "url": "https://repo1.maven.org/maven2/org/easymock/easymockclassextension/3.2/easymockclassextension-3.2.jar" - }, { "coord": "org.hamcrest:hamcrest-core:1.3", "dependencies": [], diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py index a3667318c1b7..7fef2376707d 100644 --- a/python/google/protobuf/internal/api_implementation.py +++ b/python/google/protobuf/internal/api_implementation.py @@ -41,46 +41,15 @@ # The compile-time constants in the _api_implementation module can be used to # switch to a certain implementation of the Python API at build time. _api_version = _api_implementation.api_version - _proto_extension_modules_exist_in_build = True except ImportError: _api_version = -1 # Unspecified by compiler flags. - _proto_extension_modules_exist_in_build = False if _api_version == 1: raise ValueError('api_version=1 is no longer supported.') -if _api_version < 0: # Still unspecified? - try: - # The presence of this module in a build allows the proto implementation to - # be upgraded merely via build deps rather than a compiler flag or the - # runtime environment variable. - # pylint: disable=g-import-not-at-top - from google.protobuf import _use_fast_cpp_protos - # Work around a known issue in the classic bootstrap .par import hook. - if not _use_fast_cpp_protos: - raise ImportError('_use_fast_cpp_protos import succeeded but was None') - del _use_fast_cpp_protos - _api_version = 2 - from google.protobuf import use_pure_python - raise RuntimeError( - 'Conflicting deps on both :use_fast_cpp_protos and :use_pure_python.\n' - ' go/build_deps_on_BOTH_use_fast_cpp_protos_AND_use_pure_python\n' - 'This should be impossible via a link error at build time...') - except ImportError: - try: - # pylint: disable=g-import-not-at-top - from google.protobuf import use_pure_python - del use_pure_python # Avoids a pylint error and namespace pollution. - _api_version = 0 - except ImportError: - # TODO(b/74017912): It's unsafe to enable :use_fast_cpp_protos by default; - # it can cause data loss if you have any Python-only extensions to any - # message passed back and forth with C++ code. - # - # TODO(b/17427486): Once that bug is fixed, we want to make both Python 2 - # and Python 3 default to `_api_version = 2` (C++ implementation V2). - pass - -_default_implementation_type = ('python' if _api_version <= 0 else 'cpp') + + +_default_implementation_type = ('cpp' if _api_version > 0 else 'python') + # This environment variable can be used to switch to a certain implementation # of the Python API, overriding the compile-time constants in the @@ -97,21 +66,6 @@ 'Falling back to the python implementation.') _implementation_type = 'python' -# This environment variable can be used to switch between the two -# 'cpp' implementations, overriding the compile-time constants in the -# _api_implementation module. Right now only '2' is supported. Any other -# value will cause an error to be raised. -_implementation_version_str = os.getenv( - 'PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION', '2') - -if _implementation_version_str != '2': - raise ValueError( - 'unsupported PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION_VERSION: "' + - _implementation_version_str + '" (supported versions: 2)' - ) - -_implementation_version = int(_implementation_version_str) - # Detect if serialization should be deterministic by default try: @@ -150,7 +104,7 @@ def _SetType(implementation_type): # See comment on 'Type' above. def Version(): - return _implementation_version + return 2 # For internal use only diff --git a/python/google/protobuf/message.py b/python/google/protobuf/message.py index 224d2fc49178..ee46d0e4c9c6 100644 --- a/python/google/protobuf/message.py +++ b/python/google/protobuf/message.py @@ -359,6 +359,14 @@ def ByteSize(self): """ raise NotImplementedError + @classmethod + def FromString(cls, s): + raise NotImplementedError + + @staticmethod + def RegisterExtension(extension_handle): + raise NotImplementedError + def _SetListener(self, message_listener): """Internal method used by the protocol message implementation. Clients should not call this directly. diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 4340afc4e152..cb48faa440bf 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -1919,7 +1919,9 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { // explicit in our correctness checks. if (ptr == nullptr || ctx.BytesUntilLimit(ptr) < 0) { // Parse error or the parser overshoot the limit. - PyErr_Format(DecodeError_class, "Error parsing message"); + PyErr_Format( + DecodeError_class, "Error parsing message with type '%s'", + self->GetMessageClass()->message_descriptor->full_name().c_str()); return NULL; } // ctx has an explicit limit set (length of string_view), so we have to diff --git a/python/setup.py b/python/setup.py index 63118c23cb85..ab42b6fe173d 100755 --- a/python/setup.py +++ b/python/setup.py @@ -211,11 +211,11 @@ def get_option_from_sys_argv(option_str): extra_compile_args = [] if sys.platform != 'win32': - extra_compile_args.append('-Wno-write-strings') - extra_compile_args.append('-Wno-invalid-offsetof') - extra_compile_args.append('-Wno-sign-compare') - extra_compile_args.append('-Wno-unused-variable') - extra_compile_args.append('-std=c++11') + extra_compile_args.append('-Wno-write-strings') + extra_compile_args.append('-Wno-invalid-offsetof') + extra_compile_args.append('-Wno-sign-compare') + extra_compile_args.append('-Wno-unused-variable') + extra_compile_args.append('-std=c++11') if sys.platform == 'darwin': extra_compile_args.append("-Wno-shorten-64-to-32"); @@ -285,21 +285,20 @@ def get_option_from_sys_argv(option_str): maintainer_email='protobuf@googlegroups.com', license='3-Clause BSD License', classifiers=[ - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - ], + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + ], namespace_packages=['google'], packages=find_packages( exclude=[ 'import_test_package', 'protobuf_distutils', - ], - ), + ],), test_suite='google.protobuf.internal', cmdclass={ 'clean': clean, @@ -309,5 +308,5 @@ def get_option_from_sys_argv(option_str): }, install_requires=install_requires, ext_modules=ext_module_list, - python_requires='>=3.5', + python_requires=">=3.5", ) diff --git a/src/Makefile.am b/src/Makefile.am index 102af0441794..232955f90493 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -18,7 +18,7 @@ else PTHREAD_DEF = endif -PROTOBUF_VERSION = 29:1:0 +PROTOBUF_VERSION = 28:3:0 if GCC # Turn on all warnings except for sign comparison (we ignore sign comparison @@ -145,6 +145,7 @@ nobase_include_HEADERS = \ google/protobuf/reflection.h \ google/protobuf/reflection_ops.h \ google/protobuf/repeated_field.h \ + google/protobuf/repeated_ptr_field.h \ google/protobuf/service.h \ google/protobuf/source_context.pb.h \ google/protobuf/struct.pb.h \ @@ -210,6 +211,7 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/message_lite.cc \ google/protobuf/parse_context.cc \ google/protobuf/repeated_field.cc \ + google/protobuf/repeated_ptr_field.cc \ google/protobuf/string_member_robber.h \ google/protobuf/stubs/bytestream.cc \ google/protobuf/stubs/common.cc \ @@ -541,8 +543,8 @@ EXTRA_DIST = \ google/protobuf/compiler/package_info.h \ google/protobuf/compiler/ruby/ruby_generated_code.proto \ google/protobuf/compiler/ruby/ruby_generated_code_pb.rb \ - google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \ google/protobuf/compiler/ruby/ruby_generated_code_proto2.proto \ + google/protobuf/compiler/ruby/ruby_generated_code_proto2_import.proto \ google/protobuf/compiler/ruby/ruby_generated_code_proto2_pb.rb \ google/protobuf/compiler/ruby/ruby_generated_pkg_explicit.proto \ google/protobuf/compiler/ruby/ruby_generated_pkg_explicit_legacy.proto \ diff --git a/src/google/protobuf/arena_impl.h b/src/google/protobuf/arena_impl.h index d38e31167eac..2ffac319b411 100644 --- a/src/google/protobuf/arena_impl.h +++ b/src/google/protobuf/arena_impl.h @@ -202,13 +202,6 @@ class PROTOBUF_EXPORT SerialArena { void (*cleanup)(void*); // Function pointer to the destructor or deleter. }; - // Creates a new SerialArena inside mem using the remaining memory as for - // future allocations. - static SerialArena* New(SerialArena::Memory mem, void* owner); - // Free SerialArena returning the memory passed in to New - template - Memory Free(Deallocator deallocator); - void CleanupList(); uint64_t SpaceAllocated() const { return space_allocated_.load(std::memory_order_relaxed); @@ -281,6 +274,16 @@ class PROTOBUF_EXPORT SerialArena { void set_next(SerialArena* next) { next_ = next; } private: + friend class ThreadSafeArena; + friend class ArenaBenchmark; + + // Creates a new SerialArena inside mem using the remaining memory as for + // future allocations. + static SerialArena* New(SerialArena::Memory mem, void* owner); + // Free SerialArena returning the memory passed in to New + template + Memory Free(Deallocator deallocator); + // Blocks are variable length malloc-ed objects. The following structure // describes the common header for all blocks. struct Block { diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc index 7608b13c7a4c..169f52729d61 100644 --- a/src/google/protobuf/arenastring.cc +++ b/src/google/protobuf/arenastring.cc @@ -256,6 +256,12 @@ void ArenaStringPtr::ClearToDefault(const LazyString& default_value, } } +inline void SetStrWithHeapBuffer(std::string* str, ArenaStringPtr* s) { + TaggedPtr res; + res.Set(str); + s->UnsafeSetTaggedPointer(res); +} + const char* EpsCopyInputStream::ReadArenaString(const char* ptr, ArenaStringPtr* s, Arena* arena) { @@ -264,13 +270,11 @@ const char* EpsCopyInputStream::ReadArenaString(const char* ptr, int size = ReadSize(&ptr); if (!ptr) return nullptr; - auto str = Arena::Create(arena); + auto* str = Arena::Create(arena); ptr = ReadString(ptr, size, str); GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); - TaggedPtr res; - res.Set(str); - s->UnsafeSetTaggedPointer(res); + SetStrWithHeapBuffer(str, s); return ptr; } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index cdcd9a6da225..70311dde40ed 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -334,106 +334,6 @@ void RepeatedEnumFieldGenerator::GenerateConstructorCode( // Not needed for repeated fields. } -void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStream( - io::Printer* printer) const { - Formatter format(printer, variables_); - // Don't use ReadRepeatedPrimitive here so that the enum can be validated. - format( - "int value = 0;\n" - "DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" - " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n"); - if (HasPreservingUnknownEnumSemantics(descriptor_)) { - format("add_$name$(static_cast< $type$ >(value));\n"); - } else { - format( - "if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - format( - "} else {\n" - " mutable_unknown_fields()->AddVarint(\n" - " $number$, static_cast<$uint64$>(value));\n"); - } else { - format( - "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(\n" - " static_cast<$uint32$>(value));\n"); - } - format("}\n"); - } -} - -void RepeatedEnumFieldGenerator::GenerateMergeFromCodedStreamWithPacking( - io::Printer* printer) const { - Formatter format(printer, variables_); - if (!descriptor_->is_packed()) { - // This path is rarely executed, so we use a non-inlined implementation. - if (HasPreservingUnknownEnumSemantics(descriptor_)) { - format( - "DO_((::$proto_ns$::internal::" - "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " nullptr,\n" - " nullptr,\n" - " this->_internal_mutable_$name$())));\n"); - } else if (UseUnknownFieldSet(descriptor_->file(), options_)) { - format( - "DO_((::$proto_ns$::internal::WireFormat::" - "ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " $type$_IsValid,\n" - " mutable_unknown_fields(),\n" - " this->_internal_mutable_$name$())));\n"); - } else { - format( - "DO_((::$proto_ns$::internal::" - "WireFormatLite::ReadPackedEnumPreserveUnknowns(\n" - " input,\n" - " $number$,\n" - " $type$_IsValid,\n" - " &unknown_fields_stream,\n" - " this->_internal_mutable_$name$())));\n"); - } - } else { - format( - "$uint32$ length;\n" - "DO_(input->ReadVarint32(&length));\n" - "::$proto_ns$::io::CodedInputStream::Limit limit = " - "input->PushLimit(static_cast(length));\n" - "while (input->BytesUntilLimit() > 0) {\n" - " int value = 0;\n" - " DO_((::$proto_ns$::internal::WireFormatLite::ReadPrimitive<\n" - " int, ::$proto_ns$::internal::WireFormatLite::TYPE_ENUM>(\n" - " input, &value)));\n"); - if (HasPreservingUnknownEnumSemantics(descriptor_)) { - format(" add_$name$(static_cast< $type$ >(value));\n"); - } else { - format( - " if ($type$_IsValid(value)) {\n" - " _internal_add_$name$(static_cast< $type$ >(value));\n" - " } else {\n"); - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - format( - " mutable_unknown_fields()->AddVarint(\n" - " $number$, static_cast<$uint64$>(value));\n"); - } else { - format( - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(\n" - " static_cast<$uint32$>(value));\n"); - } - format(" }\n"); - } - format( - "}\n" - "input->PopLimit(limit);\n"); - } -} - void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { Formatter format(printer, variables_); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 793ab2d7933b..e65ec0f5c075 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -98,8 +98,6 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const override; void GenerateConstructorCode(io::Printer* printer) const override; void GenerateCopyConstructorCode(io::Printer* printer) const override {} - void GenerateMergeFromCodedStream(io::Printer* printer) const; - void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 48ae2903b3e7..a95dd33e91b9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -340,7 +340,7 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator( switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: if (field->is_map()) { - return new MapFieldGenerator(field, options); + return new MapFieldGenerator(field, options, scc_analyzer); } else { return new RepeatedMessageFieldGenerator(field, options, scc_analyzer); diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 185fa8c62626..e0eb679b4c91 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -181,6 +181,10 @@ class FieldGenerator { // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; + // Generates lines to call IsInitialized() for eligible message fields. Non + // message fields won't need to override this function. + virtual void GenerateIsInitialized(io::Printer* printer) const {} + virtual bool IsInlined() const { return false; } void SetHasBitIndex(int32_t has_bit_index); diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index bae5bf2ffa18..bd4f48bc8ed1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -743,6 +743,27 @@ class PROTOC_EXPORT Formatter { void Outdent() const { printer_->Outdent(); } io::Printer* printer() const { return printer_; } + class PROTOC_EXPORT ScopedIndenter { + public: + explicit ScopedIndenter(Formatter* format) : format_(format) { + format_->Indent(); + } + ~ScopedIndenter() { format_->Outdent(); } + + private: + Formatter* format_; + }; + + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() { + return ScopedIndenter(this); + } + template + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format, + const Args&&... args) { + (*this)(format, static_cast(args)...); + return ScopedIndenter(this); + } + class PROTOC_EXPORT SaveState { public: explicit SaveState(Formatter* format) diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index 49f65f3a5dea..130e90ebbe0a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -84,8 +84,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : FieldGenerator(descriptor, options) { + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : FieldGenerator(descriptor, options), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { SetMessageVariables(descriptor, &variables_, options); } @@ -293,6 +296,15 @@ void MapFieldGenerator::GenerateByteSize(io::Printer* printer) const { "}\n"); } +void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (!::$proto_ns$::internal::AllAreInitialized($name$_)) return " + "false;\n"); +} + void MapFieldGenerator::GenerateConstinitInitializer( io::Printer* printer) const { Formatter format(printer, variables_); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 5ea04290e61b..c01ae498b1aa 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -34,6 +34,7 @@ #include #include +#include #include namespace google { @@ -43,8 +44,9 @@ namespace cpp { class MapFieldGenerator : public FieldGenerator { public: - MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~MapFieldGenerator(); + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + ~MapFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -58,10 +60,13 @@ class MapFieldGenerator : public FieldGenerator { void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; void GenerateConstinitInitializer(io::Printer* printer) const override; bool GenerateArenaDestructorCode(io::Printer* printer) const override; private: + const bool has_required_fields_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 95bbfdeeed93..70d8a57e3a9e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -230,12 +230,22 @@ bool EmitFieldNonDefaultCondition(io::Printer* printer, } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // Message fields still have has_$name$() methods. format("if ($prefix$_internal_has_$name$()) {\n"); - } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE || - field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { - // Handle float comparison to prevent -Wfloat-equal warnings + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT) { format( - "if (!($prefix$_internal_$name$() <= 0 && $prefix$_internal_$name$() " - ">= 0)) {\n"); + "static_assert(sizeof(uint32_t) == sizeof(float), \"Code assumes " + "uint32_t and float are the same size.\");\n" + "float tmp_$name$ = $prefix$_internal_$name$();\n" + "uint32_t raw_$name$;\n" + "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" + "if (raw_$name$ != 0) {\n"); + } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { + format( + "static_assert(sizeof(uint64_t) == sizeof(double), \"Code assumes " + "uint64_t and double are the same size.\");\n" + "double tmp_$name$ = $prefix$_internal_$name$();\n" + "uint64_t raw_$name$;\n" + "memcpy(&raw_$name$, &tmp_$name$, sizeof(tmp_$name$));\n" + "if (raw_$name$ != 0) {\n"); } else { format("if ($prefix$_internal_$name$() != 0) {\n"); } @@ -2737,19 +2747,22 @@ std::pair MessageGenerator::GenerateOffsets( // Some information about a field is in the pdproto profile. The profile is // only available at compile time. So we embed such information in the - // offset of the field, so that the information is available when reflective - // accessing the field at run time. + // offset of the field, so that the information is available when + // reflectively accessing the field at run time. // // Embed whether the field is used to the MSB of the offset. if (!IsFieldUsed(field, options_)) { - format(" | 0x80000000u, // unused\n"); - } else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { - format(" | 0x1u, // eagerly verified lazy\n"); + format(" | 0x80000000u // unused\n"); + } + + // Embed whether the field is eagerly verified lazy or inlined string to the + // LSB of the offset. + if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { + format(" | 0x1u // eagerly verified lazy\n"); } else if (IsStringInlined(field, options_)) { - format(" | 0x1u, // inlined\n"); - } else { - format(",\n"); + format(" | 0x1u // inlined\n"); } + format(",\n"); } int count = 0; @@ -4513,42 +4526,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all non-oneof embedded messages are initialized. for (auto field : optimized_order_) { - // TODO(ckennelly): Push this down into a generator? - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !ShouldIgnoreRequiredFieldCheck(field, options_) && - scc_analyzer_->HasRequiredFields(field->message_type())) { - if (field->is_repeated()) { - if (IsImplicitWeakField(field, options_, scc_analyzer_)) { - format( - "if " - "(!::$proto_ns$::internal::AllAreInitializedWeak($1$_.weak)" - ")" - " return false;\n", - FieldName(field)); - } else { - format( - "if (!::$proto_ns$::internal::AllAreInitialized($1$_))" - " return false;\n", - FieldName(field)); - } - } else if (field->options().weak()) { - continue; - } else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { - GOOGLE_CHECK(!field->real_containing_oneof()); - format( - "if (_internal_has_$1$()) {\n" - " if (!$1$().IsInitialized()) return false;\n" - "}\n", - FieldName(field)); - } else { - GOOGLE_CHECK(!field->real_containing_oneof()); - format( - "if (_internal_has_$1$()) {\n" - " if (!$1$_->IsInitialized()) return false;\n" - "}\n", - FieldName(field)); - } - } + field_generators_.get(field).GenerateIsInitialized(printer); } if (num_weak_fields_) { // For Weak fields. @@ -4576,23 +4554,9 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { for (auto field : FieldRange(oneof)) { format("case k$1$: {\n", UnderscoresToCamelCase(field->name(), true)); format.Indent(); - - if (!IsFieldStripped(field, options_) && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !ShouldIgnoreRequiredFieldCheck(field, options_) && - scc_analyzer_->HasRequiredFields(field->message_type())) { - GOOGLE_CHECK(!(field->options().weak() || !field->real_containing_oneof())); - if (field->options().weak()) { - // Just skip. - } else { - format( - "if (has_$1$()) {\n" - " if (!this->$1$().IsInitialized()) return false;\n" - "}\n", - FieldName(field)); - } + if (!IsFieldStripped(field, options_)) { + field_generators_.get(field).GenerateIsInitialized(printer); } - format("break;\n"); format.Outdent(); format("}\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index d6e05ea4f13f..6199903371fb 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -87,7 +87,9 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, MessageSCCAnalyzer* scc_analyzer) : FieldGenerator(descriptor, options), implicit_weak_field_( - IsImplicitWeakField(descriptor, options, scc_analyzer)) { + IsImplicitWeakField(descriptor, options, scc_analyzer)), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } @@ -480,6 +482,18 @@ void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { " *$field_member$);\n"); } +void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (_internal_has_$name$()) {\n" + " if (!$name$_->IsInitialized()) return false;\n" + "}\n"); +} + void MessageFieldGenerator::GenerateConstinitInitializer( io::Printer* printer) const { Formatter format(printer, variables_); @@ -641,6 +655,17 @@ void MessageOneofFieldGenerator::GenerateConstructorCode( // space only when this field is used. } +void MessageOneofFieldGenerator::GenerateIsInitialized( + io::Printer* printer) const { + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + format( + "if (_internal_has_$name$()) {\n" + " if (!$field_member$->IsInitialized()) return false;\n" + "}\n"); +} + // =================================================================== RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( @@ -648,7 +673,9 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( MessageSCCAnalyzer* scc_analyzer) : FieldGenerator(descriptor, options), implicit_weak_field_( - IsImplicitWeakField(descriptor, options, scc_analyzer)) { + IsImplicitWeakField(descriptor, options, scc_analyzer)), + has_required_fields_( + scc_analyzer->HasRequiredFields(descriptor->message_type())) { SetMessageVariables(descriptor, options, implicit_weak_field_, &variables_); } @@ -835,6 +862,24 @@ void RepeatedMessageFieldGenerator::GenerateByteSize( "}\n"); } +void RepeatedMessageFieldGenerator::GenerateIsInitialized( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + if (!has_required_fields_) return; + + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format( + "if (!::$proto_ns$::internal::AllAreInitializedWeak($name$_.weak))\n" + " return false;\n"); + } else { + format( + "if (!::$proto_ns$::internal::AllAreInitialized($name$_))\n" + " return false;\n"); + } +} + void RepeatedMessageFieldGenerator::GenerateConstinitInitializer( io::Printer* printer) const { Formatter format(printer, variables_); diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 712ddbfea160..2beac6253b9f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -50,7 +50,7 @@ class MessageFieldGenerator : public FieldGenerator { MessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); - ~MessageFieldGenerator(); + ~MessageFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -71,10 +71,12 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; void GenerateConstinitInitializer(io::Printer* printer) const override; protected: const bool implicit_weak_field_; + const bool has_required_fields_; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); @@ -85,7 +87,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { MessageOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); - ~MessageOneofFieldGenerator(); + ~MessageOneofFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -99,6 +101,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { void GenerateSwappingCode(io::Printer* printer) const override; void GenerateDestructorCode(io::Printer* printer) const override; void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); @@ -109,7 +112,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); - ~RepeatedMessageFieldGenerator(); + ~RepeatedMessageFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -123,10 +126,12 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; + void GenerateIsInitialized(io::Printer* printer) const override; void GenerateConstinitInitializer(io::Printer* printer) const override; private: const bool implicit_weak_field_; + const bool has_required_fields_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 57cef2f8be2a..d0f16d03479a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -70,7 +70,7 @@ struct Options { bool opensource_runtime = false; bool annotate_accessor = false; bool unused_field_stripping = false; - bool profile_driven_inline_string = false; + bool profile_driven_inline_string = true; bool force_inline_string = false; std::string runtime_include_base; int num_cc_files = 0; diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc index 4a4f5e57f008..810f240a89a1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc @@ -81,9 +81,9 @@ const char* TagType(const FieldDescriptor* field) { return CodedTagType(TagSize(field->number())); } -std::string TcParserBaseName(const Options& options) { +std::string TcParserName(const Options& options) { return StrCat("::", ProtobufNamespace(options), - "::internal::TcParserBase::"); + "::internal::TcParser::"); } std::string MessageTcParseFunctionName(const FieldDescriptor* field, @@ -93,8 +93,8 @@ std::string MessageTcParseFunctionName(const FieldDescriptor* field, // For files with `option optimize_for = CODE_SIZE`, or which derive from // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because // there is no generated tailcall function. For tailcall parsing, this is - // done by helpers in TcParserBase. - return StrCat(TcParserBaseName(options), + // done by helpers in TcParser. + return StrCat(TcParserName(options), (field->is_repeated() ? "Repeated" : "Singular"), "ParseMessage<", QualifiedClassName(field->message_type()), // @@ -108,8 +108,7 @@ std::string MessageTcParseFunctionName(const FieldDescriptor* field, } std::string FieldParseFunctionName(const FieldDescriptor* field, - const Options& options, - uint32_t table_size_log2); + const Options& options); } // namespace @@ -209,14 +208,14 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, case FieldDescriptor::TYPE_SINT64: case FieldDescriptor::TYPE_SINT32: case FieldDescriptor::TYPE_BOOL: - name = FieldParseFunctionName(field, options, table_size_log2); + name = FieldParseFunctionName(field, options); break; case FieldDescriptor::TYPE_BYTES: if (field->options().ctype() == FieldOptions::STRING && field->default_value_string().empty() && !IsStringInlined(field, options)) { - name = FieldParseFunctionName(field, options, table_size_log2); + name = FieldParseFunctionName(field, options); } break; @@ -365,9 +364,8 @@ void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { "const char* $classname$::_InternalParse(\n" " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n" "$annotate_deserialize$" - " ptr = ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n" - " this, ptr, ctx, &_table_.header);\n", - tc_table_info_->table_size_log2); + " ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n" + " this, ptr, ctx, &_table_.header);\n"); format( " return ptr;\n" "}\n\n"); @@ -426,9 +424,9 @@ void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions( "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" " ptr += $1$;\n" " hasbits |= (uint64_t{1} << data.hasbit_idx());\n" - " ::$proto_ns$::internal::TcParserBase::SyncHasbits" + " ::$proto_ns$::internal::TcParser::SyncHasbits" "(msg, hasbits, table);\n" - " auto& field = ::$proto_ns$::internal::TcParserBase::" + " auto& field = ::$proto_ns$::internal::TcParser::" "RefAt<$classtype$*>(msg, data.offset());\n" " if (field == nullptr)\n" " field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n" @@ -448,9 +446,9 @@ void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions( "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" " }\n" " ptr += $1$;\n" - " auto& field = ::$proto_ns$::internal::TcParserBase::RefAt<" + " auto& field = ::$proto_ns$::internal::TcParser::RefAt<" "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n" - " ::$proto_ns$::internal::TcParserBase::SyncHasbits" + " ::$proto_ns$::internal::TcParser::SyncHasbits" "(msg, hasbits, table);\n" " ptr = ctx->ParseMessage(field.Add(), ptr);\n" " return ptr;\n" @@ -471,7 +469,7 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { format.Indent(); } format( - "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n" + "static const ::$proto_ns$::internal::TcParseTable<$1$>\n" " _table_;\n", tc_table_info_->table_size_log2); if (should_generate_guarded_tctable()) { @@ -546,7 +544,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { if (tc_table_info_->use_generated_fallback) { fallback = ClassName(descriptor_) + "::Tct_ParseFallback"; } else { - fallback = TcParserBaseName(options_) + "GenericFallback"; + fallback = TcParserName(options_) + "GenericFallback"; if (GetOptimizeFor(descriptor_->file(), options_) == FileOptions::LITE_RUNTIME) { fallback += "Lite"; @@ -561,33 +559,48 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { // the table is sufficient we can use a generic routine, that just handles // unknown fields and potentially an extension range. format( - "const ::$proto_ns$::internal::TailCallParseTable<$1$>\n" + "const ::$proto_ns$::internal::TcParseTable<$1$>\n" " $classname$::_table_ = {\n", tc_table_info_->table_size_log2); - format.Indent(); - format("{\n"); - format.Indent(); - if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) { - format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n"); - } else { - format("0, // no _has_bits_\n"); - } - if (descriptor_->extension_range_count() == 1) { - format( - "PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n" - "$1$, $2$, // extension_range_{low,high}\n", - descriptor_->extension_range(0)->start, - descriptor_->extension_range(0)->end); - } else { - format("0, 0, 0, // no _extensions_\n"); + { + auto table_scope = format.ScopedIndent(); + format("{\n"); + { + auto header_scope = format.ScopedIndent(); + if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) { + format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n"); + } else { + format("0, // no _has_bits_\n"); + } + if (descriptor_->extension_range_count() == 1) { + format( + "PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n" + "$1$, $2$, // extension_range_{low,high}\n", + descriptor_->extension_range(0)->start, + descriptor_->extension_range(0)->end); + } else { + format("0, 0, 0, // no _extensions_\n"); + } + format( + "$1$, 0, $2$, // fast_idx_mask, reserved, num_fields\n" + "&$3$._instance,\n" + "$4$ // fallback\n", + (((1 << tc_table_info_->table_size_log2) - 1) << 3), + descriptor_->field_count(), + DefaultInstanceName(descriptor_, options_), fallback); + } + format("}, {\n"); + { + auto fast_scope = format.ScopedIndent(); + GenerateFastFieldEntries(format, fallback); + } + format("},\n"); // entries[] } - format( - "&$1$._instance,\n" - "$2$ // fallback\n", - DefaultInstanceName(descriptor_, options_), fallback); - format.Outdent(); - format("}, {\n"); - format.Indent(); + format("};\n\n"); // _table_ +} + +void ParseFunctionGenerator::GenerateFastFieldEntries( + Formatter& format, const std::string& fallback) { for (const auto& info : tc_table_info_->fast_path_fields) { if (info.field != nullptr) { PrintFieldComment(format, info.field); @@ -604,10 +617,6 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { } format("},\n"); } - format.Outdent(); - format("},\n"); // entries[] - format.Outdent(); - format("};\n\n"); // _table_ } void ParseFunctionGenerator::GenerateArenaString(Formatter& format, @@ -634,6 +643,8 @@ void ParseFunctionGenerator::GenerateArenaString(Formatter& format, ", ~0x$2$u", inlined_string_index / 32, strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8)); + } else { + GOOGLE_DCHECK(field->default_value_string().empty()); } format( ");\n" @@ -1094,8 +1105,7 @@ void ParseFunctionGenerator::GenerateFieldSwitch( namespace { std::string FieldParseFunctionName(const FieldDescriptor* field, - const Options& options, - uint32_t table_size_log2) { + const Options& options) { ParseCardinality card = // field->is_packed() ? ParseCardinality::kPacked : field->is_repeated() ? ParseCardinality::kRepeated @@ -1165,8 +1175,8 @@ std::string FieldParseFunctionName(const FieldDescriptor* field, return ""; } - return "::" + ProtobufNamespace(options) + "::internal::" + - GetTailCallFieldHandlerName(card, type_format, table_size_log2, + return "::" + ProtobufNamespace(options) + "::internal::TcParser::" + + GetTailCallFieldHandlerName(card, type_format, TagSize(field->number()), options); } @@ -1174,32 +1184,10 @@ std::string FieldParseFunctionName(const FieldDescriptor* field, std::string GetTailCallFieldHandlerName(ParseCardinality card, TypeFormat type_format, - int table_size_log2, int tag_length_bytes, const Options& options) { std::string name; - switch (card) { - case ParseCardinality::kPacked: - case ParseCardinality::kRepeated: - name = "TcParserBase::"; - break; - - case ParseCardinality::kSingular: - case ParseCardinality::kOneof: - switch (type_format) { - case TypeFormat::kBytes: - case TypeFormat::kString: - case TypeFormat::kStringValidateOnly: - name = "TcParserBase::"; - break; - - default: - name = StrCat("TcParser<", table_size_log2, ">::"); - break; - } - } - // The field implementation functions are prefixed by cardinality: // `Singular` for optional or implicit fields. // `Repeated` for non-packed repeated. @@ -1281,26 +1269,24 @@ std::string GetTailCallFieldHandlerName(ParseCardinality card, case TypeFormat::kVar64: case TypeFormat::kVar32: case TypeFormat::kBool: - name.append( - StrCat(", ", TcParserBaseName(options), "kNoConversion")); + StrAppend(&name, ", ", TcParserName(options), "kNoConversion"); break; case TypeFormat::kSInt64: case TypeFormat::kSInt32: - name.append(StrCat(", ", TcParserBaseName(options), "kZigZag")); + StrAppend(&name, ", ", TcParserName(options), "kZigZag"); break; case TypeFormat::kBytes: - name.append(StrCat(", ", TcParserBaseName(options), "kNoUtf8")); + StrAppend(&name, ", ", TcParserName(options), "kNoUtf8"); break; case TypeFormat::kString: - name.append(StrCat(", ", TcParserBaseName(options), "kUtf8")); + StrAppend(&name, ", ", TcParserName(options), "kUtf8"); break; case TypeFormat::kStringValidateOnly: - name.append( - StrCat(", ", TcParserBaseName(options), "kUtf8ValidateOnly")); + StrAppend(&name, ", ", TcParserName(options), "kUtf8ValidateOnly"); break; default: diff --git a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h index 793e6ae930e8..b921067bd2c5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h +++ b/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h @@ -118,6 +118,7 @@ class ParseFunctionGenerator { // Generates the tail-call table definition. void GenerateTailCallTable(Formatter& format); + void GenerateFastFieldEntries(Formatter& format, const std::string& fallback); // Generates parsing code for an `ArenaString` field. void GenerateArenaString(Formatter& format, const FieldDescriptor* field); @@ -187,7 +188,6 @@ enum class TypeFormat { // parse_function_inc_generator_main. std::string GetTailCallFieldHandlerName(ParseCardinality card, TypeFormat type_format, - int table_size_log2, int tag_length_bytes, const Options& options); diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 35f3bd7869c6..f67f6d39e1f2 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -159,12 +159,25 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["set_has_field_bit_builder"] = ""; (*variables)["clear_has_field_bit_builder"] = ""; - if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { - (*variables)["is_field_present_message"] = - "!" + (*variables)["name"] + "_.isEmpty()"; - } else { - (*variables)["is_field_present_message"] = - (*variables)["name"] + "_ != " + (*variables)["default"]; + switch (descriptor->type()) { + case FieldDescriptor::TYPE_BYTES: + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + break; + case FieldDescriptor::TYPE_FLOAT: + (*variables)["is_field_present_message"] = + "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] + + "_) != 0"; + break; + case FieldDescriptor::TYPE_DOUBLE: + (*variables)["is_field_present_message"] = + "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] + + "_) != 0"; + break; + default: + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + break; } } diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 8167aa64714e..5441d01a511a 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -164,12 +164,25 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["set_has_field_bit_message"] = ""; (*variables)["clear_has_field_bit_message"] = ""; - if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { - (*variables)["is_field_present_message"] = - "!" + (*variables)["name"] + "_.isEmpty()"; - } else { - (*variables)["is_field_present_message"] = - (*variables)["name"] + "_ != " + (*variables)["default"]; + switch (descriptor->type()) { + case FieldDescriptor::TYPE_BYTES: + (*variables)["is_field_present_message"] = + "!" + (*variables)["name"] + "_.isEmpty()"; + break; + case FieldDescriptor::TYPE_FLOAT: + (*variables)["is_field_present_message"] = + "java.lang.Float.floatToRawIntBits(" + (*variables)["name"] + + "_) != 0"; + break; + case FieldDescriptor::TYPE_DOUBLE: + (*variables)["is_field_present_message"] = + "java.lang.Double.doubleToRawLongBits(" + (*variables)["name"] + + "_) != 0"; + break; + default: + (*variables)["is_field_present_message"] = + (*variables)["name"] + "_ != " + (*variables)["default"]; + break; } } diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index af2d1de5d68b..e423e851be02 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -859,7 +859,8 @@ void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { } bool CodeGeneratorRequest::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(proto_file_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(proto_file_)) + return false; return true; } diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 924c23b30587..c8ce218a981d 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -6766,8 +6766,10 @@ void DescriptorBuilder::ValidateEnumValueOptions( } void DescriptorBuilder::ValidateExtensionRangeOptions( - const std::string& /*full_name*/, Descriptor::ExtensionRange* /*extension_range*/, - const DescriptorProto_ExtensionRange& /*proto*/) { + const std::string& full_name, Descriptor::ExtensionRange* extension_range, + const DescriptorProto_ExtensionRange& proto) { + (void)full_name; // Parameter is used by Google-internal code. + (void)extension_range; // Parameter is used by Google-internal code. } void DescriptorBuilder::ValidateServiceOptions( @@ -7838,7 +7840,8 @@ void DescriptorBuilder::OptionInterpreter::SetUInt64( } void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto, - const FileDescriptor* /*result*/) { + const FileDescriptor* result) { + (void)result; // Parameter is used by Google-internal code. if (!unused_dependency_.empty()) { auto itr = pool_->unused_import_track_files_.find(proto.name()); @@ -7860,7 +7863,8 @@ void DescriptorBuilder::LogUnusedDependency(const FileDescriptorProto& proto, } Symbol DescriptorPool::CrossLinkOnDemandHelper(StringPiece name, - bool /*expecting_enum*/) const { + bool expecting_enum) const { + (void)expecting_enum; // Parameter is used by Google-internal code. auto lookup_name = std::string(name); if (!lookup_name.empty() && lookup_name[0] == '.') { lookup_name = lookup_name.substr(1); diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 6f7a5af7e97c..5229e776d364 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -1429,7 +1429,8 @@ void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) { } bool FileDescriptorSet::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(file_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(file_)) + return false; return true; } @@ -2080,10 +2081,14 @@ void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) { } bool FileDescriptorProto::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(message_type_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(service_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(message_type_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(service_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) + return false; if (_internal_has_options()) { if (!options_->IsInitialized()) return false; } @@ -3165,12 +3170,18 @@ void DescriptorProto::CopyFrom(const DescriptorProto& from) { } bool DescriptorProto::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(field_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(nested_type_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_range_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) return false; - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(oneof_decl_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(field_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(nested_type_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(enum_type_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_range_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(extension_)) + return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(oneof_decl_)) + return false; if (_internal_has_options()) { if (!options_->IsInitialized()) return false; } @@ -3394,7 +3405,8 @@ bool ExtensionRangeOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -4947,7 +4959,8 @@ void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) { } bool EnumDescriptorProto::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(value_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(value_)) + return false; if (_internal_has_options()) { if (!options_->IsInitialized()) return false; } @@ -5570,7 +5583,8 @@ void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) { } bool ServiceDescriptorProto::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(method_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(method_)) + return false; if (_internal_has_options()) { if (!options_->IsInitialized()) return false; } @@ -7065,7 +7079,8 @@ bool FileOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -7459,7 +7474,8 @@ bool MessageOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -7866,7 +7882,8 @@ bool FieldOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -8079,7 +8096,8 @@ bool OneofOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -8360,7 +8378,8 @@ bool EnumOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -8609,7 +8628,8 @@ bool EnumValueOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -8853,7 +8873,8 @@ bool ServiceOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -9145,7 +9166,8 @@ bool MethodOptions::IsInitialized() const { return false; } - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(uninterpreted_option_)) + return false; return true; } @@ -9865,7 +9887,8 @@ void UninterpretedOption::CopyFrom(const UninterpretedOption& from) { } bool UninterpretedOption::IsInitialized() const { - if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(name_)) return false; + if (!::PROTOBUF_NAMESPACE_ID::internal::AllAreInitialized(name_)) + return false; return true; } diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 71dc8b42e748..1bf7a36b4003 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -1976,10 +1976,12 @@ void ExtensionSet::GrowCapacity(size_t minimum_new_capacity) { map_ = new_map; } -#if (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +#if (__cplusplus < 201703) && \ + (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) // static constexpr uint16_t ExtensionSet::kMaximumFlatCapacity; -#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 && _MSC_VER < 1912)) +#endif // (__cplusplus < 201703) && (!defined(_MSC_VER) || (_MSC_VER >= 1900 + // && _MSC_VER < 1912)) void ExtensionSet::Erase(int key) { if (PROTOBUF_PREDICT_FALSE(is_large())) { diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 900403357809..cf7cd852cdb8 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -1613,7 +1614,8 @@ std::string Reflection::GetString(const Message& message, const std::string& Reflection::GetStringReference(const Message& message, const FieldDescriptor* field, - std::string* /*scratch*/) const { + std::string* scratch) const { + (void)scratch; // Parameter is used by Google-internal code. USAGE_CHECK_ALL(GetStringReference, SINGULAR, STRING); if (field->is_extension()) { return GetExtensionSet(message).GetString(field->number(), @@ -1701,7 +1703,8 @@ std::string Reflection::GetRepeatedString(const Message& message, const std::string& Reflection::GetRepeatedStringReference( const Message& message, const FieldDescriptor* field, int index, - std::string* /*scratch*/) const { + std::string* scratch) const { + (void)scratch; // Parameter is used by Google-internal code. USAGE_CHECK_ALL(GetRepeatedStringReference, REPEATED, STRING); if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); @@ -2239,8 +2242,9 @@ void Reflection::UnsafeArenaAddAllocatedMessage(Message* message, void* Reflection::MutableRawRepeatedField(Message* message, const FieldDescriptor* field, FieldDescriptor::CppType cpptype, - int /*ctype*/, + int ctype, const Descriptor* desc) const { + (void)ctype; // Parameter is used by Google-internal code. USAGE_CHECK_REPEATED("MutableRawRepeatedField"); CheckInvalidAccess(schema_, field); @@ -2518,9 +2522,13 @@ bool Reflection::HasBit(const Message& message, case FieldDescriptor::CPPTYPE_UINT64: return GetRaw(message, field) != 0; case FieldDescriptor::CPPTYPE_FLOAT: - return GetRaw(message, field) != 0.0; + static_assert(sizeof(uint32_t) == sizeof(float), + "Code assumes uint32_t and float are the same size."); + return GetRaw(message, field) != 0; case FieldDescriptor::CPPTYPE_DOUBLE: - return GetRaw(message, field) != 0.0; + static_assert(sizeof(uint64_t) == sizeof(double), + "Code assumes uint64_t and double are the same size."); + return GetRaw(message, field) != 0; case FieldDescriptor::CPPTYPE_ENUM: return GetRaw(message, field) != 0; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -2658,7 +2666,8 @@ HANDLE_TYPE(bool, FieldDescriptor::CPPTYPE_BOOL, -1); void* Reflection::MutableRawRepeatedString(Message* message, const FieldDescriptor* field, - bool /*is_string*/) const { + bool is_string) const { + (void)is_string; // Parameter is used by Google-internal code. return MutableRawRepeatedField(message, field, FieldDescriptor::CPPTYPE_STRING, FieldOptions::STRING, nullptr); diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h index d294caa5df01..4e5c1eaba57f 100644 --- a/src/google/protobuf/generated_message_tctable_decl.h +++ b/src/google/protobuf/generated_message_tctable_decl.h @@ -65,39 +65,42 @@ struct TcFieldData { uint64_t data; }; -struct TailCallParseTableBase; +struct TcParseTableBase; // TailCallParseFunc is the function pointer type used in the tailcall table. typedef const char* (*TailCallParseFunc)(PROTOBUF_TC_PARAM_DECL); #if defined(_MSC_VER) && !defined(_WIN64) #pragma warning(push) -// TailCallParseTableBase is intentionally overaligned on 32 bit targets. +// TcParseTableBase is intentionally overaligned on 32 bit targets. #pragma warning(disable : 4324) #endif // Base class for message-level table with info for the tail-call parser. -struct alignas(uint64_t) TailCallParseTableBase { +struct alignas(uint64_t) TcParseTableBase { // Common attributes for message layout: uint16_t has_bits_offset; uint16_t extension_offset; uint32_t extension_range_low; uint32_t extension_range_high; + uint8_t fast_idx_mask; + uint8_t reserved; + uint16_t num_fields; const MessageLite* default_instance; // Handler for fields which are not handled by table dispatch. TailCallParseFunc fallback; // Table entry for fast-path tailcall dispatch handling. - struct FieldEntry { + struct FastFieldEntry { // Target function for dispatch: TailCallParseFunc target; // Field data used during parse: TcFieldData bits; }; // There is always at least one table entry. - const FieldEntry* table() const { - return reinterpret_cast(this + 1); + const FastFieldEntry* fast_entry(size_t idx) const { + return reinterpret_cast(this + 1) + idx; } }; @@ -105,12 +108,12 @@ struct alignas(uint64_t) TailCallParseTableBase { #pragma warning(pop) #endif -static_assert(sizeof(TailCallParseTableBase::FieldEntry) <= 16, +static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16, "Field entry is too big."); -template -struct TailCallParseTable { - TailCallParseTableBase header; +template +struct TcParseTable { + TcParseTableBase header; // Entries for each field. // @@ -118,15 +121,14 @@ struct TailCallParseTable { // number is masked to fit inside the table. Note that the parsing logic // generally calls `TailCallParseTableBase::table()` instead of accessing // this field directly. - TailCallParseTableBase::FieldEntry entries[(1 << kTableSizeLog2)]; + TcParseTableBase::FastFieldEntry entries[(1 << kFastTableSizeLog2)]; }; -static_assert(std::is_standard_layout>::value, - "TailCallParseTable must be standard layout."); +static_assert(std::is_standard_layout>::value, + "TcParseTable must be standard layout."); -static_assert(offsetof(TailCallParseTable<1>, entries) == - sizeof(TailCallParseTableBase), - "Table entries must be laid out after TailCallParseTableBase."); +static_assert(offsetof(TcParseTable<1>, entries) == sizeof(TcParseTableBase), + "Table entries must be laid out after TcParseTableBase."); } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_tctable_full.cc b/src/google/protobuf/generated_message_tctable_full.cc index 634c663029b1..44dcddc79613 100644 --- a/src/google/protobuf/generated_message_tctable_full.cc +++ b/src/google/protobuf/generated_message_tctable_full.cc @@ -44,7 +44,7 @@ namespace google { namespace protobuf { namespace internal { -const char* TcParserBase::GenericFallback(PROTOBUF_TC_PARAM_DECL) { +const char* TcParser::GenericFallback(PROTOBUF_TC_PARAM_DECL) { return GenericFallbackImpl(PROTOBUF_TC_PARAM_PASS); } diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 4ae5410249dc..3f2b1cabdddc 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -69,28 +69,28 @@ namespace internal { #define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) MESSAGE::Tct_ParseS1 #else #define PROTOBUF_TC_PARSE_SINGULAR1(MESSAGE) \ - ::google::protobuf::internal::TcParserBase::SingularParseMessage + ::google::protobuf::internal::TcParser::SingularParseMessage #endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR1 #if PROTOBUF_TC_STATIC_PARSE_SINGULAR2 #define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) MESSAGE::Tct_ParseS2 #else #define PROTOBUF_TC_PARSE_SINGULAR2(MESSAGE) \ - ::google::protobuf::internal::TcParserBase::SingularParseMessage + ::google::protobuf::internal::TcParser::SingularParseMessage #endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR2 #if PROTOBUF_TC_STATIC_PARSE_REPEATED1 #define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) MESSAGE::Tct_ParseR1 #else #define PROTOBUF_TC_PARSE_REPEATED1(MESSAGE) \ - ::google::protobuf::internal::TcParserBase::RepeatedParseMessage + ::google::protobuf::internal::TcParser::RepeatedParseMessage #endif // PROTOBUF_TC_STATIC_PARSE_REPEATED1 #if PROTOBUF_TC_STATIC_PARSE_REPEATED2 #define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) MESSAGE::Tct_ParseR2 #else #define PROTOBUF_TC_PARSE_REPEATED2(MESSAGE) \ - ::google::protobuf::internal::TcParserBase::RepeatedParseMessage + ::google::protobuf::internal::TcParser::RepeatedParseMessage #endif // PROTOBUF_TC_STATIC_PARSE_REPEATED2 #ifndef NDEBUG @@ -106,11 +106,52 @@ extern template void AlignFail<4>(uintptr_t); extern template void AlignFail<8>(uintptr_t); #endif -class TcParserBase { +// TcParser implements most of the parsing logic for tailcall tables. +class TcParser final { public: static const char* GenericFallback(PROTOBUF_TC_PARAM_DECL); static const char* GenericFallbackLite(PROTOBUF_TC_PARAM_DECL); + // Dispatch to the designated parse function + inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch( + PROTOBUF_TC_PARAM_DECL) { + const auto coded_tag = UnalignedLoad(ptr); + const size_t idx = coded_tag & table->fast_idx_mask; + PROTOBUF_ASSUME((idx & 7) == 0); + auto* fast_entry = table->fast_entry(idx >> 3); + data = fast_entry->bits; + data.data ^= coded_tag; + PROTOBUF_MUSTTAIL return fast_entry->target(PROTOBUF_TC_PARAM_PASS); + } + + // We can only safely call from field to next field if the call is optimized + // to a proper tail call. Otherwise we blow through stack. Clang and gcc + // reliably do this optimization in opt mode, but do not perform this in debug + // mode. Luckily the structure of the algorithm is such that it's always + // possible to just return and use the enclosing parse loop as a trampoline. + static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL) { + constexpr bool always_return = !PROTOBUF_TAILCALL; + if (always_return || !ctx->DataAvailable(ptr)) { + PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS); + } + PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS); + } + + static const char* ParseLoop(MessageLite* msg, const char* ptr, + ParseContext* ctx, + const TcParseTableBase* table) { + ScopedArenaSwap saved(msg, ctx); + const uint32_t has_bits_offset = table->has_bits_offset; + while (!ctx->Done(&ptr)) { + uint64_t hasbits = 0; + if (has_bits_offset) hasbits = RefAt(msg, has_bits_offset); + ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {}); + if (ptr == nullptr) break; + if (ctx->LastTag() != 1) break; // Ended on terminating tag + } + return ptr; + } + template PROTOBUF_NOINLINE static const char* SingularParseMessage( PROTOBUF_TC_PARAM_DECL) { @@ -145,6 +186,8 @@ class TcParserBase { return ptr; } + template + static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL); template static const char* RepeatedFixed(PROTOBUF_TC_PARAM_DECL); template @@ -152,6 +195,8 @@ class TcParserBase { enum VarintDecode { kNoConversion = 0, kZigZag = 1 }; template + static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL); + template static const char* RepeatedVarint(PROTOBUF_TC_PARAM_DECL); template static const char* PackedVarint(PROTOBUF_TC_PARAM_DECL); @@ -175,7 +220,7 @@ class TcParserBase { } static inline PROTOBUF_ALWAYS_INLINE void SyncHasbits( - MessageLite* msg, uint64_t hasbits, const TailCallParseTableBase* table) { + MessageLite* msg, uint64_t hasbits, const TcParseTableBase* table) { const uint32_t has_bits_offset = table->has_bits_offset; if (has_bits_offset) { // Only the first 32 has-bits are updated. Nothing above those is stored, @@ -185,7 +230,7 @@ class TcParserBase { } protected: - static inline PROTOBUF_ALWAYS_INLINE const char* Return( + static inline PROTOBUF_ALWAYS_INLINE const char* ToParseLoop( PROTOBUF_TC_PARAM_DECL) { (void)data; (void)ctx; @@ -245,59 +290,6 @@ class TcParserBase { } }; -// TcParser implements most of the parsing logic for tailcall tables. -// -// This is templated on lg2(table size), since dispatching depends upon the size -// of the table. The template parameter avoids runtime overhead for computing -// the table entry index. -template -struct TcParser final : TcParserBase { - // Dispatch to the designated parse function - inline PROTOBUF_ALWAYS_INLINE static const char* TagDispatch( - PROTOBUF_TC_PARAM_DECL) { - const auto coded_tag = UnalignedLoad(ptr); - constexpr size_t kIdxMask = ((1 << (kPowerOf2)) - 1); - const size_t idx = (coded_tag >> 3) & kIdxMask; - data = table->table()[idx].bits; - data.data ^= coded_tag; - PROTOBUF_MUSTTAIL return table->table()[idx].target(PROTOBUF_TC_PARAM_PASS); - } - - // We can only safely call from field to next field if the call is optimized - // to a proper tail call. Otherwise we blow through stack. Clang and gcc - // reliably do this optimization in opt mode, but do not perform this in debug - // mode. Luckily the structure of the algorithm is such that it's always - // possible to just return and use the enclosing parse loop as a trampoline. - static const char* TailCall(PROTOBUF_TC_PARAM_DECL) { - constexpr bool always_return = !PROTOBUF_TAILCALL; - if (always_return || !ctx->DataAvailable(ptr)) { - PROTOBUF_MUSTTAIL return Return(PROTOBUF_TC_PARAM_PASS); - } - PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS); - } - - static const char* ParseLoop(MessageLite* msg, const char* ptr, - ParseContext* ctx, - const TailCallParseTableBase* table) { - ScopedArenaSwap saved(msg, ctx); - const uint32_t has_bits_offset = table->has_bits_offset; - while (!ctx->Done(&ptr)) { - uint64_t hasbits = 0; - if (has_bits_offset) hasbits = RefAt(msg, has_bits_offset); - ptr = TagDispatch(msg, ptr, ctx, table, hasbits, {}); - if (ptr == nullptr) break; - if (ctx->LastTag() != 1) break; // Ended on terminating tag - } - return ptr; - } - - template - static const char* SingularFixed(PROTOBUF_TC_PARAM_DECL); - - template - static const char* SingularVarint(PROTOBUF_TC_PARAM_DECL); -}; - // Declare helper functions: #include diff --git a/src/google/protobuf/generated_message_tctable_impl.inc b/src/google/protobuf/generated_message_tctable_impl.inc index 8d38a513e274..a6831b53f50a 100644 --- a/src/google/protobuf/generated_message_tctable_impl.inc +++ b/src/google/protobuf/generated_message_tctable_impl.inc @@ -34,120 +34,59 @@ #else #define PROTOBUF_TCT_EXTERN extern #endif -PROTOBUF_TCT_EXTERN template const char *TcParser<1>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*); -PROTOBUF_TCT_EXTERN template const char *TcParser<2>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*); -PROTOBUF_TCT_EXTERN template const char *TcParser<3>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*); -PROTOBUF_TCT_EXTERN template const char *TcParser<4>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*); -PROTOBUF_TCT_EXTERN template const char *TcParser<5>::ParseLoop(::PROTOBUF_NAMESPACE_ID::MessageLite*, char const*, ::PROTOBUF_NAMESPACE_ID::internal::ParseContext*, ::PROTOBUF_NAMESPACE_ID::internal::TailCallParseTableBase const*); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<1>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<2>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<3>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<4>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParser<5>::SingularVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::PackedVarint(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL); -PROTOBUF_TCT_EXTERN template const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL); +PROTOBUF_TCT_EXTERN template const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL); #undef PROTOBUF_TCT_EXTERN // clang-format on diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc index 231ad4622db8..4350929bd1cb 100644 --- a/src/google/protobuf/generated_message_tctable_lite.cc +++ b/src/google/protobuf/generated_message_tctable_lite.cc @@ -50,7 +50,7 @@ template void AlignFail<4>(uintptr_t); template void AlignFail<8>(uintptr_t); #endif -const char* TcParserBase::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) { +const char* TcParser::GenericFallbackLite(PROTOBUF_TC_PARAM_DECL) { return GenericFallbackImpl(PROTOBUF_TC_PARAM_PASS); } @@ -75,9 +75,8 @@ inline PROTOBUF_ALWAYS_INLINE void InvertPacked(TcFieldData& data) { // Fixed fields ////////////////////////////////////////////////////////////////////////////// -template template -const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL) { +const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -85,12 +84,11 @@ const char* TcParser::SingularFixed(PROTOBUF_TC_PARAM_DECL) { hasbits |= (uint64_t{1} << data.hasbit_idx()); std::memcpy(Offset(msg, data.offset()), ptr, sizeof(LayoutType)); ptr += sizeof(LayoutType); - // TailCall syncs any pending hasbits: - PROTOBUF_MUSTTAIL return TailCall(PROTOBUF_TC_PARAM_PASS); + PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); } template -const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) { +const char* TcParser::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { // Check if the field can be parsed as packed repeated: constexpr WireFormatLite::WireType fallback_wt = @@ -117,11 +115,11 @@ const char* TcParserBase::RepeatedFixed(PROTOBUF_TC_PARAM_DECL) { if (!ctx->DataAvailable(ptr)) break; } while (UnalignedLoad(ptr) == expected_tag); field.AddNAlreadyReserved(idx - 1); - return Return(PROTOBUF_TC_PARAM_PASS); + return ToParseLoop(PROTOBUF_TC_PARAM_PASS); } template -const char* TcParserBase::PackedFixed(PROTOBUF_TC_PARAM_DECL) { +const char* TcParser::PackedFixed(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { // Try parsing as non-packed repeated: constexpr WireFormatLite::WireType fallback_wt = @@ -278,30 +276,28 @@ inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p, } } -template +template FieldType ZigZagDecodeHelper(uint64_t value) { return static_cast(value); } template <> -int32_t ZigZagDecodeHelper( +int32_t ZigZagDecodeHelper( uint64_t value) { return WireFormatLite::ZigZagDecode32(value); } template <> -int64_t ZigZagDecodeHelper( +int64_t ZigZagDecodeHelper( uint64_t value) { return WireFormatLite::ZigZagDecode64(value); } } // namespace -template -template -const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL) { +template +const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -314,13 +310,11 @@ const char* TcParser::SingularVarint(PROTOBUF_TC_PARAM_DECL) { } RefAt(msg, data.offset()) = ZigZagDecodeHelper(tmp); - PROTOBUF_MUSTTAIL return TailCall(PROTOBUF_TC_PARAM_PASS); + PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); } -template -PROTOBUF_NOINLINE const char* TcParserBase::RepeatedVarint( - PROTOBUF_TC_PARAM_DECL) { +template +PROTOBUF_NOINLINE const char* TcParser::RepeatedVarint(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { // Try parsing as non-packed repeated: InvertPacked(data); @@ -344,13 +338,11 @@ PROTOBUF_NOINLINE const char* TcParserBase::RepeatedVarint( break; } } while (UnalignedLoad(ptr) == expected_tag); - return Return(PROTOBUF_TC_PARAM_PASS); + return ToParseLoop(PROTOBUF_TC_PARAM_PASS); } -template -PROTOBUF_NOINLINE const char* TcParserBase::PackedVarint( - PROTOBUF_TC_PARAM_DECL) { +template +PROTOBUF_NOINLINE const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { InvertPacked(data); if (data.coded_tag() == 0) { @@ -400,8 +392,8 @@ const char* SingularStringParserFallback(ArenaStringPtr* s, const char* ptr, } // namespace -template -const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL) { +template +const char* TcParser::SingularString(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -420,19 +412,19 @@ const char* TcParserBase::SingularString(PROTOBUF_TC_PARAM_DECL) { #ifdef NDEBUG case kUtf8ValidateOnly: #endif - return Return(PROTOBUF_TC_PARAM_PASS); + return ToParseLoop(PROTOBUF_TC_PARAM_PASS); default: if (PROTOBUF_PREDICT_TRUE(IsStructurallyValidUTF8(field.Get()))) { - return Return(PROTOBUF_TC_PARAM_PASS); + return ToParseLoop(PROTOBUF_TC_PARAM_PASS); } PrintUTF8ErrorLog("unknown", "parsing", false); return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS) - : Return(PROTOBUF_TC_PARAM_PASS); + : ToParseLoop(PROTOBUF_TC_PARAM_PASS); } } -template -const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL) { +template +const char* TcParser::RepeatedString(PROTOBUF_TC_PARAM_DECL) { if (PROTOBUF_PREDICT_FALSE(data.coded_tag() != 0)) { return table->fallback(PROTOBUF_TC_PARAM_PASS); } @@ -453,7 +445,7 @@ const char* TcParserBase::RepeatedString(PROTOBUF_TC_PARAM_DECL) { } if (!ctx->DataAvailable(ptr)) break; } while (UnalignedLoad(ptr) == expected_tag); - return Return(PROTOBUF_TC_PARAM_PASS); + return ToParseLoop(PROTOBUF_TC_PARAM_PASS); } #define PROTOBUF_TCT_SOURCE diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index 0b1cdd57c52b..32a57d3cf7e4 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -523,7 +523,8 @@ struct PackedFieldHelper { template <> struct PackedFieldHelper { template - static void Serialize(const void* /*field*/, const FieldMetadata& md, O* /*output*/) { + static void Serialize(const void* /*field*/, const FieldMetadata& md, + O* /*output*/) { GOOGLE_LOG(FATAL) << "Not implemented field number " << md.tag << " with type " << md.type; } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 0a39c220f405..45963ef86b53 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -710,6 +710,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream { // aliasing the buffer (ie. not copying the data). The caller is responsible // to make sure the buffer is alive for the duration of the // ZeroCopyOutputStream. +#ifndef NDEBUG + PROTOBUF_NOINLINE +#endif uint8_t* WriteRawMaybeAliased(const void* data, int size, uint8_t* ptr) { if (aliasing_enabled_) { return WriteAliasedRaw(data, size, ptr); @@ -719,6 +722,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream { } +#ifndef NDEBUG + PROTOBUF_NOINLINE +#endif uint8_t* WriteStringMaybeAliased(uint32_t num, const std::string& s, uint8_t* ptr) { std::ptrdiff_t size = s.size(); @@ -750,6 +756,9 @@ class PROTOBUF_EXPORT EpsCopyOutputStream { return ptr + size; } template +#ifndef NDEBUG + PROTOBUF_NOINLINE +#endif uint8_t* WriteBytes(uint32_t num, const T& s, uint8_t* ptr) { return WriteString(num, s, ptr); } diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index aef6621c9be1..b4f8d4025be1 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -118,9 +118,10 @@ inline StringPiece as_string_view(const void* data, int size) { } // Returns true of all required fields are present / have values. -inline bool CheckFieldPresence(const internal::ParseContext& /*ctx*/, +inline bool CheckFieldPresence(const internal::ParseContext& ctx, const MessageLite& msg, MessageLite::ParseFlags parse_flags) { + (void)ctx; // Parameter is used by Google-internal code. if (PROTOBUF_PREDICT_FALSE((parse_flags & MessageLite::kMergePartial) != 0)) { return true; } diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 81cb8f8326e7..5e6fbdb5d1a7 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -95,7 +95,7 @@ class ParseContext; class ExtensionSet; class LazyField; class RepeatedPtrFieldBase; -class TcParserBase; +class TcParser; class WireFormatLite; class WeakFieldMap; @@ -482,7 +482,7 @@ class PROTOBUF_EXPORT MessageLite { friend class internal::ExtensionSet; friend class internal::LazyField; friend class internal::SwapFieldHelper; - friend class internal::TcParserBase; + friend class internal::TcParser; friend class internal::WeakFieldMap; friend class internal::WireFormatLite; diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc index 3e1de4842b73..f57fc8e070fd 100644 --- a/src/google/protobuf/message_unittest.inc +++ b/src/google/protobuf/message_unittest.inc @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -876,5 +877,21 @@ TEST(MESSAGE_TEST_NAME, CheckSerializationWhenInterleavedExtensions) { EXPECT_EQ(5, out_message.GetExtension(UNITTEST::TestExtensionRangeSerialize::bar_five)); } +TEST(MESSAGE_TEST_NAME, PreservesFloatingPointNegative0) { + UNITTEST::TestAllTypes in_message; + in_message.set_optional_float(-0.0f); + in_message.set_optional_double(-0.0); + std::string serialized; + EXPECT_TRUE(in_message.SerializeToString(&serialized)); + UNITTEST::TestAllTypes out_message; + EXPECT_TRUE(out_message.ParseFromString(serialized)); + EXPECT_EQ(in_message.optional_float(), out_message.optional_float()); + EXPECT_EQ(std::signbit(in_message.optional_float()), + std::signbit(out_message.optional_float())); + EXPECT_EQ(in_message.optional_double(), out_message.optional_double()); + EXPECT_EQ(std::signbit(in_message.optional_double()), + std::signbit(out_message.optional_double())); +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc index e8790ad53b10..afa38b561771 100644 --- a/src/google/protobuf/port_def.inc +++ b/src/google/protobuf/port_def.inc @@ -579,7 +579,8 @@ // https://github.com/protocolbuffers/protobuf/issues/8310 // Does not work yet with Visual Studio 2019 Update 16.10 #define PROTOBUF_CONSTINIT constinit -#elif !defined(_MSC_VER) && __has_cpp_attribute(clang::require_constant_initialization) +#elif !defined(_MSC_VER) && \ + __has_cpp_attribute(clang::require_constant_initialization) #define PROTOBUF_CONSTINIT [[clang::require_constant_initialization]] #else #define PROTOBUF_CONSTINIT @@ -696,7 +697,7 @@ #define PROTOBUF_TC_PARAM_DECL \ ::google::protobuf::MessageLite *msg, const char *ptr, \ ::google::protobuf::internal::ParseContext *ctx, \ - const ::google::protobuf::internal::TailCallParseTableBase *table, \ + const ::google::protobuf::internal::TcParseTableBase *table, \ uint64_t hasbits, ::google::protobuf::internal::TcFieldData data #ifdef PROTOBUF_UNUSED diff --git a/src/google/protobuf/reflection_internal.h b/src/google/protobuf/reflection_internal.h index 4a8a9bd1f097..f749c3eb11ba 100644 --- a/src/google/protobuf/reflection_internal.h +++ b/src/google/protobuf/reflection_internal.h @@ -61,7 +61,8 @@ class RandomAccessRepeatedFieldAccessor : public RepeatedFieldAccessor { const Iterator* b) const override { return a == b; } - void DeleteIterator(const Field* /*data*/, Iterator* /*iterator*/) const override {} + void DeleteIterator(const Field* /*data*/, + Iterator* /*iterator*/) const override {} const Value* GetIteratorValue(const Field* data, const Iterator* iterator, Value* scratch_space) const override { return Get(data, static_cast(IteratorToPosition(iterator)), diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 8a6b75d77eb7..28a7bd3cbd89 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -38,119 +38,12 @@ #include #include -#include #include namespace google { namespace protobuf { -namespace internal { - -void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { - int new_size = current_size_ + extend_amount; - if (total_size_ >= new_size) { - // N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence - // total_size must be non-zero since it is lower-bounded by new_size. - return &rep_->elements[current_size_]; - } - Rep* old_rep = rep_; - Arena* arena = GetArena(); - new_size = std::max(internal::kRepeatedFieldLowerClampLimit, - std::max(total_size_ * 2, new_size)); - GOOGLE_CHECK_LE(static_cast(new_size), - static_cast( - (std::numeric_limits::max() - kRepHeaderSize) / - sizeof(old_rep->elements[0]))) - << "Requested size is too large to fit into size_t."; - size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size; - if (arena == nullptr) { - rep_ = reinterpret_cast(::operator new(bytes)); - } else { - rep_ = reinterpret_cast(Arena::CreateArray(arena, bytes)); - } -#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) - const int old_total_size = total_size_; -#endif - total_size_ = new_size; - if (old_rep && old_rep->allocated_size > 0) { - memcpy(rep_->elements, old_rep->elements, - old_rep->allocated_size * sizeof(rep_->elements[0])); - rep_->allocated_size = old_rep->allocated_size; - } else { - rep_->allocated_size = 0; - } - if (arena == nullptr) { -#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) - const size_t old_size = - old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize; - ::operator delete(static_cast(old_rep), old_size); -#else - ::operator delete(static_cast(old_rep)); -#endif - } - return &rep_->elements[current_size_]; -} - -void RepeatedPtrFieldBase::Reserve(int new_size) { - if (new_size > current_size_) { - InternalExtend(new_size - current_size_); - } -} - -void RepeatedPtrFieldBase::DestroyProtos() { - GOOGLE_DCHECK(rep_); - GOOGLE_DCHECK(arena_ == nullptr); - int n = rep_->allocated_size; - void* const* elements = rep_->elements; - for (int i = 0; i < n; i++) { - delete static_cast(elements[i]); - } -#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) - const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize; - ::operator delete(static_cast(rep_), size); - rep_ = nullptr; -#else - ::operator delete(static_cast(rep_)); - rep_ = nullptr; -#endif -} - -void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) { - if (!rep_ || rep_->allocated_size == total_size_) { - InternalExtend(1); // Equivalent to "Reserve(total_size_ + 1)" - } - ++rep_->allocated_size; - rep_->elements[current_size_++] = obj; - return obj; -} - -void RepeatedPtrFieldBase::CloseGap(int start, int num) { - if (rep_ == nullptr) return; - // Close up a gap of "num" elements starting at offset "start". - for (int i = start + num; i < rep_->allocated_size; ++i) - rep_->elements[i - num] = rep_->elements[i]; - current_size_ -= num; - rep_->allocated_size -= num; -} - -MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) { - if (rep_ != nullptr && current_size_ < rep_->allocated_size) { - return reinterpret_cast(rep_->elements[current_size_++]); - } - if (!rep_ || rep_->allocated_size == total_size_) { - Reserve(total_size_ + 1); - } - ++rep_->allocated_size; - MessageLite* result = prototype - ? prototype->New(arena_) - : Arena::CreateMessage(arena_); - rep_->elements[current_size_++] = result; - return result; -} - -} // namespace internal - template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField; template class PROTOBUF_EXPORT_TEMPLATE_DEFINE RepeatedField; diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index b52e01658b44..3f362f9f0f28 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -42,6 +42,8 @@ // Typically, clients should not need to access RepeatedField objects directly, // but should instead use the accessor functions generated automatically by the // protocol compiler. +// +// This header covers RepeatedField. #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ #define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ @@ -59,11 +61,10 @@ #include #include +#include #include #include #include -#include -#include // Must be included last. @@ -77,16 +78,9 @@ namespace google { namespace protobuf { class Message; -class Reflection; - -template -struct WeakRepeatedPtrField; namespace internal { -class MergePartialFromCodedStreamHelper; -class SwapFieldHelper; - // kRepeatedFieldLowerClampLimit is the smallest size that will be allocated // when growing a repeated field. constexpr int kRepeatedFieldLowerClampLimit = 4; @@ -98,9 +92,6 @@ constexpr int kRepeatedFieldLowerClampLimit = 4; constexpr int kRepeatedFieldUpperClampLimit = (std::numeric_limits::max() / 2) + 1; -// A utility function for logging that doesn't need any template types. -void LogIndexOutOfBounds(int index, int size); - template inline int CalculateReserve(Iter begin, Iter end, std::forward_iterator_tag) { return static_cast(std::distance(begin, end)); @@ -496,13 +487,6 @@ class RepeatedField final { friend class ::google::protobuf::internal::ParseContext; }; -namespace internal { -template -class RepeatedPtrIterator; -template -class RepeatedPtrOverPtrsIterator; -} // namespace internal - namespace internal { // This is a helper template to copy an array of elements efficiently when they @@ -517,694 +501,6 @@ struct ElementCopier { } // namespace internal -namespace internal { - -// type-traits helper for RepeatedPtrFieldBase: we only want to invoke -// arena-related "copy if on different arena" behavior if the necessary methods -// exist on the contained type. In particular, we rely on MergeFrom() existing -// as a general proxy for the fact that a copy will work, and we also provide a -// specific override for std::string*. -template -struct TypeImplementsMergeBehaviorProbeForMergeFrom { - typedef char HasMerge; - typedef long HasNoMerge; - - // We accept either of: - // - void MergeFrom(const T& other) - // - bool MergeFrom(const T& other) - // - // We mangle these names a bit to avoid compatibility issues in 'unclean' - // include environments that may have, e.g., "#define test ..." (yes, this - // exists). - template - struct CheckType; - template - static HasMerge Check(CheckType*); - template - static HasMerge Check(CheckType*); - template - static HasNoMerge Check(...); - - // Resolves to either std::true_type or std::false_type. - typedef std::integral_constant(0)) == sizeof(HasMerge))> - type; -}; - -template -struct TypeImplementsMergeBehavior - : TypeImplementsMergeBehaviorProbeForMergeFrom {}; - - -template <> -struct TypeImplementsMergeBehavior { - typedef std::true_type type; -}; - -template -struct IsMovable - : std::integral_constant::value && - std::is_move_assignable::value> {}; - -// This is the common base class for RepeatedPtrFields. It deals only in void* -// pointers. Users should not use this interface directly. -// -// The methods of this interface correspond to the methods of RepeatedPtrField, -// but may have a template argument called TypeHandler. Its signature is: -// class TypeHandler { -// public: -// typedef MyType Type; -// static Type* New(); -// static Type* NewFromPrototype(const Type* prototype, -// Arena* arena); -// static void Delete(Type*); -// static void Clear(Type*); -// static void Merge(const Type& from, Type* to); -// -// // Only needs to be implemented if SpaceUsedExcludingSelf() is called. -// static int SpaceUsedLong(const Type&); -// }; -class PROTOBUF_EXPORT RepeatedPtrFieldBase { - protected: - constexpr RepeatedPtrFieldBase(); - explicit RepeatedPtrFieldBase(Arena* arena); - ~RepeatedPtrFieldBase() { -#ifndef NDEBUG - // Try to trigger segfault / asan failure in non-opt builds. If arena_ - // lifetime has ended before the destructor. - if (arena_) (void)arena_->SpaceAllocated(); -#endif - } - - // Must be called from destructor. - template - void Destroy(); - bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; } - void DestroyProtos(); - - bool empty() const; - int size() const; - - template - const typename TypeHandler::Type& at(int index) const; - template - typename TypeHandler::Type& at(int index); - - template - typename TypeHandler::Type* Mutable(int index); - template - void Delete(int index); - template - typename TypeHandler::Type* Add( - typename TypeHandler::Type* prototype = nullptr); - - public: - // The next few methods are public so that they can be called from generated - // code when implicit weak fields are used, but they should never be called by - // application code. - - template - const typename TypeHandler::Type& Get(int index) const; - - // Creates and adds an element using the given prototype, without introducing - // a link-time dependency on the concrete message type. This method is used to - // implement implicit weak fields. The prototype may be nullptr, in which case - // an ImplicitWeakMessage will be used as a placeholder. - MessageLite* AddWeak(const MessageLite* prototype); - - template - void Clear(); - - template - void MergeFrom(const RepeatedPtrFieldBase& other); - - inline void InternalSwap(RepeatedPtrFieldBase* other); - - protected: - template < - typename TypeHandler, - typename std::enable_if::type* = nullptr> - void Add(typename TypeHandler::Type&& value); - - template - void RemoveLast(); - template - void CopyFrom(const RepeatedPtrFieldBase& other); - - void CloseGap(int start, int num); - - void Reserve(int new_size); - - int Capacity() const; - - template - static inline typename TypeHandler::Type* copy( - typename TypeHandler::Type* value) { - auto* new_value = TypeHandler::NewFromPrototype(value, nullptr); - TypeHandler::Merge(*value, new_value); - return new_value; - } - - // Used for constructing iterators. - void* const* raw_data() const; - void** raw_mutable_data() const; - - template - typename TypeHandler::Type** mutable_data(); - template - const typename TypeHandler::Type* const* data() const; - - template - PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other); - - void SwapElements(int index1, int index2); - - template - size_t SpaceUsedExcludingSelfLong() const; - - // Advanced memory management -------------------------------------- - - // Like Add(), but if there are no cleared objects to use, returns nullptr. - template - typename TypeHandler::Type* AddFromCleared(); - - template - void AddAllocated(typename TypeHandler::Type* value) { - typename TypeImplementsMergeBehavior::type t; - AddAllocatedInternal(value, t); - } - - template - void UnsafeArenaAddAllocated(typename TypeHandler::Type* value); - - template - PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() { - typename TypeImplementsMergeBehavior::type t; - return ReleaseLastInternal(t); - } - - // Releases last element and returns it, but does not do out-of-arena copy. - // And just returns the raw pointer to the contained element in the arena. - template - typename TypeHandler::Type* UnsafeArenaReleaseLast(); - - int ClearedCount() const; - template - void AddCleared(typename TypeHandler::Type* value); - template - PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared(); - - template - void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type); - template - void AddAllocatedInternal(typename TypeHandler::Type* value, std::false_type); - - template - PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy( - typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena); - template - PROTOBUF_NOINLINE void AddAllocatedSlowWithoutCopy( - typename TypeHandler::Type* value); - - template - typename TypeHandler::Type* ReleaseLastInternal(std::true_type); - template - typename TypeHandler::Type* ReleaseLastInternal(std::false_type); - - template - PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other); - - inline Arena* GetArena() const { return arena_; } - - private: - static constexpr int kInitialSize = 0; - // A few notes on internal representation: - // - // We use an indirected approach, with struct Rep, to keep - // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support - // was added, namely, 3 8-byte machine words on x86-64. An instance of Rep is - // allocated only when the repeated field is non-empty, and it is a - // dynamically-sized struct (the header is directly followed by elements[]). - // We place arena_ and current_size_ directly in the object to avoid cache - // misses due to the indirection, because these fields are checked frequently. - // Placing all fields directly in the RepeatedPtrFieldBase instance costs - // significant performance for memory-sensitive workloads. - Arena* arena_; - int current_size_; - int total_size_; - struct Rep { - int allocated_size; - // Here we declare a huge array as a way of approximating C's "flexible - // array member" feature without relying on undefined behavior. - void* elements[(std::numeric_limits::max() - 2 * sizeof(int)) / - sizeof(void*)]; - }; - static constexpr size_t kRepHeaderSize = offsetof(Rep, elements); - Rep* rep_; - - template - static inline typename TypeHandler::Type* cast(void* element) { - return reinterpret_cast(element); - } - template - static inline const typename TypeHandler::Type* cast(const void* element) { - return reinterpret_cast(element); - } - - // Non-templated inner function to avoid code duplication. Takes a function - // pointer to the type-specific (templated) inner allocate/merge loop. - void MergeFromInternal(const RepeatedPtrFieldBase& other, - void (RepeatedPtrFieldBase::*inner_loop)(void**, - void**, int, - int)); - - template - PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems, - void** other_elems, int length, - int already_allocated); - - // Internal helper: extend array space if necessary to contain |extend_amount| - // more elements, and return a pointer to the element immediately following - // the old list of elements. This interface factors out common behavior from - // Reserve() and MergeFrom() to reduce code size. |extend_amount| must be > 0. - void** InternalExtend(int extend_amount); - - // Internal helper for Add: add "obj" as the next element in the - // array, including potentially resizing the array with Reserve if - // needed - void* AddOutOfLineHelper(void* obj); - - // The reflection implementation needs to call protected methods directly, - // reinterpreting pointers as being to Message instead of a specific Message - // subclass. - friend class ::PROTOBUF_NAMESPACE_ID::Reflection; - friend class ::PROTOBUF_NAMESPACE_ID::internal::SwapFieldHelper; - - // ExtensionSet stores repeated message extensions as - // RepeatedPtrField, but non-lite ExtensionSets need to implement - // SpaceUsedLong(), and thus need to call SpaceUsedExcludingSelfLong() - // reinterpreting MessageLite as Message. ExtensionSet also needs to make use - // of AddFromCleared(), which is not part of the public interface. - friend class ExtensionSet; - - // The MapFieldBase implementation needs to call protected methods directly, - // reinterpreting pointers as being to Message instead of a specific Message - // subclass. - friend class MapFieldBase; - friend class MapFieldBaseStub; - - // The table-driven MergePartialFromCodedStream implementation needs to - // operate on RepeatedPtrField. - friend class MergePartialFromCodedStreamHelper; - friend class AccessorHelper; - template - friend struct google::protobuf::WeakRepeatedPtrField; - - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase); -}; - -template -class GenericTypeHandler { - public: - typedef GenericType Type; - using Movable = IsMovable; - - static inline GenericType* New(Arena* arena) { - return Arena::CreateMaybeMessage(arena); - } - static inline GenericType* New(Arena* arena, GenericType&& value) { - return Arena::Create(arena, std::move(value)); - } - static inline GenericType* NewFromPrototype(const GenericType* prototype, - Arena* arena = nullptr); - static inline void Delete(GenericType* value, Arena* arena) { - if (arena == nullptr) { - delete value; - } - } - static inline Arena* GetOwningArena(GenericType* value) { - return Arena::GetOwningArena(value); - } - - static inline void Clear(GenericType* value) { value->Clear(); } - PROTOBUF_NOINLINE - static void Merge(const GenericType& from, GenericType* to); - static inline size_t SpaceUsedLong(const GenericType& value) { - return value.SpaceUsedLong(); - } -}; - -template -GenericType* GenericTypeHandler::NewFromPrototype( - const GenericType* /* prototype */, Arena* arena) { - return New(arena); -} -template -void GenericTypeHandler::Merge(const GenericType& from, - GenericType* to) { - to->MergeFrom(from); -} - -// NewFromPrototype() and Merge() are not defined inline here, as we will need -// to do a virtual function dispatch anyways to go from Message* to call -// New/Merge. -template <> -MessageLite* GenericTypeHandler::NewFromPrototype( - const MessageLite* prototype, Arena* arena); -template <> -inline Arena* GenericTypeHandler::GetOwningArena( - MessageLite* value) { - return value->GetOwningArena(); -} -template <> -void GenericTypeHandler::Merge(const MessageLite& from, - MessageLite* to); -template <> -inline void GenericTypeHandler::Clear(std::string* value) { - value->clear(); -} -template <> -void GenericTypeHandler::Merge(const std::string& from, - std::string* to); - -// Message specialization bodies defined in message.cc. This split is necessary -// to allow proto2-lite (which includes this header) to be independent of -// Message. -template <> -PROTOBUF_EXPORT Message* GenericTypeHandler::NewFromPrototype( - const Message* prototype, Arena* arena); -template <> -PROTOBUF_EXPORT Arena* GenericTypeHandler::GetOwningArena( - Message* value); - -class StringTypeHandler { - public: - typedef std::string Type; - using Movable = IsMovable; - - static inline std::string* New(Arena* arena) { - return Arena::Create(arena); - } - static inline std::string* New(Arena* arena, std::string&& value) { - return Arena::Create(arena, std::move(value)); - } - static inline std::string* NewFromPrototype(const std::string*, - Arena* arena) { - return New(arena); - } - static inline Arena* GetOwningArena(std::string*) { return nullptr; } - static inline void Delete(std::string* value, Arena* arena) { - if (arena == nullptr) { - delete value; - } - } - static inline void Clear(std::string* value) { value->clear(); } - static inline void Merge(const std::string& from, std::string* to) { - *to = from; - } - static size_t SpaceUsedLong(const std::string& value) { - return sizeof(value) + StringSpaceUsedExcludingSelfLong(value); - } -}; - -} // namespace internal - -// RepeatedPtrField is like RepeatedField, but used for repeated strings or -// Messages. -template -class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { - public: - constexpr RepeatedPtrField(); - explicit RepeatedPtrField(Arena* arena); - - RepeatedPtrField(const RepeatedPtrField& other); - - template ())>::value>::type> - RepeatedPtrField(Iter begin, Iter end); - - ~RepeatedPtrField(); - - RepeatedPtrField& operator=(const RepeatedPtrField& other); - - RepeatedPtrField(RepeatedPtrField&& other) noexcept; - RepeatedPtrField& operator=(RepeatedPtrField&& other) noexcept; - - bool empty() const; - int size() const; - - const Element& Get(int index) const; - Element* Mutable(int index); - Element* Add(); - void Add(Element&& value); - // Append elements in the range [begin, end) after reserving - // the appropriate number of elements. - template - void Add(Iter begin, Iter end); - - const Element& operator[](int index) const { return Get(index); } - Element& operator[](int index) { return *Mutable(index); } - - const Element& at(int index) const; - Element& at(int index); - - // Remove the last element in the array. - // Ownership of the element is retained by the array. - void RemoveLast(); - - // Delete elements with indices in the range [start .. start+num-1]. - // Caution: implementation moves all elements with indices [start+num .. ]. - // Calling this routine inside a loop can cause quadratic behavior. - void DeleteSubrange(int start, int num); - - PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear(); - void MergeFrom(const RepeatedPtrField& other); - PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedPtrField& other); - - // Replaces the contents with RepeatedPtrField(begin, end). - template - PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end); - - // Reserve space to expand the field to at least the given size. This only - // resizes the pointer array; it doesn't allocate any objects. If the - // array is grown, it will always be at least doubled in size. - void Reserve(int new_size); - - int Capacity() const; - - // Gets the underlying array. This pointer is possibly invalidated by - // any add or remove operation. - Element** mutable_data(); - const Element* const* data() const; - - // Swap entire contents with "other". If they are on separate arenas, then - // copies data. - void Swap(RepeatedPtrField* other); - - // Swap entire contents with "other". Caller should guarantee that either both - // fields are on the same arena or both are on the heap. Swapping between - // different arenas with this function is disallowed and is caught via - // GOOGLE_DCHECK. - void UnsafeArenaSwap(RepeatedPtrField* other); - - // Swap two elements. - void SwapElements(int index1, int index2); - - // STL-like iterator support - typedef internal::RepeatedPtrIterator iterator; - typedef internal::RepeatedPtrIterator const_iterator; - typedef Element value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef int size_type; - typedef ptrdiff_t difference_type; - - iterator begin(); - const_iterator begin() const; - const_iterator cbegin() const; - iterator end(); - const_iterator end() const; - const_iterator cend() const; - - // Reverse iterator support - typedef std::reverse_iterator const_reverse_iterator; - typedef std::reverse_iterator reverse_iterator; - reverse_iterator rbegin() { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const { - return const_reverse_iterator(end()); - } - reverse_iterator rend() { return reverse_iterator(begin()); } - const_reverse_iterator rend() const { - return const_reverse_iterator(begin()); - } - - // Custom STL-like iterator that iterates over and returns the underlying - // pointers to Element rather than Element itself. - typedef internal::RepeatedPtrOverPtrsIterator - pointer_iterator; - typedef internal::RepeatedPtrOverPtrsIterator - const_pointer_iterator; - pointer_iterator pointer_begin(); - const_pointer_iterator pointer_begin() const; - pointer_iterator pointer_end(); - const_pointer_iterator pointer_end() const; - - // Returns (an estimate of) the number of bytes used by the repeated field, - // excluding sizeof(*this). - size_t SpaceUsedExcludingSelfLong() const; - - int SpaceUsedExcludingSelf() const { - return internal::ToIntSize(SpaceUsedExcludingSelfLong()); - } - - // Advanced memory management -------------------------------------- - // When hardcore memory management becomes necessary -- as it sometimes - // does here at Google -- the following methods may be useful. - - // Add an already-allocated object, passing ownership to the - // RepeatedPtrField. - // - // Note that some special behavior occurs with respect to arenas: - // - // (i) if this field holds submessages, the new submessage will be copied if - // the original is in an arena and this RepeatedPtrField is either in a - // different arena, or on the heap. - // (ii) if this field holds strings, the passed-in string *must* be - // heap-allocated, not arena-allocated. There is no way to dynamically check - // this at runtime, so User Beware. - void AddAllocated(Element* value); - - // Remove the last element and return it, passing ownership to the caller. - // Requires: size() > 0 - // - // If this RepeatedPtrField is on an arena, an object copy is required to pass - // ownership back to the user (for compatible semantics). Use - // UnsafeArenaReleaseLast() if this behavior is undesired. - PROTOBUF_NODISCARD Element* ReleaseLast(); - - // Add an already-allocated object, skipping arena-ownership checks. The user - // must guarantee that the given object is in the same arena as this - // RepeatedPtrField. - // It is also useful in legacy code that uses temporary ownership to avoid - // copies. Example: - // RepeatedPtrField temp_field; - // temp_field.UnsafeArenaAddAllocated(new T); - // ... // Do something with temp_field - // temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr); - // If you put temp_field on the arena this fails, because the ownership - // transfers to the arena at the "AddAllocated" call and is not released - // anymore causing a double delete. UnsafeArenaAddAllocated prevents this. - void UnsafeArenaAddAllocated(Element* value); - - // Remove the last element and return it. Unlike ReleaseLast, the returned - // pointer is always to the original object. This may be in an arena, and - // therefore have the arena's lifetime. - // Requires: current_size_ > 0 - Element* UnsafeArenaReleaseLast(); - - // Extract elements with indices in the range "[start .. start+num-1]". - // The caller assumes ownership of the extracted elements and is responsible - // for deleting them when they are no longer needed. - // If "elements" is non-nullptr, then pointers to the extracted elements - // are stored in "elements[0 .. num-1]" for the convenience of the caller. - // If "elements" is nullptr, then the caller must use some other mechanism - // to perform any further operations (like deletion) on these elements. - // Caution: implementation also moves elements with indices [start+num ..]. - // Calling this routine inside a loop can cause quadratic behavior. - // - // Memory copying behavior is identical to ReleaseLast(), described above: if - // this RepeatedPtrField is on an arena, an object copy is performed for each - // returned element, so that all returned element pointers are to - // heap-allocated copies. If this copy is not desired, the user should call - // UnsafeArenaExtractSubrange(). - void ExtractSubrange(int start, int num, Element** elements); - - // Identical to ExtractSubrange() described above, except that no object - // copies are ever performed. Instead, the raw object pointers are returned. - // Thus, if on an arena, the returned objects must not be freed, because they - // will not be heap-allocated objects. - void UnsafeArenaExtractSubrange(int start, int num, Element** elements); - - // When elements are removed by calls to RemoveLast() or Clear(), they - // are not actually freed. Instead, they are cleared and kept so that - // they can be reused later. This can save lots of CPU time when - // repeatedly reusing a protocol message for similar purposes. - // - // Hardcore programs may choose to manipulate these cleared objects - // to better optimize memory management using the following routines. - - // Get the number of cleared objects that are currently being kept - // around for reuse. - int ClearedCount() const; -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES - // Add an element to the pool of cleared objects, passing ownership to - // the RepeatedPtrField. The element must be cleared prior to calling - // this method. - // - // This method cannot be called when the repeated field is on an arena or when - // |value| is; both cases will trigger a GOOGLE_DCHECK-failure. - void AddCleared(Element* value); - // Remove a single element from the cleared pool and return it, passing - // ownership to the caller. The element is guaranteed to be cleared. - // Requires: ClearedCount() > 0 - // - // - // This method cannot be called when the repeated field is on an arena; doing - // so will trigger a GOOGLE_DCHECK-failure. - PROTOBUF_NODISCARD Element* ReleaseCleared(); -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES - - // Removes the element referenced by position. - // - // Returns an iterator to the element immediately following the removed - // element. - // - // Invalidates all iterators at or after the removed element, including end(). - iterator erase(const_iterator position); - - // Removes the elements in the range [first, last). - // - // Returns an iterator to the element immediately following the removed range. - // - // Invalidates all iterators at or after the removed range, including end(). - iterator erase(const_iterator first, const_iterator last); - - // Gets the arena on which this RepeatedPtrField stores its elements. - inline Arena* GetArena() const; - - // For internal use only. - // - // This is public due to it being called by generated code. - void InternalSwap(RepeatedPtrField* other) { - internal::RepeatedPtrFieldBase::InternalSwap(other); - } - - private: - // Note: RepeatedPtrField SHOULD NOT be subclassed by users. - class TypeHandler; - - // Implementations for ExtractSubrange(). The copying behavior must be - // included only if the type supports the necessary operations (e.g., - // MergeFrom()), so we must resolve this at compile time. ExtractSubrange() - // uses SFINAE to choose one of the below implementations. - void ExtractSubrangeInternal(int start, int num, Element** elements, - std::true_type); - void ExtractSubrangeInternal(int start, int num, Element** elements, - std::false_type); - - friend class Arena; - - template - friend struct WeakRepeatedPtrField; - - typedef void InternalArenaConstructable_; - -}; - // implementation ==================================================== template @@ -1697,1071 +993,14 @@ struct ElementCopier { // ------------------------------------------------------------------- -namespace internal { - -constexpr RepeatedPtrFieldBase::RepeatedPtrFieldBase() - : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {} - -inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(Arena* arena) - : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {} - -template -void RepeatedPtrFieldBase::Destroy() { - if (rep_ != nullptr && arena_ == nullptr) { - int n = rep_->allocated_size; - void* const* elements = rep_->elements; - for (int i = 0; i < n; i++) { - TypeHandler::Delete(cast(elements[i]), nullptr); - } -#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) - const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize; - ::operator delete(static_cast(rep_), size); -#else - ::operator delete(static_cast(rep_)); -#endif - } - rep_ = nullptr; -} - -template -inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { -#ifdef PROTOBUF_FORCE_COPY_IN_SWAP - if (GetArena() != nullptr && GetArena() == other->GetArena()) { -#else // PROTOBUF_FORCE_COPY_IN_SWAP - if (GetArena() == other->GetArena()) { -#endif // !PROTOBUF_FORCE_COPY_IN_SWAP - InternalSwap(other); - } else { - SwapFallback(other); - } -} - -template -void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { -#ifdef PROTOBUF_FORCE_COPY_IN_SWAP - GOOGLE_DCHECK(GetArena() == nullptr || other->GetArena() != GetArena()); -#else // PROTOBUF_FORCE_COPY_IN_SWAP - GOOGLE_DCHECK(other->GetArena() != GetArena()); -#endif // !PROTOBUF_FORCE_COPY_IN_SWAP - - // Copy semantics in this case. We try to improve efficiency by placing the - // temporary on |other|'s arena so that messages are copied twice rather than - // three times. - RepeatedPtrFieldBase temp(other->GetArena()); - temp.MergeFrom(*this); - this->Clear(); - this->MergeFrom(*other); - other->InternalSwap(&temp); - temp.Destroy(); // Frees rep_ if `other` had no arena. -} - -inline bool RepeatedPtrFieldBase::empty() const { return current_size_ == 0; } - -inline int RepeatedPtrFieldBase::size() const { return current_size_; } - -template -inline const typename TypeHandler::Type& RepeatedPtrFieldBase::Get( - int index) const { - GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, current_size_); - return *cast(rep_->elements[index]); -} - -template -inline const typename TypeHandler::Type& RepeatedPtrFieldBase::at( - int index) const { - GOOGLE_CHECK_GE(index, 0); - GOOGLE_CHECK_LT(index, current_size_); - return *cast(rep_->elements[index]); -} - -template -inline typename TypeHandler::Type& RepeatedPtrFieldBase::at(int index) { - GOOGLE_CHECK_GE(index, 0); - GOOGLE_CHECK_LT(index, current_size_); - return *cast(rep_->elements[index]); -} - -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::Mutable(int index) { - GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, current_size_); - return cast(rep_->elements[index]); -} - -template -inline void RepeatedPtrFieldBase::Delete(int index) { - GOOGLE_DCHECK_GE(index, 0); - GOOGLE_DCHECK_LT(index, current_size_); - TypeHandler::Delete(cast(rep_->elements[index]), arena_); -} - -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add( - typename TypeHandler::Type* prototype) { - if (rep_ != nullptr && current_size_ < rep_->allocated_size) { - return cast(rep_->elements[current_size_++]); - } - typename TypeHandler::Type* result = - TypeHandler::NewFromPrototype(prototype, arena_); - return reinterpret_cast( - AddOutOfLineHelper(result)); -} - -template ::type*> -inline void RepeatedPtrFieldBase::Add(typename TypeHandler::Type&& value) { - if (rep_ != nullptr && current_size_ < rep_->allocated_size) { - *cast(rep_->elements[current_size_++]) = std::move(value); - return; - } - if (!rep_ || rep_->allocated_size == total_size_) { - Reserve(total_size_ + 1); - } - ++rep_->allocated_size; - typename TypeHandler::Type* result = - TypeHandler::New(arena_, std::move(value)); - rep_->elements[current_size_++] = result; -} - -template -inline void RepeatedPtrFieldBase::RemoveLast() { - GOOGLE_DCHECK_GT(current_size_, 0); - TypeHandler::Clear(cast(rep_->elements[--current_size_])); -} - -template -void RepeatedPtrFieldBase::Clear() { - const int n = current_size_; - GOOGLE_DCHECK_GE(n, 0); - if (n > 0) { - void* const* elements = rep_->elements; - int i = 0; - do { - TypeHandler::Clear(cast(elements[i++])); - } while (i < n); - current_size_ = 0; - } -} - -// To avoid unnecessary code duplication and reduce binary size, we use a -// layered approach to implementing MergeFrom(). The toplevel method is -// templated, so we get a small thunk per concrete message type in the binary. -// This calls a shared implementation with most of the logic, passing a function -// pointer to another type-specific piece of code that calls the object-allocate -// and merge handlers. -template -inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { - GOOGLE_DCHECK_NE(&other, this); - if (other.current_size_ == 0) return; - MergeFromInternal(other, - &RepeatedPtrFieldBase::MergeFromInnerLoop); -} - -inline void RepeatedPtrFieldBase::MergeFromInternal( - const RepeatedPtrFieldBase& other, - void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)) { - // Note: wrapper has already guaranteed that other.rep_ != nullptr here. - int other_size = other.current_size_; - void** other_elements = other.rep_->elements; - void** new_elements = InternalExtend(other_size); - int allocated_elems = rep_->allocated_size - current_size_; - (this->*inner_loop)(new_elements, other_elements, other_size, - allocated_elems); - current_size_ += other_size; - if (rep_->allocated_size < current_size_) { - rep_->allocated_size = current_size_; - } -} - -// Merges other_elems to our_elems. -template -void RepeatedPtrFieldBase::MergeFromInnerLoop(void** our_elems, - void** other_elems, int length, - int already_allocated) { - if (already_allocated < length) { - Arena* arena = GetArena(); - typename TypeHandler::Type* elem_prototype = - reinterpret_cast(other_elems[0]); - for (int i = already_allocated; i < length; i++) { - // Allocate a new empty element that we'll merge into below - typename TypeHandler::Type* new_elem = - TypeHandler::NewFromPrototype(elem_prototype, arena); - our_elems[i] = new_elem; - } - } - // Main loop that does the actual merging - for (int i = 0; i < length; i++) { - // Already allocated: use existing element. - typename TypeHandler::Type* other_elem = - reinterpret_cast(other_elems[i]); - typename TypeHandler::Type* new_elem = - reinterpret_cast(our_elems[i]); - TypeHandler::Merge(*other_elem, new_elem); - } -} - -template -inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) { - if (&other == this) return; - RepeatedPtrFieldBase::Clear(); - RepeatedPtrFieldBase::MergeFrom(other); -} - -inline int RepeatedPtrFieldBase::Capacity() const { return total_size_; } - -inline void* const* RepeatedPtrFieldBase::raw_data() const { - return rep_ ? rep_->elements : nullptr; -} - -inline void** RepeatedPtrFieldBase::raw_mutable_data() const { - return rep_ ? const_cast(rep_->elements) : nullptr; -} - -template -inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { - // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this - // method entirely. - return reinterpret_cast(raw_mutable_data()); -} - -template -inline const typename TypeHandler::Type* const* RepeatedPtrFieldBase::data() - const { - // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this - // method entirely. - return reinterpret_cast(raw_data()); -} - -inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { - using std::swap; // enable ADL with fallback - swap(rep_->elements[index1], rep_->elements[index2]); -} - -template -inline size_t RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() const { - size_t allocated_bytes = static_cast(total_size_) * sizeof(void*); - if (rep_ != nullptr) { - for (int i = 0; i < rep_->allocated_size; ++i) { - allocated_bytes += - TypeHandler::SpaceUsedLong(*cast(rep_->elements[i])); - } - allocated_bytes += kRepHeaderSize; - } - return allocated_bytes; -} - -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { - if (rep_ != nullptr && current_size_ < rep_->allocated_size) { - return cast(rep_->elements[current_size_++]); - } else { - return nullptr; - } -} - -// AddAllocated version that implements arena-safe copying behavior. -template -void RepeatedPtrFieldBase::AddAllocatedInternal( - typename TypeHandler::Type* value, std::true_type) { - Arena* element_arena = - reinterpret_cast(TypeHandler::GetOwningArena(value)); - Arena* arena = GetArena(); - if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) { - // Fast path: underlying arena representation (tagged pointer) is equal to - // our arena pointer, and we can add to array without resizing it (at least - // one slot that is not allocated). - void** elems = rep_->elements; - if (current_size_ < rep_->allocated_size) { - // Make space at [current] by moving first allocated element to end of - // allocated list. - elems[rep_->allocated_size] = elems[current_size_]; - } - elems[current_size_] = value; - current_size_ = current_size_ + 1; - rep_->allocated_size = rep_->allocated_size + 1; - } else { - AddAllocatedSlowWithCopy(value, element_arena, arena); - } -} - -// Slowpath handles all cases, copying if necessary. -template -void RepeatedPtrFieldBase::AddAllocatedSlowWithCopy( - // Pass value_arena and my_arena to avoid duplicate virtual call (value) or - // load (mine). - typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) { - // Ensure that either the value is in the same arena, or if not, we do the - // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy - // it to our arena/heap (otherwise). - if (my_arena != nullptr && value_arena == nullptr) { - my_arena->Own(value); - } else if (my_arena != value_arena) { - typename TypeHandler::Type* new_value = - TypeHandler::NewFromPrototype(value, my_arena); - TypeHandler::Merge(*value, new_value); - TypeHandler::Delete(value, value_arena); - value = new_value; - } - - UnsafeArenaAddAllocated(value); -} - -// AddAllocated version that does not implement arena-safe copying behavior. -template -void RepeatedPtrFieldBase::AddAllocatedInternal( - typename TypeHandler::Type* value, std::false_type) { - if (rep_ && rep_->allocated_size < total_size_) { - // Fast path: underlying arena representation (tagged pointer) is equal to - // our arena pointer, and we can add to array without resizing it (at least - // one slot that is not allocated). - void** elems = rep_->elements; - if (current_size_ < rep_->allocated_size) { - // Make space at [current] by moving first allocated element to end of - // allocated list. - elems[rep_->allocated_size] = elems[current_size_]; - } - elems[current_size_] = value; - current_size_ = current_size_ + 1; - ++rep_->allocated_size; - } else { - UnsafeArenaAddAllocated(value); - } -} - -template -void RepeatedPtrFieldBase::UnsafeArenaAddAllocated( - typename TypeHandler::Type* value) { - // Make room for the new pointer. - if (!rep_ || current_size_ == total_size_) { - // The array is completely full with no cleared objects, so grow it. - Reserve(total_size_ + 1); - ++rep_->allocated_size; - } else if (rep_->allocated_size == total_size_) { - // There is no more space in the pointer array because it contains some - // cleared objects awaiting reuse. We don't want to grow the array in this - // case because otherwise a loop calling AddAllocated() followed by Clear() - // would leak memory. - TypeHandler::Delete(cast(rep_->elements[current_size_]), - arena_); - } else if (current_size_ < rep_->allocated_size) { - // We have some cleared objects. We don't care about their order, so we - // can just move the first one to the end to make space. - rep_->elements[rep_->allocated_size] = rep_->elements[current_size_]; - ++rep_->allocated_size; - } else { - // There are no cleared objects. - ++rep_->allocated_size; - } - - rep_->elements[current_size_++] = value; -} - -// ReleaseLast() for types that implement merge/copy behavior. -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal( - std::true_type) { - // First, release an element. - typename TypeHandler::Type* result = UnsafeArenaReleaseLast(); - // Now perform a copy if we're on an arena. - Arena* arena = GetArena(); - - typename TypeHandler::Type* new_result; -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - new_result = copy(result); - if (arena == nullptr) delete result; -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - new_result = (arena == nullptr) ? result : copy(result); -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - return new_result; -} - -// ReleaseLast() for types that *do not* implement merge/copy behavior -- this -// is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if we're on -// an arena, since the user really should implement the copy operation in this -// case. -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal( - std::false_type) { - GOOGLE_DCHECK(GetArena() == nullptr) - << "ReleaseLast() called on a RepeatedPtrField that is on an arena, " - << "with a type that does not implement MergeFrom. This is unsafe; " - << "please implement MergeFrom for your type."; - return UnsafeArenaReleaseLast(); -} - -template -inline typename TypeHandler::Type* -RepeatedPtrFieldBase::UnsafeArenaReleaseLast() { - GOOGLE_DCHECK_GT(current_size_, 0); - typename TypeHandler::Type* result = - cast(rep_->elements[--current_size_]); - --rep_->allocated_size; - if (current_size_ < rep_->allocated_size) { - // There are cleared elements on the end; replace the removed element - // with the last allocated element. - rep_->elements[current_size_] = rep_->elements[rep_->allocated_size]; - } - return result; -} - -inline int RepeatedPtrFieldBase::ClearedCount() const { - return rep_ ? (rep_->allocated_size - current_size_) : 0; -} - -template -inline void RepeatedPtrFieldBase::AddCleared( - typename TypeHandler::Type* value) { - GOOGLE_DCHECK(GetArena() == nullptr) - << "AddCleared() can only be used on a RepeatedPtrField not on an arena."; - GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr) - << "AddCleared() can only accept values not on an arena."; - if (!rep_ || rep_->allocated_size == total_size_) { - Reserve(total_size_ + 1); - } - rep_->elements[rep_->allocated_size++] = value; -} - -template -inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { - GOOGLE_DCHECK(GetArena() == nullptr) - << "ReleaseCleared() can only be used on a RepeatedPtrField not on " - << "an arena."; - GOOGLE_DCHECK(GetArena() == nullptr); - GOOGLE_DCHECK(rep_ != nullptr); - GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_); - return cast(rep_->elements[--rep_->allocated_size]); -} - -} // namespace internal - -// ------------------------------------------------------------------- - -template -class RepeatedPtrField::TypeHandler - : public internal::GenericTypeHandler {}; - -template <> -class RepeatedPtrField::TypeHandler - : public internal::StringTypeHandler {}; - -template -constexpr RepeatedPtrField::RepeatedPtrField() - : RepeatedPtrFieldBase() {} - -template -inline RepeatedPtrField::RepeatedPtrField(Arena* arena) - : RepeatedPtrFieldBase(arena) {} - -template -inline RepeatedPtrField::RepeatedPtrField( - const RepeatedPtrField& other) - : RepeatedPtrFieldBase() { - MergeFrom(other); -} - -template -template -inline RepeatedPtrField::RepeatedPtrField(Iter begin, Iter end) { - Add(begin, end); -} - -template -RepeatedPtrField::~RepeatedPtrField() { -#ifdef __cpp_if_constexpr - if constexpr (std::is_base_of::value) { -#else - if (std::is_base_of::value) { -#endif - if (NeedsDestroy()) DestroyProtos(); - } else { - Destroy(); - } -} - -template -inline RepeatedPtrField& RepeatedPtrField::operator=( - const RepeatedPtrField& other) { - if (this != &other) CopyFrom(other); - return *this; -} - -template -inline RepeatedPtrField::RepeatedPtrField( - RepeatedPtrField&& other) noexcept - : RepeatedPtrField() { -#ifdef PROTOBUF_FORCE_COPY_IN_MOVE - CopyFrom(other); -#else // PROTOBUF_FORCE_COPY_IN_MOVE - // We don't just call Swap(&other) here because it would perform 3 copies if - // other is on an arena. This field can't be on an arena because arena - // construction always uses the Arena* accepting constructor. - if (other.GetArena()) { - CopyFrom(other); - } else { - InternalSwap(&other); - } -#endif // !PROTOBUF_FORCE_COPY_IN_MOVE -} - -template -inline RepeatedPtrField& RepeatedPtrField::operator=( - RepeatedPtrField&& other) noexcept { - // We don't just call Swap(&other) here because it would perform 3 copies if - // the two fields are on different arenas. - if (this != &other) { - if (GetArena() != other.GetArena() -#ifdef PROTOBUF_FORCE_COPY_IN_MOVE - || GetArena() == nullptr -#endif // !PROTOBUF_FORCE_COPY_IN_MOVE - ) { - CopyFrom(other); - } else { - InternalSwap(&other); - } - } - return *this; -} - -template -inline bool RepeatedPtrField::empty() const { - return RepeatedPtrFieldBase::empty(); -} - -template -inline int RepeatedPtrField::size() const { - return RepeatedPtrFieldBase::size(); -} - -template -inline const Element& RepeatedPtrField::Get(int index) const { - return RepeatedPtrFieldBase::Get(index); -} - -template -inline const Element& RepeatedPtrField::at(int index) const { - return RepeatedPtrFieldBase::at(index); -} - -template -inline Element& RepeatedPtrField::at(int index) { - return RepeatedPtrFieldBase::at(index); -} - - -template -inline Element* RepeatedPtrField::Mutable(int index) { - return RepeatedPtrFieldBase::Mutable(index); -} - -template -inline Element* RepeatedPtrField::Add() { - return RepeatedPtrFieldBase::Add(); -} - -template -inline void RepeatedPtrField::Add(Element&& value) { - RepeatedPtrFieldBase::Add(std::move(value)); -} - -template -template -inline void RepeatedPtrField::Add(Iter begin, Iter end) { - int reserve = internal::CalculateReserve(begin, end); - if (reserve != -1) { - Reserve(size() + reserve); - } - for (; begin != end; ++begin) { - *Add() = *begin; - } -} - -template -inline void RepeatedPtrField::RemoveLast() { - RepeatedPtrFieldBase::RemoveLast(); -} - -template -inline void RepeatedPtrField::DeleteSubrange(int start, int num) { - GOOGLE_DCHECK_GE(start, 0); - GOOGLE_DCHECK_GE(num, 0); - GOOGLE_DCHECK_LE(start + num, size()); - for (int i = 0; i < num; ++i) { - RepeatedPtrFieldBase::Delete(start + i); - } - UnsafeArenaExtractSubrange(start, num, nullptr); -} - -template -inline void RepeatedPtrField::ExtractSubrange(int start, int num, - Element** elements) { - typename internal::TypeImplementsMergeBehavior< - typename TypeHandler::Type>::type t; - ExtractSubrangeInternal(start, num, elements, t); -} - -// ExtractSubrange() implementation for types that implement merge/copy -// behavior. -template -inline void RepeatedPtrField::ExtractSubrangeInternal( - int start, int num, Element** elements, std::true_type) { - GOOGLE_DCHECK_GE(start, 0); - GOOGLE_DCHECK_GE(num, 0); - GOOGLE_DCHECK_LE(start + num, size()); - - if (num == 0) return; - - GOOGLE_DCHECK_NE(elements, nullptr) - << "Releasing elements without transferring ownership is an unsafe " - "operation. Use UnsafeArenaExtractSubrange."; - if (elements == nullptr) { - CloseGap(start, num); - return; - } - - Arena* arena = GetArena(); -#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE - // Always copy. - for (int i = 0; i < num; ++i) { - elements[i] = copy( - RepeatedPtrFieldBase::Mutable(i + start)); - } - if (arena == nullptr) { - for (int i = 0; i < num; ++i) { - delete RepeatedPtrFieldBase::Mutable(i + start); - } - } -#else // PROTOBUF_FORCE_COPY_IN_RELEASE - // If we're on an arena, we perform a copy for each element so that the - // returned elements are heap-allocated. Otherwise, just forward it. - if (arena != nullptr) { - for (int i = 0; i < num; ++i) { - elements[i] = copy( - RepeatedPtrFieldBase::Mutable(i + start)); - } - } else { - for (int i = 0; i < num; ++i) { - elements[i] = RepeatedPtrFieldBase::Mutable(i + start); - } - } -#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE - CloseGap(start, num); -} - -// ExtractSubrange() implementation for types that do not implement merge/copy -// behavior. -template -inline void RepeatedPtrField::ExtractSubrangeInternal( - int start, int num, Element** elements, std::false_type) { - // This case is identical to UnsafeArenaExtractSubrange(). However, since - // ExtractSubrange() must return heap-allocated objects by contract, and we - // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that - // we are not on an arena. - GOOGLE_DCHECK(GetArena() == nullptr) - << "ExtractSubrange() when arena is non-nullptr is only supported when " - << "the Element type supplies a MergeFrom() operation to make copies."; - UnsafeArenaExtractSubrange(start, num, elements); -} - -template -inline void RepeatedPtrField::UnsafeArenaExtractSubrange( - int start, int num, Element** elements) { - GOOGLE_DCHECK_GE(start, 0); - GOOGLE_DCHECK_GE(num, 0); - GOOGLE_DCHECK_LE(start + num, size()); - - if (num > 0) { - // Save the values of the removed elements if requested. - if (elements != nullptr) { - for (int i = 0; i < num; ++i) { - elements[i] = RepeatedPtrFieldBase::Mutable(i + start); - } - } - CloseGap(start, num); - } -} - -template -inline void RepeatedPtrField::Clear() { - RepeatedPtrFieldBase::Clear(); -} - -template -inline void RepeatedPtrField::MergeFrom( - const RepeatedPtrField& other) { - RepeatedPtrFieldBase::MergeFrom(other); -} - -template -inline void RepeatedPtrField::CopyFrom(const RepeatedPtrField& other) { - RepeatedPtrFieldBase::CopyFrom(other); -} - -template -template -inline void RepeatedPtrField::Assign(Iter begin, Iter end) { - Clear(); - Add(begin, end); -} - -template -inline typename RepeatedPtrField::iterator -RepeatedPtrField::erase(const_iterator position) { - return erase(position, position + 1); -} - -template -inline typename RepeatedPtrField::iterator -RepeatedPtrField::erase(const_iterator first, const_iterator last) { - size_type pos_offset = std::distance(cbegin(), first); - size_type last_offset = std::distance(cbegin(), last); - DeleteSubrange(pos_offset, last_offset - pos_offset); - return begin() + pos_offset; -} - -template -inline Element** RepeatedPtrField::mutable_data() { - return RepeatedPtrFieldBase::mutable_data(); -} - -template -inline const Element* const* RepeatedPtrField::data() const { - return RepeatedPtrFieldBase::data(); -} - -template -inline void RepeatedPtrField::Swap(RepeatedPtrField* other) { - if (this == other) return; - RepeatedPtrFieldBase::Swap(other); -} - -template -inline void RepeatedPtrField::UnsafeArenaSwap( - RepeatedPtrField* other) { - if (this == other) return; - RepeatedPtrFieldBase::InternalSwap(other); -} - -template -inline void RepeatedPtrField::SwapElements(int index1, int index2) { - RepeatedPtrFieldBase::SwapElements(index1, index2); -} - -template -inline Arena* RepeatedPtrField::GetArena() const { - return RepeatedPtrFieldBase::GetArena(); -} - -template -inline size_t RepeatedPtrField::SpaceUsedExcludingSelfLong() const { - return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong(); -} - -template -inline void RepeatedPtrField::AddAllocated(Element* value) { - RepeatedPtrFieldBase::AddAllocated(value); -} - -template -inline void RepeatedPtrField::UnsafeArenaAddAllocated(Element* value) { - RepeatedPtrFieldBase::UnsafeArenaAddAllocated(value); -} - -template -inline Element* RepeatedPtrField::ReleaseLast() { - return RepeatedPtrFieldBase::ReleaseLast(); -} - -template -inline Element* RepeatedPtrField::UnsafeArenaReleaseLast() { - return RepeatedPtrFieldBase::UnsafeArenaReleaseLast(); -} - -template -inline int RepeatedPtrField::ClearedCount() const { - return RepeatedPtrFieldBase::ClearedCount(); -} - -#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES -template -inline void RepeatedPtrField::AddCleared(Element* value) { - return RepeatedPtrFieldBase::AddCleared(value); -} - -template -inline Element* RepeatedPtrField::ReleaseCleared() { - return RepeatedPtrFieldBase::ReleaseCleared(); -} -#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES - -template -inline void RepeatedPtrField::Reserve(int new_size) { - return RepeatedPtrFieldBase::Reserve(new_size); -} - -template -inline int RepeatedPtrField::Capacity() const { - return RepeatedPtrFieldBase::Capacity(); -} - -// ------------------------------------------------------------------- - -namespace internal { - -// STL-like iterator implementation for RepeatedPtrField. You should not -// refer to this class directly; use RepeatedPtrField::iterator instead. -// -// The iterator for RepeatedPtrField, RepeatedPtrIterator, is -// very similar to iterator_ptr in util/gtl/iterator_adaptors.h, -// but adds random-access operators and is modified to wrap a void** base -// iterator (since RepeatedPtrField stores its array as a void* array and -// casting void** to T** would violate C++ aliasing rules). -// -// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin -// (jyasskin@google.com). -template -class RepeatedPtrIterator { - public: - using iterator = RepeatedPtrIterator; - using iterator_category = std::random_access_iterator_tag; - using value_type = typename std::remove_const::type; - using difference_type = std::ptrdiff_t; - using pointer = Element*; - using reference = Element&; - - RepeatedPtrIterator() : it_(nullptr) {} - explicit RepeatedPtrIterator(void* const* it) : it_(it) {} - - // Allow "upcasting" from RepeatedPtrIterator to - // RepeatedPtrIterator. - template - RepeatedPtrIterator(const RepeatedPtrIterator& other) - : it_(other.it_) { - // Force a compiler error if the other type is not convertible to ours. - if (false) { - implicit_cast(static_cast(nullptr)); - } - } - - // dereferenceable - reference operator*() const { return *reinterpret_cast(*it_); } - pointer operator->() const { return &(operator*()); } - - // {inc,dec}rementable - iterator& operator++() { - ++it_; - return *this; - } - iterator operator++(int) { return iterator(it_++); } - iterator& operator--() { - --it_; - return *this; - } - iterator operator--(int) { return iterator(it_--); } - - // equality_comparable - bool operator==(const iterator& x) const { return it_ == x.it_; } - bool operator!=(const iterator& x) const { return it_ != x.it_; } - - // less_than_comparable - bool operator<(const iterator& x) const { return it_ < x.it_; } - bool operator<=(const iterator& x) const { return it_ <= x.it_; } - bool operator>(const iterator& x) const { return it_ > x.it_; } - bool operator>=(const iterator& x) const { return it_ >= x.it_; } - - // addable, subtractable - iterator& operator+=(difference_type d) { - it_ += d; - return *this; - } - friend iterator operator+(iterator it, const difference_type d) { - it += d; - return it; - } - friend iterator operator+(const difference_type d, iterator it) { - it += d; - return it; - } - iterator& operator-=(difference_type d) { - it_ -= d; - return *this; - } - friend iterator operator-(iterator it, difference_type d) { - it -= d; - return it; - } - - // indexable - reference operator[](difference_type d) const { return *(*this + d); } - - // random access iterator - difference_type operator-(const iterator& x) const { return it_ - x.it_; } - - private: - template - friend class RepeatedPtrIterator; - - // The internal iterator. - void* const* it_; -}; - -// Provide an iterator that operates on pointers to the underlying objects -// rather than the objects themselves as RepeatedPtrIterator does. -// Consider using this when working with stl algorithms that change -// the array. -// The VoidPtr template parameter holds the type-agnostic pointer value -// referenced by the iterator. It should either be "void *" for a mutable -// iterator, or "const void* const" for a constant iterator. -template -class RepeatedPtrOverPtrsIterator { - public: - using iterator = RepeatedPtrOverPtrsIterator; - using iterator_category = std::random_access_iterator_tag; - using value_type = typename std::remove_const::type; - using difference_type = std::ptrdiff_t; - using pointer = Element*; - using reference = Element&; - - RepeatedPtrOverPtrsIterator() : it_(nullptr) {} - explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {} - - // dereferenceable - reference operator*() const { return *reinterpret_cast(it_); } - pointer operator->() const { return &(operator*()); } - - // {inc,dec}rementable - iterator& operator++() { - ++it_; - return *this; - } - iterator operator++(int) { return iterator(it_++); } - iterator& operator--() { - --it_; - return *this; - } - iterator operator--(int) { return iterator(it_--); } - - // equality_comparable - bool operator==(const iterator& x) const { return it_ == x.it_; } - bool operator!=(const iterator& x) const { return it_ != x.it_; } - - // less_than_comparable - bool operator<(const iterator& x) const { return it_ < x.it_; } - bool operator<=(const iterator& x) const { return it_ <= x.it_; } - bool operator>(const iterator& x) const { return it_ > x.it_; } - bool operator>=(const iterator& x) const { return it_ >= x.it_; } - - // addable, subtractable - iterator& operator+=(difference_type d) { - it_ += d; - return *this; - } - friend iterator operator+(iterator it, difference_type d) { - it += d; - return it; - } - friend iterator operator+(difference_type d, iterator it) { - it += d; - return it; - } - iterator& operator-=(difference_type d) { - it_ -= d; - return *this; - } - friend iterator operator-(iterator it, difference_type d) { - it -= d; - return it; - } - - // indexable - reference operator[](difference_type d) const { return *(*this + d); } - - // random access iterator - difference_type operator-(const iterator& x) const { return it_ - x.it_; } - - private: - template - friend class RepeatedPtrIterator; - - // The internal iterator. - VoidPtr* it_; -}; - -void RepeatedPtrFieldBase::InternalSwap(RepeatedPtrFieldBase* other) { - GOOGLE_DCHECK(this != other); - - // Swap all fields at once. - static_assert(std::is_standard_layout::value, - "offsetof() requires standard layout before c++17"); - internal::memswaprep_) - - offsetof(RepeatedPtrFieldBase, arena_)>( - reinterpret_cast(this) + offsetof(RepeatedPtrFieldBase, arena_), - reinterpret_cast(other) + offsetof(RepeatedPtrFieldBase, arena_)); -} - -} // namespace internal - -template -inline typename RepeatedPtrField::iterator -RepeatedPtrField::begin() { - return iterator(raw_data()); -} -template -inline typename RepeatedPtrField::const_iterator -RepeatedPtrField::begin() const { - return iterator(raw_data()); -} -template -inline typename RepeatedPtrField::const_iterator -RepeatedPtrField::cbegin() const { - return begin(); -} -template -inline typename RepeatedPtrField::iterator -RepeatedPtrField::end() { - return iterator(raw_data() + size()); -} -template -inline typename RepeatedPtrField::const_iterator -RepeatedPtrField::end() const { - return iterator(raw_data() + size()); -} -template -inline typename RepeatedPtrField::const_iterator -RepeatedPtrField::cend() const { - return end(); -} - -template -inline typename RepeatedPtrField::pointer_iterator -RepeatedPtrField::pointer_begin() { - return pointer_iterator(raw_mutable_data()); -} -template -inline typename RepeatedPtrField::const_pointer_iterator -RepeatedPtrField::pointer_begin() const { - return const_pointer_iterator(const_cast(raw_data())); -} -template -inline typename RepeatedPtrField::pointer_iterator -RepeatedPtrField::pointer_end() { - return pointer_iterator(raw_mutable_data() + size()); -} -template -inline typename RepeatedPtrField::const_pointer_iterator -RepeatedPtrField::pointer_end() const { - return const_pointer_iterator( - const_cast(raw_data() + size())); -} - -// Iterators and helper functions that follow the spirit of the STL -// std::back_insert_iterator and std::back_inserter but are tailor-made -// for RepeatedField and RepeatedPtrField. Typical usage would be: -// -// std::copy(some_sequence.begin(), some_sequence.end(), -// RepeatedFieldBackInserter(proto.mutable_sequence())); -// -// Ported by johannes from util/gtl/proto-array-iterators.h +// Iterators and helper functions that follow the spirit of the STL +// std::back_insert_iterator and std::back_inserter but are tailor-made +// for RepeatedField and RepeatedPtrField. Typical usage would be: +// +// std::copy(some_sequence.begin(), some_sequence.end(), +// RepeatedFieldBackInserter(proto.mutable_sequence())); +// +// Ported by johannes from util/gtl/proto-array-iterators.h namespace internal { // A back inserter for RepeatedField objects. @@ -2791,104 +1030,6 @@ class RepeatedFieldBackInsertIterator { RepeatedField* field_; }; -// A back inserter for RepeatedPtrField objects. -template -class RepeatedPtrFieldBackInsertIterator { - public: - using iterator_category = std::output_iterator_tag; - using value_type = T; - using pointer = void; - using reference = void; - using difference_type = std::ptrdiff_t; - - RepeatedPtrFieldBackInsertIterator(RepeatedPtrField* const mutable_field) - : field_(mutable_field) {} - RepeatedPtrFieldBackInsertIterator& operator=(const T& value) { - *field_->Add() = value; - return *this; - } - RepeatedPtrFieldBackInsertIterator& operator=( - const T* const ptr_to_value) { - *field_->Add() = *ptr_to_value; - return *this; - } - RepeatedPtrFieldBackInsertIterator& operator=(T&& value) { - *field_->Add() = std::move(value); - return *this; - } - RepeatedPtrFieldBackInsertIterator& operator*() { return *this; } - RepeatedPtrFieldBackInsertIterator& operator++() { return *this; } - RepeatedPtrFieldBackInsertIterator& operator++(int /* unused */) { - return *this; - } - - private: - RepeatedPtrField* field_; -}; - -// A back inserter for RepeatedPtrFields that inserts by transferring ownership -// of a pointer. -template -class AllocatedRepeatedPtrFieldBackInsertIterator { - public: - using iterator_category = std::output_iterator_tag; - using value_type = T; - using pointer = void; - using reference = void; - using difference_type = std::ptrdiff_t; - - explicit AllocatedRepeatedPtrFieldBackInsertIterator( - RepeatedPtrField* const mutable_field) - : field_(mutable_field) {} - AllocatedRepeatedPtrFieldBackInsertIterator& operator=( - T* const ptr_to_value) { - field_->AddAllocated(ptr_to_value); - return *this; - } - AllocatedRepeatedPtrFieldBackInsertIterator& operator*() { return *this; } - AllocatedRepeatedPtrFieldBackInsertIterator& operator++() { return *this; } - AllocatedRepeatedPtrFieldBackInsertIterator& operator++(int /* unused */) { - return *this; - } - - private: - RepeatedPtrField* field_; -}; - -// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one -// uses the UnsafeArenaAddAllocated instead. -template -class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator { - public: - using iterator_category = std::output_iterator_tag; - using value_type = T; - using pointer = void; - using reference = void; - using difference_type = std::ptrdiff_t; - - explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( - RepeatedPtrField* const mutable_field) - : field_(mutable_field) {} - UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator=( - T const* const ptr_to_value) { - field_->UnsafeArenaAddAllocated(const_cast(ptr_to_value)); - return *this; - } - UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator*() { - return *this; - } - UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++() { - return *this; - } - UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++( - int /* unused */) { - return *this; - } - - private: - RepeatedPtrField* field_; -}; - } // namespace internal // Provides a back insert iterator for RepeatedField instances, @@ -2899,53 +1040,6 @@ internal::RepeatedFieldBackInsertIterator RepeatedFieldBackInserter( return internal::RepeatedFieldBackInsertIterator(mutable_field); } -// Provides a back insert iterator for RepeatedPtrField instances, -// similar to std::back_inserter(). -template -internal::RepeatedPtrFieldBackInsertIterator RepeatedPtrFieldBackInserter( - RepeatedPtrField* const mutable_field) { - return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); -} - -// Special back insert iterator for RepeatedPtrField instances, just in -// case someone wants to write generic template code that can access both -// RepeatedFields and RepeatedPtrFields using a common name. -template -internal::RepeatedPtrFieldBackInsertIterator RepeatedFieldBackInserter( - RepeatedPtrField* const mutable_field) { - return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); -} - -// Provides a back insert iterator for RepeatedPtrField instances -// similar to std::back_inserter() which transfers the ownership while -// copying elements. -template -internal::AllocatedRepeatedPtrFieldBackInsertIterator -AllocatedRepeatedPtrFieldBackInserter( - RepeatedPtrField* const mutable_field) { - return internal::AllocatedRepeatedPtrFieldBackInsertIterator( - mutable_field); -} - -// Similar to AllocatedRepeatedPtrFieldBackInserter, using -// UnsafeArenaAddAllocated instead of AddAllocated. -// This is slightly faster if that matters. It is also useful in legacy code -// that uses temporary ownership to avoid copies. Example: -// RepeatedPtrField temp_field; -// temp_field.UnsafeArenaAddAllocated(new T); -// ... // Do something with temp_field -// temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr); -// If you put temp_field on the arena this fails, because the ownership -// transfers to the arena at the "AddAllocated" call and is not released anymore -// causing a double delete. Using UnsafeArenaAddAllocated prevents this. -template -internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator -UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( - RepeatedPtrField* const mutable_field) { - return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( - mutable_field); -} - // Extern declarations of common instantiations to reduce library bloat. extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; @@ -2954,8 +1048,6 @@ extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE RepeatedField; -extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE - RepeatedPtrField; } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc new file mode 100644 index 000000000000..0f0b3e2af4a5 --- /dev/null +++ b/src/google/protobuf/repeated_ptr_field.cc @@ -0,0 +1,157 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +#include + +#include +#include +#include + +#include + +namespace google { +namespace protobuf { + +namespace internal { + +void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { + int new_size = current_size_ + extend_amount; + if (total_size_ >= new_size) { + // N.B.: rep_ is non-nullptr because extend_amount is always > 0, hence + // total_size must be non-zero since it is lower-bounded by new_size. + return &rep_->elements[current_size_]; + } + Rep* old_rep = rep_; + Arena* arena = GetArena(); + new_size = std::max(internal::kRepeatedFieldLowerClampLimit, + std::max(total_size_ * 2, new_size)); + GOOGLE_CHECK_LE(static_cast(new_size), + static_cast( + (std::numeric_limits::max() - kRepHeaderSize) / + sizeof(old_rep->elements[0]))) + << "Requested size is too large to fit into size_t."; + size_t bytes = kRepHeaderSize + sizeof(old_rep->elements[0]) * new_size; + if (arena == nullptr) { + rep_ = reinterpret_cast(::operator new(bytes)); + } else { + rep_ = reinterpret_cast(Arena::CreateArray(arena, bytes)); + } +#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) + const int old_total_size = total_size_; +#endif + total_size_ = new_size; + if (old_rep && old_rep->allocated_size > 0) { + memcpy(rep_->elements, old_rep->elements, + old_rep->allocated_size * sizeof(rep_->elements[0])); + rep_->allocated_size = old_rep->allocated_size; + } else { + rep_->allocated_size = 0; + } + if (arena == nullptr) { +#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) + const size_t old_size = + old_total_size * sizeof(rep_->elements[0]) + kRepHeaderSize; + ::operator delete(static_cast(old_rep), old_size); +#else + ::operator delete(static_cast(old_rep)); +#endif + } + return &rep_->elements[current_size_]; +} + +void RepeatedPtrFieldBase::Reserve(int new_size) { + if (new_size > current_size_) { + InternalExtend(new_size - current_size_); + } +} + +void RepeatedPtrFieldBase::DestroyProtos() { + GOOGLE_DCHECK(rep_); + GOOGLE_DCHECK(arena_ == nullptr); + int n = rep_->allocated_size; + void* const* elements = rep_->elements; + for (int i = 0; i < n; i++) { + delete static_cast(elements[i]); + } +#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) + const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize; + ::operator delete(static_cast(rep_), size); + rep_ = nullptr; +#else + ::operator delete(static_cast(rep_)); + rep_ = nullptr; +#endif +} + +void* RepeatedPtrFieldBase::AddOutOfLineHelper(void* obj) { + if (!rep_ || rep_->allocated_size == total_size_) { + InternalExtend(1); // Equivalent to "Reserve(total_size_ + 1)" + } + ++rep_->allocated_size; + rep_->elements[current_size_++] = obj; + return obj; +} + +void RepeatedPtrFieldBase::CloseGap(int start, int num) { + if (rep_ == nullptr) return; + // Close up a gap of "num" elements starting at offset "start". + for (int i = start + num; i < rep_->allocated_size; ++i) + rep_->elements[i - num] = rep_->elements[i]; + current_size_ -= num; + rep_->allocated_size -= num; +} + +MessageLite* RepeatedPtrFieldBase::AddWeak(const MessageLite* prototype) { + if (rep_ != nullptr && current_size_ < rep_->allocated_size) { + return reinterpret_cast(rep_->elements[current_size_++]); + } + if (!rep_ || rep_->allocated_size == total_size_) { + Reserve(total_size_ + 1); + } + ++rep_->allocated_size; + MessageLite* result = prototype + ? prototype->New(arena_) + : Arena::CreateMessage(arena_); + rep_->elements[current_size_++] = result; + return result; +} + +} // namespace internal + +} // namespace protobuf +} // namespace google + +#include diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h new file mode 100644 index 000000000000..7d635e3bb50f --- /dev/null +++ b/src/google/protobuf/repeated_ptr_field.h @@ -0,0 +1,2014 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (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. +// +// RepeatedField and RepeatedPtrField are used by generated protocol message +// classes to manipulate repeated fields. These classes are very similar to +// STL's vector, but include a number of optimizations found to be useful +// specifically in the case of Protocol Buffers. RepeatedPtrField is +// particularly different from STL vector as it manages ownership of the +// pointers that it contains. +// +// Typically, clients should not need to access RepeatedField objects directly, +// but should instead use the accessor functions generated automatically by the +// protocol compiler. +// +// This header covers RepeatedPtrField. + +#ifndef GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__ +#define GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__ + +#include +#ifdef _MSC_VER +// This is required for min/max on VS2013 only. +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +// Must be included last. +#include + +#ifdef SWIG +#error "You cannot SWIG proto headers" +#endif + +namespace google { +namespace protobuf { + +class Message; +class Reflection; + +template +struct WeakRepeatedPtrField; + +namespace internal { + +class MergePartialFromCodedStreamHelper; +class SwapFieldHelper; + + +} // namespace internal + +namespace internal { +template +class RepeatedPtrIterator; +template +class RepeatedPtrOverPtrsIterator; +} // namespace internal + +namespace internal { + +// type-traits helper for RepeatedPtrFieldBase: we only want to invoke +// arena-related "copy if on different arena" behavior if the necessary methods +// exist on the contained type. In particular, we rely on MergeFrom() existing +// as a general proxy for the fact that a copy will work, and we also provide a +// specific override for std::string*. +template +struct TypeImplementsMergeBehaviorProbeForMergeFrom { + typedef char HasMerge; + typedef long HasNoMerge; + + // We accept either of: + // - void MergeFrom(const T& other) + // - bool MergeFrom(const T& other) + // + // We mangle these names a bit to avoid compatibility issues in 'unclean' + // include environments that may have, e.g., "#define test ..." (yes, this + // exists). + template + struct CheckType; + template + static HasMerge Check(CheckType*); + template + static HasMerge Check(CheckType*); + template + static HasNoMerge Check(...); + + // Resolves to either std::true_type or std::false_type. + typedef std::integral_constant(0)) == sizeof(HasMerge))> + type; +}; + +template +struct TypeImplementsMergeBehavior + : TypeImplementsMergeBehaviorProbeForMergeFrom {}; + + +template <> +struct TypeImplementsMergeBehavior { + typedef std::true_type type; +}; + +template +struct IsMovable + : std::integral_constant::value && + std::is_move_assignable::value> {}; + +// This is the common base class for RepeatedPtrFields. It deals only in void* +// pointers. Users should not use this interface directly. +// +// The methods of this interface correspond to the methods of RepeatedPtrField, +// but may have a template argument called TypeHandler. Its signature is: +// class TypeHandler { +// public: +// typedef MyType Type; +// static Type* New(); +// static Type* NewFromPrototype(const Type* prototype, +// Arena* arena); +// static void Delete(Type*); +// static void Clear(Type*); +// static void Merge(const Type& from, Type* to); +// +// // Only needs to be implemented if SpaceUsedExcludingSelf() is called. +// static int SpaceUsedLong(const Type&); +// }; +class PROTOBUF_EXPORT RepeatedPtrFieldBase { + protected: + constexpr RepeatedPtrFieldBase(); + explicit RepeatedPtrFieldBase(Arena* arena); + ~RepeatedPtrFieldBase() { +#ifndef NDEBUG + // Try to trigger segfault / asan failure in non-opt builds. If arena_ + // lifetime has ended before the destructor. + if (arena_) (void)arena_->SpaceAllocated(); +#endif + } + + // Must be called from destructor. + template + void Destroy(); + bool NeedsDestroy() const { return rep_ != nullptr && arena_ == nullptr; } + void DestroyProtos(); + + bool empty() const; + int size() const; + + template + const typename TypeHandler::Type& at(int index) const; + template + typename TypeHandler::Type& at(int index); + + template + typename TypeHandler::Type* Mutable(int index); + template + void Delete(int index); + template + typename TypeHandler::Type* Add( + typename TypeHandler::Type* prototype = nullptr); + + public: + // The next few methods are public so that they can be called from generated + // code when implicit weak fields are used, but they should never be called by + // application code. + + template + const typename TypeHandler::Type& Get(int index) const; + + // Creates and adds an element using the given prototype, without introducing + // a link-time dependency on the concrete message type. This method is used to + // implement implicit weak fields. The prototype may be nullptr, in which case + // an ImplicitWeakMessage will be used as a placeholder. + MessageLite* AddWeak(const MessageLite* prototype); + + template + void Clear(); + + template + void MergeFrom(const RepeatedPtrFieldBase& other); + + inline void InternalSwap(RepeatedPtrFieldBase*); + + protected: + template < + typename TypeHandler, + typename std::enable_if::type* = nullptr> + void Add(typename TypeHandler::Type&& value); + + template + void RemoveLast(); + template + void CopyFrom(const RepeatedPtrFieldBase& other); + + void CloseGap(int start, int num); + + void Reserve(int new_size); + + int Capacity() const; + + template + static inline typename TypeHandler::Type* copy( + typename TypeHandler::Type* value) { + auto* new_value = TypeHandler::NewFromPrototype(value, nullptr); + TypeHandler::Merge(*value, new_value); + return new_value; + } + + // Used for constructing iterators. + void* const* raw_data() const; + void** raw_mutable_data() const; + + template + typename TypeHandler::Type** mutable_data(); + template + const typename TypeHandler::Type* const* data() const; + + template + PROTOBUF_NDEBUG_INLINE void Swap(RepeatedPtrFieldBase* other); + + void SwapElements(int index1, int index2); + + template + size_t SpaceUsedExcludingSelfLong() const; + + // Advanced memory management -------------------------------------- + + // Like Add(), but if there are no cleared objects to use, returns nullptr. + template + typename TypeHandler::Type* AddFromCleared(); + + template + void AddAllocated(typename TypeHandler::Type* value) { + typename TypeImplementsMergeBehavior::type t; + AddAllocatedInternal(value, t); + } + + template + void UnsafeArenaAddAllocated(typename TypeHandler::Type* value); + + template + PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() { + typename TypeImplementsMergeBehavior::type t; + return ReleaseLastInternal(t); + } + + // Releases last element and returns it, but does not do out-of-arena copy. + // And just returns the raw pointer to the contained element in the arena. + template + typename TypeHandler::Type* UnsafeArenaReleaseLast(); + + int ClearedCount() const; + template + void AddCleared(typename TypeHandler::Type* value); + template + PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared(); + + template + void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type); + template + void AddAllocatedInternal(typename TypeHandler::Type* value, std::false_type); + + template + PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy( + typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena); + template + PROTOBUF_NOINLINE void AddAllocatedSlowWithoutCopy( + typename TypeHandler::Type* value); + + template + typename TypeHandler::Type* ReleaseLastInternal(std::true_type); + template + typename TypeHandler::Type* ReleaseLastInternal(std::false_type); + + template + PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other); + + inline Arena* GetArena() const { return arena_; } + + private: + static constexpr int kInitialSize = 0; + // A few notes on internal representation: + // + // We use an indirected approach, with struct Rep, to keep + // sizeof(RepeatedPtrFieldBase) equivalent to what it was before arena support + // was added, namely, 3 8-byte machine words on x86-64. An instance of Rep is + // allocated only when the repeated field is non-empty, and it is a + // dynamically-sized struct (the header is directly followed by elements[]). + // We place arena_ and current_size_ directly in the object to avoid cache + // misses due to the indirection, because these fields are checked frequently. + // Placing all fields directly in the RepeatedPtrFieldBase instance costs + // significant performance for memory-sensitive workloads. + Arena* arena_; + int current_size_; + int total_size_; + struct Rep { + int allocated_size; + // Here we declare a huge array as a way of approximating C's "flexible + // array member" feature without relying on undefined behavior. + void* elements[(std::numeric_limits::max() - 2 * sizeof(int)) / + sizeof(void*)]; + }; + static constexpr size_t kRepHeaderSize = offsetof(Rep, elements); + Rep* rep_; + + template + static inline typename TypeHandler::Type* cast(void* element) { + return reinterpret_cast(element); + } + template + static inline const typename TypeHandler::Type* cast(const void* element) { + return reinterpret_cast(element); + } + + // Non-templated inner function to avoid code duplication. Takes a function + // pointer to the type-specific (templated) inner allocate/merge loop. + void MergeFromInternal(const RepeatedPtrFieldBase& other, + void (RepeatedPtrFieldBase::*inner_loop)(void**, + void**, int, + int)); + + template + PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems, + void** other_elems, int length, + int already_allocated); + + // Internal helper: extend array space if necessary to contain |extend_amount| + // more elements, and return a pointer to the element immediately following + // the old list of elements. This interface factors out common behavior from + // Reserve() and MergeFrom() to reduce code size. |extend_amount| must be > 0. + void** InternalExtend(int extend_amount); + + // Internal helper for Add: add "obj" as the next element in the + // array, including potentially resizing the array with Reserve if + // needed + void* AddOutOfLineHelper(void* obj); + + // The reflection implementation needs to call protected methods directly, + // reinterpreting pointers as being to Message instead of a specific Message + // subclass. + friend class ::PROTOBUF_NAMESPACE_ID::Reflection; + friend class ::PROTOBUF_NAMESPACE_ID::internal::SwapFieldHelper; + + // ExtensionSet stores repeated message extensions as + // RepeatedPtrField, but non-lite ExtensionSets need to implement + // SpaceUsedLong(), and thus need to call SpaceUsedExcludingSelfLong() + // reinterpreting MessageLite as Message. ExtensionSet also needs to make use + // of AddFromCleared(), which is not part of the public interface. + friend class ExtensionSet; + + // The MapFieldBase implementation needs to call protected methods directly, + // reinterpreting pointers as being to Message instead of a specific Message + // subclass. + friend class MapFieldBase; + friend class MapFieldBaseStub; + + // The table-driven MergePartialFromCodedStream implementation needs to + // operate on RepeatedPtrField. + friend class MergePartialFromCodedStreamHelper; + friend class AccessorHelper; + template + friend struct google::protobuf::WeakRepeatedPtrField; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrFieldBase); +}; + +template +class GenericTypeHandler { + public: + typedef GenericType Type; + using Movable = IsMovable; + + static inline GenericType* New(Arena* arena) { + return Arena::CreateMaybeMessage(arena); + } + static inline GenericType* New(Arena* arena, GenericType&& value) { + return Arena::Create(arena, std::move(value)); + } + static inline GenericType* NewFromPrototype(const GenericType* prototype, + Arena* arena = nullptr); + static inline void Delete(GenericType* value, Arena* arena) { + if (arena == nullptr) { + delete value; + } + } + static inline Arena* GetOwningArena(GenericType* value) { + return Arena::GetOwningArena(value); + } + + static inline void Clear(GenericType* value) { value->Clear(); } + PROTOBUF_NOINLINE + static void Merge(const GenericType& from, GenericType* to); + static inline size_t SpaceUsedLong(const GenericType& value) { + return value.SpaceUsedLong(); + } +}; + +template +GenericType* GenericTypeHandler::NewFromPrototype( + const GenericType* /* prototype */, Arena* arena) { + return New(arena); +} +template +void GenericTypeHandler::Merge(const GenericType& from, + GenericType* to) { + to->MergeFrom(from); +} + +// NewFromPrototype() and Merge() are not defined inline here, as we will need +// to do a virtual function dispatch anyways to go from Message* to call +// New/Merge. +template <> +MessageLite* GenericTypeHandler::NewFromPrototype( + const MessageLite* prototype, Arena* arena); +template <> +inline Arena* GenericTypeHandler::GetOwningArena( + MessageLite* value) { + return value->GetOwningArena(); +} +template <> +void GenericTypeHandler::Merge(const MessageLite& from, + MessageLite* to); +template <> +inline void GenericTypeHandler::Clear(std::string* value) { + value->clear(); +} +template <> +void GenericTypeHandler::Merge(const std::string& from, + std::string* to); + +// Message specialization bodies defined in message.cc. This split is necessary +// to allow proto2-lite (which includes this header) to be independent of +// Message. +template <> +PROTOBUF_EXPORT Message* GenericTypeHandler::NewFromPrototype( + const Message* prototype, Arena* arena); +template <> +PROTOBUF_EXPORT Arena* GenericTypeHandler::GetOwningArena( + Message* value); + +class StringTypeHandler { + public: + typedef std::string Type; + using Movable = IsMovable; + + static inline std::string* New(Arena* arena) { + return Arena::Create(arena); + } + static inline std::string* New(Arena* arena, std::string&& value) { + return Arena::Create(arena, std::move(value)); + } + static inline std::string* NewFromPrototype(const std::string*, + Arena* arena) { + return New(arena); + } + static inline Arena* GetOwningArena(std::string*) { return nullptr; } + static inline void Delete(std::string* value, Arena* arena) { + if (arena == nullptr) { + delete value; + } + } + static inline void Clear(std::string* value) { value->clear(); } + static inline void Merge(const std::string& from, std::string* to) { + *to = from; + } + static size_t SpaceUsedLong(const std::string& value) { + return sizeof(value) + StringSpaceUsedExcludingSelfLong(value); + } +}; + +} // namespace internal + +// RepeatedPtrField is like RepeatedField, but used for repeated strings or +// Messages. +template +class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { + public: + constexpr RepeatedPtrField(); + explicit RepeatedPtrField(Arena* arena); + + RepeatedPtrField(const RepeatedPtrField& other); + + template ())>::value>::type> + RepeatedPtrField(Iter begin, Iter end); + + ~RepeatedPtrField(); + + RepeatedPtrField& operator=(const RepeatedPtrField& other); + + RepeatedPtrField(RepeatedPtrField&& other) noexcept; + RepeatedPtrField& operator=(RepeatedPtrField&& other) noexcept; + + bool empty() const; + int size() const; + + const Element& Get(int index) const; + Element* Mutable(int index); + Element* Add(); + void Add(Element&& value); + // Append elements in the range [begin, end) after reserving + // the appropriate number of elements. + template + void Add(Iter begin, Iter end); + + const Element& operator[](int index) const { return Get(index); } + Element& operator[](int index) { return *Mutable(index); } + + const Element& at(int index) const; + Element& at(int index); + + // Remove the last element in the array. + // Ownership of the element is retained by the array. + void RemoveLast(); + + // Delete elements with indices in the range [start .. start+num-1]. + // Caution: implementation moves all elements with indices [start+num .. ]. + // Calling this routine inside a loop can cause quadratic behavior. + void DeleteSubrange(int start, int num); + + PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear(); + void MergeFrom(const RepeatedPtrField& other); + PROTOBUF_ATTRIBUTE_REINITIALIZES void CopyFrom(const RepeatedPtrField& other); + + // Replaces the contents with RepeatedPtrField(begin, end). + template + PROTOBUF_ATTRIBUTE_REINITIALIZES void Assign(Iter begin, Iter end); + + // Reserve space to expand the field to at least the given size. This only + // resizes the pointer array; it doesn't allocate any objects. If the + // array is grown, it will always be at least doubled in size. + void Reserve(int new_size); + + int Capacity() const; + + // Gets the underlying array. This pointer is possibly invalidated by + // any add or remove operation. + Element** mutable_data(); + const Element* const* data() const; + + // Swap entire contents with "other". If they are on separate arenas, then + // copies data. + void Swap(RepeatedPtrField* other); + + // Swap entire contents with "other". Caller should guarantee that either both + // fields are on the same arena or both are on the heap. Swapping between + // different arenas with this function is disallowed and is caught via + // GOOGLE_DCHECK. + void UnsafeArenaSwap(RepeatedPtrField* other); + + // Swap two elements. + void SwapElements(int index1, int index2); + + // STL-like iterator support + typedef internal::RepeatedPtrIterator iterator; + typedef internal::RepeatedPtrIterator const_iterator; + typedef Element value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef int size_type; + typedef ptrdiff_t difference_type; + + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; + iterator end(); + const_iterator end() const; + const_iterator cend() const; + + // Reverse iterator support + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator + pointer_iterator; + typedef internal::RepeatedPtrOverPtrsIterator + const_pointer_iterator; + pointer_iterator pointer_begin(); + const_pointer_iterator pointer_begin() const; + pointer_iterator pointer_end(); + const_pointer_iterator pointer_end() const; + + // Returns (an estimate of) the number of bytes used by the repeated field, + // excluding sizeof(*this). + size_t SpaceUsedExcludingSelfLong() const; + + int SpaceUsedExcludingSelf() const { + return internal::ToIntSize(SpaceUsedExcludingSelfLong()); + } + + // Advanced memory management -------------------------------------- + // When hardcore memory management becomes necessary -- as it sometimes + // does here at Google -- the following methods may be useful. + + // Add an already-allocated object, passing ownership to the + // RepeatedPtrField. + // + // Note that some special behavior occurs with respect to arenas: + // + // (i) if this field holds submessages, the new submessage will be copied if + // the original is in an arena and this RepeatedPtrField is either in a + // different arena, or on the heap. + // (ii) if this field holds strings, the passed-in string *must* be + // heap-allocated, not arena-allocated. There is no way to dynamically check + // this at runtime, so User Beware. + void AddAllocated(Element* value); + + // Remove the last element and return it, passing ownership to the caller. + // Requires: size() > 0 + // + // If this RepeatedPtrField is on an arena, an object copy is required to pass + // ownership back to the user (for compatible semantics). Use + // UnsafeArenaReleaseLast() if this behavior is undesired. + PROTOBUF_NODISCARD Element* ReleaseLast(); + + // Add an already-allocated object, skipping arena-ownership checks. The user + // must guarantee that the given object is in the same arena as this + // RepeatedPtrField. + // It is also useful in legacy code that uses temporary ownership to avoid + // copies. Example: + // RepeatedPtrField temp_field; + // temp_field.UnsafeArenaAddAllocated(new T); + // ... // Do something with temp_field + // temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr); + // If you put temp_field on the arena this fails, because the ownership + // transfers to the arena at the "AddAllocated" call and is not released + // anymore causing a double delete. UnsafeArenaAddAllocated prevents this. + void UnsafeArenaAddAllocated(Element* value); + + // Remove the last element and return it. Unlike ReleaseLast, the returned + // pointer is always to the original object. This may be in an arena, and + // therefore have the arena's lifetime. + // Requires: current_size_ > 0 + Element* UnsafeArenaReleaseLast(); + + // Extract elements with indices in the range "[start .. start+num-1]". + // The caller assumes ownership of the extracted elements and is responsible + // for deleting them when they are no longer needed. + // If "elements" is non-nullptr, then pointers to the extracted elements + // are stored in "elements[0 .. num-1]" for the convenience of the caller. + // If "elements" is nullptr, then the caller must use some other mechanism + // to perform any further operations (like deletion) on these elements. + // Caution: implementation also moves elements with indices [start+num ..]. + // Calling this routine inside a loop can cause quadratic behavior. + // + // Memory copying behavior is identical to ReleaseLast(), described above: if + // this RepeatedPtrField is on an arena, an object copy is performed for each + // returned element, so that all returned element pointers are to + // heap-allocated copies. If this copy is not desired, the user should call + // UnsafeArenaExtractSubrange(). + void ExtractSubrange(int start, int num, Element** elements); + + // Identical to ExtractSubrange() described above, except that no object + // copies are ever performed. Instead, the raw object pointers are returned. + // Thus, if on an arena, the returned objects must not be freed, because they + // will not be heap-allocated objects. + void UnsafeArenaExtractSubrange(int start, int num, Element** elements); + + // When elements are removed by calls to RemoveLast() or Clear(), they + // are not actually freed. Instead, they are cleared and kept so that + // they can be reused later. This can save lots of CPU time when + // repeatedly reusing a protocol message for similar purposes. + // + // Hardcore programs may choose to manipulate these cleared objects + // to better optimize memory management using the following routines. + + // Get the number of cleared objects that are currently being kept + // around for reuse. + int ClearedCount() const; +#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES + // Add an element to the pool of cleared objects, passing ownership to + // the RepeatedPtrField. The element must be cleared prior to calling + // this method. + // + // This method cannot be called when the repeated field is on an arena or when + // |value| is; both cases will trigger a GOOGLE_DCHECK-failure. + void AddCleared(Element* value); + // Remove a single element from the cleared pool and return it, passing + // ownership to the caller. The element is guaranteed to be cleared. + // Requires: ClearedCount() > 0 + // + // + // This method cannot be called when the repeated field is on an arena; doing + // so will trigger a GOOGLE_DCHECK-failure. + PROTOBUF_NODISCARD Element* ReleaseCleared(); +#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES + + // Removes the element referenced by position. + // + // Returns an iterator to the element immediately following the removed + // element. + // + // Invalidates all iterators at or after the removed element, including end(). + iterator erase(const_iterator position); + + // Removes the elements in the range [first, last). + // + // Returns an iterator to the element immediately following the removed range. + // + // Invalidates all iterators at or after the removed range, including end(). + iterator erase(const_iterator first, const_iterator last); + + // Gets the arena on which this RepeatedPtrField stores its elements. + inline Arena* GetArena() const; + + // For internal use only. + // + // This is public due to it being called by generated code. + void InternalSwap(RepeatedPtrField* other) { + internal::RepeatedPtrFieldBase::InternalSwap(other); + } + + private: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. + class TypeHandler; + + // Implementations for ExtractSubrange(). The copying behavior must be + // included only if the type supports the necessary operations (e.g., + // MergeFrom()), so we must resolve this at compile time. ExtractSubrange() + // uses SFINAE to choose one of the below implementations. + void ExtractSubrangeInternal(int start, int num, Element** elements, + std::true_type); + void ExtractSubrangeInternal(int start, int num, Element** elements, + std::false_type); + + friend class Arena; + + template + friend struct WeakRepeatedPtrField; + + typedef void InternalArenaConstructable_; + +}; + +// implementation ==================================================== + +namespace internal { + +constexpr RepeatedPtrFieldBase::RepeatedPtrFieldBase() + : arena_(nullptr), current_size_(0), total_size_(0), rep_(nullptr) {} + +inline RepeatedPtrFieldBase::RepeatedPtrFieldBase(Arena* arena) + : arena_(arena), current_size_(0), total_size_(0), rep_(nullptr) {} + +template +void RepeatedPtrFieldBase::Destroy() { + if (rep_ != nullptr && arena_ == nullptr) { + int n = rep_->allocated_size; + void* const* elements = rep_->elements; + for (int i = 0; i < n; i++) { + TypeHandler::Delete(cast(elements[i]), nullptr); + } +#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation) + const size_t size = total_size_ * sizeof(elements[0]) + kRepHeaderSize; + ::operator delete(static_cast(rep_), size); +#else + ::operator delete(static_cast(rep_)); +#endif + } + rep_ = nullptr; +} + +template +inline void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { +#ifdef PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() != nullptr && GetArena() == other->GetArena()) { +#else // PROTOBUF_FORCE_COPY_IN_SWAP + if (GetArena() == other->GetArena()) { +#endif // !PROTOBUF_FORCE_COPY_IN_SWAP + InternalSwap(other); + } else { + SwapFallback(other); + } +} + +template +void RepeatedPtrFieldBase::SwapFallback(RepeatedPtrFieldBase* other) { +#ifdef PROTOBUF_FORCE_COPY_IN_SWAP + GOOGLE_DCHECK(GetArena() == nullptr || other->GetArena() != GetArena()); +#else // PROTOBUF_FORCE_COPY_IN_SWAP + GOOGLE_DCHECK(other->GetArena() != GetArena()); +#endif // !PROTOBUF_FORCE_COPY_IN_SWAP + + // Copy semantics in this case. We try to improve efficiency by placing the + // temporary on |other|'s arena so that messages are copied twice rather than + // three times. + RepeatedPtrFieldBase temp(other->GetArena()); + temp.MergeFrom(*this); + this->Clear(); + this->MergeFrom(*other); + other->InternalSwap(&temp); + temp.Destroy(); // Frees rep_ if `other` had no arena. +} + +inline bool RepeatedPtrFieldBase::empty() const { return current_size_ == 0; } + +inline int RepeatedPtrFieldBase::size() const { return current_size_; } + +template +inline const typename TypeHandler::Type& RepeatedPtrFieldBase::Get( + int index) const { + GOOGLE_DCHECK_GE(index, 0); + GOOGLE_DCHECK_LT(index, current_size_); + return *cast(rep_->elements[index]); +} + +template +inline const typename TypeHandler::Type& RepeatedPtrFieldBase::at( + int index) const { + GOOGLE_CHECK_GE(index, 0); + GOOGLE_CHECK_LT(index, current_size_); + return *cast(rep_->elements[index]); +} + +template +inline typename TypeHandler::Type& RepeatedPtrFieldBase::at(int index) { + GOOGLE_CHECK_GE(index, 0); + GOOGLE_CHECK_LT(index, current_size_); + return *cast(rep_->elements[index]); +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::Mutable(int index) { + GOOGLE_DCHECK_GE(index, 0); + GOOGLE_DCHECK_LT(index, current_size_); + return cast(rep_->elements[index]); +} + +template +inline void RepeatedPtrFieldBase::Delete(int index) { + GOOGLE_DCHECK_GE(index, 0); + GOOGLE_DCHECK_LT(index, current_size_); + TypeHandler::Delete(cast(rep_->elements[index]), arena_); +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::Add( + typename TypeHandler::Type* prototype) { + if (rep_ != nullptr && current_size_ < rep_->allocated_size) { + return cast(rep_->elements[current_size_++]); + } + typename TypeHandler::Type* result = + TypeHandler::NewFromPrototype(prototype, arena_); + return reinterpret_cast( + AddOutOfLineHelper(result)); +} + +template ::type*> +inline void RepeatedPtrFieldBase::Add(typename TypeHandler::Type&& value) { + if (rep_ != nullptr && current_size_ < rep_->allocated_size) { + *cast(rep_->elements[current_size_++]) = std::move(value); + return; + } + if (!rep_ || rep_->allocated_size == total_size_) { + Reserve(total_size_ + 1); + } + ++rep_->allocated_size; + typename TypeHandler::Type* result = + TypeHandler::New(arena_, std::move(value)); + rep_->elements[current_size_++] = result; +} + +template +inline void RepeatedPtrFieldBase::RemoveLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + TypeHandler::Clear(cast(rep_->elements[--current_size_])); +} + +template +void RepeatedPtrFieldBase::Clear() { + const int n = current_size_; + GOOGLE_DCHECK_GE(n, 0); + if (n > 0) { + void* const* elements = rep_->elements; + int i = 0; + do { + TypeHandler::Clear(cast(elements[i++])); + } while (i < n); + current_size_ = 0; + } +} + +// To avoid unnecessary code duplication and reduce binary size, we use a +// layered approach to implementing MergeFrom(). The toplevel method is +// templated, so we get a small thunk per concrete message type in the binary. +// This calls a shared implementation with most of the logic, passing a function +// pointer to another type-specific piece of code that calls the object-allocate +// and merge handlers. +template +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { + GOOGLE_DCHECK_NE(&other, this); + if (other.current_size_ == 0) return; + MergeFromInternal(other, + &RepeatedPtrFieldBase::MergeFromInnerLoop); +} + +inline void RepeatedPtrFieldBase::MergeFromInternal( + const RepeatedPtrFieldBase& other, + void (RepeatedPtrFieldBase::*inner_loop)(void**, void**, int, int)) { + // Note: wrapper has already guaranteed that other.rep_ != nullptr here. + int other_size = other.current_size_; + void** other_elements = other.rep_->elements; + void** new_elements = InternalExtend(other_size); + int allocated_elems = rep_->allocated_size - current_size_; + (this->*inner_loop)(new_elements, other_elements, other_size, + allocated_elems); + current_size_ += other_size; + if (rep_->allocated_size < current_size_) { + rep_->allocated_size = current_size_; + } +} + +// Merges other_elems to our_elems. +template +void RepeatedPtrFieldBase::MergeFromInnerLoop(void** our_elems, + void** other_elems, int length, + int already_allocated) { + if (already_allocated < length) { + Arena* arena = GetArena(); + typename TypeHandler::Type* elem_prototype = + reinterpret_cast(other_elems[0]); + for (int i = already_allocated; i < length; i++) { + // Allocate a new empty element that we'll merge into below + typename TypeHandler::Type* new_elem = + TypeHandler::NewFromPrototype(elem_prototype, arena); + our_elems[i] = new_elem; + } + } + // Main loop that does the actual merging + for (int i = 0; i < length; i++) { + // Already allocated: use existing element. + typename TypeHandler::Type* other_elem = + reinterpret_cast(other_elems[i]); + typename TypeHandler::Type* new_elem = + reinterpret_cast(our_elems[i]); + TypeHandler::Merge(*other_elem, new_elem); + } +} + +template +inline void RepeatedPtrFieldBase::CopyFrom(const RepeatedPtrFieldBase& other) { + if (&other == this) return; + RepeatedPtrFieldBase::Clear(); + RepeatedPtrFieldBase::MergeFrom(other); +} + +inline int RepeatedPtrFieldBase::Capacity() const { return total_size_; } + +inline void* const* RepeatedPtrFieldBase::raw_data() const { + return rep_ ? rep_->elements : nullptr; +} + +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return rep_ ? const_cast(rep_->elements) : nullptr; +} + +template +inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(raw_mutable_data()); +} + +template +inline const typename TypeHandler::Type* const* RepeatedPtrFieldBase::data() + const { + // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this + // method entirely. + return reinterpret_cast(raw_data()); +} + +inline void RepeatedPtrFieldBase::SwapElements(int index1, int index2) { + using std::swap; // enable ADL with fallback + swap(rep_->elements[index1], rep_->elements[index2]); +} + +template +inline size_t RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong() const { + size_t allocated_bytes = static_cast(total_size_) * sizeof(void*); + if (rep_ != nullptr) { + for (int i = 0; i < rep_->allocated_size; ++i) { + allocated_bytes += + TypeHandler::SpaceUsedLong(*cast(rep_->elements[i])); + } + allocated_bytes += kRepHeaderSize; + } + return allocated_bytes; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { + if (rep_ != nullptr && current_size_ < rep_->allocated_size) { + return cast(rep_->elements[current_size_++]); + } else { + return nullptr; + } +} + +// AddAllocated version that implements arena-safe copying behavior. +template +void RepeatedPtrFieldBase::AddAllocatedInternal( + typename TypeHandler::Type* value, std::true_type) { + Arena* element_arena = + reinterpret_cast(TypeHandler::GetOwningArena(value)); + Arena* arena = GetArena(); + if (arena == element_arena && rep_ && rep_->allocated_size < total_size_) { + // Fast path: underlying arena representation (tagged pointer) is equal to + // our arena pointer, and we can add to array without resizing it (at least + // one slot that is not allocated). + void** elems = rep_->elements; + if (current_size_ < rep_->allocated_size) { + // Make space at [current] by moving first allocated element to end of + // allocated list. + elems[rep_->allocated_size] = elems[current_size_]; + } + elems[current_size_] = value; + current_size_ = current_size_ + 1; + rep_->allocated_size = rep_->allocated_size + 1; + } else { + AddAllocatedSlowWithCopy(value, element_arena, arena); + } +} + +// Slowpath handles all cases, copying if necessary. +template +void RepeatedPtrFieldBase::AddAllocatedSlowWithCopy( + // Pass value_arena and my_arena to avoid duplicate virtual call (value) or + // load (mine). + typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) { + // Ensure that either the value is in the same arena, or if not, we do the + // appropriate thing: Own() it (if it's on heap and we're in an arena) or copy + // it to our arena/heap (otherwise). + if (my_arena != nullptr && value_arena == nullptr) { + my_arena->Own(value); + } else if (my_arena != value_arena) { + typename TypeHandler::Type* new_value = + TypeHandler::NewFromPrototype(value, my_arena); + TypeHandler::Merge(*value, new_value); + TypeHandler::Delete(value, value_arena); + value = new_value; + } + + UnsafeArenaAddAllocated(value); +} + +// AddAllocated version that does not implement arena-safe copying behavior. +template +void RepeatedPtrFieldBase::AddAllocatedInternal( + typename TypeHandler::Type* value, std::false_type) { + if (rep_ && rep_->allocated_size < total_size_) { + // Fast path: underlying arena representation (tagged pointer) is equal to + // our arena pointer, and we can add to array without resizing it (at least + // one slot that is not allocated). + void** elems = rep_->elements; + if (current_size_ < rep_->allocated_size) { + // Make space at [current] by moving first allocated element to end of + // allocated list. + elems[rep_->allocated_size] = elems[current_size_]; + } + elems[current_size_] = value; + current_size_ = current_size_ + 1; + ++rep_->allocated_size; + } else { + UnsafeArenaAddAllocated(value); + } +} + +template +void RepeatedPtrFieldBase::UnsafeArenaAddAllocated( + typename TypeHandler::Type* value) { + // Make room for the new pointer. + if (!rep_ || current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++rep_->allocated_size; + } else if (rep_->allocated_size == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast(rep_->elements[current_size_]), + arena_); + } else if (current_size_ < rep_->allocated_size) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. + rep_->elements[rep_->allocated_size] = rep_->elements[current_size_]; + ++rep_->allocated_size; + } else { + // There are no cleared objects. + ++rep_->allocated_size; + } + + rep_->elements[current_size_++] = value; +} + +// ReleaseLast() for types that implement merge/copy behavior. +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal( + std::true_type) { + // First, release an element. + typename TypeHandler::Type* result = UnsafeArenaReleaseLast(); + // Now perform a copy if we're on an arena. + Arena* arena = GetArena(); + + typename TypeHandler::Type* new_result; +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + new_result = copy(result); + if (arena == nullptr) delete result; +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + new_result = (arena == nullptr) ? result : copy(result); +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + return new_result; +} + +// ReleaseLast() for types that *do not* implement merge/copy behavior -- this +// is the same as UnsafeArenaReleaseLast(). Note that we GOOGLE_DCHECK-fail if we're on +// an arena, since the user really should implement the copy operation in this +// case. +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLastInternal( + std::false_type) { + GOOGLE_DCHECK(GetArena() == nullptr) + << "ReleaseLast() called on a RepeatedPtrField that is on an arena, " + << "with a type that does not implement MergeFrom. This is unsafe; " + << "please implement MergeFrom for your type."; + return UnsafeArenaReleaseLast(); +} + +template +inline typename TypeHandler::Type* +RepeatedPtrFieldBase::UnsafeArenaReleaseLast() { + GOOGLE_DCHECK_GT(current_size_, 0); + typename TypeHandler::Type* result = + cast(rep_->elements[--current_size_]); + --rep_->allocated_size; + if (current_size_ < rep_->allocated_size) { + // There are cleared elements on the end; replace the removed element + // with the last allocated element. + rep_->elements[current_size_] = rep_->elements[rep_->allocated_size]; + } + return result; +} + +inline int RepeatedPtrFieldBase::ClearedCount() const { + return rep_ ? (rep_->allocated_size - current_size_) : 0; +} + +template +inline void RepeatedPtrFieldBase::AddCleared( + typename TypeHandler::Type* value) { + GOOGLE_DCHECK(GetArena() == nullptr) + << "AddCleared() can only be used on a RepeatedPtrField not on an arena."; + GOOGLE_DCHECK(TypeHandler::GetOwningArena(value) == nullptr) + << "AddCleared() can only accept values not on an arena."; + if (!rep_ || rep_->allocated_size == total_size_) { + Reserve(total_size_ + 1); + } + rep_->elements[rep_->allocated_size++] = value; +} + +template +inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { + GOOGLE_DCHECK(GetArena() == nullptr) + << "ReleaseCleared() can only be used on a RepeatedPtrField not on " + << "an arena."; + GOOGLE_DCHECK(GetArena() == nullptr); + GOOGLE_DCHECK(rep_ != nullptr); + GOOGLE_DCHECK_GT(rep_->allocated_size, current_size_); + return cast(rep_->elements[--rep_->allocated_size]); +} + +} // namespace internal + +// ------------------------------------------------------------------- + +template +class RepeatedPtrField::TypeHandler + : public internal::GenericTypeHandler {}; + +template <> +class RepeatedPtrField::TypeHandler + : public internal::StringTypeHandler {}; + +template +constexpr RepeatedPtrField::RepeatedPtrField() + : RepeatedPtrFieldBase() {} + +template +inline RepeatedPtrField::RepeatedPtrField(Arena* arena) + : RepeatedPtrFieldBase(arena) {} + +template +inline RepeatedPtrField::RepeatedPtrField( + const RepeatedPtrField& other) + : RepeatedPtrFieldBase() { + MergeFrom(other); +} + +template +template +inline RepeatedPtrField::RepeatedPtrField(Iter begin, Iter end) { + Add(begin, end); +} + +template +RepeatedPtrField::~RepeatedPtrField() { +#ifdef __cpp_if_constexpr + if constexpr (std::is_base_of::value) { +#else + if (std::is_base_of::value) { +#endif + if (NeedsDestroy()) DestroyProtos(); + } else { + Destroy(); + } +} + +template +inline RepeatedPtrField& RepeatedPtrField::operator=( + const RepeatedPtrField& other) { + if (this != &other) CopyFrom(other); + return *this; +} + +template +inline RepeatedPtrField::RepeatedPtrField( + RepeatedPtrField&& other) noexcept + : RepeatedPtrField() { +#ifdef PROTOBUF_FORCE_COPY_IN_MOVE + CopyFrom(other); +#else // PROTOBUF_FORCE_COPY_IN_MOVE + // We don't just call Swap(&other) here because it would perform 3 copies if + // other is on an arena. This field can't be on an arena because arena + // construction always uses the Arena* accepting constructor. + if (other.GetArena()) { + CopyFrom(other); + } else { + InternalSwap(&other); + } +#endif // !PROTOBUF_FORCE_COPY_IN_MOVE +} + +template +inline RepeatedPtrField& RepeatedPtrField::operator=( + RepeatedPtrField&& other) noexcept { + // We don't just call Swap(&other) here because it would perform 3 copies if + // the two fields are on different arenas. + if (this != &other) { + if (GetArena() != other.GetArena() +#ifdef PROTOBUF_FORCE_COPY_IN_MOVE + || GetArena() == nullptr +#endif // !PROTOBUF_FORCE_COPY_IN_MOVE + ) { + CopyFrom(other); + } else { + InternalSwap(&other); + } + } + return *this; +} + +template +inline bool RepeatedPtrField::empty() const { + return RepeatedPtrFieldBase::empty(); +} + +template +inline int RepeatedPtrField::size() const { + return RepeatedPtrFieldBase::size(); +} + +template +inline const Element& RepeatedPtrField::Get(int index) const { + return RepeatedPtrFieldBase::Get(index); +} + +template +inline const Element& RepeatedPtrField::at(int index) const { + return RepeatedPtrFieldBase::at(index); +} + +template +inline Element& RepeatedPtrField::at(int index) { + return RepeatedPtrFieldBase::at(index); +} + + +template +inline Element* RepeatedPtrField::Mutable(int index) { + return RepeatedPtrFieldBase::Mutable(index); +} + +template +inline Element* RepeatedPtrField::Add() { + return RepeatedPtrFieldBase::Add(); +} + +template +inline void RepeatedPtrField::Add(Element&& value) { + RepeatedPtrFieldBase::Add(std::move(value)); +} + +template +template +inline void RepeatedPtrField::Add(Iter begin, Iter end) { + if (std::is_base_of< + std::forward_iterator_tag, + typename std::iterator_traits::iterator_category>::value) { + int reserve = std::distance(begin, end); + Reserve(size() + reserve); + } + for (; begin != end; ++begin) { + *Add() = *begin; + } +} + +template +inline void RepeatedPtrField::RemoveLast() { + RepeatedPtrFieldBase::RemoveLast(); +} + +template +inline void RepeatedPtrField::DeleteSubrange(int start, int num) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + for (int i = 0; i < num; ++i) { + RepeatedPtrFieldBase::Delete(start + i); + } + UnsafeArenaExtractSubrange(start, num, nullptr); +} + +template +inline void RepeatedPtrField::ExtractSubrange(int start, int num, + Element** elements) { + typename internal::TypeImplementsMergeBehavior< + typename TypeHandler::Type>::type t; + ExtractSubrangeInternal(start, num, elements, t); +} + +// ExtractSubrange() implementation for types that implement merge/copy +// behavior. +template +inline void RepeatedPtrField::ExtractSubrangeInternal( + int start, int num, Element** elements, std::true_type) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + + if (num == 0) return; + + GOOGLE_DCHECK_NE(elements, nullptr) + << "Releasing elements without transferring ownership is an unsafe " + "operation. Use UnsafeArenaExtractSubrange."; + if (elements == nullptr) { + CloseGap(start, num); + return; + } + + Arena* arena = GetArena(); +#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE + // Always copy. + for (int i = 0; i < num; ++i) { + elements[i] = copy( + RepeatedPtrFieldBase::Mutable(i + start)); + } + if (arena == nullptr) { + for (int i = 0; i < num; ++i) { + delete RepeatedPtrFieldBase::Mutable(i + start); + } + } +#else // PROTOBUF_FORCE_COPY_IN_RELEASE + // If we're on an arena, we perform a copy for each element so that the + // returned elements are heap-allocated. Otherwise, just forward it. + if (arena != nullptr) { + for (int i = 0; i < num; ++i) { + elements[i] = copy( + RepeatedPtrFieldBase::Mutable(i + start)); + } + } else { + for (int i = 0; i < num; ++i) { + elements[i] = RepeatedPtrFieldBase::Mutable(i + start); + } + } +#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE + CloseGap(start, num); +} + +// ExtractSubrange() implementation for types that do not implement merge/copy +// behavior. +template +inline void RepeatedPtrField::ExtractSubrangeInternal( + int start, int num, Element** elements, std::false_type) { + // This case is identical to UnsafeArenaExtractSubrange(). However, since + // ExtractSubrange() must return heap-allocated objects by contract, and we + // cannot fulfill this contract if we are an on arena, we must GOOGLE_DCHECK() that + // we are not on an arena. + GOOGLE_DCHECK(GetArena() == nullptr) + << "ExtractSubrange() when arena is non-nullptr is only supported when " + << "the Element type supplies a MergeFrom() operation to make copies."; + UnsafeArenaExtractSubrange(start, num, elements); +} + +template +inline void RepeatedPtrField::UnsafeArenaExtractSubrange( + int start, int num, Element** elements) { + GOOGLE_DCHECK_GE(start, 0); + GOOGLE_DCHECK_GE(num, 0); + GOOGLE_DCHECK_LE(start + num, size()); + + if (num > 0) { + // Save the values of the removed elements if requested. + if (elements != nullptr) { + for (int i = 0; i < num; ++i) { + elements[i] = RepeatedPtrFieldBase::Mutable(i + start); + } + } + CloseGap(start, num); + } +} + +template +inline void RepeatedPtrField::Clear() { + RepeatedPtrFieldBase::Clear(); +} + +template +inline void RepeatedPtrField::MergeFrom( + const RepeatedPtrField& other) { + RepeatedPtrFieldBase::MergeFrom(other); +} + +template +inline void RepeatedPtrField::CopyFrom(const RepeatedPtrField& other) { + RepeatedPtrFieldBase::CopyFrom(other); +} + +template +template +inline void RepeatedPtrField::Assign(Iter begin, Iter end) { + Clear(); + Add(begin, end); +} + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::erase(const_iterator position) { + return erase(position, position + 1); +} + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::erase(const_iterator first, const_iterator last) { + size_type pos_offset = std::distance(cbegin(), first); + size_type last_offset = std::distance(cbegin(), last); + DeleteSubrange(pos_offset, last_offset - pos_offset); + return begin() + pos_offset; +} + +template +inline Element** RepeatedPtrField::mutable_data() { + return RepeatedPtrFieldBase::mutable_data(); +} + +template +inline const Element* const* RepeatedPtrField::data() const { + return RepeatedPtrFieldBase::data(); +} + +template +inline void RepeatedPtrField::Swap(RepeatedPtrField* other) { + if (this == other) return; + RepeatedPtrFieldBase::Swap(other); +} + +template +inline void RepeatedPtrField::UnsafeArenaSwap( + RepeatedPtrField* other) { + if (this == other) return; + RepeatedPtrFieldBase::InternalSwap(other); +} + +template +inline void RepeatedPtrField::SwapElements(int index1, int index2) { + RepeatedPtrFieldBase::SwapElements(index1, index2); +} + +template +inline Arena* RepeatedPtrField::GetArena() const { + return RepeatedPtrFieldBase::GetArena(); +} + +template +inline size_t RepeatedPtrField::SpaceUsedExcludingSelfLong() const { + return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong(); +} + +template +inline void RepeatedPtrField::AddAllocated(Element* value) { + RepeatedPtrFieldBase::AddAllocated(value); +} + +template +inline void RepeatedPtrField::UnsafeArenaAddAllocated(Element* value) { + RepeatedPtrFieldBase::UnsafeArenaAddAllocated(value); +} + +template +inline Element* RepeatedPtrField::ReleaseLast() { + return RepeatedPtrFieldBase::ReleaseLast(); +} + +template +inline Element* RepeatedPtrField::UnsafeArenaReleaseLast() { + return RepeatedPtrFieldBase::UnsafeArenaReleaseLast(); +} + +template +inline int RepeatedPtrField::ClearedCount() const { + return RepeatedPtrFieldBase::ClearedCount(); +} + +#ifndef PROTOBUF_FUTURE_BREAKING_CHANGES +template +inline void RepeatedPtrField::AddCleared(Element* value) { + return RepeatedPtrFieldBase::AddCleared(value); +} + +template +inline Element* RepeatedPtrField::ReleaseCleared() { + return RepeatedPtrFieldBase::ReleaseCleared(); +} +#endif // !PROTOBUF_FUTURE_BREAKING_CHANGES + +template +inline void RepeatedPtrField::Reserve(int new_size) { + return RepeatedPtrFieldBase::Reserve(new_size); +} + +template +inline int RepeatedPtrField::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + +// ------------------------------------------------------------------- + +namespace internal { + +// STL-like iterator implementation for RepeatedPtrField. You should not +// refer to this class directly; use RepeatedPtrField::iterator instead. +// +// The iterator for RepeatedPtrField, RepeatedPtrIterator, is +// very similar to iterator_ptr in util/gtl/iterator_adaptors.h, +// but adds random-access operators and is modified to wrap a void** base +// iterator (since RepeatedPtrField stores its array as a void* array and +// casting void** to T** would violate C++ aliasing rules). +// +// This code based on net/proto/proto-array-internal.h by Jeffrey Yasskin +// (jyasskin@google.com). +template +class RepeatedPtrIterator { + public: + using iterator = RepeatedPtrIterator; + using iterator_category = std::random_access_iterator_tag; + using value_type = typename std::remove_const::type; + using difference_type = std::ptrdiff_t; + using pointer = Element*; + using reference = Element&; + + RepeatedPtrIterator() : it_(nullptr) {} + explicit RepeatedPtrIterator(void* const* it) : it_(it) {} + + // Allow "upcasting" from RepeatedPtrIterator to + // RepeatedPtrIterator. + template + RepeatedPtrIterator(const RepeatedPtrIterator& other) + : it_(other.it_) { + // Force a compiler error if the other type is not convertible to ours. + if (false) { + static_cast([](OtherElement* from) -> Element* { return from; }); + } + } + + // dereferenceable + reference operator*() const { return *reinterpret_cast(*it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { + ++it_; + return *this; + } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { + --it_; + return *this; + } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, const difference_type d) { + it += d; + return it; + } + friend iterator operator+(const difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void* const* it_; +}; + +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +// The VoidPtr template parameter holds the type-agnostic pointer value +// referenced by the iterator. It should either be "void *" for a mutable +// iterator, or "const void* const" for a constant iterator. +template +class RepeatedPtrOverPtrsIterator { + public: + using iterator = RepeatedPtrOverPtrsIterator; + using iterator_category = std::random_access_iterator_tag; + using value_type = typename std::remove_const::type; + using difference_type = std::ptrdiff_t; + using pointer = Element*; + using reference = Element&; + + RepeatedPtrOverPtrsIterator() : it_(nullptr) {} + explicit RepeatedPtrOverPtrsIterator(VoidPtr* it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { + ++it_; + return *this; + } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { + --it_; + return *this; + } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + VoidPtr* it_; +}; + +void RepeatedPtrFieldBase::InternalSwap(RepeatedPtrFieldBase* rhs) { + GOOGLE_DCHECK(this != rhs); + + // Swap all fields at once. + auto temp = std::make_tuple(rhs->arena_, rhs->current_size_, rhs->total_size_, + rhs->rep_); + std::tie(rhs->arena_, rhs->current_size_, rhs->total_size_, rhs->rep_) = + std::make_tuple(arena_, current_size_, total_size_, rep_); + std::tie(arena_, current_size_, total_size_, rep_) = temp; +} + +} // namespace internal + +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::begin() { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::begin() const { + return iterator(raw_data()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::cbegin() const { + return begin(); +} +template +inline typename RepeatedPtrField::iterator +RepeatedPtrField::end() { + return iterator(raw_data() + size()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::end() const { + return iterator(raw_data() + size()); +} +template +inline typename RepeatedPtrField::const_iterator +RepeatedPtrField::cend() const { + return end(); +} + +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template +inline typename RepeatedPtrField::const_pointer_iterator +RepeatedPtrField::pointer_begin() const { + return const_pointer_iterator(const_cast(raw_data())); +} +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} +template +inline typename RepeatedPtrField::const_pointer_iterator +RepeatedPtrField::pointer_end() const { + return const_pointer_iterator( + const_cast(raw_data() + size())); +} + +// Iterators and helper functions that follow the spirit of the STL +// std::back_insert_iterator and std::back_inserter but are tailor-made +// for RepeatedField and RepeatedPtrField. Typical usage would be: +// +// std::copy(some_sequence.begin(), some_sequence.end(), +// RepeatedFieldBackInserter(proto.mutable_sequence())); +// +// Ported by johannes from util/gtl/proto-array-iterators.h + +namespace internal { + +// A back inserter for RepeatedPtrField objects. +template +class RepeatedPtrFieldBackInsertIterator { + public: + using iterator_category = std::output_iterator_tag; + using value_type = T; + using pointer = void; + using reference = void; + using difference_type = std::ptrdiff_t; + + RepeatedPtrFieldBackInsertIterator(RepeatedPtrField* const mutable_field) + : field_(mutable_field) {} + RepeatedPtrFieldBackInsertIterator& operator=(const T& value) { + *field_->Add() = value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator=( + const T* const ptr_to_value) { + *field_->Add() = *ptr_to_value; + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator=(T&& value) { + *field_->Add() = std::move(value); + return *this; + } + RepeatedPtrFieldBackInsertIterator& operator*() { return *this; } + RepeatedPtrFieldBackInsertIterator& operator++() { return *this; } + RepeatedPtrFieldBackInsertIterator& operator++(int /* unused */) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; + +// A back inserter for RepeatedPtrFields that inserts by transferring ownership +// of a pointer. +template +class AllocatedRepeatedPtrFieldBackInsertIterator { + public: + using iterator_category = std::output_iterator_tag; + using value_type = T; + using pointer = void; + using reference = void; + using difference_type = std::ptrdiff_t; + + explicit AllocatedRepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) {} + AllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T* const ptr_to_value) { + field_->AddAllocated(ptr_to_value); + return *this; + } + AllocatedRepeatedPtrFieldBackInsertIterator& operator*() { return *this; } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++() { return *this; } + AllocatedRepeatedPtrFieldBackInsertIterator& operator++(int /* unused */) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; + +// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one +// uses the UnsafeArenaAddAllocated instead. +template +class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator { + public: + using iterator_category = std::output_iterator_tag; + using value_type = T; + using pointer = void; + using reference = void; + using difference_type = std::ptrdiff_t; + + explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( + RepeatedPtrField* const mutable_field) + : field_(mutable_field) {} + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T const* const ptr_to_value) { + field_->UnsafeArenaAddAllocated(const_cast(ptr_to_value)); + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++( + int /* unused */) { + return *this; + } + + private: + RepeatedPtrField* field_; +}; + +} // namespace internal + +// Provides a back insert iterator for RepeatedPtrField instances, +// similar to std::back_inserter(). +template +internal::RepeatedPtrFieldBackInsertIterator RepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Special back insert iterator for RepeatedPtrField instances, just in +// case someone wants to write generic template code that can access both +// RepeatedFields and RepeatedPtrFields using a common name. +template +internal::RepeatedPtrFieldBackInsertIterator RepeatedFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::RepeatedPtrFieldBackInsertIterator(mutable_field); +} + +// Provides a back insert iterator for RepeatedPtrField instances +// similar to std::back_inserter() which transfers the ownership while +// copying elements. +template +internal::AllocatedRepeatedPtrFieldBackInsertIterator +AllocatedRepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::AllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + +// Similar to AllocatedRepeatedPtrFieldBackInserter, using +// UnsafeArenaAddAllocated instead of AddAllocated. +// This is slightly faster if that matters. It is also useful in legacy code +// that uses temporary ownership to avoid copies. Example: +// RepeatedPtrField temp_field; +// temp_field.UnsafeArenaAddAllocated(new T); +// ... // Do something with temp_field +// temp_field.UnsafeArenaExtractSubrange(0, temp_field.size(), nullptr); +// If you put temp_field on the arena this fails, because the ownership +// transfers to the arena at the "AddAllocated" call and is not released anymore +// causing a double delete. Using UnsafeArenaAddAllocated prevents this. +template +internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator +UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + RepeatedPtrField* const mutable_field) { + return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + +extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE + RepeatedPtrField; + +} // namespace protobuf +} // namespace google + +#include + +#endif // GOOGLE_PROTOBUF_REPEATED_PTR_FIELD_H__ diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto index d064fbb88b3c..39fc123f4932 100644 --- a/src/google/protobuf/test_messages_proto2.proto +++ b/src/google/protobuf/test_messages_proto2.proto @@ -194,6 +194,22 @@ message TestAllTypesProto2 { optional uint32 group_uint32 = 203; } + // default values + optional int32 default_int32 = 241 [ default = -123456789]; + optional int64 default_int64 = 242 [ default = -9123456789123456789]; + optional uint32 default_uint32 = 243 [ default = 2123456789]; + optional uint64 default_uint64 = 244 [ default = 10123456789123456789]; + optional sint32 default_sint32 = 245 [ default = -123456789]; + optional sint64 default_sint64 = 246 [default = -9123456789123456789]; + optional fixed32 default_fixed32 = 247 [ default = 2123456789]; + optional fixed64 default_fixed64 = 248 [ default = 10123456789123456789]; + optional sfixed32 default_sfixed32 = 249 [ default = -123456789]; + optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789]; + optional float default_float = 251 [ default = 9e9]; + optional double default_double = 252 [ default = 7e22]; + optional bool default_bool = 253 [ default = true]; + optional string default_string = 254 [ default = "Rosebud"]; + // Test field-name-to-JSON-name convention. // (protobuf says names can be any valid C/C++ identifier.) optional int32 fieldname1 = 401; diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index c94fb7ef5acd..8b20d76df9d8 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -426,14 +426,19 @@ class TextFormat::Parser::ParserImpl { TryConsume("[")) { std::string full_type_name, prefix; DO(ConsumeAnyTypeUrl(&full_type_name, &prefix)); - DO(Consume("]")); - TryConsume(":"); // ':' is optional between message labels and values. + std::string prefix_and_full_type_name = + StrCat(prefix, full_type_name); + DO(ConsumeBeforeWhitespace("]")); + TryConsumeWhitespace(prefix_and_full_type_name, "Any"); + // ':' is optional between message labels and values. + TryConsumeBeforeWhitespace(":"); + TryConsumeWhitespace(prefix_and_full_type_name, "Any"); std::string serialized_value; const Descriptor* value_descriptor = finder_ ? finder_->FindAnyType(*message, prefix, full_type_name) : DefaultFinderFindAnyType(*message, prefix, full_type_name); if (value_descriptor == nullptr) { - ReportError("Could not find type \"" + prefix + full_type_name + + ReportError("Could not find type \"" + prefix_and_full_type_name + "\" stored in google.protobuf.Any."); return false; } @@ -449,14 +454,15 @@ class TextFormat::Parser::ParserImpl { } } reflection->SetString(message, any_type_url_field, - std::string(prefix + full_type_name)); + prefix_and_full_type_name); reflection->SetString(message, any_value_field, serialized_value); return true; } if (TryConsume("[")) { // Extension. DO(ConsumeFullTypeName(&field_name)); - DO(Consume("]")); + DO(ConsumeBeforeWhitespace("]")); + TryConsumeWhitespace(message->GetTypeName(), "Extension"); field = finder_ ? finder_->FindExtension(message, field_name) : DefaultFinderFindExtension(message, field_name); @@ -475,7 +481,8 @@ class TextFormat::Parser::ParserImpl { } } } else { - DO(ConsumeIdentifier(&field_name)); + DO(ConsumeIdentifierBeforeWhitespace(&field_name)); + TryConsumeWhitespace(message->GetTypeName(), "Normal"); int32_t field_number; if (allow_field_number_ && safe_strto32(field_name, &field_number)) { @@ -543,11 +550,13 @@ class TextFormat::Parser::ParserImpl { // start with "{" or "<" which indicates the beginning of a message body. // If there is no ":" or there is a "{" or "<" after ":", this field has // to be a message or the input is ill-formed. - if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) { - return SkipFieldValue(); - } else { - return SkipFieldMessage(); + if (TryConsumeBeforeWhitespace(":")) { + TryConsumeWhitespace(message->GetTypeName(), "Unknown/Reserved"); + if (!LookingAt("{") && !LookingAt("<")) { + return SkipFieldValue(); + } } + return SkipFieldMessage(); } if (singular_overwrite_policy_ == FORBID_SINGULAR_OVERWRITES) { @@ -577,7 +586,8 @@ class TextFormat::Parser::ParserImpl { // Perform special handling for embedded message types. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { // ':' is optional here. - bool consumed_semicolon = TryConsume(":"); + bool consumed_semicolon = TryConsumeBeforeWhitespace(":"); + TryConsumeWhitespace(message->GetTypeName(), "Normal"); if (consumed_semicolon && field->options().weak() && LookingAtType(io::Tokenizer::TYPE_STRING)) { // we are getting a bytes string for a weak field. @@ -591,7 +601,8 @@ class TextFormat::Parser::ParserImpl { } } else { // ':' is required here. - DO(Consume(":")); + DO(ConsumeBeforeWhitespace(":")); + TryConsumeWhitespace(message->GetTypeName(), "Normal"); } if (field->is_repeated() && TryConsume("[")) { @@ -645,11 +656,12 @@ class TextFormat::Parser::ParserImpl { if (TryConsume("[")) { // Extension name or type URL. DO(ConsumeTypeUrlOrFullTypeName()); - DO(Consume("]")); + DO(ConsumeBeforeWhitespace("]")); } else { std::string field_name; - DO(ConsumeIdentifier(&field_name)); + DO(ConsumeIdentifierBeforeWhitespace(&field_name)); } + TryConsumeWhitespace("Unknown/Reserved", "n/a"); // Try to guess the type of this field. // If this field is not a message, there should be a ":" between the @@ -657,8 +669,13 @@ class TextFormat::Parser::ParserImpl { // start with "{" or "<" which indicates the beginning of a message body. // If there is no ":" or there is a "{" or "<" after ":", this field has // to be a message or the input is ill-formed. - if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) { - DO(SkipFieldValue()); + if (TryConsumeBeforeWhitespace(":")) { + TryConsumeWhitespace("Unknown/Reserved", "n/a"); + if (!LookingAt("{") && !LookingAt("<")) { + DO(SkipFieldValue()); + } else { + DO(SkipFieldMessage()); + } } else { DO(SkipFieldMessage()); } @@ -980,6 +997,15 @@ class TextFormat::Parser::ParserImpl { return false; } + // Similar to `ConsumeIdentifier`, but any following whitespace token may + // be reported. + bool ConsumeIdentifierBeforeWhitespace(std::string* identifier) { + tokenizer_.set_report_whitespace(true); + bool result = ConsumeIdentifier(identifier); + tokenizer_.set_report_whitespace(false); + return result; + } + // Consume a string of form ".....". bool ConsumeFullTypeName(std::string* name) { DO(ConsumeIdentifier(name)); @@ -1207,6 +1233,16 @@ class TextFormat::Parser::ParserImpl { return true; } + // Similar to `Consume`, but the following token may be tokenized as + // TYPE_WHITESPACE. + bool ConsumeBeforeWhitespace(const std::string& value) { + // Report whitespace after this token, but only once. + tokenizer_.set_report_whitespace(true); + bool result = Consume(value); + tokenizer_.set_report_whitespace(false); + return result; + } + // Attempts to consume the supplied value. Returns false if a the // token found does not match the value specified. bool TryConsume(const std::string& value) { @@ -1218,6 +1254,26 @@ class TextFormat::Parser::ParserImpl { } } + // Similar to `TryConsume`, but the following token may be tokenized as + // TYPE_WHITESPACE. + bool TryConsumeBeforeWhitespace(const std::string& value) { + // Report whitespace after this token, but only once. + tokenizer_.set_report_whitespace(true); + bool result = TryConsume(value); + tokenizer_.set_report_whitespace(false); + return result; + } + + bool TryConsumeWhitespace(const std::string& message_type, + const char* field_type) { + if (LookingAtType(io::Tokenizer::TYPE_WHITESPACE)) { + tokenizer_.Next(); + return true; + } + + return false; + } + // An internal instance of the Tokenizer's error collector, used to // collect any base-level parse errors and feed them to the ParserImpl. class ParserErrorCollector : public io::ErrorCollector { @@ -1768,7 +1824,8 @@ void TextFormat::FastFieldValuePrinter::PrintDouble( generator->PrintString(!std::isnan(val) ? SimpleDtoa(val) : "nan"); } void TextFormat::FastFieldValuePrinter::PrintEnum( - int32_t /*val*/, const std::string& name, BaseTextGenerator* generator) const { + int32_t /*val*/, const std::string& name, + BaseTextGenerator* generator) const { generator->PrintString(name); } @@ -1879,8 +1936,8 @@ class FieldValuePrinterWrapper : public TextFormat::FastFieldValuePrinter { TextFormat::BaseTextGenerator* generator) const override { generator->PrintString(delegate_->PrintEnum(val, name)); } - void PrintFieldName(const Message& message, int /*field_index*/, int /*field_count*/, - const Reflection* reflection, + void PrintFieldName(const Message& message, int /*field_index*/, + int /*field_count*/, const Reflection* reflection, const FieldDescriptor* field, TextFormat::BaseTextGenerator* generator) const override { generator->PrintString( diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index bc998b250cdd..1da753bfffaf 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -1965,6 +1965,102 @@ TEST_F(TextFormatParserTest, SetRecursionLimitUnknownFieldMessage) { ExpectSuccessAndTree(input, &message, nullptr); } +TEST_F(TextFormatParserTest, ParseAnyFieldWithAdditionalWhiteSpaces) { + Any any; + std::string parse_string = + "[type.googleapis.com/protobuf_unittest.TestAllTypes] \t : \t {\n" + " optional_int32: 321\n" + " optional_string: \"teststr0\"\n" + "}\n"; + + ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &any)); + + TextFormat::Printer printer; + printer.SetExpandAny(true); + std::string text; + ASSERT_TRUE(printer.PrintToString(any, &text)); + EXPECT_EQ(text, + "[type.googleapis.com/protobuf_unittest.TestAllTypes] {\n" + " optional_int32: 321\n" + " optional_string: \"teststr0\"\n" + "}\n"); +} + +TEST_F(TextFormatParserTest, ParseExtensionFieldWithAdditionalWhiteSpaces) { + unittest::TestAllExtensions proto; + std::string parse_string = + "[protobuf_unittest.optional_int32_extension] : \t 101\n" + "[protobuf_unittest.optional_int64_extension] \t : 102\n"; + + ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto)); + + TextFormat::Printer printer; + std::string text; + ASSERT_TRUE(printer.PrintToString(proto, &text)); + EXPECT_EQ(text, + "[protobuf_unittest.optional_int32_extension]: 101\n" + "[protobuf_unittest.optional_int64_extension]: 102\n"); +} + +TEST_F(TextFormatParserTest, ParseNormalFieldWithAdditionalWhiteSpaces) { + unittest::TestAllTypes proto; + std::string parse_string = + "repeated_int32 : \t 1\n" + "repeated_int32: 2\n" + "repeated_nested_message: {\n" + " bb: 3\n" + "}\n" + "repeated_nested_message : \t {\n" + " bb: 4\n" + "}\n" + "repeated_nested_message {\n" + " bb: 5\n" + "}\n"; + + ASSERT_TRUE(TextFormat::ParseFromString(parse_string, &proto)); + + TextFormat::Printer printer; + std::string text; + ASSERT_TRUE(printer.PrintToString(proto, &text)); + EXPECT_EQ(text, + "repeated_int32: 1\n" + "repeated_int32: 2\n" + "repeated_nested_message {\n" + " bb: 3\n" + "}\n" + "repeated_nested_message {\n" + " bb: 4\n" + "}\n" + "repeated_nested_message {\n" + " bb: 5\n" + "}\n"); +} + +TEST_F(TextFormatParserTest, ParseSkippedFieldWithAdditionalWhiteSpaces) { + protobuf_unittest::TestAllTypes proto; + TextFormat::Parser parser; + parser.AllowUnknownField(true); + EXPECT_TRUE( + parser.ParseFromString("optional_int32: 321\n" + "unknown_field1 : \t 12345\n" + "[somewhere.unknown_extension1] {\n" + " unknown_field2 \t : 12345\n" + "}\n" + "[somewhere.unknown_extension2] : \t {\n" + " unknown_field3 \t : 12345\n" + " [somewhere.unknown_extension3] \t : {\n" + " unknown_field4: 10\n" + " }\n" + " [somewhere.unknown_extension4] \t {\n" + " }\n" + "}\n", + &proto)); + std::string text; + TextFormat::Printer printer; + ASSERT_TRUE(printer.PrintToString(proto, &text)); + EXPECT_EQ(text, "optional_int32: 321\n"); +} + class TextFormatMessageSetTest : public testing::Test { protected: static const char proto_debug_string_[]; @@ -2279,6 +2375,24 @@ TEST_F(TextFormatSilentMarkerTest, MapFieldAsFirstField) { } +TEST(TextFormatFloatingPointTest, PreservesNegative0) { + proto3_unittest::TestAllTypes in_message; + in_message.set_optional_float(-0.0f); + in_message.set_optional_double(-0.0); + TextFormat::Printer printer; + std::string serialized; + EXPECT_TRUE(printer.PrintToString(in_message, &serialized)); + proto3_unittest::TestAllTypes out_message; + TextFormat::Parser parser; + EXPECT_TRUE(parser.ParseFromString(serialized, &out_message)); + EXPECT_EQ(in_message.optional_float(), out_message.optional_float()); + EXPECT_EQ(std::signbit(in_message.optional_float()), + std::signbit(out_message.optional_float())); + EXPECT_EQ(in_message.optional_double(), out_message.optional_double()); + EXPECT_EQ(std::signbit(in_message.optional_double()), + std::signbit(out_message.optional_double())); +} + } // namespace text_format_unittest } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 2b66dc07fa8a..423f3e7624c8 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -251,7 +251,8 @@ void UnknownField::Delete() { } } -void UnknownField::DeepCopy(const UnknownField& /*other*/) { +void UnknownField::DeepCopy(const UnknownField& other) { + (void)other; // Parameter is used by Google-internal code. switch (type()) { case UnknownField::TYPE_LENGTH_DELIMITED: data_.length_delimited_.string_value = diff --git a/src/google/protobuf/util/internal/error_listener.h b/src/google/protobuf/util/internal/error_listener.h index d8c59063667e..745b66a95247 100644 --- a/src/google/protobuf/util/internal/error_listener.h +++ b/src/google/protobuf/util/internal/error_listener.h @@ -84,15 +84,15 @@ class PROTOBUF_EXPORT NoopErrorListener : public ErrorListener { ~NoopErrorListener() override {} void InvalidName(const LocationTrackerInterface& /*loc*/, - StringPiece /*invalid_name*/, - StringPiece /*message*/) override {} + StringPiece /* invalid_name */, + StringPiece /* message */) override {} void InvalidValue(const LocationTrackerInterface& /*loc*/, - StringPiece /*type_name*/, - StringPiece /*value*/) override {} + StringPiece /* type_name */, + StringPiece /* value */) override {} - void MissingField(const LocationTrackerInterface& /*loc*/, - StringPiece /*missing_name*/) override {} + void MissingField(const LocationTrackerInterface& /* loc */, + StringPiece /* missing_name */) override {} private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(NoopErrorListener); diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index e3f3870cf31c..f52c5448e2e0 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -863,7 +863,8 @@ bool JsonStreamParser::IsEmptyNullAllowed(TokenType type) { } util::Status JsonStreamParser::ReportFailure(StringPiece message, - ParseErrorType /*parse_code*/) { + ParseErrorType parse_code) { + (void)parse_code; // Parameter is used in Google-internal code. static const int kContextLength = 20; const char* p_start = p_.data(); const char* json_start = json_.data(); diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 5674b2249922..221c42f00c1f 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -252,7 +252,7 @@ util::StatusOr ProtoStreamObjectSource::RenderList( } util::StatusOr ProtoStreamObjectSource::RenderMap( - const google::protobuf::Field* field, StringPiece /*name*/, + const google::protobuf::Field* field, StringPiece /* name */, uint32_t list_tag, ObjectWriter* ow) const { const google::protobuf::Type* field_type = typeinfo_->GetTypeByTypeUrl(field->type_url()); diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 568346f532c6..bf933ab08704 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -78,25 +78,28 @@ class NumDiffsReporter : public google::protobuf::util::MessageDifferencer::Repo // Report that a field has been added into Message2. void ReportAdded( - const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/, + const google::protobuf::Message& /* message1 */, + const google::protobuf::Message& /* message2 */, const std::vector& - /*field_path*/) override { + /*field_path*/) override { ++num_diffs_; } // Report that a field has been deleted from Message1. void ReportDeleted( - const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/, + const google::protobuf::Message& /* message1 */, + const google::protobuf::Message& /* message2 */, const std::vector& - /*field_path*/) override { + /*field_path*/) override { ++num_diffs_; } // Report that the value of a field has been modified. void ReportModified( - const google::protobuf::Message& /*message1*/, const google::protobuf::Message& /*message2*/, + const google::protobuf::Message& /* message1 */, + const google::protobuf::Message& /* message2 */, const std::vector& - /*field_path*/) override { + /*field_path*/) override { ++num_diffs_; } diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index 1ee6a38fc4fa..fbb5d206d516 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -212,20 +212,6 @@ class PROTOBUF_EXPORT MessageDifferencer { int unknown_field_index2 = -1; }; - // Class for processing Any deserialization. This logic is used by both the - // MessageDifferencer and StreamReporter classes. - class UnpackAnyField { - private: - std::unique_ptr dynamic_message_factory_; - - public: - UnpackAnyField() = default; - ~UnpackAnyField() = default; - // If "any" is of type google.protobuf.Any, extract its payload using - // DynamicMessageFactory and store in "data". - bool UnpackAny(const Message& any, std::unique_ptr* data); - }; - // Abstract base class from which all MessageDifferencer // reporters derive. The five Report* methods below will be called when // a field has been added, deleted, modified, moved, or matched. The third @@ -628,6 +614,22 @@ class PROTOBUF_EXPORT MessageDifferencer { // differences to any previously set reporters or output strings. void ReportDifferencesTo(Reporter* reporter); + private: + // Class for processing Any deserialization. This logic is used by both the + // MessageDifferencer and StreamReporter classes. + class UnpackAnyField { + private: + std::unique_ptr dynamic_message_factory_; + + public: + UnpackAnyField() = default; + ~UnpackAnyField() = default; + // If "any" is of type google.protobuf.Any, extract its payload using + // DynamicMessageFactory and store in "data". + bool UnpackAny(const Message& any, std::unique_ptr* data); + }; + + public: // An implementation of the MessageDifferencer Reporter that outputs // any differences found in human-readable form to the supplied // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 5a2ee29124f8..b16edb4f1d0a 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -571,8 +571,9 @@ bool WireFormatLite::ReadBytes(io::CodedInputStream* input, std::string** p) { } void PrintUTF8ErrorLog(const char* field_name, const char* operation_str, - bool /*emit_stacktrace*/) { + bool emit_stacktrace) { std::string stacktrace; + (void)emit_stacktrace; // Parameter is used by Google-internal code. std::string quoted_field_name = ""; if (field_name != nullptr) { quoted_field_name = StringPrintf(" '%s'", field_name); diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 92758b567eda..2ce0df18fda1 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -349,7 +349,11 @@ uint8_t* DoubleValue::_InternalSerialize( (void) cached_has_bits; // double value = 1; - if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) { + static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size."); + double tmp_value = this->_internal_value(); + uint64_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteDoubleToArray(1, this->_internal_value(), target); } @@ -371,7 +375,11 @@ size_t DoubleValue::ByteSizeLong() const { (void) cached_has_bits; // double value = 1; - if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) { + static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size."); + double tmp_value = this->_internal_value(); + uint64_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { total_size += 1 + 8; } @@ -397,7 +405,11 @@ void DoubleValue::MergeFrom(const DoubleValue& from) { uint32_t cached_has_bits = 0; (void) cached_has_bits; - if (!(from._internal_value() <= 0 && from._internal_value() >= 0)) { + static_assert(sizeof(uint64_t) == sizeof(double), "Code assumes uint64_t and double are the same size."); + double tmp_value = from._internal_value(); + uint64_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { _internal_set_value(from._internal_value()); } _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_); @@ -527,7 +539,11 @@ uint8_t* FloatValue::_InternalSerialize( (void) cached_has_bits; // float value = 1; - if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) { + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_value = this->_internal_value(); + uint32_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { target = stream->EnsureSpace(target); target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::WriteFloatToArray(1, this->_internal_value(), target); } @@ -549,7 +565,11 @@ size_t FloatValue::ByteSizeLong() const { (void) cached_has_bits; // float value = 1; - if (!(this->_internal_value() <= 0 && this->_internal_value() >= 0)) { + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_value = this->_internal_value(); + uint32_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { total_size += 1 + 4; } @@ -575,7 +595,11 @@ void FloatValue::MergeFrom(const FloatValue& from) { uint32_t cached_has_bits = 0; (void) cached_has_bits; - if (!(from._internal_value() <= 0 && from._internal_value() >= 0)) { + static_assert(sizeof(uint32_t) == sizeof(float), "Code assumes uint32_t and float are the same size."); + float tmp_value = from._internal_value(); + uint32_t raw_value; + memcpy(&raw_value, &tmp_value, sizeof(tmp_value)); + if (raw_value != 0) { _internal_set_value(from._internal_value()); } _internal_metadata_.MergeFrom<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(from._internal_metadata_);