Browse Source

Merge branch 'dev' of github.com:eesast/THUAI6 into dev

tags/0.1.0
gsy1519 2 years ago
parent
commit
7555b7adeb
100 changed files with 31540 additions and 10 deletions
  1. +3
    -1
      CAPI/cpp/.gitattributes
  2. +1
    -0
      CAPI/cpp/.gitignore
  3. +47
    -0
      CAPI/cpp/API/API.vcxproj
  4. +85
    -0
      CAPI/cpp/API/API.vcxproj.filters
  5. +7
    -2
      CAPI/cpp/API/include/constants.h
  6. +2
    -2
      CAPI/cpp/API/include/logic.h
  7. +1
    -0
      CAPI/cpp/API/include/state.h
  8. +3
    -1
      CAPI/cpp/API/include/structures.h
  9. +8
    -1
      CAPI/cpp/API/include/utils.hpp
  10. +0
    -1
      CAPI/cpp/API/src/Communication.cpp
  11. +1
    -1
      CAPI/cpp/API/src/logic.cpp
  12. +0
    -1
      CAPI/cpp/API/src/main.cpp
  13. +31
    -0
      CAPI/cpp/CAPI.sln
  14. +610
    -0
      CAPI/cpp/grpc/LICENSE
  15. +162
    -0
      CAPI/cpp/grpc/include/absl/algorithm/algorithm.h
  16. +1623
    -0
      CAPI/cpp/grpc/include/absl/algorithm/container.h
  17. +761
    -0
      CAPI/cpp/grpc/include/absl/base/attributes.h
  18. +234
    -0
      CAPI/cpp/grpc/include/absl/base/call_once.h
  19. +179
    -0
      CAPI/cpp/grpc/include/absl/base/casts.h
  20. +908
    -0
      CAPI/cpp/grpc/include/absl/base/config.h
  21. +78
    -0
      CAPI/cpp/grpc/include/absl/base/const_init.h
  22. +487
    -0
      CAPI/cpp/grpc/include/absl/base/dynamic_annotations.h
  23. +225
    -0
      CAPI/cpp/grpc/include/absl/base/internal/atomic_hook.h
  24. +36
    -0
      CAPI/cpp/grpc/include/absl/base/internal/atomic_hook_test_helper.h
  25. +168
    -0
      CAPI/cpp/grpc/include/absl/base/internal/cycleclock.h
  26. +177
    -0
      CAPI/cpp/grpc/include/absl/base/internal/direct_mmap.h
  27. +416
    -0
      CAPI/cpp/grpc/include/absl/base/internal/dynamic_annotations.h
  28. +472
    -0
      CAPI/cpp/grpc/include/absl/base/internal/endian.h
  29. +55
    -0
      CAPI/cpp/grpc/include/absl/base/internal/errno_saver.h
  30. +1345
    -0
      CAPI/cpp/grpc/include/absl/base/internal/exception_safety_testing.h
  31. +42
    -0
      CAPI/cpp/grpc/include/absl/base/internal/exception_testing.h
  32. +54
    -0
      CAPI/cpp/grpc/include/absl/base/internal/fast_type_id.h
  33. +56
    -0
      CAPI/cpp/grpc/include/absl/base/internal/hide_ptr.h
  34. +40
    -0
      CAPI/cpp/grpc/include/absl/base/internal/identity.h
  35. +107
    -0
      CAPI/cpp/grpc/include/absl/base/internal/inline_variable.h
  36. +49
    -0
      CAPI/cpp/grpc/include/absl/base/internal/inline_variable_testing.h
  37. +267
    -0
      CAPI/cpp/grpc/include/absl/base/internal/invoke.h
  38. +130
    -0
      CAPI/cpp/grpc/include/absl/base/internal/low_level_alloc.h
  39. +152
    -0
      CAPI/cpp/grpc/include/absl/base/internal/low_level_scheduling.h
  40. +52
    -0
      CAPI/cpp/grpc/include/absl/base/internal/per_thread_tls.h
  41. +156
    -0
      CAPI/cpp/grpc/include/absl/base/internal/prefetch.h
  42. +33
    -0
      CAPI/cpp/grpc/include/absl/base/internal/pretty_function.h
  43. +197
    -0
      CAPI/cpp/grpc/include/absl/base/internal/raw_logging.h
  44. +61
    -0
      CAPI/cpp/grpc/include/absl/base/internal/scheduling_mode.h
  45. +48
    -0
      CAPI/cpp/grpc/include/absl/base/internal/scoped_set_env.h
  46. +286
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock.h
  47. +35
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock_akaros.inc
  48. +71
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock_linux.inc
  49. +46
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock_posix.inc
  50. +97
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock_wait.h
  51. +37
    -0
      CAPI/cpp/grpc/include/absl/base/internal/spinlock_win32.inc
  52. +41
    -0
      CAPI/cpp/grpc/include/absl/base/internal/strerror.h
  53. +76
    -0
      CAPI/cpp/grpc/include/absl/base/internal/sysinfo.h
  54. +273
    -0
      CAPI/cpp/grpc/include/absl/base/internal/thread_annotations.h
  55. +272
    -0
      CAPI/cpp/grpc/include/absl/base/internal/thread_identity.h
  56. +77
    -0
      CAPI/cpp/grpc/include/absl/base/internal/throw_delegate.h
  57. +68
    -0
      CAPI/cpp/grpc/include/absl/base/internal/tsan_mutex_interface.h
  58. +96
    -0
      CAPI/cpp/grpc/include/absl/base/internal/unaligned_access.h
  59. +138
    -0
      CAPI/cpp/grpc/include/absl/base/internal/unscaledcycleclock.h
  60. +177
    -0
      CAPI/cpp/grpc/include/absl/base/log_severity.h
  61. +165
    -0
      CAPI/cpp/grpc/include/absl/base/macros.h
  62. +263
    -0
      CAPI/cpp/grpc/include/absl/base/optimization.h
  63. +235
    -0
      CAPI/cpp/grpc/include/absl/base/options.h
  64. +111
    -0
      CAPI/cpp/grpc/include/absl/base/policy_checks.h
  65. +25
    -0
      CAPI/cpp/grpc/include/absl/base/port.h
  66. +339
    -0
      CAPI/cpp/grpc/include/absl/base/thread_annotations.h
  67. +146
    -0
      CAPI/cpp/grpc/include/absl/cleanup/cleanup.h
  68. +118
    -0
      CAPI/cpp/grpc/include/absl/cleanup/internal/cleanup.h
  69. +869
    -0
      CAPI/cpp/grpc/include/absl/container/btree_map.h
  70. +816
    -0
      CAPI/cpp/grpc/include/absl/container/btree_set.h
  71. +215
    -0
      CAPI/cpp/grpc/include/absl/container/btree_test.h
  72. +653
    -0
      CAPI/cpp/grpc/include/absl/container/fixed_array.h
  73. +634
    -0
      CAPI/cpp/grpc/include/absl/container/flat_hash_map.h
  74. +527
    -0
      CAPI/cpp/grpc/include/absl/container/flat_hash_set.h
  75. +984
    -0
      CAPI/cpp/grpc/include/absl/container/inlined_vector.h
  76. +3419
    -0
      CAPI/cpp/grpc/include/absl/container/internal/btree.h
  77. +863
    -0
      CAPI/cpp/grpc/include/absl/container/internal/btree_container.h
  78. +258
    -0
      CAPI/cpp/grpc/include/absl/container/internal/common.h
  79. +339
    -0
      CAPI/cpp/grpc/include/absl/container/internal/compressed_tuple.h
  80. +499
    -0
      CAPI/cpp/grpc/include/absl/container/internal/container_memory.h
  81. +144
    -0
      CAPI/cpp/grpc/include/absl/container/internal/counting_allocator.h
  82. +195
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hash_function_defaults.h
  83. +209
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hash_generator_testing.h
  84. +240
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hash_policy_testing.h
  85. +226
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hash_policy_traits.h
  86. +122
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hashtable_debug.h
  87. +95
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hashtable_debug_hooks.h
  88. +353
    -0
      CAPI/cpp/grpc/include/absl/container/internal/hashtablez_sampler.h
  89. +1111
    -0
      CAPI/cpp/grpc/include/absl/container/internal/inlined_vector.h
  90. +809
    -0
      CAPI/cpp/grpc/include/absl/container/internal/layout.h
  91. +105
    -0
      CAPI/cpp/grpc/include/absl/container/internal/node_slot_policy.h
  92. +218
    -0
      CAPI/cpp/grpc/include/absl/container/internal/raw_hash_map.h
  93. +2748
    -0
      CAPI/cpp/grpc/include/absl/container/internal/raw_hash_set.h
  94. +340
    -0
      CAPI/cpp/grpc/include/absl/container/internal/test_instance_tracker.h
  95. +106
    -0
      CAPI/cpp/grpc/include/absl/container/internal/tracked.h
  96. +546
    -0
      CAPI/cpp/grpc/include/absl/container/internal/unordered_map_constructor_test.h
  97. +125
    -0
      CAPI/cpp/grpc/include/absl/container/internal/unordered_map_lookup_test.h
  98. +90
    -0
      CAPI/cpp/grpc/include/absl/container/internal/unordered_map_members_test.h
  99. +370
    -0
      CAPI/cpp/grpc/include/absl/container/internal/unordered_map_modifiers_test.h
  100. +551
    -0
      CAPI/cpp/grpc/include/absl/container/internal/unordered_set_constructor_test.h

+ 3
- 1
CAPI/cpp/.gitattributes View File

@@ -1,6 +1,8 @@
tclap/** linguist-vendored
* text=auto

tclap/** linguist-vendored
spdlog/** linguist-vendored
grpc/** linguist-vendored

proto/** linguist-generated



+ 1
- 0
CAPI/cpp/.gitignore View File

@@ -499,3 +499,4 @@ CTestTestfile.cmake
_deps

/build/
/lib/

+ 47
- 0
CAPI/cpp/API/API.vcxproj View File

@@ -90,10 +90,15 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalIncludeDirectories>..\spdlog\include;..\tclap\include;..\grpc\include;..\proto;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\lib\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>absl_bad_any_cast_impl.lib;absl_bad_optional_access.lib;absl_bad_variant_access.lib;absl_base.lib;absl_city.lib;absl_civil_time.lib;absl_cord.lib;absl_cordz_functions.lib;absl_cordz_handle.lib;absl_cordz_info.lib;absl_cordz_sample_token.lib;absl_cord_internal.lib;absl_debugging_internal.lib;absl_demangle_internal.lib;absl_examine_stack.lib;absl_exponential_biased.lib;absl_failure_signal_handler.lib;absl_flags.lib;absl_flags_commandlineflag.lib;absl_flags_commandlineflag_internal.lib;absl_flags_config.lib;absl_flags_internal.lib;absl_flags_marshalling.lib;absl_flags_parse.lib;absl_flags_private_handle_accessor.lib;absl_flags_program_name.lib;absl_flags_reflection.lib;absl_flags_usage.lib;absl_flags_usage_internal.lib;absl_graphcycles_internal.lib;absl_hash.lib;absl_hashtablez_sampler.lib;absl_int128.lib;absl_leak_check.lib;absl_log_severity.lib;absl_low_level_hash.lib;absl_malloc_internal.lib;absl_periodic_sampler.lib;absl_random_distributions.lib;absl_random_internal_distribution_test_util.lib;absl_random_internal_platform.lib;absl_random_internal_pool_urbg.lib;absl_random_internal_randen.lib;absl_random_internal_randen_hwaes.lib;absl_random_internal_randen_hwaes_impl.lib;absl_random_internal_randen_slow.lib;absl_random_internal_seed_material.lib;absl_random_seed_gen_exception.lib;absl_random_seed_sequences.lib;absl_raw_hash_set.lib;absl_raw_logging_internal.lib;absl_scoped_set_env.lib;absl_spinlock_wait.lib;absl_stacktrace.lib;absl_status.lib;absl_statusor.lib;absl_strerror.lib;absl_strings.lib;absl_strings_internal.lib;absl_str_format_internal.lib;absl_symbolize.lib;absl_synchronization.lib;absl_throw_delegate.lib;absl_time.lib;absl_time_zone.lib;address_sorting.lib;cares.lib;descriptor_upb_proto.lib;gpr.lib;grpc++.lib;grpc++_alts.lib;grpc++_error_details.lib;grpc++_unsecure.lib;grpc.lib;grpc_plugin_support.lib;grpc_unsecure.lib;libcrypto.lib;libprotobuf-lited.lib;libprotobufd.lib;libprotocd.lib;libssl.lib;re2.lib;upb.lib;upb_collections.lib;upb_extension_registry.lib;upb_fastdecode.lib;upb_json.lib;upb_mini_table.lib;upb_reflection.lib;upb_textformat.lib;upb_utf8_range.lib;zlibd.lib;Ws2_32.lib;Crypt32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -106,12 +111,17 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalIncludeDirectories>..\spdlog\include;..\tclap\include;..\grpc\include;..\proto;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>absl_bad_any_cast_impl.lib;absl_bad_optional_access.lib;absl_bad_variant_access.lib;absl_base.lib;absl_city.lib;absl_civil_time.lib;absl_cord.lib;absl_cordz_functions.lib;absl_cordz_handle.lib;absl_cordz_info.lib;absl_cordz_sample_token.lib;absl_cord_internal.lib;absl_debugging_internal.lib;absl_demangle_internal.lib;absl_examine_stack.lib;absl_exponential_biased.lib;absl_failure_signal_handler.lib;absl_flags.lib;absl_flags_commandlineflag.lib;absl_flags_commandlineflag_internal.lib;absl_flags_config.lib;absl_flags_internal.lib;absl_flags_marshalling.lib;absl_flags_parse.lib;absl_flags_private_handle_accessor.lib;absl_flags_program_name.lib;absl_flags_reflection.lib;absl_flags_usage.lib;absl_flags_usage_internal.lib;absl_graphcycles_internal.lib;absl_hash.lib;absl_hashtablez_sampler.lib;absl_int128.lib;absl_leak_check.lib;absl_log_severity.lib;absl_low_level_hash.lib;absl_malloc_internal.lib;absl_periodic_sampler.lib;absl_random_distributions.lib;absl_random_internal_distribution_test_util.lib;absl_random_internal_platform.lib;absl_random_internal_pool_urbg.lib;absl_random_internal_randen.lib;absl_random_internal_randen_hwaes.lib;absl_random_internal_randen_hwaes_impl.lib;absl_random_internal_randen_slow.lib;absl_random_internal_seed_material.lib;absl_random_seed_gen_exception.lib;absl_random_seed_sequences.lib;absl_raw_hash_set.lib;absl_raw_logging_internal.lib;absl_scoped_set_env.lib;absl_spinlock_wait.lib;absl_stacktrace.lib;absl_status.lib;absl_statusor.lib;absl_strerror.lib;absl_strings.lib;absl_strings_internal.lib;absl_str_format_internal.lib;absl_symbolize.lib;absl_synchronization.lib;absl_throw_delegate.lib;absl_time.lib;absl_time_zone.lib;address_sorting.lib;cares.lib;descriptor_upb_proto.lib;gpr.lib;grpc++.lib;grpc++_alts.lib;grpc++_error_details.lib;grpc++_unsecure.lib;grpc.lib;grpc_plugin_support.lib;grpc_unsecure.lib;libcrypto.lib;libprotobuf-lite.lib;libprotobuf.lib;libprotoc.lib;libssl.lib;re2.lib;upb.lib;upb_collections.lib;upb_extension_registry.lib;upb_fastdecode.lib;upb_json.lib;upb_mini_table.lib;upb_reflection.lib;upb_textformat.lib;upb_utf8_range.lib;zlib.lib;Ws2_32.lib;Crypt32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\lib\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -122,10 +132,15 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalIncludeDirectories>..\spdlog\include;..\tclap\include;..\grpc\include;..\proto;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\lib\debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>absl_bad_any_cast_impl.lib;absl_bad_optional_access.lib;absl_bad_variant_access.lib;absl_base.lib;absl_city.lib;absl_civil_time.lib;absl_cord.lib;absl_cordz_functions.lib;absl_cordz_handle.lib;absl_cordz_info.lib;absl_cordz_sample_token.lib;absl_cord_internal.lib;absl_debugging_internal.lib;absl_demangle_internal.lib;absl_examine_stack.lib;absl_exponential_biased.lib;absl_failure_signal_handler.lib;absl_flags.lib;absl_flags_commandlineflag.lib;absl_flags_commandlineflag_internal.lib;absl_flags_config.lib;absl_flags_internal.lib;absl_flags_marshalling.lib;absl_flags_parse.lib;absl_flags_private_handle_accessor.lib;absl_flags_program_name.lib;absl_flags_reflection.lib;absl_flags_usage.lib;absl_flags_usage_internal.lib;absl_graphcycles_internal.lib;absl_hash.lib;absl_hashtablez_sampler.lib;absl_int128.lib;absl_leak_check.lib;absl_log_severity.lib;absl_low_level_hash.lib;absl_malloc_internal.lib;absl_periodic_sampler.lib;absl_random_distributions.lib;absl_random_internal_distribution_test_util.lib;absl_random_internal_platform.lib;absl_random_internal_pool_urbg.lib;absl_random_internal_randen.lib;absl_random_internal_randen_hwaes.lib;absl_random_internal_randen_hwaes_impl.lib;absl_random_internal_randen_slow.lib;absl_random_internal_seed_material.lib;absl_random_seed_gen_exception.lib;absl_random_seed_sequences.lib;absl_raw_hash_set.lib;absl_raw_logging_internal.lib;absl_scoped_set_env.lib;absl_spinlock_wait.lib;absl_stacktrace.lib;absl_status.lib;absl_statusor.lib;absl_strerror.lib;absl_strings.lib;absl_strings_internal.lib;absl_str_format_internal.lib;absl_symbolize.lib;absl_synchronization.lib;absl_throw_delegate.lib;absl_time.lib;absl_time_zone.lib;address_sorting.lib;cares.lib;descriptor_upb_proto.lib;gpr.lib;grpc++.lib;grpc++_alts.lib;grpc++_error_details.lib;grpc++_unsecure.lib;grpc.lib;grpc_plugin_support.lib;grpc_unsecure.lib;libcrypto.lib;libprotobuf-lited.lib;libprotobufd.lib;libprotocd.lib;libssl.lib;re2.lib;upb.lib;upb_collections.lib;upb_extension_registry.lib;upb_fastdecode.lib;upb_json.lib;upb_mini_table.lib;upb_reflection.lib;upb_textformat.lib;upb_utf8_range.lib;zlibd.lib;Ws2_32.lib;Crypt32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -138,15 +153,47 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalIncludeDirectories>..\spdlog\include;..\tclap\include;..\grpc\include;..\proto;include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/source-charset:utf-8 %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>absl_bad_any_cast_impl.lib;absl_bad_optional_access.lib;absl_bad_variant_access.lib;absl_base.lib;absl_city.lib;absl_civil_time.lib;absl_cord.lib;absl_cordz_functions.lib;absl_cordz_handle.lib;absl_cordz_info.lib;absl_cordz_sample_token.lib;absl_cord_internal.lib;absl_debugging_internal.lib;absl_demangle_internal.lib;absl_examine_stack.lib;absl_exponential_biased.lib;absl_failure_signal_handler.lib;absl_flags.lib;absl_flags_commandlineflag.lib;absl_flags_commandlineflag_internal.lib;absl_flags_config.lib;absl_flags_internal.lib;absl_flags_marshalling.lib;absl_flags_parse.lib;absl_flags_private_handle_accessor.lib;absl_flags_program_name.lib;absl_flags_reflection.lib;absl_flags_usage.lib;absl_flags_usage_internal.lib;absl_graphcycles_internal.lib;absl_hash.lib;absl_hashtablez_sampler.lib;absl_int128.lib;absl_leak_check.lib;absl_log_severity.lib;absl_low_level_hash.lib;absl_malloc_internal.lib;absl_periodic_sampler.lib;absl_random_distributions.lib;absl_random_internal_distribution_test_util.lib;absl_random_internal_platform.lib;absl_random_internal_pool_urbg.lib;absl_random_internal_randen.lib;absl_random_internal_randen_hwaes.lib;absl_random_internal_randen_hwaes_impl.lib;absl_random_internal_randen_slow.lib;absl_random_internal_seed_material.lib;absl_random_seed_gen_exception.lib;absl_random_seed_sequences.lib;absl_raw_hash_set.lib;absl_raw_logging_internal.lib;absl_scoped_set_env.lib;absl_spinlock_wait.lib;absl_stacktrace.lib;absl_status.lib;absl_statusor.lib;absl_strerror.lib;absl_strings.lib;absl_strings_internal.lib;absl_str_format_internal.lib;absl_symbolize.lib;absl_synchronization.lib;absl_throw_delegate.lib;absl_time.lib;absl_time_zone.lib;address_sorting.lib;cares.lib;descriptor_upb_proto.lib;gpr.lib;grpc++.lib;grpc++_alts.lib;grpc++_error_details.lib;grpc++_unsecure.lib;grpc.lib;grpc_plugin_support.lib;grpc_unsecure.lib;libcrypto.lib;libprotobuf-lite.lib;libprotobuf.lib;libprotoc.lib;libssl.lib;re2.lib;upb.lib;upb_collections.lib;upb_extension_registry.lib;upb_fastdecode.lib;upb_json.lib;upb_mini_table.lib;upb_reflection.lib;upb_textformat.lib;upb_utf8_range.lib;zlib.lib;Ws2_32.lib;Crypt32.lib;Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\lib\release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\proto\Message2Clients.pb.cc" />
<ClCompile Include="..\proto\Message2Server.pb.cc" />
<ClCompile Include="..\proto\MessageType.pb.cc" />
<ClCompile Include="..\proto\Services.grpc.pb.cc" />
<ClCompile Include="..\proto\Services.pb.cc" />
<ClCompile Include="src\AI.cpp" />
<ClCompile Include="src\API.cpp" />
<ClCompile Include="src\Communication.cpp" />
<ClCompile Include="src\DebugAPI.cpp" />
<ClCompile Include="src\logic.cpp" />
<ClCompile Include="src\main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\proto\Message2Clients.pb.h" />
<ClInclude Include="..\proto\Message2Server.pb.h" />
<ClInclude Include="..\proto\MessageType.pb.h" />
<ClInclude Include="..\proto\Services.grpc.pb.h" />
<ClInclude Include="..\proto\Services.pb.h" />
<ClInclude Include="include\AI.h" />
<ClInclude Include="include\API.h" />
<ClInclude Include="include\Communication.h" />
<ClInclude Include="include\ConcurrentQueue.hpp" />
<ClInclude Include="include\constants.h" />
<ClInclude Include="include\logic.h" />
<ClInclude Include="include\state.h" />
<ClInclude Include="include\structures.h" />
<ClInclude Include="include\utils.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">


+ 85
- 0
CAPI/cpp/API/API.vcxproj.filters View File

@@ -13,5 +13,90 @@
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="源文件\proto">
<UniqueIdentifier>{6aeaa732-c471-4ec4-9de4-1e6f8acc7e92}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\proto">
<UniqueIdentifier>{3de9b3fe-8273-490b-b433-5fde647f1a60}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\AI.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\API.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\Communication.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\DebugAPI.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\logic.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="src\main.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\proto\Message2Clients.pb.cc">
<Filter>源文件\proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\Message2Server.pb.cc">
<Filter>源文件\proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\MessageType.pb.cc">
<Filter>源文件\proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\Services.grpc.pb.cc">
<Filter>源文件\proto</Filter>
</ClCompile>
<ClCompile Include="..\proto\Services.pb.cc">
<Filter>源文件\proto</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\AI.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\API.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\Communication.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\ConcurrentQueue.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\constants.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\logic.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\state.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\structures.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="include\utils.hpp">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="..\proto\Message2Clients.pb.h">
<Filter>头文件\proto</Filter>
</ClInclude>
<ClInclude Include="..\proto\Message2Server.pb.h">
<Filter>头文件\proto</Filter>
</ClInclude>
<ClInclude Include="..\proto\MessageType.pb.h">
<Filter>头文件\proto</Filter>
</ClInclude>
<ClInclude Include="..\proto\Services.grpc.pb.h">
<Filter>头文件\proto</Filter>
</ClInclude>
<ClInclude Include="..\proto\Services.pb.h">
<Filter>头文件\proto</Filter>
</ClInclude>
</ItemGroup>
</Project>

+ 7
- 2
CAPI/cpp/API/include/constants.h View File

@@ -44,7 +44,7 @@ namespace Constants
SCCI int basicStudentAlertnessRadius = 15 * numOfGridPerCell;
SCCI int basicTrickerAlertnessRadius = 17 * numOfGridPerCell;
SCCI int basicStudentViewRange = 10 * numOfGridPerCell;
SCCI int basicTrickerViewRange = 15 * numOfGridPerCell;
SCCI int basicTrickerViewRange = 13 * numOfGridPerCell;
SCCI int PinningDownRange = 5 * numOfGridPerCell;

SCCI int maxNumOfProp = 3; // 人物道具栏容量
@@ -218,8 +218,13 @@ namespace Constants

SCCI int timeOfStunnedWhenJumpyDumpty = 3070;

SCCI double addedTimeOfSpeedWhenInspire = 0.6;
SCCI double addedTimeOfSpeedWhenInspire = 1.6;
SCCI int timeOfAddingSpeedWhenInspire = 6000;

SCCI int addHpWhenEncourage = basicHp / 4;

SCCI int checkIntervalWhenShowTime = 200;
SCCI int addAddictionPer100msWhenShowTime = 300;
struct CanBeginToCharge
{
SCCI int skillCD = commonSkillCD * 2;


+ 2
- 2
CAPI/cpp/API/include/logic.h View File

@@ -42,12 +42,12 @@ private:
std::unique_ptr<Communication> pComm;

// ID、阵营记录
int64_t playerID;
THUAI6::PlayerType playerType;
int64_t playerID;

// 类型记录
THUAI6::StudentType studentType;
THUAI6::TrickerType trickerType;
THUAI6::StudentType studentType;

// GUID信息
std::vector<int64_t> playerGUIDs;


+ 1
- 0
CAPI/cpp/API/include/state.h View File

@@ -5,6 +5,7 @@
#include <vector>
#include <array>
#include <map>
#include <memory>

#include "structures.h"



+ 3
- 1
CAPI/cpp/API/include/structures.h View File

@@ -5,6 +5,8 @@
#include <cstdint>
#include <array>
#include <map>
#include <vector>
#include <string>

namespace THUAI6
{
@@ -175,7 +177,7 @@ namespace THUAI6
int32_t viewRange; // 视野范围
int64_t playerID; // 玩家ID
int64_t guid; // 全局唯一ID
int16_t radius; // 圆形物体的半径或正方形物体的内切圆半径
int32_t radius; // 圆形物体的半径或正方形物体的内切圆半径
int32_t score; // 分数

double facingDirection; // 朝向


+ 8
- 1
CAPI/cpp/API/include/utils.hpp View File

@@ -5,6 +5,8 @@

#include <cstdint>
#include <cmath>
#include <map>
#include <vector>
#include "Message2Clients.pb.h"
#include "Message2Server.pb.h"
#include "MessageType.pb.h"
@@ -21,6 +23,11 @@ namespace AssistFunction
return grid / numOfGridPerCell;
}

[[nodiscard]] constexpr inline int GridToCell(double grid) noexcept
{
return int(grid) / numOfGridPerCell;
}

inline bool HaveView(int viewRange, int x, int y, int newX, int newY, std::vector<std::vector<THUAI6::PlaceType>>& map)
{
int deltaX = newX - x;
@@ -417,7 +424,7 @@ namespace THUAI62Proto
return playerMsg;
}

inline protobuf::IDMsg THUAI62ProtobufID(int playerID)
inline protobuf::IDMsg THUAI62ProtobufID(int64_t playerID)
{
protobuf::IDMsg idMsg;
idMsg.set_player_id(playerID);


+ 0
- 1
CAPI/cpp/API/src/Communication.cpp View File

@@ -19,7 +19,6 @@ bool Communication::Move(int64_t time, double angle, int64_t playerID)
protobuf::MoveRes moveResult;
ClientContext context;
auto request = THUAI62Proto::THUAI62ProtobufMove(time, angle, playerID);
std::cout << "Move request sent" << std::endl;
auto status = THUAI6Stub->Move(&context, request, &moveResult);
if (status.ok())
return moveResult.act_success();


+ 1
- 1
CAPI/cpp/API/src/logic.cpp View File

@@ -84,7 +84,7 @@ std::vector<std::vector<THUAI6::PlaceType>> Logic::GetFullMap() const
THUAI6::PlaceType Logic::GetPlaceType(int32_t cellX, int32_t cellY) const
{
std::unique_lock<std::mutex> lock(mtxState);
if (cellX < 0 || cellX >= currentState->gameMap.size() || cellY < 0 || cellY >= currentState->gameMap[0].size())
if (cellX < 0 || uint64_t(cellX) >= currentState->gameMap.size() || cellY < 0 || uint64_t(cellY) >= currentState->gameMap[0].size())
{
logger->warn("Invalid position!");
return THUAI6::PlaceType::NullPlaceType;


+ 0
- 1
CAPI/cpp/API/src/main.cpp View File

@@ -69,7 +69,6 @@ int THUAI6Main(int argc, char** argv, CreateAIFunc AIBuilder)
std::cerr << "Parsing error: " << e.error() << " for arg " << e.argId() << std::endl;
return 1;
}
std::cout << file << std::endl;
try
{
Logic logic(playerType, pID, trickerType, studentType);


+ 31
- 0
CAPI/cpp/CAPI.sln View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33424.131
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "API", "API\API.vcxproj", "{E1983CDE-00FA-474B-92DA-F4964660D7BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Debug|x64.ActiveCfg = Debug|x64
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Debug|x64.Build.0 = Debug|x64
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Debug|x86.ActiveCfg = Debug|Win32
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Debug|x86.Build.0 = Debug|Win32
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Release|x64.ActiveCfg = Release|x64
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Release|x64.Build.0 = Release|x64
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Release|x86.ActiveCfg = Release|Win32
{E1983CDE-00FA-474B-92DA-F4964660D7BA}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F032F3C-43BF-4F8F-B7F8-72A7354CF4A9}
EndGlobalSection
EndGlobal

+ 610
- 0
CAPI/cpp/grpc/LICENSE View File

@@ -0,0 +1,610 @@

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-----------------------------------------------------------

BSD 3-Clause License

Copyright 2016, Google Inc.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.

-----------------------------------------------------------

Mozilla Public License Version 2.0
==================================

1. Definitions
--------------

1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.

1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.

1.3. "Contribution"
means Covered Software of a particular Contributor.

1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.

1.5. "Incompatible With Secondary Licenses"
means

(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or

(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.

1.6. "Executable Form"
means any form of the work other than Source Code Form.

1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.

1.8. "License"
means this document.

1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.

1.10. "Modifications"
means any of the following:

(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or

(b) any new file in Source Code Form that contains any Covered
Software.

1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.

1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.

1.13. "Source Code Form"
means the form of the work preferred for making modifications.

1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.

2. License Grants and Conditions
--------------------------------

2.1. Grants

Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and

(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.

2.2. Effective Date

The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.

2.3. Limitations on Grant Scope

The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:

(a) for any code that a Contributor has removed from Covered Software;
or

(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or

(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.

This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).

2.4. Subsequent Licenses

No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).

2.5. Representation

Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.

2.6. Fair Use

This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.

2.7. Conditions

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.

3. Responsibilities
-------------------

3.1. Distribution of Source Form

All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.

3.2. Distribution of Executable Form

If You distribute Covered Software in Executable Form then:

(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and

(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work

You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).

3.4. Notices

You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.

3.5. Application of Additional Terms

You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.

4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------

If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.

5. Termination
--------------

5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.

************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************

************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************

8. Litigation
-------------

Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.

9. Miscellaneous
----------------

This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.

10. Versions of the License
---------------------------

10.1. New Versions

Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.

10.2. Effect of New Versions

You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.

10.3. Modified Versions

If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses

If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.

Exhibit A - Source Code Form License Notice
-------------------------------------------

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------

This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

+ 162
- 0
CAPI/cpp/grpc/include/absl/algorithm/algorithm.h View File

@@ -0,0 +1,162 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: algorithm.h
// -----------------------------------------------------------------------------
//
// This header file contains Google extensions to the standard <algorithm> C++
// header.

#ifndef ABSL_ALGORITHM_ALGORITHM_H_
#define ABSL_ALGORITHM_ALGORITHM_H_

#include <algorithm>
#include <iterator>
#include <type_traits>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

namespace algorithm_internal
{

// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`.
struct EqualTo
{
template<typename T, typename U>
bool operator()(const T& a, const U& b) const
{
return a == b;
}
};

template<typename InputIter1, typename InputIter2, typename Pred>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2, Pred pred, std::input_iterator_tag, std::input_iterator_tag)
{
while (true)
{
if (first1 == last1)
return first2 == last2;
if (first2 == last2)
return false;
if (!pred(*first1, *first2))
return false;
++first1;
++first2;
}
}

template<typename InputIter1, typename InputIter2, typename Pred>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2, Pred&& pred, std::random_access_iterator_tag, std::random_access_iterator_tag)
{
return (last1 - first1 == last2 - first2) &&
std::equal(first1, last1, first2, std::forward<Pred>(pred));
}

// When we are using our own internal predicate that just applies operator==, we
// forward to the non-predicate form of std::equal. This enables an optimization
// in libstdc++ that can result in std::memcmp being used for integer types.
template<typename InputIter1, typename InputIter2>
bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2, algorithm_internal::EqualTo /* unused */, std::random_access_iterator_tag, std::random_access_iterator_tag)
{
return (last1 - first1 == last2 - first2) &&
std::equal(first1, last1, first2);
}

template<typename It>
It RotateImpl(It first, It middle, It last, std::true_type)
{
return std::rotate(first, middle, last);
}

template<typename It>
It RotateImpl(It first, It middle, It last, std::false_type)
{
std::rotate(first, middle, last);
return std::next(first, std::distance(middle, last));
}

} // namespace algorithm_internal

// equal()
//
// Compares the equality of two ranges specified by pairs of iterators, using
// the given predicate, returning true iff for each corresponding iterator i1
// and i2 in the first and second range respectively, pred(*i1, *i2) == true
//
// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`)
// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are
// both random-access iterators, and `last1` - `first1` != `last2` - `first2`,
// then the predicate is never invoked and the function returns false.
//
// This is a C++11-compatible implementation of C++14 `std::equal`. See
// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
template<typename InputIter1, typename InputIter2, typename Pred>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2, Pred&& pred)
{
return algorithm_internal::EqualImpl(
first1, last1, first2, last2, std::forward<Pred>(pred), typename std::iterator_traits<InputIter1>::iterator_category{}, typename std::iterator_traits<InputIter2>::iterator_category{}
);
}

// Overload of equal() that performs comparison of two ranges specified by pairs
// of iterators using operator==.
template<typename InputIter1, typename InputIter2>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, InputIter2 last2)
{
return absl::equal(first1, last1, first2, last2, algorithm_internal::EqualTo{});
}

// linear_search()
//
// Performs a linear search for `value` using the iterator `first` up to
// but not including `last`, returning true if [`first`, `last`) contains an
// element equal to `value`.
//
// A linear search is of O(n) complexity which is guaranteed to make at most
// n = (`last` - `first`) comparisons. A linear search over short containers
// may be faster than a binary search, even when the container is sorted.
template<typename InputIterator, typename EqualityComparable>
bool linear_search(InputIterator first, InputIterator last, const EqualityComparable& value)
{
return std::find(first, last, value) != last;
}

// rotate()
//
// Performs a left rotation on a range of elements (`first`, `last`) such that
// `middle` is now the first element. `rotate()` returns an iterator pointing to
// the first element before rotation. This function is exactly the same as
// `std::rotate`, but fixes a bug in gcc
// <= 4.9 where `std::rotate` returns `void` instead of an iterator.
//
// The complexity of this algorithm is the same as that of `std::rotate`, but if
// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
// performs an additional pass over the range to construct the return value.
template<typename ForwardIterator>
ForwardIterator rotate(ForwardIterator first, ForwardIterator middle, ForwardIterator last)
{
return algorithm_internal::RotateImpl(
first, middle, last, std::is_same<decltype(std::rotate(first, middle, last)), ForwardIterator>()
);
}

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_ALGORITHM_ALGORITHM_H_

+ 1623
- 0
CAPI/cpp/grpc/include/absl/algorithm/container.h
File diff suppressed because it is too large
View File


+ 761
- 0
CAPI/cpp/grpc/include/absl/base/attributes.h View File

@@ -0,0 +1,761 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This header file defines macros for declaring attributes for functions,
// types, and variables.
//
// These macros are used within Abseil and allow the compiler to optimize, where
// applicable, certain function calls.
//
// Most macros here are exposing GCC or Clang features, and are stubbed out for
// other compilers.
//
// GCC attributes documentation:
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
//
// Most attributes in this file are already supported by GCC 4.7. However, some
// of them are not supported in older version of Clang. Thus, we check
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
// assume the attribute exists on GCC (which is verified on GCC 4.7).

#ifndef ABSL_BASE_ATTRIBUTES_H_
#define ABSL_BASE_ATTRIBUTES_H_

#include "absl/base/config.h"

// ABSL_HAVE_ATTRIBUTE
//
// A function-like feature checking macro that is a wrapper around
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
// nonzero constant integer if the attribute is supported or 0 if not.
//
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
//
// GCC: https://gcc.gnu.org/gcc-5/changes.html
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
#ifdef __has_attribute
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define ABSL_HAVE_ATTRIBUTE(x) 0
#endif

// ABSL_HAVE_CPP_ATTRIBUTE
//
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
#if defined(__cplusplus) && defined(__has_cpp_attribute)
// NOTE: requiring __cplusplus above should not be necessary, but
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
#endif

// -----------------------------------------------------------------------------
// Function Attributes
// -----------------------------------------------------------------------------
//
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
// Clang: https://clang.llvm.org/docs/AttributeReference.html

// ABSL_PRINTF_ATTRIBUTE
// ABSL_SCANF_ATTRIBUTE
//
// Tells the compiler to perform `printf` format string checking if the
// compiler supports it; see the 'format' attribute in
// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
// should be counted from two, not one."
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__printf__, string_index, first_to_check)))
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__scanf__, string_index, first_to_check)))
#else
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
#endif

// ABSL_ATTRIBUTE_ALWAYS_INLINE
// ABSL_ATTRIBUTE_NOINLINE
//
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
#else
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
#endif

#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
#else
#define ABSL_ATTRIBUTE_NOINLINE
#endif

// ABSL_ATTRIBUTE_NO_TAIL_CALL
//
// Prevents the compiler from optimizing away stack frames for functions which
// end in a call to another function.
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
__attribute__((optimize("no-optimize-sibling-calls")))
#else
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
#endif

// ABSL_ATTRIBUTE_WEAK
//
// Tags a function as weak for the purposes of compilation and linking.
// Weak attributes did not work properly in LLVM's Windows backend before
// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
// for further information.
// The MinGW compiler doesn't complain about the weak attribute until the link
// step, presumably because Windows doesn't use ELF binaries.
#if (ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__))) && \
(!defined(_WIN32) || (defined(__clang__) && __clang_major__ >= 9)) && \
!defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
#else
#define ABSL_ATTRIBUTE_WEAK
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
#endif

// ABSL_ATTRIBUTE_NONNULL
//
// Tells the compiler either (a) that a particular function parameter
// should be a non-null pointer, or (b) that all pointer arguments should
// be non-null.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
// should be counted from two, not one."
//
// Args are indexed starting at 1.
//
// For non-static class member functions, the implicit `this` argument
// is arg 1, and the first explicit argument is arg 2. For static class member
// functions, there is no implicit `this`, and the first explicit argument is
// arg 1.
//
// Example:
//
// /* arg_a cannot be null, but arg_b can */
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
//
// class C {
// /* arg_a cannot be null, but arg_b can */
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
//
// /* arg_a cannot be null, but arg_b can */
// static void StaticMethod(void* arg_a, void* arg_b)
// ABSL_ATTRIBUTE_NONNULL(1);
// };
//
// If no arguments are provided, then all pointer arguments should be non-null.
//
// /* No pointer arguments may be null. */
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
//
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
// ABSL_ATTRIBUTE_NONNULL does not.
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
#else
#define ABSL_ATTRIBUTE_NONNULL(...)
#endif

// ABSL_ATTRIBUTE_NORETURN
//
// Tells the compiler that a given function never returns.
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define ABSL_ATTRIBUTE_NORETURN
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
//
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
// function. Useful for cases when a function reads random locations on stack,
// calls _exit from a cloned subprocess, deliberately accesses buffer
// out of bounds or does other scary things with memory.
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#elif defined(_MSC_VER) && _MSC_VER >= 1928
// https://docs.microsoft.com/en-us/cpp/cpp/no-sanitize-address
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec(no_sanitize_address)
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
//
// Tells the MemorySanitizer to relax the handling of a given function. All "Use
// of uninitialized value" warnings from such functions will be suppressed, and
// all values loaded from memory will be considered fully initialized. This
// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
// above, but deals with initialized-ness rather than addressability issues.
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
//
// Tells the ThreadSanitizer to not instrument a given function.
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
//
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
// where certain behavior (eg. division by zero) is being used intentionally.
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
// https://gcc.gnu.org/gcc-4.9/changes.html
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize_undefined))
#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
//
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
#endif

// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
//
// Tells the SafeStack to not instrument a given function.
// See https://clang.llvm.org/docs/SafeStack.html for details.
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
__attribute__((no_sanitize("safe-stack")))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
#endif

// ABSL_ATTRIBUTE_RETURNS_NONNULL
//
// Tells the compiler that a particular function never returns a null pointer.
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull)
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
#endif

// ABSL_HAVE_ATTRIBUTE_SECTION
//
// Indicates whether labeled sections are supported. Weak symbol support is
// a prerequisite. Labeled sections are not supported on Darwin/iOS.
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (ABSL_HAVE_ATTRIBUTE(section) || (defined(__GNUC__) && !defined(__clang__))) && \
!defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
#define ABSL_HAVE_ATTRIBUTE_SECTION 1

// ABSL_ATTRIBUTE_SECTION
//
// Tells the compiler/linker to put a given function into a section and define
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
// This functionality is supported by GNU linker. Any function annotated with
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
// whatever section its caller is placed into.
//
#ifndef ABSL_ATTRIBUTE_SECTION
#define ABSL_ATTRIBUTE_SECTION(name) \
__attribute__((section(#name))) __attribute__((noinline))
#endif

// ABSL_ATTRIBUTE_SECTION_VARIABLE
//
// Tells the compiler/linker to put a given variable into a section and define
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
// This functionality is supported by GNU linker.
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
#ifdef _AIX
// __attribute__((section(#name))) on AIX is achived by using the `.csect` psudo
// op which includes an additional integer as part of its syntax indcating
// alignment. If data fall under different alignments then you might get a
// compilation error indicating a `Section type conflict`.
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
#else
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
#endif
#endif

// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
//
// A weak section declaration to be used as a global declaration
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
// a no-op on ELF but not on Mach-O.
//
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
#endif
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#endif

// ABSL_ATTRIBUTE_SECTION_START
//
// Returns `void*` pointers to start/end of a section of code with
// functions having ABSL_ATTRIBUTE_SECTION(name).
// Returns 0 if no such functions exist.
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
// link.
//
#define ABSL_ATTRIBUTE_SECTION_START(name) \
(reinterpret_cast<void*>(__start_##name))
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
(reinterpret_cast<void*>(__stop_##name))

#else // !ABSL_HAVE_ATTRIBUTE_SECTION

#define ABSL_HAVE_ATTRIBUTE_SECTION 0

// provide dummy definitions
#define ABSL_ATTRIBUTE_SECTION(name)
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(0))
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(0))

#endif // ABSL_ATTRIBUTE_SECTION

// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
//
// Support for aligning the stack on 32-bit x86.
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
(defined(__GNUC__) && !defined(__clang__))
#if defined(__i386__)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
__attribute__((force_align_arg_pointer))
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#elif defined(__x86_64__)
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#else // !__i386__ && !__x86_64
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#endif // __i386__
#else
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#endif

// ABSL_MUST_USE_RESULT
//
// Tells the compiler to warn about unused results.
//
// For code or headers that are assured to only build with C++17 and up, prefer
// just using the standard `[[nodiscard]]` directly over this macro.
//
// When annotating a function, it must appear as the first part of the
// declaration or definition. The compiler will warn if the return value from
// such a function is unused:
//
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
// AllocateSprocket(); // Triggers a warning.
//
// When annotating a class, it is equivalent to annotating every function which
// returns an instance.
//
// class ABSL_MUST_USE_RESULT Sprocket {};
// Sprocket(); // Triggers a warning.
//
// Sprocket MakeSprocket();
// MakeSprocket(); // Triggers a warning.
//
// Note that references and pointers are not instances:
//
// Sprocket* SprocketPointer();
// SprocketPointer(); // Does *not* trigger a warning.
//
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
// warning. For that, warn_unused_result is used only for clang but not for gcc.
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
//
// Note: past advice was to place the macro after the argument list.
//
// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is
// compliant with the stricter [[nodiscard]].
#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define ABSL_MUST_USE_RESULT
#endif

// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
//
// Tells GCC that a function is hot or cold. GCC can use this information to
// improve static analysis, i.e. a conditional branch to a cold function
// is likely to be not-taken.
// This annotation is used for function declarations.
//
// Example:
//
// int foo() ABSL_ATTRIBUTE_HOT;
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
#else
#define ABSL_ATTRIBUTE_HOT
#endif

#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
#else
#define ABSL_ATTRIBUTE_COLD
#endif

// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
//
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
// macro used as an attribute to mark functions that must always or never be
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
//
// For reference on the LLVM XRay instrumentation, see
// http://llvm.org/docs/XRay.html.
//
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
// will always get the XRay instrumentation sleds. These sleds may introduce
// some binary size and runtime overhead and must be used sparingly.
//
// These attributes only take effect when the following conditions are met:
//
// * The file/target is built in at least C++11 mode, with a Clang compiler
// that supports XRay attributes.
// * The file/target is built with the -fxray-instrument flag set for the
// Clang/LLVM compiler.
// * The function is defined in the translation unit (the compiler honors the
// attribute in either the definition or the declaration, and must match).
//
// There are cases when, even when building with XRay instrumentation, users
// might want to control specifically which functions are instrumented for a
// particular build using special-case lists provided to the compiler. These
// special case lists are provided to Clang via the
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
// attributes in source take precedence over these special-case lists.
//
// To disable the XRay attributes at build-time, users may define
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
// packages/targets, as this may lead to conflicting definitions of functions at
// link-time.
//
// XRay isn't currently supported on Android:
// https://github.com/android/ndk/issues/368
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
!defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
#define ABSL_XRAY_LOG_ARGS(N) \
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
#else
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
#endif
#else
#define ABSL_XRAY_ALWAYS_INSTRUMENT
#define ABSL_XRAY_NEVER_INSTRUMENT
#define ABSL_XRAY_LOG_ARGS(N)
#endif

// ABSL_ATTRIBUTE_REINITIALIZES
//
// Indicates that a member function reinitializes the entire object to a known
// state, independent of the previous state of the object.
//
// The clang-tidy check bugprone-use-after-move allows member functions marked
// with this attribute to be called on objects that have been moved from;
// without the attribute, this would result in a use-after-move warning.
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
#else
#define ABSL_ATTRIBUTE_REINITIALIZES
#endif

// -----------------------------------------------------------------------------
// Variable Attributes
// -----------------------------------------------------------------------------

// ABSL_ATTRIBUTE_UNUSED
//
// Prevents the compiler from complaining about variables that appear unused.
//
// For code or headers that are assured to only build with C++17 and up, prefer
// just using the standard '[[maybe_unused]]' directly over this macro.
//
// Due to differences in positioning requirements between the old, compiler
// specific __attribute__ syntax and the now standard [[maybe_unused]], this
// macro does not attempt to take advantage of '[[maybe_unused]]'.
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
#else
#define ABSL_ATTRIBUTE_UNUSED
#endif

// ABSL_ATTRIBUTE_INITIAL_EXEC
//
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
#else
#define ABSL_ATTRIBUTE_INITIAL_EXEC
#endif

// ABSL_ATTRIBUTE_PACKED
//
// Instructs the compiler not to use natural alignment for a tagged data
// structure, but instead to reduce its alignment to 1.
//
// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
// so can cause atomic variables to be mis-aligned and silently violate
// atomicity on x86.
//
// This attribute can either be applied to members of a structure or to a
// structure in its entirety. Applying this attribute (judiciously) to a
// structure in its entirety to optimize the memory footprint of very
// commonly-used structs is fine. Do not apply this attribute to a structure in
// its entirety if the purpose is to control the offsets of the members in the
// structure. Instead, apply this attribute only to structure members that need
// it.
//
// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
// natural alignment of structure members not annotated is preserved. Aligned
// member accesses are faster than non-aligned member accesses even if the
// targeted microprocessor supports non-aligned accesses.
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
#else
#define ABSL_ATTRIBUTE_PACKED
#endif

// ABSL_ATTRIBUTE_FUNC_ALIGN
//
// Tells the compiler to align the function start at least to certain
// alignment boundary
#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
#else
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif

// ABSL_FALLTHROUGH_INTENDED
//
// Annotates implicit fall-through between switch labels, allowing a case to
// indicate intentional fallthrough and turn off warnings about any lack of a
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
// a semicolon and can be used in most places where `break` can, provided that
// no statements exist between it and the next switch label.
//
// Example:
//
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
// // in comments
// } else {
// return x;
// }
// case 42:
// ...
//
// Notes: When supported, GCC and Clang can issue a warning on switch labels
// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See
// clang documentation on language extensions for details:
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
//
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has
// no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code.

#ifdef ABSL_FALLTHROUGH_INTENDED
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough)
#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]]
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough)
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough)
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#else
#define ABSL_FALLTHROUGH_INTENDED \
do \
{ \
} while (0)
#endif

// ABSL_DEPRECATED()
//
// Marks a deprecated class, struct, enum, function, method and variable
// declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative).
//
// For code or headers that are assured to only build with C++14 and up, prefer
// just using the standard `[[deprecated("message")]]` directly over this macro.
//
// Examples:
//
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
//
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
//
// template <typename T>
// ABSL_DEPRECATED("Use DoThat() instead")
// void DoThis();
//
// enum FooEnum {
// kBar ABSL_DEPRECATED("Use kBaz instead"),
// };
//
// Every usage of a deprecated entity will trigger a warning when compiled with
// GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain
// turns this warning off by default, instead relying on clang-tidy to report
// new uses of deprecated code.
#if ABSL_HAVE_ATTRIBUTE(deprecated)
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#else
#define ABSL_DEPRECATED(message)
#endif

// ABSL_CONST_INIT
//
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
// not compile (on supported platforms) unless the variable has a constant
// initializer. This is useful for variables with static and thread storage
// duration, because it guarantees that they will not suffer from the so-called
// "static init order fiasco".
//
// This attribute must be placed on the initializing declaration of the
// variable. Some compilers will give a -Wmissing-constinit warning when this
// attribute is placed on some other declaration but missing from the
// initializing declaration.
//
// In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can
// also be used in a non-initializing declaration to tell the compiler that a
// variable is already initialized, reducing overhead that would otherwise be
// incurred by a hidden guard variable. Thus annotating all declarations with
// this attribute is recommended to potentially enhance optimization.
//
// Example:
//
// class MyClass {
// public:
// ABSL_CONST_INIT static MyType my_var;
// };
//
// ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...);
//
// For code or headers that are assured to only build with C++20 and up, prefer
// just using the standard `constinit` keyword directly over this macro.
//
// Note that this attribute is redundant if the variable is declared constexpr.
#if defined(__cpp_constinit) && __cpp_constinit >= 201907L
#define ABSL_CONST_INIT constinit
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
#else
#define ABSL_CONST_INIT
#endif

// ABSL_ATTRIBUTE_PURE_FUNCTION
//
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
// functions. A function is pure if its return value is only a function of its
// arguments. The pure attribute prohibits a function from modifying the state
// of the program that is observable by means other than inspecting the
// function's return value. Declaring such functions with the pure attribute
// allows the compiler to avoid emitting some calls in repeated invocations of
// the function with the same argument values.
//
// Example:
//
// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
#elif ABSL_HAVE_ATTRIBUTE(pure)
#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
#else
#define ABSL_ATTRIBUTE_PURE_FUNCTION
#endif

// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function
// parameter or implicit object parameter is retained by the return value of the
// annotated function (or, for a parameter of a constructor, in the value of the
// constructed object). This attribute causes warnings to be produced if a
// temporary object does not live long enough.
//
// When applied to a reference parameter, the referenced object is assumed to be
// retained by the return value of the function. When applied to a non-reference
// parameter (for example, a pointer or a class type), all temporaries
// referenced by the parameter are assumed to be retained by the return value of
// the function.
//
// See also the upstream documentation:
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]]
#elif ABSL_HAVE_ATTRIBUTE(lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound))
#else
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
#endif

#endif // ABSL_BASE_ATTRIBUTES_H_

+ 234
- 0
CAPI/cpp/grpc/include/absl/base/call_once.h View File

@@ -0,0 +1,234 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: call_once.h
// -----------------------------------------------------------------------------
//
// This header file provides an Abseil version of `std::call_once` for invoking
// a given function at most once, across all threads. This Abseil version is
// faster than the C++11 version and incorporates the C++17 argument-passing
// fix, so that (for example) non-const references may be passed to the invoked
// function.

#ifndef ABSL_BASE_CALL_ONCE_H_
#define ABSL_BASE_CALL_ONCE_H_

#include <algorithm>
#include <atomic>
#include <cstdint>
#include <type_traits>
#include <utility>

#include "absl/base/internal/invoke.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock_wait.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

class once_flag;

namespace base_internal
{
std::atomic<uint32_t>* ControlWord(absl::once_flag* flag);
} // namespace base_internal

// call_once()
//
// For all invocations using a given `once_flag`, invokes a given `fn` exactly
// once across all threads. The first call to `call_once()` with a particular
// `once_flag` argument (that does not throw an exception) will run the
// specified function with the provided `args`; other calls with the same
// `once_flag` argument will not run the function, but will wait
// for the provided function to finish running (if it is still running).
//
// This mechanism provides a safe, simple, and fast mechanism for one-time
// initialization in a multi-threaded process.
//
// Example:
//
// class MyInitClass {
// public:
// ...
// mutable absl::once_flag once_;
//
// MyInitClass* init() const {
// absl::call_once(once_, &MyInitClass::Init, this);
// return ptr_;
// }
//
template<typename Callable, typename... Args>
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args);

// once_flag
//
// Objects of this type are used to distinguish calls to `call_once()` and
// ensure the provided function is only invoked once across all threads. This
// type is not copyable or movable. However, it has a `constexpr`
// constructor, and is safe to use as a namespace-scoped global variable.
class once_flag
{
public:
constexpr once_flag() :
control_(0)
{
}
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;

private:
friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag);
std::atomic<uint32_t> control_;
};

//------------------------------------------------------------------------------
// End of public interfaces.
// Implementation details follow.
//------------------------------------------------------------------------------

namespace base_internal
{

// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
// initialize entities used by the scheduler implementation.
template<typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args);

// Disables scheduling while on stack when scheduling mode is non-cooperative.
// No effect for cooperative scheduling modes.
class SchedulingHelper
{
public:
explicit SchedulingHelper(base_internal::SchedulingMode mode) :
mode_(mode)
{
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY)
{
guard_result_ = base_internal::SchedulingGuard::DisableRescheduling();
}
}

~SchedulingHelper()
{
if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY)
{
base_internal::SchedulingGuard::EnableRescheduling(guard_result_);
}
}

private:
base_internal::SchedulingMode mode_;
bool guard_result_;
};

// Bit patterns for call_once state machine values. Internal implementation
// detail, not for use by clients.
//
// The bit patterns are arbitrarily chosen from unlikely values, to aid in
// debugging. However, kOnceInit must be 0, so that a zero-initialized
// once_flag will be valid for immediate use.
enum
{
kOnceInit = 0,
kOnceRunning = 0x65C2937B,
kOnceWaiter = 0x05A308D2,
// A very small constant is chosen for kOnceDone so that it fit in a single
// compare with immediate instruction for most common ISAs. This is verified
// for x86, POWER and ARM.
kOnceDone = 221, // Random Number
};

template<typename Callable, typename... Args>
ABSL_ATTRIBUTE_NOINLINE void CallOnceImpl(std::atomic<uint32_t>* control, base_internal::SchedulingMode scheduling_mode, Callable&& fn, Args&&... args)
{
#ifndef NDEBUG
{
uint32_t old_control = control->load(std::memory_order_relaxed);
if (old_control != kOnceInit &&
old_control != kOnceRunning &&
old_control != kOnceWaiter &&
old_control != kOnceDone)
{
ABSL_RAW_LOG(FATAL, "Unexpected value for control word: 0x%lx",
static_cast<unsigned long>(old_control)); // NOLINT
}
}
#endif // NDEBUG
static const base_internal::SpinLockWaitTransition trans[] = {
{kOnceInit, kOnceRunning, true},
{kOnceRunning, kOnceWaiter, false},
{kOnceDone, kOnceDone, true}};

// Must do this before potentially modifying control word's state.
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
// Short circuit the simplest case to avoid procedure call overhead.
// The base_internal::SpinLockWait() call returns either kOnceInit or
// kOnceDone. If it returns kOnceDone, it must have loaded the control word
// with std::memory_order_acquire and seen a value of kOnceDone.
uint32_t old_control = kOnceInit;
if (control->compare_exchange_strong(old_control, kOnceRunning, std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, scheduling_mode) == kOnceInit)
{
base_internal::invoke(std::forward<Callable>(fn), std::forward<Args>(args)...);
old_control =
control->exchange(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter)
{
base_internal::SpinLockWake(control, true);
}
} // else *control is already kOnceDone
}

inline std::atomic<uint32_t>* ControlWord(once_flag* flag)
{
return &flag->control_;
}

template<typename Callable, typename... Args>
void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args)
{
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone))
{
base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY, std::forward<Callable>(fn), std::forward<Args>(args)...);
}
}

} // namespace base_internal

template<typename Callable, typename... Args>
void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args)
{
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone))
{
base_internal::CallOnceImpl(
once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL, std::forward<Callable>(fn), std::forward<Args>(args)...
);
}
}

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_CALL_ONCE_H_

+ 179
- 0
CAPI/cpp/grpc/include/absl/base/casts.h View File

@@ -0,0 +1,179 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: casts.h
// -----------------------------------------------------------------------------
//
// This header file defines casting templates to fit use cases not covered by
// the standard casts provided in the C++ standard. As with all cast operations,
// use these with caution and only if alternatives do not exist.

#ifndef ABSL_BASE_CASTS_H_
#define ABSL_BASE_CASTS_H_

#include <cstring>
#include <memory>
#include <type_traits>
#include <utility>

#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
#include <bit> // For std::bit_cast.
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L

#include "absl/base/internal/identity.h"
#include "absl/base/macros.h"
#include "absl/meta/type_traits.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

// implicit_cast()
//
// Performs an implicit conversion between types following the language
// rules for implicit conversion; if an implicit conversion is otherwise
// allowed by the language in the given context, this function performs such an
// implicit conversion.
//
// Example:
//
// // If the context allows implicit conversion:
// From from;
// To to = from;
//
// // Such code can be replaced by:
// implicit_cast<To>(from);
//
// An `implicit_cast()` may also be used to annotate numeric type conversions
// that, although safe, may produce compiler warnings (such as `long` to `int`).
// Additionally, an `implicit_cast()` is also useful within return statements to
// indicate a specific implicit conversion is being undertaken.
//
// Example:
//
// return implicit_cast<double>(size_in_bytes) / capacity_;
//
// Annotating code with `implicit_cast()` allows you to explicitly select
// particular overloads and template instantiations, while providing a safer
// cast than `reinterpret_cast()` or `static_cast()`.
//
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
// type hierarchy where incorrect use of `static_cast()` could accidentally
// allow downcasting.
//
// Finally, an `implicit_cast()` can be used to perform implicit conversions
// from unrelated types that otherwise couldn't be implicitly cast directly;
// C++ will normally only implicitly cast "one step" in such conversions.
//
// That is, if C is a type which can be implicitly converted to B, with B being
// a type that can be implicitly converted to A, an `implicit_cast()` can be
// used to convert C to B (which the compiler can then implicitly convert to A
// using language rules).
//
// Example:
//
// // Assume an object C is convertible to B, which is implicitly convertible
// // to A
// A a = implicit_cast<B>(C);
//
// Such implicit cast chaining may be useful within template logic.
template<typename To>
constexpr To implicit_cast(typename absl::internal::identity_t<To> to)
{
return to;
}

// bit_cast()
//
// Creates a value of the new type `Dest` whose representation is the same as
// that of the argument, which is of (deduced) type `Source` (a "bitwise cast";
// every bit in the value representation of the result is equal to the
// corresponding bit in the object representation of the source). Source and
// destination types must be of the same size, and both types must be trivially
// copyable.
//
// As with most casts, use with caution. A `bit_cast()` might be needed when you
// need to treat a value as the value of some other type, for example, to access
// the individual bits of an object which are not normally accessible through
// the object's type, such as for working with the binary representation of a
// floating point value:
//
// float f = 3.14159265358979;
// int i = bit_cast<int>(f);
// // i = 0x40490fdb
//
// Reinterpreting and accessing a value directly as a different type (as shown
// below) usually results in undefined behavior.
//
// Example:
//
// // WRONG
// float f = 3.14159265358979;
// int i = reinterpret_cast<int&>(f); // Wrong
// int j = *reinterpret_cast<int*>(&f); // Equally wrong
// int k = *bit_cast<int*>(&f); // Equally wrong
//
// Reinterpret-casting results in undefined behavior according to the ISO C++
// specification, section [basic.lval]. Roughly, this section says: if an object
// in memory has one type, and a program accesses it with a different type, the
// result is undefined behavior for most "different type".
//
// Using bit_cast on a pointer and then dereferencing it is no better than using
// reinterpret_cast. You should only use bit_cast on the value itself.
//
// Such casting results in type punning: holding an object in memory of one type
// and reading its bits back using a different type. A `bit_cast()` avoids this
// issue by copying the object representation to a new value, which avoids
// introducing this undefined behavior (since the original value is never
// accessed in the wrong way).
//
// The requirements of `absl::bit_cast` are more strict than that of
// `std::bit_cast` unless compiler support is available. Specifically, without
// compiler support, this implementation also requires `Dest` to be
// default-constructible. In C++20, `absl::bit_cast` is replaced by
// `std::bit_cast`.
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L

using std::bit_cast;

#else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L

template<typename Dest, typename Source, typename std::enable_if<sizeof(Dest) == sizeof(Source) && type_traits_internal::is_trivially_copyable<Source>::value && type_traits_internal::is_trivially_copyable<Dest>::value
#if !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
&& std::is_default_constructible<Dest>::value
#endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
,
int>::type = 0>
#if ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline constexpr Dest bit_cast(const Source& source)
{
return __builtin_bit_cast(Dest, source);
}
#else // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline Dest bit_cast(const Source& source)
{
Dest dest;
memcpy(static_cast<void*>(std::addressof(dest)), static_cast<const void*>(std::addressof(source)), sizeof(dest));
return dest;
}
#endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast)

#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_CASTS_H_

+ 908
- 0
CAPI/cpp/grpc/include/absl/base/config.h View File

@@ -0,0 +1,908 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: config.h
// -----------------------------------------------------------------------------
//
// This header file defines a set of macros for checking the presence of
// important compiler and platform features. Such macros can be used to
// produce portable code by parameterizing compilation based on the presence or
// lack of a given feature.
//
// We define a "feature" as some interface we wish to program to: for example,
// a library function or system call. A value of `1` indicates support for
// that feature; any other value indicates the feature support is undefined.
//
// Example:
//
// Suppose a programmer wants to write a program that uses the 'mmap()' system
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
// selectively include the `mmap.h` header and bracket code using that feature
// in the macro:
//
// #include "absl/base/config.h"
//
// #ifdef ABSL_HAVE_MMAP
// #include "sys/mman.h"
// #endif //ABSL_HAVE_MMAP
//
// ...
// #ifdef ABSL_HAVE_MMAP
// void *ptr = mmap(...);
// ...
// #endif // ABSL_HAVE_MMAP

#ifndef ABSL_BASE_CONFIG_H_
#define ABSL_BASE_CONFIG_H_

// Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h>

#ifdef __cplusplus
// Included for __GLIBCXX__, _LIBCPP_VERSION
#include <cstddef>
#endif // __cplusplus

// ABSL_INTERNAL_CPLUSPLUS_LANG
//
// MSVC does not set the value of __cplusplus correctly, but instead uses
// _MSVC_LANG as a stand-in.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
//
// However, there are reports that MSVC even sets _MSVC_LANG incorrectly at
// times, for example:
// https://github.com/microsoft/vscode-cpptools/issues/1770
// https://reviews.llvm.org/D70996
//
// For this reason, this symbol is considered INTERNAL and code outside of
// Abseil must not use it.
#if defined(_MSVC_LANG)
#define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG
#elif defined(__cplusplus)
#define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus
#endif

#if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0.
#include <Availability.h>
#include <TargetConditionals.h>
#endif

#include "absl/base/options.h"
#include "absl/base/policy_checks.h"

// Abseil long-term support (LTS) releases will define
// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the
// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the
// integer representing the patch-level for that release.
//
// For example, for LTS release version "20300401.2", this would give us
// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2
//
// These symbols will not be defined in non-LTS code.
//
// Abseil recommends that clients live-at-head. Therefore, if you are using
// these symbols to assert a minimum version requirement, we recommend you do it
// as
//
// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401
// #error Project foo requires Abseil LTS version >= 20300401
// #endif
//
// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes
// live-at-head clients from the minimum version assertion.
//
// See https://abseil.io/about/releases for more information on Abseil release
// management.
//
// LTS releases can be obtained from
// https://github.com/abseil/abseil-cpp/releases.
#define ABSL_LTS_RELEASE_VERSION 20220623
#define ABSL_LTS_RELEASE_PATCH_LEVEL 1

// Helper macro to convert a CPP variable to a string literal.
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)

// -----------------------------------------------------------------------------
// Abseil namespace annotations
// -----------------------------------------------------------------------------

// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
//
// An annotation placed at the beginning/end of each `namespace absl` scope.
// This is used to inject an inline namespace.
//
// The proper way to write Abseil code in the `absl` namespace is:
//
// namespace absl {
// ABSL_NAMESPACE_BEGIN
//
// void Foo(); // absl::Foo().
//
// ABSL_NAMESPACE_END
// } // namespace absl
//
// Users of Abseil should not use these macros, because users of Abseil should
// not write `namespace absl {` in their own code for any reason. (Abseil does
// not support forward declarations of its own types, nor does it support
// user-provided specialization of Abseil templates. Code that violates these
// rules may be broken without warning.)
#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
!defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
#error options.h is misconfigured.
#endif

// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1

#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)

static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0', "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
"not be empty.");
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' || ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' || ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' || ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0', "options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
"be changed to a new, unique identifier name.");

#endif

#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
#define ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_END
#define ABSL_INTERNAL_C_SYMBOL(x) x
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
#define ABSL_NAMESPACE_BEGIN \
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME \
{
#define ABSL_NAMESPACE_END }
#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
#define ABSL_INTERNAL_C_SYMBOL(x) \
ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
#else
#error options.h is misconfigured.
#endif

// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------

// ABSL_HAVE_BUILTIN()
//
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
// so, checks whether it supports the provided builtin function "x" where x
// is one of the functions noted in
// https://clang.llvm.org/docs/LanguageExtensions.html
//
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
#ifdef __has_builtin
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define ABSL_HAVE_BUILTIN(x) 0
#endif

#ifdef __has_feature
#define ABSL_HAVE_FEATURE(f) __has_feature(f)
#else
#define ABSL_HAVE_FEATURE(f) 0
#endif

// Portable check for GCC minimum version:
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0
#endif

#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \
(__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
#else
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
#endif

// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
// We assume __thread is supported on Linux or Asylo when compiled with Clang or
// compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined.
#ifdef ABSL_HAVE_TLS
#error ABSL_HAVE_TLS cannot be directly set
#elif (defined(__linux__) || defined(__ASYLO__)) && \
(defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
#define ABSL_HAVE_TLS 1
#endif

// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
//
// Checks whether `std::is_trivially_destructible<T>` is supported.
//
// Notes: All supported compilers using libc++ support this feature, as does
// gcc >= 4.8.1 using libstdc++, and Visual Studio.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \
(!defined(__clang__) && defined(__GLIBCXX__) && \
ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8))
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif

// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
//
// Checks whether `std::is_trivially_default_constructible<T>` and
// `std::is_trivially_copy_constructible<T>` are supported.

// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
//
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.

// Notes: Clang with libc++ supports these features, as does gcc >= 7.4 with
// libstdc++, or gcc >= 8.2 with libc++, and Visual Studio (but not NVCC).
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
(!defined(__clang__) && \
((ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && defined(__GLIBCXX__)) || \
(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(8, 2) && \
defined(_LIBCPP_VERSION)))) || \
(defined(_MSC_VER) && !defined(__NVCC__))
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif

// ABSL_HAVE_THREAD_LOCAL
//
// Checks whether C++11's `thread_local` storage duration specifier is
// supported.
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__)
// Notes:
// * Xcode's clang did not support `thread_local` until version 8, and
// even then not for all iOS < 9.0.
// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
// targeting iOS 9.x.
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
// making ABSL_HAVE_FEATURE unreliable there.
//
#if ABSL_HAVE_FEATURE(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif

// There are platforms for which TLS should not be used even though the compiler
// makes it seem like it's supported (Android NDK < r12b for example).
// This is primarily because of linker problems and toolchain misconfiguration:
// Abseil does not intend to support this indefinitely. Currently, the newest
// toolchain that we intend to support that requires this behavior is the
// r11 NDK - allowing for a 5 year support window on that means this option
// is likely to be removed around June of 2021.
// TLS isn't supported until NDK r12b per
// https://developer.android.com/ndk/downloads/revision_history.html
// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
// <android/ndk-version.h>. For NDK < r16, users should define these macros,
// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11.
#if defined(__ANDROID__) && defined(__clang__)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif // __has_include(<android/ndk-version.h>)
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
defined(__NDK_MINOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef ABSL_HAVE_TLS
#undef ABSL_HAVE_THREAD_LOCAL
#endif
#endif // defined(__ANDROID__) && defined(__clang__)

// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
// supported.
//
// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
// supported, but we avoid using it in certain cases:
// * On Clang:
// * Building using Clang for Windows, where the Clang runtime library has
// 128-bit support only on LP64 architectures, but Windows is LLP64.
// * On Nvidia's nvcc:
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
// actually support __int128.
#ifdef ABSL_HAVE_INTRINSIC_INT128
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
#if (defined(__clang__) && !defined(_WIN32)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define ABSL_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__)
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
// string explaining that it has been removed starting with CUDA 9. We use
// nested #ifs because there is no short-circuiting in the preprocessor.
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
#if __CUDACC_VER__ >= 70000
#define ABSL_HAVE_INTRINSIC_INT128 1
#endif // __CUDACC_VER__ >= 70000
#endif // defined(__CUDACC__)
#endif // ABSL_HAVE_INTRINSIC_INT128

// ABSL_HAVE_EXCEPTIONS
//
// Checks whether the compiler both supports and enables exceptions. Many
// compilers support a "no exceptions" mode that disables exceptions.
//
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
//
// * Code using `throw` and `try` may not compile.
// * The `noexcept` specifier will still compile and behave as normal.
// * The `noexcept` operator may still return `false`.
//
// For further details, consult the compiler's documentation.
#ifdef ABSL_HAVE_EXCEPTIONS
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
// Clang >= 3.6
#if ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
#endif // ABSL_HAVE_FEATURE(cxx_exceptions)
#elif defined(__clang__)
// Clang < 3.6
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
// Handle remaining special cases and default to exceptions being supported.
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
!(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) && \
!defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define ABSL_HAVE_EXCEPTIONS 1
#endif

// -----------------------------------------------------------------------------
// Platform Feature Checks
// -----------------------------------------------------------------------------

// Currently supported operating systems and associated preprocessor
// symbols:
//
// Linux and Linux-derived __linux__
// Android __ANDROID__ (implies __linux__)
// Linux (non-Android) __linux__ && !__ANDROID__
// Darwin (macOS and iOS) __APPLE__
// Akaros (http://akaros.org) __ros__
// Windows _WIN32
// NaCL __native_client__
// AsmJS __asmjs__
// WebAssembly __wasm__
// Fuchsia __Fuchsia__
//
// Note that since Android defines both __ANDROID__ and __linux__, one
// may probe for either Linux or Android by simply testing for __linux__.

// ABSL_HAVE_MMAP
//
// Checks whether the platform has an mmap(2) implementation as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_MMAP
#error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__native_client__) || \
defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \
defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \
defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__QNX__)
#define ABSL_HAVE_MMAP 1
#endif

// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
//
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
// functions as defined in POSIX.1-2001.
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \
defined(__NetBSD__)
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
#endif

// ABSL_HAVE_SCHED_GETCPU
//
// Checks whether sched_getcpu is available.
#ifdef ABSL_HAVE_SCHED_GETCPU
#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
#elif defined(__linux__)
#define ABSL_HAVE_SCHED_GETCPU 1
#endif

// ABSL_HAVE_SCHED_YIELD
//
// Checks whether the platform implements sched_yield(2) as defined in
// POSIX.1-2001.
#ifdef ABSL_HAVE_SCHED_YIELD
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__)
#define ABSL_HAVE_SCHED_YIELD 1
#endif

// ABSL_HAVE_SEMAPHORE_H
//
// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
// family of functions as standardized in POSIX.1-2001.
//
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
// explicitly deprecated and will cause build failures if enabled for those
// platforms. We side-step the issue by not defining it here for Apple
// platforms.
#ifdef ABSL_HAVE_SEMAPHORE_H
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
#elif defined(__linux__) || defined(__ros__)
#define ABSL_HAVE_SEMAPHORE_H 1
#endif

// ABSL_HAVE_ALARM
//
// Checks whether the platform supports the <signal.h> header and alarm(2)
// function as standardized in POSIX.1-2001.
#ifdef ABSL_HAVE_ALARM
#error ABSL_HAVE_ALARM cannot be directly set
#elif defined(__GOOGLE_GRTE_VERSION__)
// feature tests for Google's GRTE
#define ABSL_HAVE_ALARM 1
#elif defined(__GLIBC__)
// feature test for glibc
#define ABSL_HAVE_ALARM 1
#elif defined(_MSC_VER)
// feature tests for Microsoft's library
#elif defined(__MINGW32__)
// mingw32 doesn't provide alarm(2):
// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
// mingw-w64 provides a no-op implementation:
// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
#elif defined(__EMSCRIPTEN__)
// emscripten doesn't support signals
#elif defined(__Fuchsia__)
// Signals don't exist on fuchsia.
#elif defined(__native_client__)
#else
// other standard libraries
#define ABSL_HAVE_ALARM 1
#endif

// ABSL_IS_LITTLE_ENDIAN
// ABSL_IS_BIG_ENDIAN
//
// Checks the endianness of the platform.
//
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
// Clang (since 3.2); see
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
#if defined(ABSL_IS_BIG_ENDIAN)
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
#endif
#if defined(ABSL_IS_LITTLE_ENDIAN)
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
#endif

#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define ABSL_IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define ABSL_IS_BIG_ENDIAN 1
#elif defined(_WIN32)
#define ABSL_IS_LITTLE_ENDIAN 1
#else
#error "absl endian detection needs to be set up for your compiler"
#endif

// macOS < 10.13 and iOS < 11 don't let you use <any>, <optional>, or <variant>
// even though the headers exist and are publicly noted to work, because the
// libc++ shared library shipped on the system doesn't have the requisite
// exported symbols. See https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
//
// libc++ spells out the availability requirements in the file
// llvm-project/libcxx/include/__config via the #define
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
//
// Unfortunately, Apple initially mis-stated the requirements as macOS < 10.14
// and iOS < 12 in the libc++ headers. This was corrected by
// https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953
// which subsequently made it into the XCode 12.5 release. We need to match the
// old (incorrect) conditions when built with old XCode, but can use the
// corrected earlier versions with new XCode.
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
((_LIBCPP_VERSION >= 11000 && /* XCode 12.5 or later: */ \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 110000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 40000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 110000))) || \
(_LIBCPP_VERSION < 11000 && /* Pre-XCode 12.5: */ \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
#endif

// ABSL_HAVE_STD_ANY
//
// Checks whether C++17 std::any is available by checking whether <any> exists.
#ifdef ABSL_HAVE_STD_ANY
#error "ABSL_HAVE_STD_ANY cannot be directly set."
#endif

#ifdef __has_include
#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_ANY 1
#endif
#endif

// ABSL_HAVE_STD_OPTIONAL
//
// Checks whether C++17 std::optional is available.
#ifdef ABSL_HAVE_STD_OPTIONAL
#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
#endif

#ifdef __has_include
#if __has_include(<optional>) && defined(__cplusplus) && \
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_OPTIONAL 1
#endif
#endif

// ABSL_HAVE_STD_VARIANT
//
// Checks whether C++17 std::variant is available.
#ifdef ABSL_HAVE_STD_VARIANT
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
#endif

#ifdef __has_include
#if __has_include(<variant>) && defined(__cplusplus) && \
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_VARIANT 1
#endif
#endif

// ABSL_HAVE_STD_STRING_VIEW
//
// Checks whether C++17 std::string_view is available.
#ifdef ABSL_HAVE_STD_STRING_VIEW
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
#endif

#ifdef __has_include
#if __has_include(<string_view>) && defined(__cplusplus) && \
__cplusplus >= 201703L
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
#endif

// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than
// the support for <optional>, <any>, <string_view>, <variant>. So we use
// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>,
// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
// version.
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \
(defined(__cplusplus) && __cplusplus > 201402))
// #define ABSL_HAVE_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif

// ABSL_USES_STD_ANY
//
// Indicates whether absl::any is an alias for std::any.
#if !defined(ABSL_OPTION_USE_STD_ANY)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_ANY == 0 || \
(ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
#undef ABSL_USES_STD_ANY
#elif ABSL_OPTION_USE_STD_ANY == 1 || \
(ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
#define ABSL_USES_STD_ANY 1
#else
#error options.h is misconfigured.
#endif

// ABSL_USES_STD_OPTIONAL
//
// Indicates whether absl::optional is an alias for std::optional.
#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
#undef ABSL_USES_STD_OPTIONAL
#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
#define ABSL_USES_STD_OPTIONAL 1
#else
#error options.h is misconfigured.
#endif

// ABSL_USES_STD_VARIANT
//
// Indicates whether absl::variant is an alias for std::variant.
#if !defined(ABSL_OPTION_USE_STD_VARIANT)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
(ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
#undef ABSL_USES_STD_VARIANT
#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
(ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
#define ABSL_USES_STD_VARIANT 1
#else
#error options.h is misconfigured.
#endif

// ABSL_USES_STD_STRING_VIEW
//
// Indicates whether absl::string_view is an alias for std::string_view.
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
#error options.h is misconfigured.
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
!defined(ABSL_HAVE_STD_STRING_VIEW))
#undef ABSL_USES_STD_STRING_VIEW
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
defined(ABSL_HAVE_STD_STRING_VIEW))
#define ABSL_USES_STD_STRING_VIEW 1
#else
#error options.h is misconfigured.
#endif

// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
// SEH exception from emplace for variant<SomeStruct> when constructing the
// struct can throw. This defeats some of variant_test and
// variant_exception_safety_test.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
#endif

// ABSL_INTERNAL_MANGLED_NS
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
//
// Internal macros for building up mangled names in our internal fork of CCTZ.
// This implementation detail is only needed and provided for the MSVC build.
//
// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
// the mangled spelling of the `absl` namespace, and
// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
// the proper count to skip past the CCTZ fork namespace names. (This number
// is one larger when there is an inline namespace name to skip.)
#if defined(_MSC_VER)
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
#define ABSL_INTERNAL_MANGLED_NS "absl"
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
#else
#define ABSL_INTERNAL_MANGLED_NS \
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) \
"@absl"
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
#endif
#endif

// ABSL_DLL
//
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
// so we can annotate symbols appropriately as being exported. When used in
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
// that consumers know the symbol is defined inside the DLL. In all other cases,
// the macro expands to nothing.
#if defined(_MSC_VER)
#if defined(ABSL_BUILD_DLL)
#define ABSL_DLL __declspec(dllexport)
#elif defined(ABSL_CONSUME_DLL)
#define ABSL_DLL __declspec(dllimport)
#else
#define ABSL_DLL
#endif
#else
#define ABSL_DLL
#endif // defined(_MSC_VER)

// ABSL_HAVE_MEMORY_SANITIZER
//
// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
// a compiler instrumentation module and a run-time library.
#ifdef ABSL_HAVE_MEMORY_SANITIZER
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
#define ABSL_HAVE_MEMORY_SANITIZER 1
#endif

// ABSL_HAVE_THREAD_SANITIZER
//
// ThreadSanitizer (TSan) is a fast data race detector.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_THREAD__)
#define ABSL_HAVE_THREAD_SANITIZER 1
#elif ABSL_HAVE_FEATURE(thread_sanitizer)
#define ABSL_HAVE_THREAD_SANITIZER 1
#endif

// ABSL_HAVE_ADDRESS_SANITIZER
//
// AddressSanitizer (ASan) is a fast memory error detector.
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_ADDRESS__)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(address_sanitizer)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#endif

// ABSL_HAVE_HWADDRESS_SANITIZER
//
// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan
// memory error detector which can use CPU features like ARM TBI, Intel LAM or
// AMD UAI.
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_HWADDRESS__)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#endif

// ABSL_HAVE_LEAK_SANITIZER
//
// LeakSanitizer (or lsan) is a detector of memory leaks.
// https://clang.llvm.org/docs/LeakSanitizer.html
// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
//
// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time
// whether the LeakSanitizer is potentially available. However, just because the
// LeakSanitizer is available does not mean it is active. Use the
// always-available run-time interface in //absl/debugging/leak_check.h for
// interacting with LeakSanitizer.
#ifdef ABSL_HAVE_LEAK_SANITIZER
#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set."
#elif defined(LEAK_SANITIZER)
// GCC provides no method for detecting the presense of the standalone
// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also
// use -DLEAK_SANITIZER.
#define ABSL_HAVE_LEAK_SANITIZER 1
// Clang standalone LeakSanitizer (-fsanitize=leak)
#elif ABSL_HAVE_FEATURE(leak_sanitizer)
#define ABSL_HAVE_LEAK_SANITIZER 1
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER)
// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer.
#define ABSL_HAVE_LEAK_SANITIZER 1
#endif

// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
//
// Class template argument deduction is a language feature added in C++17.
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
#elif defined(__cpp_deduction_guides)
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
#endif

// ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
//
// Prior to C++17, static constexpr variables defined in classes required a
// separate definition outside of the class body, for example:
//
// class Foo {
// static constexpr int kBar = 0;
// };
// constexpr int Foo::kBar;
//
// In C++17, these variables defined in classes are considered inline variables,
// and the extra declaration is redundant. Since some compilers warn on the
// extra declarations, ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL can be used
// conditionally ignore them:
//
// #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
// constexpr int Foo::kBar;
// #endif
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
#define ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
#endif

// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
// RTTI support.
#ifdef ABSL_INTERNAL_HAS_RTTI
#error ABSL_INTERNAL_HAS_RTTI cannot be directly set
#elif !defined(__GNUC__) || defined(__GXX_RTTI)
#define ABSL_INTERNAL_HAS_RTTI 1
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)

// ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE
#error ABSL_INTERNAL_HAVE_SSE cannot be directly set
#elif defined(__SSE__)
#define ABSL_INTERNAL_HAVE_SSE 1
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1
// indicates that at least SSE was targeted with the /arch:SSE option.
// All x86-64 processors support SSE, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE 1
#endif

// ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE2
#error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set
#elif defined(__SSE2__)
#define ABSL_INTERNAL_HAVE_SSE2 1
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2
// indicates that at least SSE2 was targeted with the /arch:SSE2 option.
// All x86-64 processors support SSE2, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE2 1
#endif

// ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
//
// MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3
// with MSVC requires either assuming that the code will only every run on CPUs
// that support SSSE3, otherwise __cpuid() can be used to detect support at
// runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported
// by the CPU.
#ifdef ABSL_INTERNAL_HAVE_SSSE3
#error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set
#elif defined(__SSSE3__)
#define ABSL_INTERNAL_HAVE_SSSE3 1
#endif

// ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM
// SIMD).
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
#elif defined(__ARM_NEON)
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
#endif

#endif // ABSL_BASE_CONFIG_H_

+ 78
- 0
CAPI/cpp/grpc/include/absl/base/const_init.h View File

@@ -0,0 +1,78 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// kConstInit
// -----------------------------------------------------------------------------
//
// A constructor tag used to mark an object as safe for use as a global
// variable, avoiding the usual lifetime issues that can affect globals.

#ifndef ABSL_BASE_CONST_INIT_H_
#define ABSL_BASE_CONST_INIT_H_

#include "absl/base/config.h"

// In general, objects with static storage duration (such as global variables)
// can trigger tricky object lifetime situations. Attempting to access them
// from the constructors or destructors of other global objects can result in
// undefined behavior, unless their constructors and destructors are designed
// with this issue in mind.
//
// The normal way to deal with this issue in C++11 is to use constant
// initialization and trivial destructors.
//
// Constant initialization is guaranteed to occur before any other code
// executes. Constructors that are declared 'constexpr' are eligible for
// constant initialization. You can annotate a variable declaration with the
// ABSL_CONST_INIT macro to express this intent. For compilers that support
// it, this annotation will cause a compilation error for declarations that
// aren't subject to constant initialization (perhaps because a runtime value
// was passed as a constructor argument).
//
// On program shutdown, lifetime issues can be avoided on global objects by
// ensuring that they contain trivial destructors. A class has a trivial
// destructor unless it has a user-defined destructor, a virtual method or base
// class, or a data member or base class with a non-trivial destructor of its
// own. Objects with static storage duration and a trivial destructor are not
// cleaned up on program shutdown, and are thus safe to access from other code
// running during shutdown.
//
// For a few core Abseil classes, we make a best effort to allow for safe global
// instances, even though these classes have non-trivial destructors. These
// objects can be created with the absl::kConstInit tag. For example:
// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
//
// The line above declares a global variable of type absl::Mutex which can be
// accessed at any point during startup or shutdown. global_mutex's destructor
// will still run, but will not invalidate the object. Note that C++ specifies
// that accessing an object after its destructor has run results in undefined
// behavior, but this pattern works on the toolchains we support.
//
// The absl::kConstInit tag should only be used to define objects with static
// or thread_local storage duration.

namespace absl
{
ABSL_NAMESPACE_BEGIN

enum ConstInitType
{
kConstInit,
};

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_CONST_INIT_H_

+ 487
- 0
CAPI/cpp/grpc/include/absl/base/dynamic_annotations.h View File

@@ -0,0 +1,487 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file defines dynamic annotations for use with dynamic analysis tool
// such as valgrind, PIN, etc.
//
// Dynamic annotation is a source code annotation that affects the generated
// code (that is, the annotation is not a comment). Each such annotation is
// attached to a particular instruction and/or to a particular object (address)
// in the program.
//
// The annotations that should be used by users are macros in all upper-case
// (e.g., ABSL_ANNOTATE_THREAD_NAME).
//
// Actual implementation of these macros may differ depending on the dynamic
// analysis tool being used.
//
// This file supports the following configurations:
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
// In this case, macros expand to functions implemented by Thread Sanitizer,
// when building with TSan. When not provided an external implementation,
// dynamic_annotations.cc provides no-op implementations.
//
// - Static Clang thread-safety warnings enabled.
// When building with a Clang compiler that supports thread-safety warnings,
// a subset of annotations can be statically-checked at compile-time. We
// expand these macros to static-inline functions that can be analyzed for
// thread-safety, but afterwards elided when building the final binary.
//
// - All annotations are disabled.
// If neither Dynamic Annotations nor Clang thread-safety warnings are
// enabled, then all annotation-macros expand to empty.

#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_

#include <stddef.h>

#include "absl/base/attributes.h"
#include "absl/base/config.h"
#ifdef __cplusplus
#include "absl/base/macros.h"
#endif

// TODO(rogeeff): Remove after the backward compatibility period.
#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export

// -------------------------------------------------------------------------
// Decide which features are enabled.

#ifdef ABSL_HAVE_THREAD_SANITIZER

#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1

#else

#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0

// Clang provides limited support for static thread-safety analysis through a
// feature called Annotalysis. We configure macro-definitions according to
// whether Annotalysis support is available. When running in opt-mode, GCC
// will issue a warning, if these attributes are compiled. Only include them
// when compiling using Clang.

#if defined(__clang__)
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
#if !defined(SWIG)
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
#endif
#else
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
#endif

// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
ABSL_INTERNAL_ANNOTALYSIS_ENABLED

#endif // ABSL_HAVE_THREAD_SANITIZER

#ifdef __cplusplus
#define ABSL_INTERNAL_BEGIN_EXTERN_C \
extern "C" \
{
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
#define ABSL_INTERNAL_STATIC_INLINE inline
#else
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
#define ABSL_INTERNAL_END_EXTERN_C // empty
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
#define ABSL_INTERNAL_STATIC_INLINE static inline
#endif

// -------------------------------------------------------------------------
// Define race annotations.

#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
// defined by the compiler-based santizer implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.

// -------------------------------------------------------------
// Annotations that suppress errors. It is usually better to express the
// program's synchronization using the other annotations, but these can be used
// when all else fails.

// Report that we may have a benign race at `pointer`, with size
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
// point where `pointer` has been allocated, preferably close to the point
// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)

// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
// the memory range [`address`, `address`+`size`).
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, address, size, description)

// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
// This annotation could be useful if you want to skip expensive race analysis
// during some period of program execution, e.g. during initialization.
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
(__FILE__, __LINE__, enable)

// -------------------------------------------------------------
// Annotations useful for debugging.

// Report the current thread `name` to a race detector.
#define ABSL_ANNOTATE_THREAD_NAME(name) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName) \
(__FILE__, __LINE__, name)

// -------------------------------------------------------------
// Annotations useful when implementing locks. They are not normally needed by
// modules that merely use locks. The `lock` argument is a pointer to the lock
// object.

// Report that a lock has been created at address `lock`.
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate) \
(__FILE__, __LINE__, lock)

// Report that a linker initialized lock has been created at address `lock`.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
(__FILE__, __LINE__, lock)
#else
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
ABSL_ANNOTATE_RWLOCK_CREATE(lock)
#endif

// Report that the lock at address `lock` is about to be destroyed.
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy) \
(__FILE__, __LINE__, lock)

// Report that the lock at address `lock` has been acquired.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
(__FILE__, __LINE__, lock, is_w)

// Report that the lock at address `lock` is about to be released.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
(__FILE__, __LINE__, lock, is_w)

// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
namespace \
{ \
class static_var##_annotator \
{ \
public: \
static_var##_annotator() \
{ \
ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), #static_var ": " description); \
} \
}; \
static static_var##_annotator the##static_var##_annotator; \
} // namespace

// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateRWLockCreate(const char* file, int line, const volatile void* lock);
void AnnotateRWLockCreateStatic(const char* file, int line, const volatile void* lock);
void AnnotateRWLockDestroy(const char* file, int line, const volatile void* lock);
void AnnotateRWLockAcquired(const char* file, int line, const volatile void* lock, long is_w); // NOLINT
void AnnotateRWLockReleased(const char* file, int line, const volatile void* lock, long is_w); // NOLINT
void AnnotateBenignRace(const char* file, int line, const volatile void* address, const char* description);
void AnnotateBenignRaceSized(const char* file, int line, const volatile void* address, size_t size, const char* description);
void AnnotateThreadName(const char* file, int line, const char* name);
void AnnotateEnableRaceDetection(const char* file, int line, int enable);
ABSL_INTERNAL_END_EXTERN_C

#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0

#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
#define ABSL_ANNOTATE_THREAD_NAME(name) // empty
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty

#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED

// -------------------------------------------------------------------------
// Define memory annotations.

#ifdef ABSL_HAVE_MEMORY_SANITIZER

#include <sanitizer/msan_interface.h>

#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
__msan_unpoison(address, size)

#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
__msan_allocated_memory(address, size)

#else // !defined(ABSL_HAVE_MEMORY_SANITIZER)

// TODO(rogeeff): remove this branch
#ifdef ABSL_HAVE_THREAD_SANITIZER
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
do \
{ \
(void)(address); \
(void)(size); \
} while (0)
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
do \
{ \
(void)(address); \
(void)(size); \
} while (0)
#else

#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty

#endif

#endif // ABSL_HAVE_MEMORY_SANITIZER

// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END attributes.

#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
__attribute((exclusive_lock_function("*")))
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
__attribute((unlock_function("*")))

#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty

#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END annotations.

#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
// defined by the compiler-based implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.

// Request the analysis tool to ignore all reads in the current thread until
// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
// reads, while still checking other reads and all writes.
// See also ABSL_ANNOTATE_UNPROTECTED_READ.
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
(__FILE__, __LINE__)

// Stop ignoring reads.
#define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
(__FILE__, __LINE__)

// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateIgnoreReadsBegin(const char* file, int line)
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
void AnnotateIgnoreReadsEnd(const char* file, int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
ABSL_INTERNAL_END_EXTERN_C

#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)

// When Annotalysis is enabled without Dynamic Annotations, the use of
// static-inline functions allows the annotations to be read at compile-time,
// while still letting the compiler elide the functions from the final build.
//
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
// allows IGNORE_READS_AND_WRITES to work properly.

#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED( \
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin) \
) \
()

#define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED( \
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd) \
) \
()

ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
AbslInternalAnnotateIgnoreReadsBegin
)()
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE
{
}

ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
AbslInternalAnnotateIgnoreReadsEnd
)()
ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE
{
}

#else

#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_READS_END() // empty

#endif

// -------------------------------------------------------------------------
// Define IGNORE_WRITES_BEGIN/_END annotations.

#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1

// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin) \
(__FILE__, __LINE__)

// Stop ignoring writes.
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd) \
(__FILE__, __LINE__)

// Function prototypes of annotations provided by the compiler-based sanitizer
// implementation.
ABSL_INTERNAL_BEGIN_EXTERN_C
void AnnotateIgnoreWritesBegin(const char* file, int line);
void AnnotateIgnoreWritesEnd(const char* file, int line);
ABSL_INTERNAL_END_EXTERN_C

#else

#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty

#endif

// -------------------------------------------------------------------------
// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
// primitive annotations defined above.
//
// Instead of doing
// ABSL_ANNOTATE_IGNORE_READS_BEGIN();
// ... = x;
// ABSL_ANNOTATE_IGNORE_READS_END();
// one can use
// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);

#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)

// Start ignoring all memory accesses (both reads and writes).
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
do \
{ \
ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
} while (0)

// Stop ignoring both reads and writes.
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
do \
{ \
ABSL_ANNOTATE_IGNORE_WRITES_END(); \
ABSL_ANNOTATE_IGNORE_READS_END(); \
} while (0)

#ifdef __cplusplus
// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
absl::base_internal::AnnotateUnprotectedRead(x)

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

template<typename T>
inline T AnnotateUnprotectedRead(const volatile T& x)
{ // NOLINT
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
T res = x;
ABSL_ANNOTATE_IGNORE_READS_END();
return res;
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif

#else

#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)

#endif

// -------------------------------------------------------------------------
// Address sanitizer annotations

#ifdef ABSL_HAVE_ADDRESS_SANITIZER
// Describe the current state of a contiguous container such as e.g.
// std::vector or std::string. For more details see
// sanitizer/common_interface_defs.h, which is provided by the compiler.
#include <sanitizer/common_interface_defs.h>

#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
struct \
{ \
alignas(8) char x[8]; \
} name

#else

#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")

#endif // ABSL_HAVE_ADDRESS_SANITIZER

// -------------------------------------------------------------------------
// Undefine the macros intended only for this file.

#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
#undef ABSL_INTERNAL_END_EXTERN_C
#undef ABSL_INTERNAL_STATIC_INLINE

#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_

+ 225
- 0
CAPI/cpp/grpc/include/absl/base/internal/atomic_hook.h View File

@@ -0,0 +1,225 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_

#include <atomic>
#include <cassert>
#include <cstdint>
#include <utility>

#include "absl/base/attributes.h"
#include "absl/base/config.h"

#if defined(_MSC_VER) && !defined(__clang__)
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
#else
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
#endif

#if defined(_MSC_VER)
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
#else
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

template<typename T>
class AtomicHook;

// To workaround AtomicHook not being constant-initializable on some platforms,
// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
// instead of `ABSL_CONST_INIT`.
#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
#else
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
#endif

// `AtomicHook` is a helper class, templatized on a raw function pointer type,
// for implementing Abseil customization hooks. It is a callable object that
// dispatches to the registered hook. Objects of type `AtomicHook` must have
// static or thread storage duration.
//
// A default constructed object performs a no-op (and returns a default
// constructed object) if no hook has been registered.
//
// Hooks can be pre-registered via constant initialization, for example:
//
// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
// my_hook(DefaultAction);
//
// and then changed at runtime via a call to `Store()`.
//
// Reads and writes guarantee memory_order_acquire/memory_order_release
// semantics.
template<typename ReturnType, typename... Args>
class AtomicHook<ReturnType (*)(Args...)>
{
public:
using FnPtr = ReturnType (*)(Args...);

// Constructs an object that by default performs a no-op (and
// returns a default constructed object) when no hook as been registered.
constexpr AtomicHook() :
AtomicHook(DummyFunction)
{
}

// Constructs an object that by default dispatches to/returns the
// pre-registered default_fn when no hook has been registered at runtime.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn) :
hook_(default_fn),
default_fn_(default_fn)
{
}
#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
explicit constexpr AtomicHook(FnPtr default_fn) :
hook_(kUninitialized),
default_fn_(default_fn)
{
}
#else
// As of January 2020, on all known versions of MSVC this constructor runs in
// the global constructor sequence. If `Store()` is called by a dynamic
// initializer, we want to preserve the value, even if this constructor runs
// after the call to `Store()`. If not, `hook_` will be
// zero-initialized by the linker and we have no need to set it.
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
explicit constexpr AtomicHook(FnPtr default_fn) :
/* hook_(deliberately omitted), */ default_fn_(default_fn)
{
static_assert(kUninitialized == 0, "here we rely on zero-initialization");
}
#endif

// Stores the provided function pointer as the value for this hook.
//
// This is intended to be called once. Multiple calls are legal only if the
// same function pointer is provided for each call. The store is implemented
// as a memory_order_release operation, and read accesses are implemented as
// memory_order_acquire.
void Store(FnPtr fn)
{
bool success = DoStore(fn);
static_cast<void>(success);
assert(success);
}

// Invokes the registered callback. If no callback has yet been registered, a
// default-constructed object of the appropriate type is returned instead.
template<typename... CallArgs>
ReturnType operator()(CallArgs&&... args) const
{
return DoLoad()(std::forward<CallArgs>(args)...);
}

// Returns the registered callback, or nullptr if none has been registered.
// Useful if client code needs to conditionalize behavior based on whether a
// callback was registered.
//
// Note that atomic_hook.Load()() and atomic_hook() have different semantics:
// operator()() will perform a no-op if no callback was registered, while
// Load()() will dereference a null function pointer. Prefer operator()() to
// Load()() unless you must conditionalize behavior on whether a hook was
// registered.
FnPtr Load() const
{
FnPtr ptr = DoLoad();
return (ptr == DummyFunction) ? nullptr : ptr;
}

private:
static ReturnType DummyFunction(Args...)
{
return ReturnType();
}

// Current versions of MSVC (as of September 2017) have a broken
// implementation of std::atomic<T*>: Its constructor attempts to do the
// equivalent of a reinterpret_cast in a constexpr context, which is not
// allowed.
//
// This causes an issue when building with LLVM under Windows. To avoid this,
// we use a less-efficient, intptr_t-based implementation on Windows.
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
// Return the stored value, or DummyFunction if no value has been stored.
FnPtr DoLoad() const
{
return hook_.load(std::memory_order_acquire);
}

// Store the given value. Returns false if a different value was already
// stored to this object.
bool DoStore(FnPtr fn)
{
assert(fn);
FnPtr expected = default_fn_;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire
);
const bool same_value_already_stored = (expected == fn);
return store_succeeded || same_value_already_stored;
}

std::atomic<FnPtr> hook_;
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
// Use a sentinel value unlikely to be the address of an actual function.
static constexpr intptr_t kUninitialized = 0;

static_assert(sizeof(intptr_t) >= sizeof(FnPtr), "intptr_t can't contain a function pointer");

FnPtr DoLoad() const
{
const intptr_t value = hook_.load(std::memory_order_acquire);
if (value == kUninitialized)
{
return default_fn_;
}
return reinterpret_cast<FnPtr>(value);
}

bool DoStore(FnPtr fn)
{
assert(fn);
const auto value = reinterpret_cast<intptr_t>(fn);
intptr_t expected = kUninitialized;
const bool store_succeeded = hook_.compare_exchange_strong(
expected, value, std::memory_order_acq_rel, std::memory_order_acquire
);
const bool same_value_already_stored = (expected == value);
return store_succeeded || same_value_already_stored;
}

std::atomic<intptr_t> hook_;
#endif

const FnPtr default_fn_;
};

#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_

+ 36
- 0
CAPI/cpp/grpc/include/absl/base/internal/atomic_hook_test_helper.h View File

@@ -0,0 +1,36 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
#define ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_

#include "absl/base/internal/atomic_hook.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace atomic_hook_internal
{

using VoidF = void (*)();
extern absl::base_internal::AtomicHook<VoidF> func;
extern int default_func_calls;
void DefaultFunc();
void RegisterFunc(VoidF func);

} // namespace atomic_hook_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_

+ 168
- 0
CAPI/cpp/grpc/include/absl/base/internal/cycleclock.h View File

@@ -0,0 +1,168 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// -----------------------------------------------------------------------------
// File: cycleclock.h
// -----------------------------------------------------------------------------
//
// This header file defines a `CycleClock`, which yields the value and frequency
// of a cycle counter that increments at a rate that is approximately constant.
//
// NOTE:
//
// The cycle counter frequency is not necessarily related to the core clock
// frequency and should not be treated as such. That is, `CycleClock` cycles are
// not necessarily "CPU cycles" and code should not rely on that behavior, even
// if experimentally observed.
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.

#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_

#include <atomic>
#include <cstdint>

#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/unscaledcycleclock.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

using CycleClockSourceFunc = int64_t (*)();

// -----------------------------------------------------------------------------
// CycleClock
// -----------------------------------------------------------------------------
class CycleClock
{
public:
// CycleClock::Now()
//
// Returns the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();

// CycleClock::Frequency()
//
// Returns the amount by which `CycleClock::Now()` increases per second. Note
// that this value may not necessarily match the core CPU clock frequency.
static double Frequency();

private:
#if ABSL_USE_UNSCALED_CYCLECLOCK
static CycleClockSourceFunc LoadCycleClockSource();

#ifdef NDEBUG
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
static constexpr int32_t kShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
static constexpr int32_t kShift = 0;
#endif
#else // NDEBUG
// In debug mode use a different shift to discourage depending on a
// particular shift value.
static constexpr int32_t kShift = 2;
#endif // NDEBUG

static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
ABSL_CONST_INIT static std::atomic<CycleClockSourceFunc> cycle_clock_source_;
#endif // ABSL_USE_UNSCALED_CYCLECLOC

CycleClock() = delete; // no instances
CycleClock(const CycleClock&) = delete;
CycleClock& operator=(const CycleClock&) = delete;

friend class CycleClockSource;
};

class CycleClockSource
{
private:
// CycleClockSource::Register()
//
// Register a function that provides an alternate source for the unscaled CPU
// cycle count value. The source function must be async signal safe, must not
// call CycleClock::Now(), and must have a frequency that matches that of the
// unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
// the default source.
static void Register(CycleClockSourceFunc source);
};

#if ABSL_USE_UNSCALED_CYCLECLOCK

inline CycleClockSourceFunc CycleClock::LoadCycleClockSource()
{
#if !defined(__x86_64__)
// Optimize for the common case (no callback) by first doing a relaxed load;
// this is significantly faster on non-x86 platforms.
if (cycle_clock_source_.load(std::memory_order_relaxed) == nullptr)
{
return nullptr;
}
#endif // !defined(__x86_64__)

// This corresponds to the store(std::memory_order_release) in
// CycleClockSource::Register, and makes sure that any updates made prior to
// registering the callback are visible to this thread before the callback
// is invoked.
return cycle_clock_source_.load(std::memory_order_acquire);
}

// Accessing globals in inlined code in Window DLLs is problematic.
#ifndef _WIN32
inline int64_t CycleClock::Now()
{
auto fn = LoadCycleClockSource();
if (fn == nullptr)
{
return base_internal::UnscaledCycleClock::Now() >> kShift;
}
return fn() >> kShift;
}
#endif

inline double CycleClock::Frequency()
{
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}

#endif // ABSL_USE_UNSCALED_CYCLECLOCK

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_

+ 177
- 0
CAPI/cpp/grpc/include/absl/base/internal/direct_mmap.h View File

@@ -0,0 +1,177 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Functions for directly invoking mmap() via syscall, avoiding the case where
// mmap() has been locally overridden.

#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_
#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_

#include "absl/base/config.h"

#ifdef ABSL_HAVE_MMAP

#include <sys/mman.h>

#ifdef __linux__

#include <sys/types.h>
#ifdef __BIONIC__
#include <sys/syscall.h>
#else
#include <syscall.h>
#endif

#include <linux/unistd.h>
#include <unistd.h>
#include <cerrno>
#include <cstdarg>
#include <cstdint>

#ifdef __mips__
// Include definitions of the ABI currently in use.
#if defined(__BIONIC__) || !defined(__GLIBC__)
// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
// definitions we need.
#include <asm/sgidefs.h>
#else
#include <sgidefs.h>
#endif // __BIONIC__ || !__GLIBC__
#endif // __mips__

// SYS_mmap and SYS_munmap are not defined in Android.
#ifdef __BIONIC__
extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#if defined(__NR_mmap) && !defined(SYS_mmap)
#define SYS_mmap __NR_mmap
#endif
#ifndef SYS_munmap
#define SYS_munmap __NR_munmap
#endif
#endif // __BIONIC__

#if defined(__NR_mmap2) && !defined(SYS_mmap2)
#define SYS_mmap2 __NR_mmap2
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Platform specific logic extracted from
// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, off64_t offset) noexcept
{
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
defined(__m68k__) || defined(__sh__) || \
(defined(__hppa__) && !defined(__LP64__)) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \
(defined(__riscv) && __riscv_xlen == 32) || \
(defined(__s390__) && !defined(__s390x__)) || \
(defined(__sparc__) && !defined(__arch64__))
// On these architectures, implement mmap with mmap2.
static int pagesize = 0;
if (pagesize == 0)
{
#if defined(__wasm__) || defined(__asmjs__)
pagesize = getpagesize();
#else
pagesize = sysconf(_SC_PAGESIZE);
#endif
}
if (offset < 0 || offset % pagesize != 0)
{
errno = EINVAL;
return MAP_FAILED;
}
#ifdef __BIONIC__
// SYS_mmap2 has problems on Android API level <= 16.
// Workaround by invoking __mmap2() instead.
return __mmap2(start, length, prot, flags, fd, offset / pagesize);
#else
return reinterpret_cast<void*>(
syscall(SYS_mmap2, start, length, prot, flags, fd, static_cast<off_t>(offset / pagesize))
);
#endif
#elif defined(__s390x__)
// On s390x, mmap() arguments are passed in memory.
unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT
static_cast<unsigned long>(length), // NOLINT
static_cast<unsigned long>(prot), // NOLINT
static_cast<unsigned long>(flags), // NOLINT
static_cast<unsigned long>(fd), // NOLINT
static_cast<unsigned long>(offset)}; // NOLINT
return reinterpret_cast<void*>(syscall(SYS_mmap, buf));
#elif defined(__x86_64__)
// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit.
// We need to explicitly cast to an unsigned 64 bit type to avoid implicit
// sign extension. We can't cast pointers directly because those are
// 32 bits, and gcc will dump ugly warnings about casting from a pointer
// to an integer of a different size. We also need to make sure __off64_t
// isn't truncated to 32-bits under x32.
#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x))
return reinterpret_cast<void*>(
syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length), MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags), MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset))
);
#undef MMAP_SYSCALL_ARG
#else // Remaining 64-bit aritectures.
static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit");
return reinterpret_cast<void*>(
syscall(SYS_mmap, start, length, prot, flags, fd, offset)
);
#endif
}

inline int DirectMunmap(void* start, size_t length)
{
return static_cast<int>(syscall(SYS_munmap, start, length));
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#else // !__linux__

// For non-linux platforms where we have mmap, just dispatch directly to the
// actual mmap()/munmap() methods.

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, off_t offset)
{
return mmap(start, length, prot, flags, fd, offset);
}

inline int DirectMunmap(void* start, size_t length)
{
return munmap(start, length);
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // __linux__

#endif // ABSL_HAVE_MMAP

#endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_

+ 416
- 0
CAPI/cpp/grpc/include/absl/base/internal/dynamic_annotations.h View File

@@ -0,0 +1,416 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file defines dynamic annotations for use with dynamic analysis tool
// such as valgrind, PIN, etc.
//
// Dynamic annotation is a source code annotation that affects the generated
// code (that is, the annotation is not a comment). Each such annotation is
// attached to a particular instruction and/or to a particular object (address)
// in the program.
//
// The annotations that should be used by users are macros in all upper-case
// (e.g., ANNOTATE_THREAD_NAME).
//
// Actual implementation of these macros may differ depending on the dynamic
// analysis tool being used.
//
// This file supports the following configurations:
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
// In this case, macros expand to functions implemented by Thread Sanitizer,
// when building with TSan. When not provided an external implementation,
// dynamic_annotations.cc provides no-op implementations.
//
// - Static Clang thread-safety warnings enabled.
// When building with a Clang compiler that supports thread-safety warnings,
// a subset of annotations can be statically-checked at compile-time. We
// expand these macros to static-inline functions that can be analyzed for
// thread-safety, but afterwards elided when building the final binary.
//
// - All annotations are disabled.
// If neither Dynamic Annotations nor Clang thread-safety warnings are
// enabled, then all annotation-macros expand to empty.

#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_

#include <stddef.h>

#include "absl/base/config.h"

// -------------------------------------------------------------------------
// Decide which features are enabled

#ifndef DYNAMIC_ANNOTATIONS_ENABLED
#define DYNAMIC_ANNOTATIONS_ENABLED 0
#endif

#if defined(__clang__) && !defined(SWIG)
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
#endif

#if DYNAMIC_ANNOTATIONS_ENABLED != 0

#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1

#else

#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0

// Clang provides limited support for static thread-safety analysis through a
// feature called Annotalysis. We configure macro-definitions according to
// whether Annotalysis support is available. When running in opt-mode, GCC
// will issue a warning, if these attributes are compiled. Only include them
// when compiling using Clang.

// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
#endif

// Memory annotations are also made available to LLVM's Memory Sanitizer
#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
#endif

#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
#endif

#ifdef __cplusplus
#define ABSL_INTERNAL_BEGIN_EXTERN_C \
extern "C" \
{
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
#define ABSL_INTERNAL_STATIC_INLINE inline
#else
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
#define ABSL_INTERNAL_END_EXTERN_C // empty
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
#define ABSL_INTERNAL_STATIC_INLINE static inline
#endif

// -------------------------------------------------------------------------
// Define race annotations.

#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1

// -------------------------------------------------------------
// Annotations that suppress errors. It is usually better to express the
// program's synchronization using the other annotations, but these can be used
// when all else fails.

// Report that we may have a benign race at `pointer`, with size
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
// point where `pointer` has been allocated, preferably close to the point
// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
#define ANNOTATE_BENIGN_RACE(pointer, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)

// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
// the memory range [`address`, `address`+`size`).
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
(__FILE__, __LINE__, address, size, description)

// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
// This annotation could be useful if you want to skip expensive race analysis
// during some period of program execution, e.g. during initialization.
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
(__FILE__, __LINE__, enable)

// -------------------------------------------------------------
// Annotations useful for debugging.

// Report the current thread `name` to a race detector.
#define ANNOTATE_THREAD_NAME(name) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName) \
(__FILE__, __LINE__, name)

// -------------------------------------------------------------
// Annotations useful when implementing locks. They are not normally needed by
// modules that merely use locks. The `lock` argument is a pointer to the lock
// object.

// Report that a lock has been created at address `lock`.
#define ANNOTATE_RWLOCK_CREATE(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate) \
(__FILE__, __LINE__, lock)

// Report that a linker initialized lock has been created at address `lock`.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
(__FILE__, __LINE__, lock)
#else
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
#endif

// Report that the lock at address `lock` is about to be destroyed.
#define ANNOTATE_RWLOCK_DESTROY(lock) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy) \
(__FILE__, __LINE__, lock)

// Report that the lock at address `lock` has been acquired.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
(__FILE__, __LINE__, lock, is_w)

// Report that the lock at address `lock` is about to be released.
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
(__FILE__, __LINE__, lock, is_w)

// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
namespace \
{ \
class static_var##_annotator \
{ \
public: \
static_var##_annotator() \
{ \
ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), #static_var ": " description); \
} \
}; \
static static_var##_annotator the##static_var##_annotator; \
} // namespace

#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0

#define ANNOTATE_RWLOCK_CREATE(lock) // empty
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
#define ANNOTATE_RWLOCK_DESTROY(lock) // empty
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
#define ANNOTATE_BENIGN_RACE(address, description) // empty
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
#define ANNOTATE_THREAD_NAME(name) // empty
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty

#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED

// -------------------------------------------------------------------------
// Define memory annotations.

#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1

#include <sanitizer/msan_interface.h>

#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
__msan_unpoison(address, size)

#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
__msan_allocated_memory(address, size)

#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0

#if DYNAMIC_ANNOTATIONS_ENABLED == 1
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
do \
{ \
(void)(address); \
(void)(size); \
} while (0)
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
do \
{ \
(void)(address); \
(void)(size); \
} while (0)
#else
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
#endif

#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED

// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END attributes.

#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
__attribute((exclusive_lock_function("*")))
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
__attribute((unlock_function("*")))

#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty

#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)

// -------------------------------------------------------------------------
// Define IGNORE_READS_BEGIN/_END annotations.

#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1

// Request the analysis tool to ignore all reads in the current thread until
// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
// reads, while still checking other reads and all writes.
// See also ANNOTATE_UNPROTECTED_READ.
#define ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
(__FILE__, __LINE__)

// Stop ignoring reads.
#define ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
(__FILE__, __LINE__)

#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)

// When Annotalysis is enabled without Dynamic Annotations, the use of
// static-inline functions allows the annotations to be read at compile-time,
// while still letting the compiler elide the functions from the final build.
//
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
// allows IGNORE_READS_AND_WRITES to work properly.

#define ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin) \
()

#define ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd) \
()

#else

#define ANNOTATE_IGNORE_READS_BEGIN() // empty
#define ANNOTATE_IGNORE_READS_END() // empty

#endif

// -------------------------------------------------------------------------
// Define IGNORE_WRITES_BEGIN/_END annotations.

#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1

// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin) \
(__FILE__, __LINE__)

// Stop ignoring writes.
#define ANNOTATE_IGNORE_WRITES_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd) \
(__FILE__, __LINE__)

#else

#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty
#define ANNOTATE_IGNORE_WRITES_END() // empty

#endif

// -------------------------------------------------------------------------
// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
// primitive annotations defined above.
//
// Instead of doing
// ANNOTATE_IGNORE_READS_BEGIN();
// ... = x;
// ANNOTATE_IGNORE_READS_END();
// one can use
// ... = ANNOTATE_UNPROTECTED_READ(x);

#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)

// Start ignoring all memory accesses (both reads and writes).
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
do \
{ \
ANNOTATE_IGNORE_READS_BEGIN(); \
ANNOTATE_IGNORE_WRITES_BEGIN(); \
} while (0)

// Stop ignoring both reads and writes.
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
do \
{ \
ANNOTATE_IGNORE_WRITES_END(); \
ANNOTATE_IGNORE_READS_END(); \
} while (0)

#ifdef __cplusplus
// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
#define ANNOTATE_UNPROTECTED_READ(x) \
absl::base_internal::AnnotateUnprotectedRead(x)

#endif

#else

#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
#define ANNOTATE_UNPROTECTED_READ(x) (x)

#endif

// -------------------------------------------------------------------------
// Address sanitizer annotations

#ifdef ABSL_HAVE_ADDRESS_SANITIZER
// Describe the current state of a contiguous container such as e.g.
// std::vector or std::string. For more details see
// sanitizer/common_interface_defs.h, which is provided by the compiler.
#include <sanitizer/common_interface_defs.h>

#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
#define ADDRESS_SANITIZER_REDZONE(name) \
struct \
{ \
char x[8] __attribute__((aligned(8))); \
} name

#else

#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")

#endif // ABSL_HAVE_ADDRESS_SANITIZER

// -------------------------------------------------------------------------
// Undefine the macros intended only for this file.

#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
#undef ABSL_INTERNAL_END_EXTERN_C
#undef ABSL_INTERNAL_STATIC_INLINE

#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_

+ 472
- 0
CAPI/cpp/grpc/include/absl/base/internal/endian.h View File

@@ -0,0 +1,472 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
#define ABSL_BASE_INTERNAL_ENDIAN_H_

#include <cstdint>
#include <cstdlib>

#include "absl/base/casts.h"
#include "absl/base/config.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/base/port.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

inline uint64_t gbswap_64(uint64_t host_int)
{
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
return __builtin_bswap64(host_int);
#elif defined(_MSC_VER)
return _byteswap_uint64(host_int);
#else
return (((host_int & uint64_t{0xFF}) << 56) | ((host_int & uint64_t{0xFF00}) << 40) | ((host_int & uint64_t{0xFF0000}) << 24) | ((host_int & uint64_t{0xFF000000}) << 8) | ((host_int & uint64_t{0xFF00000000}) >> 8) | ((host_int & uint64_t{0xFF0000000000}) >> 24) | ((host_int & uint64_t{0xFF000000000000}) >> 40) | ((host_int & uint64_t{0xFF00000000000000}) >> 56));
#endif
}

inline uint32_t gbswap_32(uint32_t host_int)
{
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
return __builtin_bswap32(host_int);
#elif defined(_MSC_VER)
return _byteswap_ulong(host_int);
#else
return (((host_int & uint32_t{0xFF}) << 24) | ((host_int & uint32_t{0xFF00}) << 8) | ((host_int & uint32_t{0xFF0000}) >> 8) | ((host_int & uint32_t{0xFF000000}) >> 24));
#endif
}

inline uint16_t gbswap_16(uint16_t host_int)
{
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
return __builtin_bswap16(host_int);
#elif defined(_MSC_VER)
return _byteswap_ushort(host_int);
#else
return (((host_int & uint16_t{0xFF}) << 8) | ((host_int & uint16_t{0xFF00}) >> 8));
#endif
}

#ifdef ABSL_IS_LITTLE_ENDIAN

// Portable definitions for htonl (host-to-network) and friends on little-endian
// architectures.
inline uint16_t ghtons(uint16_t x)
{
return gbswap_16(x);
}
inline uint32_t ghtonl(uint32_t x)
{
return gbswap_32(x);
}
inline uint64_t ghtonll(uint64_t x)
{
return gbswap_64(x);
}

#elif defined ABSL_IS_BIG_ENDIAN

// Portable definitions for htonl (host-to-network) etc on big-endian
// architectures. These definitions are simpler since the host byte order is the
// same as network byte order.
inline uint16_t ghtons(uint16_t x)
{
return x;
}
inline uint32_t ghtonl(uint32_t x)
{
return x;
}
inline uint64_t ghtonll(uint64_t x)
{
return x;
}

#else
#error \
"Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
"ABSL_IS_LITTLE_ENDIAN must be defined"
#endif // byte order

inline uint16_t gntohs(uint16_t x)
{
return ghtons(x);
}
inline uint32_t gntohl(uint32_t x)
{
return ghtonl(x);
}
inline uint64_t gntohll(uint64_t x)
{
return ghtonll(x);
}

// Utilities to convert numbers between the current hosts's native byte
// order and little-endian byte order
//
// Load/Store methods are alignment safe
namespace little_endian
{
// Conversion functions.
#ifdef ABSL_IS_LITTLE_ENDIAN

inline uint16_t FromHost16(uint16_t x)
{
return x;
}
inline uint16_t ToHost16(uint16_t x)
{
return x;
}

inline uint32_t FromHost32(uint32_t x)
{
return x;
}
inline uint32_t ToHost32(uint32_t x)
{
return x;
}

inline uint64_t FromHost64(uint64_t x)
{
return x;
}
inline uint64_t ToHost64(uint64_t x)
{
return x;
}

inline constexpr bool IsLittleEndian()
{
return true;
}

#elif defined ABSL_IS_BIG_ENDIAN

inline uint16_t FromHost16(uint16_t x)
{
return gbswap_16(x);
}
inline uint16_t ToHost16(uint16_t x)
{
return gbswap_16(x);
}

inline uint32_t FromHost32(uint32_t x)
{
return gbswap_32(x);
}
inline uint32_t ToHost32(uint32_t x)
{
return gbswap_32(x);
}

inline uint64_t FromHost64(uint64_t x)
{
return gbswap_64(x);
}
inline uint64_t ToHost64(uint64_t x)
{
return gbswap_64(x);
}

inline constexpr bool IsLittleEndian()
{
return false;
}

#endif /* ENDIAN */

inline uint8_t FromHost(uint8_t x)
{
return x;
}
inline uint16_t FromHost(uint16_t x)
{
return FromHost16(x);
}
inline uint32_t FromHost(uint32_t x)
{
return FromHost32(x);
}
inline uint64_t FromHost(uint64_t x)
{
return FromHost64(x);
}
inline uint8_t ToHost(uint8_t x)
{
return x;
}
inline uint16_t ToHost(uint16_t x)
{
return ToHost16(x);
}
inline uint32_t ToHost(uint32_t x)
{
return ToHost32(x);
}
inline uint64_t ToHost(uint64_t x)
{
return ToHost64(x);
}

inline int8_t FromHost(int8_t x)
{
return x;
}
inline int16_t FromHost(int16_t x)
{
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x)
{
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x)
{
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x)
{
return x;
}
inline int16_t ToHost(int16_t x)
{
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x)
{
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x)
{
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}

// Functions to do unaligned loads and stores in little-endian order.
inline uint16_t Load16(const void* p)
{
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}

inline void Store16(void* p, uint16_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}

inline uint32_t Load32(const void* p)
{
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}

inline void Store32(void* p, uint32_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}

inline uint64_t Load64(const void* p)
{
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}

inline void Store64(void* p, uint64_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}

} // namespace little_endian

// Utilities to convert numbers between the current hosts's native byte
// order and big-endian byte order (same as network byte order)
//
// Load/Store methods are alignment safe
namespace big_endian
{
#ifdef ABSL_IS_LITTLE_ENDIAN

inline uint16_t FromHost16(uint16_t x)
{
return gbswap_16(x);
}
inline uint16_t ToHost16(uint16_t x)
{
return gbswap_16(x);
}

inline uint32_t FromHost32(uint32_t x)
{
return gbswap_32(x);
}
inline uint32_t ToHost32(uint32_t x)
{
return gbswap_32(x);
}

inline uint64_t FromHost64(uint64_t x)
{
return gbswap_64(x);
}
inline uint64_t ToHost64(uint64_t x)
{
return gbswap_64(x);
}

inline constexpr bool IsLittleEndian()
{
return true;
}

#elif defined ABSL_IS_BIG_ENDIAN

inline uint16_t FromHost16(uint16_t x)
{
return x;
}
inline uint16_t ToHost16(uint16_t x)
{
return x;
}

inline uint32_t FromHost32(uint32_t x)
{
return x;
}
inline uint32_t ToHost32(uint32_t x)
{
return x;
}

inline uint64_t FromHost64(uint64_t x)
{
return x;
}
inline uint64_t ToHost64(uint64_t x)
{
return x;
}

inline constexpr bool IsLittleEndian()
{
return false;
}

#endif /* ENDIAN */

inline uint8_t FromHost(uint8_t x)
{
return x;
}
inline uint16_t FromHost(uint16_t x)
{
return FromHost16(x);
}
inline uint32_t FromHost(uint32_t x)
{
return FromHost32(x);
}
inline uint64_t FromHost(uint64_t x)
{
return FromHost64(x);
}
inline uint8_t ToHost(uint8_t x)
{
return x;
}
inline uint16_t ToHost(uint16_t x)
{
return ToHost16(x);
}
inline uint32_t ToHost(uint32_t x)
{
return ToHost32(x);
}
inline uint64_t ToHost(uint64_t x)
{
return ToHost64(x);
}

inline int8_t FromHost(int8_t x)
{
return x;
}
inline int16_t FromHost(int16_t x)
{
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x)
{
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x)
{
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x)
{
return x;
}
inline int16_t ToHost(int16_t x)
{
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x)
{
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x)
{
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}

// Functions to do unaligned loads and stores in big-endian order.
inline uint16_t Load16(const void* p)
{
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}

inline void Store16(void* p, uint16_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}

inline uint32_t Load32(const void* p)
{
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}

inline void Store32(void* p, uint32_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}

inline uint64_t Load64(const void* p)
{
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}

inline void Store64(void* p, uint64_t v)
{
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}

} // namespace big_endian

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_ENDIAN_H_

+ 55
- 0
CAPI/cpp/grpc/include/absl/base/internal/errno_saver.h View File

@@ -0,0 +1,55 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_

#include <cerrno>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// `ErrnoSaver` captures the value of `errno` upon construction and restores it
// upon deletion. It is used in low-level code and must be super fast. Do not
// add instrumentation, even in debug modes.
class ErrnoSaver
{
public:
ErrnoSaver() :
saved_errno_(errno)
{
}
~ErrnoSaver()
{
errno = saved_errno_;
}
int operator()() const
{
return saved_errno_;
}

private:
const int saved_errno_;
};

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_

+ 1345
- 0
CAPI/cpp/grpc/include/absl/base/internal/exception_safety_testing.h
File diff suppressed because it is too large
View File


+ 42
- 0
CAPI/cpp/grpc/include/absl/base/internal/exception_testing.h View File

@@ -0,0 +1,42 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Testing utilities for ABSL types which throw exceptions.

#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_
#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_

#include "gtest/gtest.h"
#include "absl/base/config.h"

// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception
// if exceptions are enabled, or for death with a specified text in the error
// message
#ifdef ABSL_HAVE_EXCEPTIONS

#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_THROW(expr, exception_t)

#elif defined(__ANDROID__)
// Android asserts do not log anywhere that gtest can currently inspect.
// So we expect exit, but cannot match the message.
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_DEATH(expr, ".*")
#else
#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \
EXPECT_DEATH_IF_SUPPORTED(expr, text)

#endif

#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_

+ 54
- 0
CAPI/cpp/grpc/include/absl/base/internal/fast_type_id.h View File

@@ -0,0 +1,54 @@
//
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

template<typename Type>
struct FastTypeTag
{
constexpr static char dummy_var = 0;
};

#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
template<typename Type>
constexpr char FastTypeTag<Type>::dummy_var;
#endif

// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
// passed-in type. These are meant to be good match for keys into maps or
// straight up comparisons.
using FastTypeIdType = const void*;

template<typename Type>
constexpr inline FastTypeIdType FastTypeId()
{
return &FastTypeTag<Type>::dummy_var;
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_

+ 56
- 0
CAPI/cpp/grpc/include/absl/base/internal/hide_ptr.h View File

@@ -0,0 +1,56 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_
#define ABSL_BASE_INTERNAL_HIDE_PTR_H_

#include <cstdint>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Arbitrary value with high bits set. Xor'ing with it is unlikely
// to map one valid pointer to another valid pointer.
constexpr uintptr_t HideMask()
{
return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU;
}

// Hide a pointer from the leak checker. For internal use only.
// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr
// and all objects reachable from ptr to be ignored by the leak checker.
template<class T>
inline uintptr_t HidePtr(T* ptr)
{
return reinterpret_cast<uintptr_t>(ptr) ^ HideMask();
}

// Return a pointer that has been hidden from the leak checker.
// For internal use only.
template<class T>
inline T* UnhidePtr(uintptr_t hidden)
{
return reinterpret_cast<T*>(hidden ^ HideMask());
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_

+ 40
- 0
CAPI/cpp/grpc/include/absl/base/internal/identity.h View File

@@ -0,0 +1,40 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
#define ABSL_BASE_INTERNAL_IDENTITY_H_

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace internal
{

template<typename T>
struct identity
{
typedef T type;
};

template<typename T>
using identity_t = typename identity<T>::type;

} // namespace internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_IDENTITY_H_

+ 107
- 0
CAPI/cpp/grpc/include/absl/base/internal/inline_variable.h View File

@@ -0,0 +1,107 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_
#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_

#include <type_traits>

#include "absl/base/internal/identity.h"

// File:
// This file define a macro that allows the creation of or emulation of C++17
// inline variables based on whether or not the feature is supported.

////////////////////////////////////////////////////////////////////////////////
// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
//
// Description:
// Expands to the equivalent of an inline constexpr instance of the specified
// `type` and `name`, initialized to the value `init`. If the compiler being
// used is detected as supporting actual inline variables as a language
// feature, then the macro expands to an actual inline variable definition.
//
// Requires:
// `type` is a type that is usable in an extern variable declaration.
//
// Requires: `name` is a valid identifier
//
// Requires:
// `init` is an expression that can be used in the following definition:
// constexpr type name = init;
//
// Usage:
//
// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
//
// Differences in implementation:
// For a direct, language-level inline variable, decltype(name) will be the
// type that was specified along with const qualification, whereas for
// emulated inline variables, decltype(name) may be different (in practice
// it will likely be a reference type).
////////////////////////////////////////////////////////////////////////////////

#ifdef __cpp_inline_variables

// Clang's -Wmissing-variable-declarations option erroneously warned that
// inline constexpr objects need to be pre-declared. This has now been fixed,
// but we will need to support this workaround for people building with older
// versions of clang.
//
// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
//
// Note:
// identity_t is used here so that the const and name are in the
// appropriate place for pointer types, reference types, function pointer
// types, etc..
#if defined(__clang__)
#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
extern const ::absl::internal::identity_t<type> name;
#else // Otherwise, just define the macro to do nothing.
#define ABSL_INTERNAL_EXTERN_DECL(type, name)
#endif // defined(__clang__)

// See above comment at top of file for details.
#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
ABSL_INTERNAL_EXTERN_DECL(type, name) \
inline constexpr ::absl::internal::identity_t<type> name = init

#else

// See above comment at top of file for details.
//
// Note:
// identity_t is used here so that the const and name are in the
// appropriate place for pointer types, reference types, function pointer
// types, etc..
#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
template<class /*AbslInternalDummy*/ = void> \
struct AbslInternalInlineVariableHolder##name \
{ \
static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \
}; \
\
template<class AbslInternalDummy> \
constexpr ::absl::internal::identity_t<var_type> \
AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
\
static constexpr const ::absl::internal::identity_t<var_type>& \
name = /* NOLINT */ \
AbslInternalInlineVariableHolder##name<>::kInstance; \
static_assert(sizeof(void (*)(decltype(name))) != 0, "Silence unused variable warnings.")

#endif // __cpp_inline_variables

#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_

+ 49
- 0
CAPI/cpp/grpc/include/absl/base/internal/inline_variable_testing.h View File

@@ -0,0 +1,49 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_
#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_

#include "absl/base/internal/inline_variable.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace inline_variable_testing_internal
{

struct Foo
{
int value = 5;
};

ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {});
ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {});

ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5);
ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5);

ABSL_INTERNAL_INLINE_CONSTEXPR(void (*)(), inline_variable_fun_ptr, nullptr);

const Foo& get_foo_a();
const Foo& get_foo_b();

const int& get_int_a();
const int& get_int_b();

} // namespace inline_variable_testing_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_

+ 267
- 0
CAPI/cpp/grpc/include/absl/base/internal/invoke.h View File

@@ -0,0 +1,267 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// absl::base_internal::invoke(f, args...) is an implementation of
// INVOKE(f, args...) from section [func.require] of the C++ standard.
// When compiled as C++17 and later versions, it is implemented as an alias of
// std::invoke.
//
// [func.require]
// Define INVOKE (f, t1, t2, ..., tN) as follows:
// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
// and t1 is an object of type T or a reference to an object of type T or a
// reference to an object of a type derived from T;
// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
// class T and t1 is not one of the types described in the previous item;
// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
// an object of type T or a reference to an object of type T or a reference
// to an object of a type derived from T;
// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
// is not one of the types described in the previous item;
// 5. f(t1, t2, ..., tN) in all other cases.
//
// The implementation is SFINAE-friendly: substitution failure within invoke()
// isn't an error.

#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
#define ABSL_BASE_INTERNAL_INVOKE_H_

#include "absl/base/config.h"

#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L

#include <functional>

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

using std::invoke;
using std::invoke_result_t;
using std::is_invocable_r;

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L

#include <algorithm>
#include <type_traits>
#include <utility>

#include "absl/meta/type_traits.h"

// The following code is internal implementation detail. See the comment at the
// top of this file for the API documentation.

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// The five classes below each implement one of the clauses from the definition
// of INVOKE. The inner class template Accept<F, Args...> checks whether the
// clause is applicable; static function template Invoke(f, args...) does the
// invocation.
//
// By separating the clause selection logic from invocation we make sure that
// Invoke() does exactly what the standard says.

template<typename Derived>
struct StrippedAccept
{
template<typename... Args>
struct Accept : Derived::template AcceptImpl<typename std::remove_cv<typename std::remove_reference<Args>::type>::type...>
{
};
};

// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
// and t1 is an object of type T or a reference to an object of type T or a
// reference to an object of a type derived from T.
struct MemFunAndRef : StrippedAccept<MemFunAndRef>
{
template<typename... Args>
struct AcceptImpl : std::false_type
{
};

template<typename MemFunType, typename C, typename Obj, typename... Args>
struct AcceptImpl<MemFunType C::*, Obj, Args...> : std::integral_constant<bool, std::is_base_of<C, Obj>::value && absl::is_function<MemFunType>::value>
{
};

template<typename MemFun, typename Obj, typename... Args>
static decltype((std::declval<Obj>().*std::declval<MemFun>())(std::declval<Args>()...))
Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args)
{
// Ignore bogus GCC warnings on this line.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example.
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
return (std::forward<Obj>(obj).*std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
#pragma GCC diagnostic pop
#endif
}
};

// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
// class T and t1 is not one of the types described in the previous item.
struct MemFunAndPtr : StrippedAccept<MemFunAndPtr>
{
template<typename... Args>
struct AcceptImpl : std::false_type
{
};

template<typename MemFunType, typename C, typename Ptr, typename... Args>
struct AcceptImpl<MemFunType C::*, Ptr, Args...> : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value && absl::is_function<MemFunType>::value>
{
};

template<typename MemFun, typename Ptr, typename... Args>
static decltype(((*std::declval<Ptr>()).*std::declval<MemFun>())(std::declval<Args>()...))
Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args)
{
return ((*std::forward<Ptr>(ptr)).*std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
}
};

// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
// an object of type T or a reference to an object of type T or a reference
// to an object of a type derived from T.
struct DataMemAndRef : StrippedAccept<DataMemAndRef>
{
template<typename... Args>
struct AcceptImpl : std::false_type
{
};

template<typename R, typename C, typename Obj>
struct AcceptImpl<R C::*, Obj> : std::integral_constant<bool, std::is_base_of<C, Obj>::value && !absl::is_function<R>::value>
{
};

template<typename DataMem, typename Ref>
static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
DataMem&& data_mem, Ref&& ref
)
{
return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
}
};

// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
// is not one of the types described in the previous item.
struct DataMemAndPtr : StrippedAccept<DataMemAndPtr>
{
template<typename... Args>
struct AcceptImpl : std::false_type
{
};

template<typename R, typename C, typename Ptr>
struct AcceptImpl<R C::*, Ptr> : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value && !absl::is_function<R>::value>
{
};

template<typename DataMem, typename Ptr>
static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
DataMem&& data_mem, Ptr&& ptr
)
{
return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
}
};

// f(t1, t2, ..., tN) in all other cases.
struct Callable
{
// Callable doesn't have Accept because it's the last clause that gets picked
// when none of the previous clauses are applicable.
template<typename F, typename... Args>
static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
F&& f, Args&&... args
)
{
return std::forward<F>(f)(std::forward<Args>(args)...);
}
};

// Resolves to the first matching clause.
template<typename... Args>
struct Invoker
{
typedef typename std::conditional<
MemFunAndRef::Accept<Args...>::value,
MemFunAndRef,
typename std::conditional<
MemFunAndPtr::Accept<Args...>::value,
MemFunAndPtr,
typename std::conditional<
DataMemAndRef::Accept<Args...>::value,
DataMemAndRef,
typename std::conditional<DataMemAndPtr::Accept<Args...>::value, DataMemAndPtr, Callable>::type>::type>::
type>::type type;
};

// The result type of Invoke<F, Args...>.
template<typename F, typename... Args>
using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
std::declval<F>(), std::declval<Args>()...
));

// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
// [func.require] of the C++ standard.
template<typename F, typename... Args>
invoke_result_t<F, Args...> invoke(F&& f, Args&&... args)
{
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

template<typename AlwaysVoid, typename, typename, typename...>
struct IsInvocableRImpl : std::false_type
{
};

template<typename R, typename F, typename... Args>
struct IsInvocableRImpl<
absl::void_t<absl::base_internal::invoke_result_t<F, Args...>>,
R,
F,
Args...> : std::integral_constant<bool, std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>, R>::value || std::is_void<R>::value>
{
};

// Type trait whose member `value` is true if invoking `F` with `Args` is valid,
// and either the return type is convertible to `R`, or `R` is void.
// C++11-compatible version of `std::is_invocable_r`.
template<typename R, typename F, typename... Args>
using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>;

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L

#endif // ABSL_BASE_INTERNAL_INVOKE_H_

+ 130
- 0
CAPI/cpp/grpc/include/absl/base/internal/low_level_alloc.h View File

@@ -0,0 +1,130 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_

// A simple thread-safe memory allocator that does not depend on
// mutexes or thread-specific data. It is intended to be used
// sparingly, and only when malloc() would introduce an unwanted
// dependency, such as inside the heap-checker, or the Mutex
// implementation.

// IWYU pragma: private, include "base/low_level_alloc.h"

#include <sys/types.h>

#include <cstdint>

#include "absl/base/attributes.h"
#include "absl/base/config.h"

// LowLevelAlloc requires that the platform support low-level
// allocation of virtual memory. Platforms lacking this cannot use
// LowLevelAlloc.
#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
#endif

// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
// asm.js / WebAssembly.
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
// for more information.
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__)
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
#endif

#include <cstddef>

#include "absl/base/port.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

class LowLevelAlloc
{
public:
struct Arena; // an arena from which memory may be allocated

// Returns a pointer to a block of at least "request" bytes
// that have been newly allocated from the specific arena.
// for Alloc() call the DefaultArena() is used.
// Returns 0 if passed request==0.
// Does not return 0 under other circumstances; it crashes if memory
// is not available.
static void* Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
static void* AllocWithArena(size_t request, Arena* arena)
ABSL_ATTRIBUTE_SECTION(malloc_hook);

// Deallocates a region of memory that was previously allocated with
// Alloc(). Does nothing if passed 0. "s" must be either 0,
// or must have been returned from a call to Alloc() and not yet passed to
// Free() since that call to Alloc(). The space is returned to the arena
// from which it was allocated.
static void Free(void* s) ABSL_ATTRIBUTE_SECTION(malloc_hook);

// ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
// are to put all callers of MallocHook::Invoke* in this module
// into special section,
// so that MallocHook::GetCallerStackTrace can function accurately.

// Create a new arena.
// The root metadata for the new arena is allocated in the
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
// These values may be ored into flags:
enum
{
// Report calls to Alloc() and Free() via the MallocHook interface.
// Set in the DefaultArena.
kCallMallocHook = 0x0001,

#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
// Make calls to Alloc(), Free() be async-signal-safe. Not set in
// DefaultArena(). Not supported on all platforms.
kAsyncSignalSafe = 0x0002,
#endif
};
// Construct a new arena. The allocation of the underlying metadata honors
// the provided flags. For example, the call NewArena(kAsyncSignalSafe)
// is itself async-signal-safe, as well as generatating an arena that provides
// async-signal-safe Alloc/Free.
static Arena* NewArena(int32_t flags);

// Destroys an arena allocated by NewArena and returns true,
// provided no allocated blocks remain in the arena.
// If allocated blocks remain in the arena, does nothing and
// returns false.
// It is illegal to attempt to destroy the DefaultArena().
static bool DeleteArena(Arena* arena);

// The default arena that always exists.
static Arena* DefaultArena();

private:
LowLevelAlloc(); // no instances
};

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_

+ 152
- 0
CAPI/cpp/grpc/include/absl/base/internal/low_level_scheduling.h View File

@@ -0,0 +1,152 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.

#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_

#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h"

// The following two declarations exist so SchedulingGuard may friend them with
// the appropriate language linkage. These callbacks allow libc internals, such
// as function level statics, to schedule cooperatively when locking.
extern "C" bool __google_disable_rescheduling(void);
extern "C" void __google_enable_rescheduling(bool disable_result);

namespace absl
{
ABSL_NAMESPACE_BEGIN
class CondVar;
class Mutex;

namespace synchronization_internal
{
int MutexDelay(int32_t c, int mode);
} // namespace synchronization_internal

namespace base_internal
{

class SchedulingHelper; // To allow use of SchedulingGuard.
class SpinLock; // To allow use of SchedulingGuard.

// SchedulingGuard
// Provides guard semantics that may be used to disable cooperative rescheduling
// of the calling thread within specific program blocks. This is used to
// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
// scheduling depends on.
//
// Domain implementations capable of rescheduling in reaction to involuntary
// kernel thread actions (e.g blocking due to a pagefault or syscall) must
// guarantee that an annotated thread is not allowed to (cooperatively)
// reschedule until the annotated region is complete.
//
// It is an error to attempt to use a cooperatively scheduled resource (e.g.
// Mutex) within a rescheduling-disabled region.
//
// All methods are async-signal safe.
class SchedulingGuard
{
public:
// Returns true iff the calling thread may be cooperatively rescheduled.
static bool ReschedulingIsAllowed();
SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete;

private:
// Disable cooperative rescheduling of the calling thread. It may still
// initiate scheduling operations (e.g. wake-ups), however, it may not itself
// reschedule. Nestable. The returned result is opaque, clients should not
// attempt to interpret it.
// REQUIRES: Result must be passed to a pairing EnableScheduling().
static bool DisableRescheduling();

// Marks the end of a rescheduling disabled region, previously started by
// DisableRescheduling().
// REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
static void EnableRescheduling(bool disable_result);

// A scoped helper for {Disable, Enable}Rescheduling().
// REQUIRES: destructor must run in same thread as constructor.
struct ScopedDisable
{
ScopedDisable()
{
disabled = SchedulingGuard::DisableRescheduling();
}
~ScopedDisable()
{
SchedulingGuard::EnableRescheduling(disabled);
}

bool disabled;
};

// A scoped helper to enable rescheduling temporarily.
// REQUIRES: destructor must run in same thread as constructor.
class ScopedEnable
{
public:
ScopedEnable();
~ScopedEnable();

private:
int scheduling_disabled_depth_;
};

// Access to SchedulingGuard is explicitly permitted.
friend class absl::CondVar;
friend class absl::Mutex;
friend class SchedulingHelper;
friend class SpinLock;
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
};

//------------------------------------------------------------------------------
// End of public interfaces.
//------------------------------------------------------------------------------

inline bool SchedulingGuard::ReschedulingIsAllowed()
{
return false;
}

inline bool SchedulingGuard::DisableRescheduling()
{
return false;
}

inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */)
{
return;
}

inline SchedulingGuard::ScopedEnable::ScopedEnable() :
scheduling_disabled_depth_(0)
{
}
inline SchedulingGuard::ScopedEnable::~ScopedEnable()
{
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_

+ 52
- 0
CAPI/cpp/grpc/include/absl/base/internal/per_thread_tls.h View File

@@ -0,0 +1,52 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_

// This header defines two macros:
//
// If the platform supports thread-local storage:
//
// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
// thread-local variable
// * ABSL_PER_THREAD_TLS is 1
//
// Otherwise:
//
// * ABSL_PER_THREAD_TLS_KEYWORD is empty
// * ABSL_PER_THREAD_TLS is 0
//
// Microsoft C supports thread-local storage.
// GCC supports it if the appropriate version of glibc is available,
// which the programmer can indicate by defining ABSL_HAVE_TLS

#include "absl/base/port.h" // For ABSL_HAVE_TLS

#if defined(ABSL_PER_THREAD_TLS)
#error ABSL_PER_THREAD_TLS cannot be directly set
#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
#elif defined(ABSL_HAVE_TLS)
#define ABSL_PER_THREAD_TLS_KEYWORD __thread
#define ABSL_PER_THREAD_TLS 1
#elif defined(_MSC_VER)
#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
#define ABSL_PER_THREAD_TLS 1
#else
#define ABSL_PER_THREAD_TLS_KEYWORD
#define ABSL_PER_THREAD_TLS 0
#endif

#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_

+ 156
- 0
CAPI/cpp/grpc/include/absl/base/internal/prefetch.h View File

@@ -0,0 +1,156 @@
// Copyright 2022 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_PREFETCH_H_
#define ABSL_BASE_INTERNAL_PREFETCH_H_

#include "absl/base/config.h"

#ifdef __SSE__
#include <xmmintrin.h>
#endif

#if defined(_MSC_VER) && defined(ABSL_INTERNAL_HAVE_SSE)
#include <intrin.h>
#pragma intrinsic(_mm_prefetch)
#endif

// Compatibility wrappers around __builtin_prefetch, to prefetch data
// for read if supported by the toolchain.

// Move data into the cache before it is read, or "prefetch" it.
//
// The value of `addr` is the address of the memory to prefetch. If
// the target and compiler support it, data prefetch instructions are
// generated. If the prefetch is done some time before the memory is
// read, it may be in the cache by the time the read occurs.
//
// The function names specify the temporal locality heuristic applied,
// using the names of Intel prefetch instructions:
//
// T0 - high degree of temporal locality; data should be left in as
// many levels of the cache possible
// T1 - moderate degree of temporal locality
// T2 - low degree of temporal locality
// Nta - no temporal locality, data need not be left in the cache
// after the read
//
// Incorrect or gratuitous use of these functions can degrade
// performance, so use them only when representative benchmarks show
// an improvement.
//
// Example usage:
//
// absl::base_internal::PrefetchT0(addr);
//
// Currently, the different prefetch calls behave on some Intel
// architectures as follows:
//
// SNB..SKL SKX
// PrefetchT0() L1/L2/L3 L1/L2
// PrefetchT1() L2/L3 L2
// PrefetchT2() L2/L3 L2
// PrefetchNta() L1/--/L3 L1*
//
// * On SKX PrefetchNta() will bring the line into L1 but will evict
// from L3 cache. This might result in surprising behavior.
//
// SNB = Sandy Bridge, SKL = Skylake, SKX = Skylake Xeon.
//
namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

void PrefetchT0(const void* addr);
void PrefetchT1(const void* addr);
void PrefetchT2(const void* addr);
void PrefetchNta(const void* addr);

// Implementation details follow.

#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)

#define ABSL_INTERNAL_HAVE_PREFETCH 1

// See __builtin_prefetch:
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
//
// These functions speculatively load for read only. This is
// safe for all currently supported platforms. However, prefetch for
// store may have problems depending on the target platform.
//
inline void PrefetchT0(const void* addr)
{
// Note: this uses prefetcht0 on Intel.
__builtin_prefetch(addr, 0, 3);
}
inline void PrefetchT1(const void* addr)
{
// Note: this uses prefetcht1 on Intel.
__builtin_prefetch(addr, 0, 2);
}
inline void PrefetchT2(const void* addr)
{
// Note: this uses prefetcht2 on Intel.
__builtin_prefetch(addr, 0, 1);
}
inline void PrefetchNta(const void* addr)
{
// Note: this uses prefetchtnta on Intel.
__builtin_prefetch(addr, 0, 0);
}

#elif defined(ABSL_INTERNAL_HAVE_SSE)

#define ABSL_INTERNAL_HAVE_PREFETCH 1

inline void PrefetchT0(const void* addr)
{
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0);
}
inline void PrefetchT1(const void* addr)
{
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T1);
}
inline void PrefetchT2(const void* addr)
{
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T2);
}
inline void PrefetchNta(const void* addr)
{
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA);
}

#else
inline void PrefetchT0(const void*)
{
}
inline void PrefetchT1(const void*)
{
}
inline void PrefetchT2(const void*)
{
}
inline void PrefetchNta(const void*)
{
}
#endif

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_PREFETCH_H_

+ 33
- 0
CAPI/cpp/grpc/include/absl/base/internal/pretty_function.h View File

@@ -0,0 +1,33 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_
#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_

// ABSL_PRETTY_FUNCTION
//
// In C++11, __func__ gives the undecorated name of the current function. That
// is, "main", not "int main()". Various compilers give extra macros to get the
// decorated function name, including return type and arguments, to
// differentiate between overload sets. ABSL_PRETTY_FUNCTION is a portable
// version of these macros which forwards to the correct macro on each compiler.
#if defined(_MSC_VER)
#define ABSL_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__)
#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#error "Unsupported compiler"
#endif

#endif // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_

+ 197
- 0
CAPI/cpp/grpc/include/absl/base/internal/raw_logging.h View File

@@ -0,0 +1,197 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation, synchronization, and signal-handling code.

#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_

#include <string>

#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h"
#include "absl/base/log_severity.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"

// This is similar to LOG(severity) << format..., but
// * it is to be used ONLY by low-level modules that can't use normal LOG()
// * it is designed to be a low-level logger that does not allocate any
// memory and does not need any locks, hence:
// * it logs straight and ONLY to STDERR w/o buffering
// * it uses an explicit printf-format and arguments list
// * it will silently chop off really long message strings
// Usage example:
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// This will print an almost standard log line like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file

#define ABSL_RAW_LOG(severity, ...) \
do \
{ \
constexpr const char* absl_raw_logging_internal_basename = \
::absl::raw_logging_internal::Basename(__FILE__, sizeof(__FILE__) - 1); \
::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, absl_raw_logging_internal_basename, __LINE__, __VA_ARGS__); \
} while (0)

// Similar to CHECK(condition) << message, but for low-level modules:
// we use only ABSL_RAW_LOG that does not allocate memory.
// We do not want to provide args list here to encourage this usage:
// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
// so that the args are not computed when not needed.
#define ABSL_RAW_CHECK(condition, message) \
do \
{ \
if (ABSL_PREDICT_FALSE(!(condition))) \
{ \
ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
} \
} while (0)

// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
// except that if the richer log library is linked into the binary, we dispatch
// to that instead. This is potentially useful for internal logging and
// assertions, where we are using RAW_LOG neither for its async-signal-safety
// nor for its non-allocating nature, but rather because raw logging has very
// few other dependencies.
//
// The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message.
#define ABSL_INTERNAL_LOG(severity, message) \
do \
{ \
constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
::absl::raw_logging_internal::internal_log_function( \
ABSL_RAW_LOGGING_INTERNAL_##severity, \
absl_raw_logging_internal_filename, \
__LINE__, \
message \
); \
if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
ABSL_INTERNAL_UNREACHABLE; \
} while (0)

#define ABSL_INTERNAL_CHECK(condition, message) \
do \
{ \
if (ABSL_PREDICT_FALSE(!(condition))) \
{ \
std::string death_message = "Check " #condition " failed: "; \
death_message += std::string(message); \
ABSL_INTERNAL_LOG(FATAL, death_message); \
} \
} while (0)

#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning
#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError
#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal
#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \
::absl::NormalizeLogSeverity(severity)

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace raw_logging_internal
{

// Helper function to implement ABSL_RAW_LOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
// This does not allocate memory or acquire locks.
void RawLog(absl::LogSeverity severity, const char* file, int line, const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);

// Writes the provided buffer directly to stderr, in a signal-safe, low-level
// manner.
void AsyncSignalSafeWriteToStderr(const char* s, size_t len);

// compile-time function to get the "base" filename, that is, the part of
// a filename after the last "/" or "\" path separator. The search starts at
// the end of the string; the second parameter is the length of the string.
constexpr const char* Basename(const char* fname, int offset)
{
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\' ? fname + offset : Basename(fname, offset - 1);
}

// For testing only.
// Returns true if raw logging is fully supported. When it is not
// fully supported, no messages will be emitted, but a log at FATAL
// severity will cause an abort.
//
// TODO(gfalcon): Come up with a better name for this method.
bool RawLoggingFullySupported();

// Function type for a raw_logging customization hook for suppressing messages
// by severity, and for writing custom prefixes on non-suppressed messages.
//
// The installed hook is called for every raw log invocation. The message will
// be logged to stderr only if the hook returns true. FATAL errors will cause
// the process to abort, even if writing to stderr is suppressed. The hook is
// also provided with an output buffer, where it can write a custom log message
// prefix.
//
// The raw_logging system does not allocate memory or grab locks. User-provided
// hooks must avoid these operations, and must not throw exceptions.
//
// 'severity' is the severity level of the message being written.
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the
// hook writes a prefix, it must increment *buf and decrement *buf_size
// accordingly.
using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity, const char* file, int line, char** buf, int* buf_size);

// Function type for a raw_logging customization hook called to abort a process
// when a FATAL message is logged. If the provided AbortHook() returns, the
// logging system will call abort().
//
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located.
// The NUL-terminated logged message lives in the buffer between 'buf_start'
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
// buffer (as written by the LogFilterAndPrefixHook.)
//
// The lifetime of the filename and message buffers will not end while the
// process remains alive.
using AbortHook = void (*)(const char* file, int line, const char* buf_start, const char* prefix_end, const char* buf_end);

// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
using InternalLogFunction = void (*)(absl::LogSeverity severity, const char* file, int line, const std::string& message);

ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
InternalLogFunction>
internal_log_function;

// Registers hooks of the above types. Only a single hook of each type may be
// registered. It is an error to call these functions multiple times with
// different input arguments.
//
// These functions are safe to call at any point during initialization; they do
// not block or malloc, and are async-signal safe.
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);
void RegisterAbortHook(AbortHook func);
void RegisterInternalLogFunction(InternalLogFunction func);

} // namespace raw_logging_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_

+ 61
- 0
CAPI/cpp/grpc/include/absl/base/internal/scheduling_mode.h View File

@@ -0,0 +1,61 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Core interfaces and definitions used by by low-level interfaces such as
// SpinLock.

#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Used to describe how a thread may be scheduled. Typically associated with
// the declaration of a resource supporting synchronized access.
//
// SCHEDULE_COOPERATIVE_AND_KERNEL:
// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
// reschedule (using base::scheduling semantics); allowing other cooperative
// threads to proceed.
//
// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
// Specifies that no cooperative scheduling semantics may be used, even if the
// current thread is itself cooperatively scheduled. This means that
// cooperative threads will NOT allow other cooperative threads to execute in
// their place while waiting for a resource of this type. Host operating system
// semantics (e.g. a futex) may still be used.
//
// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which
// base::scheduling (e.g. the implementation of a Scheduler) may depend.
//
// NOTE: Cooperative resources may not be nested below non-cooperative ones.
// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
enum SchedulingMode
{
SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS.
SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling.
};

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_

+ 48
- 0
CAPI/cpp/grpc/include/absl/base/internal/scoped_set_env.h View File

@@ -0,0 +1,48 @@
//
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_

#include <string>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

class ScopedSetEnv
{
public:
ScopedSetEnv(const char* var_name, const char* new_value);
~ScopedSetEnv();

private:
std::string var_name_;
std::string old_value_;

// True if the environment variable was initially not set.
bool was_unset_;
};

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_

+ 286
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock.h View File

@@ -0,0 +1,286 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

// Most users requiring mutual exclusion should use Mutex.
// SpinLock is provided for use in two situations:
// - for use by Abseil internal code that Mutex itself depends on
// - for async signal safety (see below)

// SpinLock is async signal safe. If a spinlock is used within a signal
// handler, all code that acquires the lock must ensure that the signal cannot
// arrive while they are holding the lock. Typically, this is done by blocking
// the signal.
//
// Threads waiting on a SpinLock may be woken in an arbitrary order.

#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_H_

#include <stdint.h>
#include <sys/types.h>

#include <atomic>

#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/tsan_mutex_interface.h"
#include "absl/base/macros.h"
#include "absl/base/port.h"
#include "absl/base/thread_annotations.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

class ABSL_LOCKABLE SpinLock
{
public:
SpinLock() :
lockword_(kSpinLockCooperative)
{
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}

// Constructors that allow non-cooperative spinlocks to be created for use
// inside thread schedulers. Normal clients should not use these.
explicit SpinLock(base_internal::SchedulingMode mode);

// Constructor for global SpinLock instances. See absl/base/const_init.h.
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode) :
lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0)
{
}

// For global SpinLock instances prefer trivial destructor when possible.
// Default but non-trivial destructor in some build configurations causes an
// extra static initializer.
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
~SpinLock()
{
ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static);
}
#else
~SpinLock() = default;
#endif

// Acquire this SpinLock.
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION()
{
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
if (!TryLockImpl())
{
SlowLock();
}
ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
}

// Try to acquire this SpinLock without blocking and return true if the
// acquisition was successful. If the lock was not acquired, false is
// returned. If this SpinLock is free at the time of the call, TryLock
// will return true with high probability.
inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true)
{
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
bool res = TryLockImpl();
ABSL_TSAN_MUTEX_POST_LOCK(
this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed), 0
);
return res;
}

// Release this SpinLock, which must be held by the calling thread.
inline void Unlock() ABSL_UNLOCK_FUNCTION()
{
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
lock_value = lockword_.exchange(lock_value & kSpinLockCooperative, std::memory_order_release);

if ((lock_value & kSpinLockDisabledScheduling) != 0)
{
base_internal::SchedulingGuard::EnableRescheduling(true);
}
if ((lock_value & kWaitTimeMask) != 0)
{
// Collect contentionz profile info, and speed the wakeup of any waiter.
// The wait_cycles value indicates how long this thread spent waiting
// for the lock.
SlowUnlock(lock_value);
}
ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
}

// Determine if the lock is held. When the lock is held by the invoking
// thread, true will always be returned. Intended to be used as
// CHECK(lock.IsHeld()).
inline bool IsHeld() const
{
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
}

// Return immediately if this thread holds the SpinLock exclusively.
// Otherwise, report an error by crashing with a diagnostic.
inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK()
{
if (!IsHeld())
{
ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
}
}

protected:
// These should not be exported except for testing.

// Store number of cycles between wait_start_time and wait_end_time in a
// lock value.
static uint32_t EncodeWaitCycles(int64_t wait_start_time, int64_t wait_end_time);

// Extract number of wait cycles in a lock value.
static uint64_t DecodeWaitCycles(uint32_t lock_value);

// Provide access to protected method above. Use for testing only.
friend struct SpinLockTest;

private:
// lockword_ is used to store the following:
//
// bit[0] encodes whether a lock is being held.
// bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether the current lock holder disabled scheduling when
// acquiring the lock. Only set when kSpinLockHeld is also set.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
// This is set by the lock holder to indicate how long it waited on
// the lock before eventually acquiring it. The number of cycles is
// encoded as a 29-bit unsigned int, or in the case that the current
// holder did not wait but another waiter is queued, the LSB
// (kSpinLockSleeper) is set. The implementation does not explicitly
// track the number of queued waiters beyond this. It must always be
// assumed that waiters may exist if the current holder was required to
// queue.
//
// Invariant: if the lock is not held, the value is either 0 or
// kSpinLockCooperative.
static constexpr uint32_t kSpinLockHeld = 1;
static constexpr uint32_t kSpinLockCooperative = 2;
static constexpr uint32_t kSpinLockDisabledScheduling = 4;
static constexpr uint32_t kSpinLockSleeper = 8;
// Includes kSpinLockSleeper.
static constexpr uint32_t kWaitTimeMask =
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);

// Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative(
base_internal::SchedulingMode scheduling_mode
)
{
return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
}

uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
void SlowLock() ABSL_ATTRIBUTE_COLD;
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
uint32_t SpinLoop();

inline bool TryLockImpl()
{
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
}

std::atomic<uint32_t> lockword_;

SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
};

// Corresponding locker object that arranges to acquire a spinlock for
// the duration of a C++ scope.
class ABSL_SCOPED_LOCKABLE SpinLockHolder
{
public:
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l) :
lock_(l)
{
l->Lock();
}
inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION()
{
lock_->Unlock();
}

SpinLockHolder(const SpinLockHolder&) = delete;
SpinLockHolder& operator=(const SpinLockHolder&) = delete;

private:
SpinLock* lock_;
};

// Register a hook for profiling support.
//
// The function pointer registered here will be called whenever a spinlock is
// contended. The callback is given an opaque handle to the contended spinlock
// and the number of wait cycles. This is thread-safe, but only a single
// profiler can be registered. It is an error to call this function multiple
// times with different arguments.
void RegisterSpinLockProfiler(void (*fn)(const void* lock, int64_t wait_cycles));

//------------------------------------------------------------------------------
// Public interface ends here.
//------------------------------------------------------------------------------

// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
// Otherwise, returns last observed value for lockword_.
inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value, uint32_t wait_cycles)
{
if ((lock_value & kSpinLockHeld) != 0)
{
return lock_value;
}

uint32_t sched_disabled_bit = 0;
if ((lock_value & kSpinLockCooperative) == 0)
{
// For non-cooperative locks we must make sure we mark ourselves as
// non-reschedulable before we attempt to CompareAndSwap.
if (base_internal::SchedulingGuard::DisableRescheduling())
{
sched_disabled_bit = kSpinLockDisabledScheduling;
}
}

if (!lockword_.compare_exchange_strong(
lock_value,
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
std::memory_order_acquire,
std::memory_order_relaxed
))
{
base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
}

return lock_value;
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_

+ 35
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock_akaros.inc View File

@@ -0,0 +1,35 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is an Akaros-specific part of spinlock_wait.cc

#include <atomic>

#include "absl/base/internal/scheduling_mode.h"

extern "C" {

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
// In Akaros, one must take care not to call anything that could cause a
// malloc(), a blocking system call, or a uthread_yield() while holding a
// spinlock. Our callers assume will not call into libraries or other
// arbitrary code.
}

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}

} // extern "C"

+ 71
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock_linux.inc View File

@@ -0,0 +1,71 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Linux-specific part of spinlock_wait.cc

#include <linux/futex.h>
#include <sys/syscall.h>
#include <unistd.h>

#include <atomic>
#include <climits>
#include <cstdint>
#include <ctime>

#include "absl/base/attributes.h"
#include "absl/base/internal/errno_saver.h"

// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
// by SYS_futex. We also assume that reads/writes done to the lockword
// by SYS_futex have rational semantics with regard to the
// std::atomic<> API. C++ provides no guarantees of these assumptions,
// but they are believed to hold in practice.
static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
"SpinLock lockword has the wrong size for a futex");

// Some Android headers are missing these definitions even though they
// support these futex operations.
#ifdef __BIONIC__
#ifndef SYS_futex
#define SYS_futex __NR_futex
#endif
#ifndef FUTEX_PRIVATE_FLAG
#define FUTEX_PRIVATE_FLAG 128
#endif
#endif

#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif

#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif

extern "C" {

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t> *w, uint32_t value, int,
absl::base_internal::SchedulingMode) {
absl::base_internal::ErrnoSaver errno_saver;
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, nullptr);
}

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t> *w, bool all) {
syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
}

} // extern "C"

+ 46
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock_posix.inc View File

@@ -0,0 +1,46 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Posix-specific part of spinlock_wait.cc

#include <sched.h>

#include <atomic>
#include <ctime>

#include "absl/base/internal/errno_saver.h"
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/port.h"

extern "C" {

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
absl::base_internal::ErrnoSaver errno_saver;
if (loop == 0) {
} else if (loop == 1) {
sched_yield();
} else {
struct timespec tm;
tm.tv_sec = 0;
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
nanosleep(&tm, nullptr);
}
}

ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}

} // extern "C"

+ 97
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock_wait.h View File

@@ -0,0 +1,97 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_

// Operations to make atomic transitions on a word, and to allow
// waiting for those transitions to become possible.

#include <stdint.h>
#include <atomic>

#include "absl/base/internal/scheduling_mode.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// SpinLockWait() waits until it can perform one of several transitions from
// "from" to "to". It returns when it performs a transition where done==true.
struct SpinLockWaitTransition
{
uint32_t from;
uint32_t to;
bool done;
};

// Wait until *w can transition from trans[i].from to trans[i].to for some i
// satisfying 0<=i<n && trans[i].done, atomically make the transition,
// then return the old value of *w. Make any other atomic transitions
// where !trans[i].done, but continue waiting.
//
// Wakeups for threads blocked on SpinLockWait do not respect priorities.
uint32_t SpinLockWait(std::atomic<uint32_t>* w, int n, const SpinLockWaitTransition trans[], SchedulingMode scheduling_mode);

// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all`
// is true, wake all such threads. On some systems, this may be a no-op; on
// those systems, threads calling SpinLockDelay() will always wake eventually
// even if SpinLockWake() is never called.
void SpinLockWake(std::atomic<uint32_t>* w, bool all);

// Wait for an appropriate spin delay on iteration "loop" of a
// spin loop on location *w, whose previously observed value was "value".
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
// or may wait for a call to SpinLockWake(w).
void SpinLockDelay(std::atomic<uint32_t>* w, uint32_t value, int loop, base_internal::SchedulingMode scheduling_mode);

// Helper used by AbslInternalSpinLockDelay.
// Returns a suggested delay in nanoseconds for iteration number "loop".
int SpinLockSuggestedDelayNS(int loop);

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

// In some build configurations we pass --detect-odr-violations to the
// gold linker. This causes it to flag weak symbol overrides as ODR
// violations. Because ODR only applies to C++ and not C,
// --detect-odr-violations ignores symbols not mangled with C++ names.
// By changing our extension points to be extern "C", we dodge this
// check.
extern "C"
{
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t>* w, bool all);
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* w, uint32_t value, int loop, absl::base_internal::SchedulingMode scheduling_mode
);
}

inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t>* w, bool all)
{
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)
(w, all);
}

inline void absl::base_internal::SpinLockDelay(
std::atomic<uint32_t>* w, uint32_t value, int loop, absl::base_internal::SchedulingMode scheduling_mode
)
{
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)
(w, value, loop, scheduling_mode);
}

#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_

+ 37
- 0
CAPI/cpp/grpc/include/absl/base/internal/spinlock_win32.inc View File

@@ -0,0 +1,37 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is a Win32-specific part of spinlock_wait.cc

#include <windows.h>
#include <atomic>
#include "absl/base/internal/scheduling_mode.h"

extern "C" {

void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) {
if (loop == 0) {
} else if (loop == 1) {
Sleep(0);
} else {
Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000);
}
}

void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}

} // extern "C"

+ 41
- 0
CAPI/cpp/grpc/include/absl/base/internal/strerror.h View File

@@ -0,0 +1,41 @@
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
#define ABSL_BASE_INTERNAL_STRERROR_H_

#include <string>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// A portable and thread-safe alternative to C89's `strerror`.
//
// The C89 specification of `strerror` is not suitable for use in a
// multi-threaded application as the returned string may be changed by calls to
// `strerror` from another thread. The many non-stdlib alternatives differ
// enough in their names, availability, and semantics to justify this wrapper
// around them. `errno` will not be modified by a call to `absl::StrError`.
std::string StrError(int errnum);

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_STRERROR_H_

+ 76
- 0
CAPI/cpp/grpc/include/absl/base/internal/sysinfo.h View File

@@ -0,0 +1,76 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file includes routines to find out characteristics
// of the machine a program is running on. It is undoubtedly
// system-dependent.

// Functions listed here that accept a pid_t as an argument act on the
// current process if the pid_t argument is 0
// All functions here are thread-hostile due to file caching unless
// commented otherwise.

#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_
#define ABSL_BASE_INTERNAL_SYSINFO_H_

#ifndef _WIN32
#include <sys/types.h>
#endif

#include <cstdint>

#include "absl/base/config.h"
#include "absl/base/port.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Nominal core processor cycles per second of each processor. This is _not_
// necessarily the frequency of the CycleClock counter (see cycleclock.h)
// Thread-safe.
double NominalCPUFrequency();

// Number of logical processors (hyperthreads) in system. Thread-safe.
int NumCPUs();

// Return the thread id of the current thread, as told by the system.
// No two currently-live threads implemented by the OS shall have the same ID.
// Thread ids of exited threads may be reused. Multiple user-level threads
// may have the same thread ID if multiplexed on the same OS thread.
//
// On Linux, you may send a signal to the resulting ID with kill(). However,
// it is recommended for portability that you use pthread_kill() instead.
#ifdef _WIN32
// On Windows, process id and thread id are of the same type according to the
// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
// 32-bit type.
using pid_t = uint32_t;
#endif
pid_t GetTID();

// Like GetTID(), but caches the result in thread-local storage in order
// to avoid unnecessary system calls. Note that there are some cases where
// one must call through to GetTID directly, which is why this exists as a
// separate function. For example, GetCachedTID() is not safe to call in
// an asynchronous signal-handling context nor right after a call to fork().
pid_t GetCachedTID();

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_SYSINFO_H_

+ 273
- 0
CAPI/cpp/grpc/include/absl/base/internal/thread_annotations.h View File

@@ -0,0 +1,273 @@
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: thread_annotations.h
// -----------------------------------------------------------------------------
//
// WARNING: This is a backwards compatible header and it will be removed after
// the migration to prefixed thread annotations is finished; please include
// "absl/base/thread_annotations.h".
//
// This header file contains macro definitions for thread safety annotations
// that allow developers to document the locking policies of multi-threaded
// code. The annotations can also help program analysis tools to identify
// potential thread safety issues.
//
// These annotations are implemented using compiler attributes. Using the macros
// defined here instead of raw attributes allow for portability and future
// compatibility.
//
// When referring to mutexes in the arguments of the attributes, you should
// use variable names or more complex expressions (e.g. my_object->mutex_)
// that evaluate to a concrete mutex object whenever possible. If the mutex
// you want to refer to is not in scope, you may use a member pointer
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.

#ifndef ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_

#if defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif

// GUARDED_BY()
//
// Documents if a shared field or global variable needs to be protected by a
// mutex. GUARDED_BY() allows the user to specify a particular mutex that
// should be held when accessing the annotated variable.
//
// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
// local variables, a local variable and its associated mutex can often be
// combined into a small class or struct, thereby allowing the annotation.
//
// Example:
//
// class Foo {
// Mutex mu_;
// int p1_ GUARDED_BY(mu_);
// ...
// };
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))

// PT_GUARDED_BY()
//
// Documents if the memory location pointed to by a pointer should be guarded
// by a mutex when dereferencing the pointer.
//
// Example:
// class Foo {
// Mutex mu_;
// int *p1_ PT_GUARDED_BY(mu_);
// ...
// };
//
// Note that a pointer variable to a shared memory location could itself be a
// shared variable.
//
// Example:
//
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))

// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
//
// Documents the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
//
// As with GUARDED_BY, this is only applicable to mutexes that are shared
// fields or global variables.
//
// Example:
//
// Mutex m1_;
// Mutex m2_ ACQUIRED_AFTER(m1_);
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))

#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))

// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
//
// Documents a function that expects a mutex to be held prior to entry.
// The mutex is expected to be held both on entry to, and exit from, the
// function.
//
// An exclusive lock allows read-write access to the guarded data member(s), and
// only one thread can acquire a lock exclusively at any one time. A shared lock
// allows read-only access, and any number of threads can acquire a shared lock
// concurrently.
//
// Generally, non-const methods should be annotated with
// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
// SHARED_LOCKS_REQUIRED.
//
// Example:
//
// Mutex mu1, mu2;
// int a GUARDED_BY(mu1);
// int b GUARDED_BY(mu2);
//
// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))

#define SHARED_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))

// LOCKS_EXCLUDED()
//
// Documents the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as Abseil's `Mutex` locks are
// non-reentrant).
#define LOCKS_EXCLUDED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))

// LOCK_RETURNED()
//
// Documents a function that returns a mutex without acquiring it. For example,
// a public getter method that returns a pointer to a private mutex should
// be annotated with LOCK_RETURNED.
#define LOCK_RETURNED(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

// LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
#define LOCKABLE \
THREAD_ANNOTATION_ATTRIBUTE__(lockable)

// SCOPED_LOCKABLE
//
// Documents if a class does RAII locking (such as the `MutexLock` class).
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
#define SCOPED_LOCKABLE \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)

// EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
#define EXCLUSIVE_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))

// SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
#define SHARED_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))

// UNLOCK_FUNCTION()
//
// Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function.
#define UNLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))

// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
//
// Documents functions that try to acquire a lock, and return success or failure
// (or a non-boolean value that can be interpreted as a boolean).
// The first argument should be `true` for functions that return `true` on
// success, or `false` for functions that return `false` on success. The second
// argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`.
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))

#define SHARED_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))

// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
#define ASSERT_EXCLUSIVE_LOCK(...) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))

#define ASSERT_SHARED_LOCK(...) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))

// NO_THREAD_SAFETY_ANALYSIS
//
// Turns off thread safety checking within the body of a particular function.
// This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle.
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

//------------------------------------------------------------------------------
// Tool-Supplied Annotations
//------------------------------------------------------------------------------

// TS_UNCHECKED should be placed around lock expressions that are not valid
// C++ syntax, but which are present for documentation purposes. These
// annotations will be ignored by the analysis.
#define TS_UNCHECKED(x) ""

// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
// It is used by automated tools to mark and disable invalid expressions.
// The annotation should either be fixed, or changed to TS_UNCHECKED.
#define TS_FIXME(x) ""

// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
// a particular function. However, this attribute is used to mark functions
// that are incorrect and need to be fixed. It is used by automated tools to
// avoid breaking the build when the analysis is updated.
// Code owners are expected to eventually fix the routine.
#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS

// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
// annotation that needs to be fixed, because it is producing thread safety
// warning. It disables the GUARDED_BY.
#define GUARDED_BY_FIXME(x)

// Disables warnings for a single read operation. This can be used to avoid
// warnings when it is known that the read is not actually involved in a race,
// but the compiler cannot confirm that.
#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)

namespace thread_safety_analysis
{

// Takes a reference to a guarded data member, and returns an unguarded
// reference.
template<typename T>
inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS
{
return v;
}

template<typename T>
inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS
{
return v;
}

} // namespace thread_safety_analysis

#endif // ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_

+ 272
- 0
CAPI/cpp/grpc/include/absl/base/internal/thread_identity.h View File

@@ -0,0 +1,272 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Each active thread has an ThreadIdentity that may represent the thread in
// various level interfaces. ThreadIdentity objects are never deallocated.
// When a thread terminates, its ThreadIdentity object may be reused for a
// thread created later.

#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_

#ifndef _WIN32
#include <pthread.h>
// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
// supported.
#include <unistd.h>
#endif

#include <atomic>
#include <cstdint>

#include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h"
#include "absl/base/optimization.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

struct SynchLocksHeld;
struct SynchWaitParams;

namespace base_internal
{

class SpinLock;
struct ThreadIdentity;

// Used by the implementation of absl::Mutex and absl::CondVar.
struct PerThreadSynch
{
// The internal representation of absl::Mutex and absl::CondVar rely
// on the alignment of PerThreadSynch. Both store the address of the
// PerThreadSynch in the high-order bits of their internal state,
// which means the low kLowZeroBits of the address of PerThreadSynch
// must be zero.
static constexpr int kLowZeroBits = 8;
static constexpr int kAlignment = 1 << kLowZeroBits;

// Returns the associated ThreadIdentity.
// This can be implemented as a cast because we guarantee
// PerThreadSynch is the first element of ThreadIdentity.
ThreadIdentity* thread_identity()
{
return reinterpret_cast<ThreadIdentity*>(this);
}

PerThreadSynch* next; // Circular waiter queue; initialized to 0.
PerThreadSynch* skip; // If non-zero, all entries in Mutex queue
// up to and including "skip" have same
// condition as this, and will be woken later
bool may_skip; // if false while on mutex queue, a mutex unlocker
// is using this PerThreadSynch as a terminator. Its
// skip field must not be filled in because the loop
// might then skip over the terminator.
bool wake; // This thread is to be woken from a Mutex.
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
//
// The value of "x->cond_waiter" is meaningless if "x" is not on a
// Mutex waiter list.
bool cond_waiter;
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
// true if UnlockSlow could be searching
// for a waiter to wake. Used for an optimization
// in Enqueue(). true is always a valid value.
// Can be reset to false when the unlocker or any
// writer releases the lock, or a reader fully
// releases the lock. It may not be set to false
// by a reader that decrements the count to
// non-zero. protected by mutex spinlock
bool suppress_fatal_errors; // If true, try to proceed even in the face
// of broken invariants. This is used within
// fatal signal handlers to improve the
// chances of debug logging information being
// output successfully.
int priority; // Priority of thread (updated every so often).

// State values:
// kAvailable: This PerThreadSynch is available.
// kQueued: This PerThreadSynch is unavailable, it's currently queued on a
// Mutex or CondVar waistlist.
//
// Transitions from kQueued to kAvailable require a release
// barrier. This is needed as a waiter may use "state" to
// independently observe that it's no longer queued.
//
// Transitions from kAvailable to kQueued require no barrier, they
// are externally ordered by the Mutex.
enum State
{
kAvailable,
kQueued
};
std::atomic<State> state;

// The wait parameters of the current wait. waitp is null if the
// thread is not waiting. Transitions from null to non-null must
// occur before the enqueue commit point (state = kQueued in
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
// null must occur after the wait is finished (state = kAvailable in
// Mutex::Block() and CondVar::WaitCommon()). This field may be
// changed only by the thread that describes this PerThreadSynch. A
// special case is Fer(), which calls Enqueue() on another thread,
// but with an identical SynchWaitParams pointer, thus leaving the
// pointer unchanged.
SynchWaitParams* waitp;

intptr_t readers; // Number of readers in mutex.

// When priority will next be read (cycles).
int64_t next_priority_read_cycles;

// Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld* all_locks;
};

// The instances of this class are allocated in NewThreadIdentity() with an
// alignment of PerThreadSynch::kAlignment.
struct ThreadIdentity
{
// Must be the first member. The Mutex implementation requires that
// the PerThreadSynch object associated with each thread is
// PerThreadSynch::kAlignment aligned. We provide this alignment on
// ThreadIdentity itself.
PerThreadSynch per_thread_synch;

// Private: Reserved for absl::synchronization_internal::Waiter.
struct WaiterState
{
alignas(void*) char data[128];
} waiter_state;

// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
std::atomic<int>* blocked_count_ptr;

// The following variables are mostly read/written just by the
// thread itself. The only exception is that these are read by
// a ticker thread as a hint.
std::atomic<int> ticker; // Tick counter, incremented once per second.
std::atomic<int> wait_start; // Ticker value when thread started waiting.
std::atomic<bool> is_idle; // Has thread become idle yet?

ThreadIdentity* next;
};

// Returns the ThreadIdentity object representing the calling thread; guaranteed
// to be unique for its lifetime. The returned object will remain valid for the
// program's lifetime; although it may be re-assigned to a subsequent thread.
// If one does not exist, return nullptr instead.
//
// Does not malloc(*), and is async-signal safe.
// [*] Technically pthread_setspecific() does malloc on first use; however this
// is handled internally within tcmalloc's initialization already.
//
// New ThreadIdentity objects can be constructed and associated with a thread
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
ThreadIdentity* CurrentThreadIdentityIfPresent();

using ThreadIdentityReclaimerFunction = void (*)(void*);

// Sets the current thread identity to the given value. 'reclaimer' is a
// pointer to the global function for cleaning up instances on thread
// destruction.
void SetCurrentThreadIdentity(ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer);

// Removes the currently associated ThreadIdentity from the running thread.
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
// from that function.
void ClearCurrentThreadIdentity();

// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
// index>
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
#endif

#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
#endif

#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set
#else
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
#endif

#ifdef ABSL_THREAD_IDENTITY_MODE
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
#elif defined(_WIN32) && !defined(__MINGW32__)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
// Support for async-safe TLS was specifically added in GRTEv4. It's not
// present in the upstream eglibc.
// Note: Current default for production systems.
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
#else
#define ABSL_THREAD_IDENTITY_MODE \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#endif

#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11

#if ABSL_PER_THREAD_TLS
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
thread_identity_ptr;
#elif defined(ABSL_HAVE_THREAD_LOCAL)
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
#else
#error Thread-local storage not detected on this platform
#endif

// thread_local variables cannot be in headers exposed by DLLs or in certain
// build configurations on Apple platforms. However, it is important for
// performance reasons in general that `CurrentThreadIdentityIfPresent` be
// inlined. In the other cases we opt to have the function not be inlined. Note
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
// this entire inline definition.
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
!defined(ABSL_CONSUME_DLL)
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
#endif

#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
inline ThreadIdentity* CurrentThreadIdentityIfPresent()
{
return thread_identity_ptr;
}
#endif

#elif ABSL_THREAD_IDENTITY_MODE != \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error Unknown ABSL_THREAD_IDENTITY_MODE
#endif

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_

+ 77
- 0
CAPI/cpp/grpc/include/absl/base/internal/throw_delegate.h View File

@@ -0,0 +1,77 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_

#include <string>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Helper functions that allow throwing exceptions consistently from anywhere.
// The main use case is for header-based libraries (eg templates), as they will
// be built by many different targets with their own compiler options.
// In particular, this will allow a safe way to throw exceptions even if the
// caller is compiled with -fno-exceptions. This is intended for implementing
// things like map<>::at(), which the standard documents as throwing an
// exception on error.
//
// Using other techniques like #if tricks could lead to ODR violations.
//
// You shouldn't use it unless you're writing code that you know will be built
// both with and without exceptions and you need to conform to an interface
// that uses exceptions.

[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
[[noreturn]] void ThrowStdLogicError(const char* what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
[[noreturn]] void ThrowStdDomainError(const char* what_arg);
[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
[[noreturn]] void ThrowStdLengthError(const char* what_arg);
[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
[[noreturn]] void ThrowStdRangeError(const char* what_arg);
[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);

[[noreturn]] void ThrowStdBadFunctionCall();
[[noreturn]] void ThrowStdBadAlloc();

// ThrowStdBadArrayNewLength() cannot be consistently supported because
// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
// libcxx (as of 3.2) and msvc (as of 2015) both have it.
// [[noreturn]] void ThrowStdBadArrayNewLength();

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_

+ 68
- 0
CAPI/cpp/grpc/include/absl/base/internal/tsan_mutex_interface.h View File

@@ -0,0 +1,68 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This file is intended solely for spinlock.h.
// It provides ThreadSanitizer annotations for custom mutexes.
// See <sanitizer/tsan_interface.h> for meaning of these annotations.

#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_

#include "absl/base/config.h"

// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
// Macro intended only for internal use.
//
// Checks whether LLVM Thread Sanitizer interfaces are available.
// First made available in LLVM 5.0 (Sep 2017).
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
#endif

#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
#if __has_include(<sanitizer/tsan_interface.h>)
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
#endif
#endif

#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
#include <sanitizer/tsan_interface.h>

#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert

#else

#define ABSL_TSAN_MUTEX_CREATE(...)
#define ABSL_TSAN_MUTEX_DESTROY(...)
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
#define ABSL_TSAN_MUTEX_POST_DIVERT(...)

#endif

#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_

+ 96
- 0
CAPI/cpp/grpc/include/absl/base/internal/unaligned_access.h View File

@@ -0,0 +1,96 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_

#include <string.h>

#include <cstdint>

#include "absl/base/attributes.h"
#include "absl/base/config.h"

// unaligned APIs

// Portable handling of unaligned loads, stores, and copies.

// The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus)
namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

inline uint16_t UnalignedLoad16(const void* p)
{
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}

inline uint32_t UnalignedLoad32(const void* p)
{
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}

inline uint64_t UnalignedLoad64(const void* p)
{
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}

inline void UnalignedStore16(void* p, uint16_t v)
{
memcpy(p, &v, sizeof v);
}

inline void UnalignedStore32(void* p, uint32_t v)
{
memcpy(p, &v, sizeof v);
}

inline void UnalignedStore64(void* p, uint64_t v)
{
memcpy(p, &v, sizeof v);
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))

#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))

#endif // defined(__cplusplus), end of unaligned API

#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_

+ 138
- 0
CAPI/cpp/grpc/include/absl/base/internal/unscaledcycleclock.h View File

@@ -0,0 +1,138 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// UnscaledCycleClock
// An UnscaledCycleClock yields the value and frequency of a cycle counter
// that increments at a rate that is approximately constant.
// This class is for internal use only, you should consider using CycleClock
// instead.
//
// Notes:
// The cycle counter frequency is not necessarily the core clock frequency.
// That is, CycleCounter cycles are not necessarily "CPU cycles".
//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
// slightly when read from different CPUs of a multiprocessor. Usually,
// we try to ensure that the operating system adjusts values periodically
// so that values agree approximately. If you need stronger guarantees,
// consider using alternate interfaces.
//
// The CPU is not required to maintain the ordering of a cycle counter read
// with respect to surrounding instructions.

#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_

#include <cstdint>

#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif

#include "absl/base/port.h"

// The following platforms have an implementation of a hardware counter.
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__riscv) || \
defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC))
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
#else
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
#endif

// The following platforms often disable access to the hardware
// counter (through a sandbox) even if the underlying hardware has a
// usable counter. The CycleTimer interface also requires a *scaled*
// CycleClock that runs at atleast 1 MHz. We've found some Android
// ARM64 devices where this is not the case, so we disable it by
// default on Android ARM64.
#if defined(__native_client__) || (defined(__APPLE__)) || \
(defined(__ANDROID__) && defined(__aarch64__))
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
#else
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1
#endif

// UnscaledCycleClock is an optional internal feature.
// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence.
// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1
#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK)
#define ABSL_USE_UNSCALED_CYCLECLOCK \
(ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \
ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT)
#endif

#if ABSL_USE_UNSCALED_CYCLECLOCK

// This macro can be used to test if UnscaledCycleClock::Frequency()
// is NominalCPUFrequency() on a particular platform.
#if (defined(__i386__) || defined(__x86_64__) || defined(__riscv) || defined(_M_IX86) || defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace time_internal
{
class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal

namespace base_internal
{
class CycleClock;
class UnscaledCycleClockWrapperForInitializeFrequency;

class UnscaledCycleClock
{
private:
UnscaledCycleClock() = delete;

// Return the value of a cycle counter that counts at a rate that is
// approximately constant.
static int64_t Now();

// Return the how much UnscaledCycleClock::Now() increases per second.
// This is not necessarily the core CPU clock frequency.
// It may be the nominal value report by the kernel, rather than a measured
// value.
static double Frequency();

// Allowed users
friend class base_internal::CycleClock;
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
};

#if defined(__x86_64__)

inline int64_t UnscaledCycleClock::Now()
{
uint64_t low, high;
__asm__ volatile("rdtsc"
: "=a"(low), "=d"(high));
return (high << 32) | low;
}

#endif

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_USE_UNSCALED_CYCLECLOCK

#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_

+ 177
- 0
CAPI/cpp/grpc/include/absl/base/log_severity.h View File

@@ -0,0 +1,177 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_BASE_LOG_SEVERITY_H_
#define ABSL_BASE_LOG_SEVERITY_H_

#include <array>
#include <ostream>

#include "absl/base/attributes.h"
#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

// absl::LogSeverity
//
// Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no
// special semantics.
//
// Values other than the four defined levels (e.g. produced by `static_cast`)
// are valid, but their semantics when passed to a function, macro, or flag
// depend on the function, macro, or flag. The usual behavior is to normalize
// such values to a defined severity level, however in some cases values other
// than the defined levels are useful for comparison.
//
// Example:
//
// // Effectively disables all logging:
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
//
// Abseil flags may be defined with type `LogSeverity`. Dependency layering
// constraints require that the `AbslParseFlag()` overload be declared and
// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
// overload is defined there as well for consistency.
//
// absl::LogSeverity Flag String Representation
//
// An `absl::LogSeverity` has a string representation used for parsing
// command-line flags based on the enumerator name (e.g. `kFatal`) or
// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
//
// Additionally, the parser accepts arbitrary integers (as if the type were
// `int`).
//
// Examples:
//
// --my_log_level=kInfo
// --my_log_level=INFO
// --my_log_level=info
// --my_log_level=0
//
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
// the standard levels and a base-ten integer otherwise.
enum class LogSeverity : int
{
kInfo = 0,
kWarning = 1,
kError = 2,
kFatal = 3,
};

// LogSeverities()
//
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
// least to most severe.
constexpr std::array<absl::LogSeverity, 4> LogSeverities()
{
return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning, absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
}

// LogSeverityName()
//
// Returns the all-caps string representation (e.g. "INFO") of the specified
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
constexpr const char* LogSeverityName(absl::LogSeverity s)
{
return s == absl::LogSeverity::kInfo ? "INFO" : s == absl::LogSeverity::kWarning ? "WARNING" :
s == absl::LogSeverity::kError ? "ERROR" :
s == absl::LogSeverity::kFatal ? "FATAL" :
"UNKNOWN";
}

// NormalizeLogSeverity()
//
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
// normalize to `kError` (**NOT** `kFatal`).
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s)
{
return s < absl::LogSeverity::kInfo ? absl::LogSeverity::kInfo : s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError :
s;
}
constexpr absl::LogSeverity NormalizeLogSeverity(int s)
{
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
}

// operator<<
//
// The exact representation of a streamed `absl::LogSeverity` is deliberately
// unspecified; do not rely on it.
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);

// Enums representing a lower bound for LogSeverity. APIs that only operate on
// messages of at least a certain level (for example, `SetMinLogLevel()`) use
// this type to specify that level. absl::LogSeverityAtLeast::kInfinity is
// a level above all threshold levels and therefore no log message will
// ever meet this threshold.
enum class LogSeverityAtLeast : int
{
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
kInfinity = 1000,
};

std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s);

// Enums representing an upper bound for LogSeverity. APIs that only operate on
// messages of at most a certain level (for example, buffer all messages at or
// below a certain level) use this type to specify that level.
// absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold
// levels and therefore will exclude all log messages.
enum class LogSeverityAtMost : int
{
kNegativeInfinity = -1000,
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
};

std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s);

#define COMPOP(op1, op2, T) \
constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) \
{ \
return static_cast<absl::LogSeverity>(lhs) op1 rhs; \
} \
constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) \
{ \
return lhs op2 static_cast<absl::LogSeverity>(rhs); \
}

// Comparisons between `LogSeverity` and `LogSeverityAtLeast`/
// `LogSeverityAtMost` are only supported in one direction.
// Valid checks are:
// LogSeverity >= LogSeverityAtLeast
// LogSeverity < LogSeverityAtLeast
// LogSeverity <= LogSeverityAtMost
// LogSeverity > LogSeverityAtMost
COMPOP(>, <, LogSeverityAtLeast)
COMPOP(<=, >=, LogSeverityAtLeast)
COMPOP(<, >, LogSeverityAtMost)
COMPOP(>=, <=, LogSeverityAtMost)
#undef COMPOP

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_LOG_SEVERITY_H_

+ 165
- 0
CAPI/cpp/grpc/include/absl/base/macros.h View File

@@ -0,0 +1,165 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: macros.h
// -----------------------------------------------------------------------------
//
// This header file defines the set of language macros used within Abseil code.
// For the set of macros used to determine supported compilers and platforms,
// see absl/base/config.h instead.
//
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.

#ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_

#include <cassert>
#include <cstddef>

#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"

// ABSL_ARRAYSIZE()
//
// Returns the number of elements in an array as a compile-time constant, which
// can be used in defining new arrays. If you use this macro on a pointer by
// mistake, you will get a compile-time error.
#define ABSL_ARRAYSIZE(array) \
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace macros_internal
{
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template<typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
ABSL_NAMESPACE_END
} // namespace absl

// ABSL_BAD_CALL_IF()
//
// Used on a function overload to trap bad calls: any call that matches the
// overload will cause a compile-time error. This macro uses a clang-specific
// "enable_if" attribute, as described at
// https://clang.llvm.org/docs/AttributeReference.html#enable-if
//
// Overloads which use this macro should be bracketed by
// `#ifdef ABSL_BAD_CALL_IF`.
//
// Example:
//
// int isdigit(int c);
// #ifdef ABSL_BAD_CALL_IF
// int isdigit(int c)
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
// "'c' must have the value of an unsigned char or EOF");
// #endif // ABSL_BAD_CALL_IF
#if ABSL_HAVE_ATTRIBUTE(enable_if)
#define ABSL_BAD_CALL_IF(expr, msg) \
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
#endif

// ABSL_ASSERT()
//
// In C++11, `assert` can't be used portably within constexpr functions.
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
// functions. Example:
//
// constexpr double Divide(double a, double b) {
// return ABSL_ASSERT(b != 0), a / b;
// }
//
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
#define ABSL_ASSERT(expr) \
(false ? static_cast<void>(expr) : static_cast<void>(0))
#else
#define ABSL_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) : [] { assert(false && #expr); }()) // NOLINT
#endif

// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
// aborts the program in release mode (when NDEBUG is defined). The
// implementation should abort the program as quickly as possible and ideally it
// should not be possible to ignore the abort request.
#if (ABSL_HAVE_BUILTIN(__builtin_trap) && ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_INTERNAL_HARDENING_ABORT() \
do \
{ \
__builtin_trap(); \
__builtin_unreachable(); \
} while (false)
#else
#define ABSL_INTERNAL_HARDENING_ABORT() abort()
#endif

// ABSL_HARDENING_ASSERT()
//
// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
// runtime assertions that should be enabled in hardened builds even when
// `NDEBUG` is defined.
//
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
// `ABSL_ASSERT()`.
//
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
// hardened mode.
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
#define ABSL_HARDENING_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
#else
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
#endif

#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
#define ABSL_INTERNAL_RETHROW \
do \
{ \
throw; \
} while (false)
#else // ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY if (true)
#define ABSL_INTERNAL_CATCH_ANY else if (false)
#define ABSL_INTERNAL_RETHROW \
do \
{ \
} while (false)
#endif // ABSL_HAVE_EXCEPTIONS

// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which
// reaches one has undefined behavior, and the compiler may optimize
// accordingly.
#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define ABSL_INTERNAL_UNREACHABLE __assume(0)
#else
#define ABSL_INTERNAL_UNREACHABLE
#endif

#endif // ABSL_BASE_MACROS_H_

+ 263
- 0
CAPI/cpp/grpc/include/absl/base/optimization.h View File

@@ -0,0 +1,263 @@
//
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: optimization.h
// -----------------------------------------------------------------------------
//
// This header file defines portable macros for performance optimization.

#ifndef ABSL_BASE_OPTIMIZATION_H_
#define ABSL_BASE_OPTIMIZATION_H_

#include <assert.h>

#include "absl/base/config.h"

// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
//
// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
// useful when you wish to preserve the existing function order within a stack
// trace for logging, debugging, or profiling purposes.
//
// Example:
//
// int f() {
// int result = g();
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
// return result;
// }
#if defined(__pnacl__)
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() \
if (volatile int x = 0) \
{ \
(void)x; \
}
#elif defined(__clang__)
// Clang will not tail call given inline volatile assembly.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(__GNUC__)
// GCC will not tail call given inline volatile assembly.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(_MSC_VER)
#include <intrin.h>
// The __nop() intrinsic blocks the optimisation.
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
#else
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() \
if (volatile int x = 0) \
{ \
(void)x; \
}
#endif

// ABSL_CACHELINE_SIZE
//
// Explicitly defines the size of the L1 cache for purposes of alignment.
// Setting the cacheline size allows you to specify that certain objects be
// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
// (See below.)
//
// NOTE: this macro should be replaced with the following C++17 features, when
// those are generally available:
//
// * `std::hardware_constructive_interference_size`
// * `std::hardware_destructive_interference_size`
//
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
#if defined(__GNUC__)
// Cache line alignment
#if defined(__i386__) || defined(__x86_64__)
#define ABSL_CACHELINE_SIZE 64
#elif defined(__powerpc64__)
#define ABSL_CACHELINE_SIZE 128
#elif defined(__aarch64__)
// We would need to read special register ctr_el0 to find out L1 dcache size.
// This value is a good estimate based on a real aarch64 machine.
#define ABSL_CACHELINE_SIZE 64
#elif defined(__arm__)
// Cache line sizes for ARM: These values are not strictly correct since
// cache line sizes depend on implementations, not architectures. There
// are even implementations with cache line sizes configurable at boot
// time.
#if defined(__ARM_ARCH_5T__)
#define ABSL_CACHELINE_SIZE 32
#elif defined(__ARM_ARCH_7A__)
#define ABSL_CACHELINE_SIZE 64
#endif
#endif

#ifndef ABSL_CACHELINE_SIZE
// A reasonable default guess. Note that overestimates tend to waste more
// space, while underestimates tend to waste more time.
#define ABSL_CACHELINE_SIZE 64
#endif

// ABSL_CACHELINE_ALIGNED
//
// Indicates that the declared object be cache aligned using
// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
// load a set of related objects in the L1 cache for performance improvements.
// Cacheline aligning objects properly allows constructive memory sharing and
// prevents destructive (or "false") memory sharing.
//
// NOTE: callers should replace uses of this macro with `alignas()` using
// `std::hardware_constructive_interference_size` and/or
// `std::hardware_destructive_interference_size` when C++17 becomes available to
// them.
//
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
//
// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
// or `__declspec` attribute. For compilers where this is not known to work,
// the macro expands to nothing.
//
// No further guarantees are made here. The result of applying the macro
// to variables and types is always implementation-defined.
//
// WARNING: It is easy to use this attribute incorrectly, even to the point
// of causing bugs that are difficult to diagnose, crash, etc. It does not
// of itself guarantee that objects are aligned to a cache line.
//
// NOTE: Some compilers are picky about the locations of annotations such as
// this attribute, so prefer to put it at the beginning of your declaration.
// For example,
//
// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
//
// class ABSL_CACHELINE_ALIGNED Bar { ...
//
// Recommendations:
//
// 1) Consult compiler documentation; this comment is not kept in sync as
// toolchains evolve.
// 2) Verify your use has the intended effect. This often requires inspecting
// the generated machine code.
// 3) Prefer applying this attribute to individual variables. Avoid
// applying it to types. This tends to localize the effect.
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
#elif defined(_MSC_VER)
#define ABSL_CACHELINE_SIZE 64
#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
#else
#define ABSL_CACHELINE_SIZE 64
#define ABSL_CACHELINE_ALIGNED
#endif

// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
//
// Enables the compiler to prioritize compilation using static analysis for
// likely paths within a boolean branch.
//
// Example:
//
// if (ABSL_PREDICT_TRUE(expression)) {
// return result; // Faster if more likely
// } else {
// return 0;
// }
//
// Compilers can use the information that a certain branch is not likely to be
// taken (for instance, a CHECK failure) to optimize for the common case in
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
//
// Recommendation: Modern CPUs dynamically predict branch execution paths,
// typically with accuracy greater than 97%. As a result, annotating every
// branch in a codebase is likely counterproductive; however, annotating
// specific branches that are both hot and consistently mispredicted is likely
// to yield performance improvements.
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
#else
#define ABSL_PREDICT_FALSE(x) (x)
#define ABSL_PREDICT_TRUE(x) (x)
#endif

// ABSL_ASSUME(cond)
//
// Informs the compiler that a condition is always true and that it can assume
// it to be true for optimization purposes.
//
// WARNING: If the condition is false, the program can produce undefined and
// potentially dangerous behavior.
//
// In !NDEBUG mode, the condition is checked with an assert().
//
// NOTE: The expression must not have side effects, as it may only be evaluated
// in some compilation modes and not others. Some compilers may issue a warning
// if the compiler cannot prove the expression has no side effects. For example,
// the expression should not use a function call since the compiler cannot prove
// that a function call does not have side effects.
//
// Example:
//
// int x = ...;
// ABSL_ASSUME(x >= 0);
// // The compiler can optimize the division to a simple right shift using the
// // assumption specified above.
// int y = x / 16;
//
#if !defined(NDEBUG)
#define ABSL_ASSUME(cond) assert(cond)
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_ASSUME(cond) __builtin_assume(cond)
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_ASSUME(cond) \
do \
{ \
if (!(cond)) \
__builtin_unreachable(); \
} while (0)
#elif defined(_MSC_VER)
#define ABSL_ASSUME(cond) __assume(cond)
#else
#define ABSL_ASSUME(cond) \
do \
{ \
static_cast<void>(false && (cond)); \
} while (0)
#endif

// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
// This macro forces small unique name on a static file level symbols like
// static local variables or static functions. This is intended to be used in
// macro definitions to optimize the cost of generated code. Do NOT use it on
// symbols exported from translation unit since it may cause a link time
// conflict.
//
// Example:
//
// #define MY_MACRO(txt)
// namespace {
// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
// const char* VeryVeryLongFuncName() { return txt; }
// }
//

#if defined(__GNUC__)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
#else
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
#endif

#endif // ABSL_BASE_OPTIMIZATION_H_

+ 235
- 0
CAPI/cpp/grpc/include/absl/base/options.h View File

@@ -0,0 +1,235 @@
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: options.h
// -----------------------------------------------------------------------------
//
// This file contains Abseil configuration options for setting specific
// implementations instead of letting Abseil determine which implementation to
// use at compile-time. Setting these options may be useful for package or build
// managers who wish to guarantee ABI stability within binary builds (which are
// otherwise difficult to enforce).
//
// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
// maintainers of package managers who wish to package Abseil read and
// understand this file! ***
//
// Abseil contains a number of possible configuration endpoints, based on
// parameters such as the detected platform, language version, or command-line
// flags used to invoke the underlying binary. As is the case with all
// libraries, binaries which contain Abseil code must ensure that separate
// packages use the same compiled copy of Abseil to avoid a diamond dependency
// problem, which can occur if two packages built with different Abseil
// configuration settings are linked together. Diamond dependency problems in
// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
// linker errors), or undefined behavior (resulting in crashes).
//
// Diamond dependency problems can be avoided if all packages utilize the same
// exact version of Abseil. Building from source code with the same compilation
// parameters is the easiest way to avoid such dependency problems. However, for
// package managers who cannot control such compilation parameters, we are
// providing the file to allow you to inject ABI (Application Binary Interface)
// stability across builds. Settings options in this file will neither change
// API nor ABI, providing a stable copy of Abseil between packages.
//
// Care must be taken to keep options within these configurations isolated
// from any other dynamic settings, such as command-line flags which could alter
// these options. This file is provided specifically to help build and package
// managers provide a stable copy of Abseil within their libraries and binaries;
// other developers should not have need to alter the contents of this file.
//
// -----------------------------------------------------------------------------
// Usage
// -----------------------------------------------------------------------------
//
// For any particular package release, set the appropriate definitions within
// this file to whatever value makes the most sense for your package(s). Note
// that, by default, most of these options, at the moment, affect the
// implementation of types; future options may affect other implementation
// details.
//
// NOTE: the defaults within this file all assume that Abseil can select the
// proper Abseil implementation at compile-time, which will not be sufficient
// to guarantee ABI stability to package managers.

#ifndef ABSL_BASE_OPTIONS_H_
#define ABSL_BASE_OPTIONS_H_

// Include a standard library header to allow configuration based on the
// standard library in use.
#ifdef __cplusplus
#include <ciso646>
#endif

// -----------------------------------------------------------------------------
// Type Compatibility Options
// -----------------------------------------------------------------------------
//
// ABSL_OPTION_USE_STD_ANY
//
// This option controls whether absl::any is implemented as an alias to
// std::any, or as an independent implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use an alias to std::any. This requires that all code
// using Abseil is built in C++17 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if a working std::any is available. This option is
// useful when you are building your entire program, including all of its
// dependencies, from source. It should not be used otherwise -- for example,
// if you are distributing Abseil in a binary package manager -- since in
// mode 2, absl::any will name a different type, with a different mangled name
// and binary layout, depending on the compiler flags passed by the end user.
// For more info, see https://abseil.io/about/design/dropin-types.
//
// User code should not inspect this macro. To check in the preprocessor if
// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.

#define ABSL_OPTION_USE_STD_ANY 0

// ABSL_OPTION_USE_STD_OPTIONAL
//
// This option controls whether absl::optional is implemented as an alias to
// std::optional, or as an independent implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use an alias to std::optional. This requires that all
// code using Abseil is built in C++17 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if a working std::optional is available. This option
// is useful when you are building your program from source. It should not be
// used otherwise -- for example, if you are distributing Abseil in a binary
// package manager -- since in mode 2, absl::optional will name a different
// type, with a different mangled name and binary layout, depending on the
// compiler flags passed by the end user. For more info, see
// https://abseil.io/about/design/dropin-types.

// User code should not inspect this macro. To check in the preprocessor if
// absl::optional is a typedef of std::optional, use the feature macro
// ABSL_USES_STD_OPTIONAL.

#define ABSL_OPTION_USE_STD_OPTIONAL 0

// ABSL_OPTION_USE_STD_STRING_VIEW
//
// This option controls whether absl::string_view is implemented as an alias to
// std::string_view, or as an independent implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use an alias to std::string_view. This requires that
// all code using Abseil is built in C++17 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if a working std::string_view is available. This
// option is useful when you are building your program from source. It should
// not be used otherwise -- for example, if you are distributing Abseil in a
// binary package manager -- since in mode 2, absl::string_view will name a
// different type, with a different mangled name and binary layout, depending on
// the compiler flags passed by the end user. For more info, see
// https://abseil.io/about/design/dropin-types.
//
// User code should not inspect this macro. To check in the preprocessor if
// absl::string_view is a typedef of std::string_view, use the feature macro
// ABSL_USES_STD_STRING_VIEW.

#define ABSL_OPTION_USE_STD_STRING_VIEW 0

// ABSL_OPTION_USE_STD_VARIANT
//
// This option controls whether absl::variant is implemented as an alias to
// std::variant, or as an independent implementation.
//
// A value of 0 means to use Abseil's implementation. This requires only C++11
// support, and is expected to work on every toolchain we support.
//
// A value of 1 means to use an alias to std::variant. This requires that all
// code using Abseil is built in C++17 mode or later.
//
// A value of 2 means to detect the C++ version being used to compile Abseil,
// and use an alias only if a working std::variant is available. This option
// is useful when you are building your program from source. It should not be
// used otherwise -- for example, if you are distributing Abseil in a binary
// package manager -- since in mode 2, absl::variant will name a different
// type, with a different mangled name and binary layout, depending on the
// compiler flags passed by the end user. For more info, see
// https://abseil.io/about/design/dropin-types.
//
// User code should not inspect this macro. To check in the preprocessor if
// absl::variant is a typedef of std::variant, use the feature macro
// ABSL_USES_STD_VARIANT.

#define ABSL_OPTION_USE_STD_VARIANT 0

// ABSL_OPTION_USE_INLINE_NAMESPACE
// ABSL_OPTION_INLINE_NAMESPACE_NAME
//
// These options controls whether all entities in the absl namespace are
// contained within an inner inline namespace. This does not affect the
// user-visible API of Abseil, but it changes the mangled names of all symbols.
//
// This can be useful as a version tag if you are distributing Abseil in
// precompiled form. This will prevent a binary library build of Abseil with
// one inline namespace being used with headers configured with a different
// inline namespace name. Binary packagers are reminded that Abseil does not
// guarantee any ABI stability in Abseil, so any update of Abseil or
// configuration change in such a binary package should be combined with a
// new, unique value for the inline namespace name.
//
// A value of 0 means not to use inline namespaces.
//
// A value of 1 means to use an inline namespace with the given name inside
// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
// be changed to a new, unique identifier name. In particular "head" is not
// allowed.

#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20220623

// ABSL_OPTION_HARDENED
//
// This option enables a "hardened" build in release mode (in this context,
// release mode is defined as a build where the `NDEBUG` macro is defined).
//
// A value of 0 means that "hardened" mode is not enabled.
//
// A value of 1 means that "hardened" mode is enabled.
//
// Hardened builds have additional security checks enabled when `NDEBUG` is
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
// no-op, as well as disabling other bespoke program consistency checks. By
// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
// release mode. These checks guard against programming errors that may lead to
// security vulnerabilities. In release mode, when one of these programming
// errors is encountered, the program will immediately abort, possibly without
// any attempt at logging.
//
// The checks enabled by this option are not free; they do incur runtime cost.
//
// The checks enabled by this option are always active when `NDEBUG` is not
// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
// checks enabled by this option may abort the program in a different way and
// log additional information when `NDEBUG` is not defined.

#define ABSL_OPTION_HARDENED 0

#endif // ABSL_BASE_OPTIONS_H_

+ 111
- 0
CAPI/cpp/grpc/include/absl/base/policy_checks.h View File

@@ -0,0 +1,111 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: policy_checks.h
// -----------------------------------------------------------------------------
//
// This header enforces a minimum set of policies at build time, such as the
// supported compiler and library versions. Unsupported configurations are
// reported with `#error`. This enforcement is best effort, so successfully
// compiling this header does not guarantee a supported configuration.

#ifndef ABSL_BASE_POLICY_CHECKS_H_
#define ABSL_BASE_POLICY_CHECKS_H_

// Included for the __GLIBC_PREREQ macro used below.
#include <limits.h>

// Included for the _STLPORT_VERSION macro used below.
#if defined(__cplusplus)
#include <cstddef>
#endif

// -----------------------------------------------------------------------------
// Operating System Check
// -----------------------------------------------------------------------------

#if defined(__CYGWIN__)
#error "Cygwin is not supported."
#endif

// -----------------------------------------------------------------------------
// Toolchain Check
// -----------------------------------------------------------------------------

// We support MSVC++ 14.0 update 2 and later.
// This minimum will go up.
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
#error "This package requires Visual Studio 2015 Update 2 or higher."
#endif

// We support gcc 4.7 and later.
// This minimum will go up.
#if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
#error "This package requires gcc 4.7 or higher."
#endif
#endif

// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
// This corresponds to Apple Xcode version 4.5.
// This minimum will go up.
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
#error "This package requires __apple_build_version__ of 4211165 or higher."
#endif

// -----------------------------------------------------------------------------
// C++ Version Check
// -----------------------------------------------------------------------------

// Enforce C++11 as the minimum. Note that Visual Studio has not
// advanced __cplusplus despite being good enough for our purposes, so
// so we exempt it from the check.
#if defined(__cplusplus) && !defined(_MSC_VER)
#if __cplusplus < 201103L
#error "C++ versions less than C++11 are not supported."
#endif
#endif

// -----------------------------------------------------------------------------
// Standard Library Check
// -----------------------------------------------------------------------------

#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif

// -----------------------------------------------------------------------------
// `char` Size Check
// -----------------------------------------------------------------------------

// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
// platform where this is not the case, please provide us with the details about
// your platform so we can consider relaxing this requirement.
#if CHAR_BIT != 8
#error "Abseil assumes CHAR_BIT == 8."
#endif

// -----------------------------------------------------------------------------
// `int` Size Check
// -----------------------------------------------------------------------------

// Abseil currently assumes that an int is 4 bytes. If you would like to use
// Abseil on a platform where this is not the case, please provide us with the
// details about your platform so we can consider relaxing this requirement.
#if INT_MAX < 2147483647
#error "Abseil assumes that int is at least 4 bytes. "
#endif

#endif // ABSL_BASE_POLICY_CHECKS_H_

+ 25
- 0
CAPI/cpp/grpc/include/absl/base/port.h View File

@@ -0,0 +1,25 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This files is a forwarding header for other headers containing various
// portability macros and functions.

#ifndef ABSL_BASE_PORT_H_
#define ABSL_BASE_PORT_H_

#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"

#endif // ABSL_BASE_PORT_H_

+ 339
- 0
CAPI/cpp/grpc/include/absl/base/thread_annotations.h View File

@@ -0,0 +1,339 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: thread_annotations.h
// -----------------------------------------------------------------------------
//
// This header file contains macro definitions for thread safety annotations
// that allow developers to document the locking policies of multi-threaded
// code. The annotations can also help program analysis tools to identify
// potential thread safety issues.
//
// These annotations are implemented using compiler attributes. Using the macros
// defined here instead of raw attributes allow for portability and future
// compatibility.
//
// When referring to mutexes in the arguments of the attributes, you should
// use variable names or more complex expressions (e.g. my_object->mutex_)
// that evaluate to a concrete mutex object whenever possible. If the mutex
// you want to refer to is not in scope, you may use a member pointer
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.

#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_

#include "absl/base/attributes.h"
#include "absl/base/config.h"
// TODO(mbonadei): Remove after the backward compatibility period.
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export

// ABSL_GUARDED_BY()
//
// Documents if a shared field or global variable needs to be protected by a
// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
// should be held when accessing the annotated variable.
//
// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
// local variables, a local variable and its associated mutex can often be
// combined into a small class or struct, thereby allowing the annotation.
//
// Example:
//
// class Foo {
// Mutex mu_;
// int p1_ ABSL_GUARDED_BY(mu_);
// ...
// };
#if ABSL_HAVE_ATTRIBUTE(guarded_by)
#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
#else
#define ABSL_GUARDED_BY(x)
#endif

// ABSL_PT_GUARDED_BY()
//
// Documents if the memory location pointed to by a pointer should be guarded
// by a mutex when dereferencing the pointer.
//
// Example:
// class Foo {
// Mutex mu_;
// int *p1_ ABSL_PT_GUARDED_BY(mu_);
// ...
// };
//
// Note that a pointer variable to a shared memory location could itself be a
// shared variable.
//
// Example:
//
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
#else
#define ABSL_PT_GUARDED_BY(x)
#endif

// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
//
// Documents the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
// and ABSL_ACQUIRED_BEFORE.)
//
// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
// fields or global variables.
//
// Example:
//
// Mutex m1_;
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_AFTER(...)
#endif

#if ABSL_HAVE_ATTRIBUTE(acquired_before)
#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_BEFORE(...)
#endif

// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
//
// Documents a function that expects a mutex to be held prior to entry.
// The mutex is expected to be held both on entry to, and exit from, the
// function.
//
// An exclusive lock allows read-write access to the guarded data member(s), and
// only one thread can acquire a lock exclusively at any one time. A shared lock
// allows read-only access, and any number of threads can acquire a shared lock
// concurrently.
//
// Generally, non-const methods should be annotated with
// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
// ABSL_SHARED_LOCKS_REQUIRED.
//
// Example:
//
// Mutex mu1, mu2;
// int a ABSL_GUARDED_BY(mu1);
// int b ABSL_GUARDED_BY(mu2);
//
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
__attribute__((exclusive_locks_required(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
#endif

#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
__attribute__((shared_locks_required(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCKS_REQUIRED(...)
#endif

// ABSL_LOCKS_EXCLUDED()
//
// Documents the locks that cannot be held by callers of this function, as they
// might be acquired by this function (Abseil's `Mutex` locks are
// non-reentrant).
#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
#else
#define ABSL_LOCKS_EXCLUDED(...)
#endif

// ABSL_LOCK_RETURNED()
//
// Documents a function that returns a mutex without acquiring it. For example,
// a public getter method that returns a pointer to a private mutex should
// be annotated with ABSL_LOCK_RETURNED.
#if ABSL_HAVE_ATTRIBUTE(lock_returned)
#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
#else
#define ABSL_LOCK_RETURNED(x)
#endif

// ABSL_LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
#if ABSL_HAVE_ATTRIBUTE(lockable)
#define ABSL_LOCKABLE __attribute__((lockable))
#else
#define ABSL_LOCKABLE
#endif

// ABSL_SCOPED_LOCKABLE
//
// Documents if a class does RAII locking (such as the `MutexLock` class).
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
#else
#define ABSL_SCOPED_LOCKABLE
#endif

// ABSL_EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
__attribute__((exclusive_lock_function(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
#endif

// ABSL_SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
#define ABSL_SHARED_LOCK_FUNCTION(...) \
__attribute__((shared_lock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCK_FUNCTION(...)
#endif

// ABSL_UNLOCK_FUNCTION()
//
// Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function.
#if ABSL_HAVE_ATTRIBUTE(unlock_function)
#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
#else
#define ABSL_UNLOCK_FUNCTION(...)
#endif

// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
//
// Documents functions that try to acquire a lock, and return success or failure
// (or a non-boolean value that can be interpreted as a boolean).
// The first argument should be `true` for functions that return `true` on
// success, or `false` for functions that return `false` on success. The second
// argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`.
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
#endif

#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
__attribute__((shared_trylock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
#endif

// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
__attribute__((assert_exclusive_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
#endif

#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
#define ABSL_ASSERT_SHARED_LOCK(...) \
__attribute__((assert_shared_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_SHARED_LOCK(...)
#endif

// ABSL_NO_THREAD_SAFETY_ANALYSIS
//
// Turns off thread safety checking within the body of a particular function.
// This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle.
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
__attribute__((no_thread_safety_analysis))
#else
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
#endif

//------------------------------------------------------------------------------
// Tool-Supplied Annotations
//------------------------------------------------------------------------------

// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
// C++ syntax, but which are present for documentation purposes. These
// annotations will be ignored by the analysis.
#define ABSL_TS_UNCHECKED(x) ""

// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
// It is used by automated tools to mark and disable invalid expressions.
// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
#define ABSL_TS_FIXME(x) ""

// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
// of a particular function. However, this attribute is used to mark functions
// that are incorrect and need to be fixed. It is used by automated tools to
// avoid breaking the build when the analysis is updated.
// Code owners are expected to eventually fix the routine.
#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS

// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
// thread safety warning. It disables the ABSL_GUARDED_BY.
#define ABSL_GUARDED_BY_FIXME(x)

// Disables warnings for a single read operation. This can be used to avoid
// warnings when it is known that the read is not actually involved in a race,
// but the compiler cannot confirm that.
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace base_internal
{

// Takes a reference to a guarded data member, and returns an unguarded
// reference.
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
template<typename T>
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS
{
return v;
}

template<typename T>
inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS
{
return v;
}

} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_

+ 146
- 0
CAPI/cpp/grpc/include/absl/cleanup/cleanup.h View File

@@ -0,0 +1,146 @@
// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: cleanup.h
// -----------------------------------------------------------------------------
//
// `absl::Cleanup` implements the scope guard idiom, invoking the contained
// callback's `operator()() &&` on scope exit.
//
// Example:
//
// ```
// absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
// FILE* source_file = fopen(source_path, "r");
// if (source_file == nullptr) {
// return absl::NotFoundError("No source file"); // No cleanups execute
// }
//
// // C++17 style cleanup using class template argument deduction
// absl::Cleanup source_closer = [source_file] { fclose(source_file); };
//
// FILE* sink_file = fopen(sink_path, "w");
// if (sink_file == nullptr) {
// return absl::NotFoundError("No sink file"); // First cleanup executes
// }
//
// // C++11 style cleanup using the factory function
// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
//
// Data data;
// while (ReadData(source_file, &data)) {
// if (!data.IsGood()) {
// absl::Status result = absl::FailedPreconditionError("Read bad data");
// return result; // Both cleanups execute
// }
// SaveData(sink_file, &data);
// }
//
// return absl::OkStatus(); // Both cleanups execute
// }
// ```
//
// Methods:
//
// `std::move(cleanup).Cancel()` will prevent the callback from executing.
//
// `std::move(cleanup).Invoke()` will execute the callback early, before
// destruction, and prevent the callback from executing in the destructor.
//
// Usage:
//
// `absl::Cleanup` is not an interface type. It is only intended to be used
// within the body of a function. It is not a value type and instead models a
// control flow construct. Check out `defer` in Golang for something similar.

#ifndef ABSL_CLEANUP_CLEANUP_H_
#define ABSL_CLEANUP_CLEANUP_H_

#include <utility>

#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/cleanup/internal/cleanup.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

template<typename Arg, typename Callback = void()>
class ABSL_MUST_USE_RESULT Cleanup final
{
static_assert(cleanup_internal::WasDeduced<Arg>(), "Explicit template parameters are not supported.");

static_assert(cleanup_internal::ReturnsVoid<Callback>(), "Callbacks that return values are not supported.");

public:
Cleanup(Callback callback) :
storage_(std::move(callback))
{
} // NOLINT

Cleanup(Cleanup&& other) = default;

void Cancel() &&
{
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
storage_.DestroyCallback();
}

void Invoke() &&
{
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
storage_.InvokeCallback();
storage_.DestroyCallback();
}

~Cleanup()
{
if (storage_.IsCallbackEngaged())
{
storage_.InvokeCallback();
storage_.DestroyCallback();
}
}

private:
cleanup_internal::Storage<Callback> storage_;
};

// `absl::Cleanup c = /* callback */;`
//
// C++17 type deduction API for creating an instance of `absl::Cleanup`
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
template<typename Callback>
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)

// `auto c = absl::MakeCleanup(/* callback */);`
//
// C++11 type deduction API for creating an instance of `absl::Cleanup`
template<typename... Args, typename Callback>
absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback)
{
static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(), "Explicit template parameters are not supported.");

static_assert(cleanup_internal::ReturnsVoid<Callback>(), "Callbacks that return values are not supported.");

return {std::move(callback)};
}

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CLEANUP_CLEANUP_H_

+ 118
- 0
CAPI/cpp/grpc/include/absl/cleanup/internal/cleanup.h View File

@@ -0,0 +1,118 @@
// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CLEANUP_INTERNAL_CLEANUP_H_
#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_

#include <new>
#include <type_traits>
#include <utility>

#include "absl/base/internal/invoke.h"
#include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
#include "absl/utility/utility.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

namespace cleanup_internal
{

struct Tag
{
};

template<typename Arg, typename... Args>
constexpr bool WasDeduced()
{
return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
(sizeof...(Args) == 0);
}

template<typename Callback>
constexpr bool ReturnsVoid()
{
return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
}

template<typename Callback>
class Storage
{
public:
Storage() = delete;

explicit Storage(Callback callback)
{
// Placement-new into a character buffer is used for eager destruction when
// the cleanup is invoked or cancelled. To ensure this optimizes well, the
// behavior is implemented locally instead of using an absl::optional.
::new (GetCallbackBuffer()) Callback(std::move(callback));
is_callback_engaged_ = true;
}

Storage(Storage&& other)
{
ABSL_HARDENING_ASSERT(other.IsCallbackEngaged());

::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback()));
is_callback_engaged_ = true;

other.DestroyCallback();
}

Storage(const Storage& other) = delete;

Storage& operator=(Storage&& other) = delete;

Storage& operator=(const Storage& other) = delete;

void* GetCallbackBuffer()
{
return static_cast<void*>(+callback_buffer_);
}

Callback& GetCallback()
{
return *reinterpret_cast<Callback*>(GetCallbackBuffer());
}

bool IsCallbackEngaged() const
{
return is_callback_engaged_;
}

void DestroyCallback()
{
is_callback_engaged_ = false;
GetCallback().~Callback();
}

void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS
{
std::move(GetCallback())();
}

private:
bool is_callback_engaged_;
alignas(Callback) char callback_buffer_[sizeof(Callback)];
};

} // namespace cleanup_internal

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_

+ 869
- 0
CAPI/cpp/grpc/include/absl/container/btree_map.h View File

@@ -0,0 +1,869 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: btree_map.h
// -----------------------------------------------------------------------------
//
// This header file defines B-tree maps: sorted associative containers mapping
// keys to values.
//
// * `absl::btree_map<>`
// * `absl::btree_multimap<>`
//
// These B-tree types are similar to the corresponding types in the STL
// (`std::map` and `std::multimap`) and generally conform to the STL interfaces
// of those types. However, because they are implemented using B-trees, they
// are more efficient in most situations.
//
// Unlike `std::map` and `std::multimap`, which are commonly implemented using
// red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold
// multiple values per node. Holding multiple values per node often makes
// B-tree maps perform better than their `std::map` counterparts, because
// multiple entries can be checked within the same cache hit.
//
// However, these types should not be considered drop-in replacements for
// `std::map` and `std::multimap` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
//
// Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only
// an issue if insertion and deletion operations are interleaved with the use of
// more than one iterator, pointer, or reference simultaneously. For this
// reason, `insert()` and `erase()` return a valid iterator at the current
// position. Another important difference is that key-types must be
// copy-constructible.

#ifndef ABSL_CONTAINER_BTREE_MAP_H_
#define ABSL_CONTAINER_BTREE_MAP_H_

#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/btree_container.h" // IWYU pragma: export

namespace absl
{
ABSL_NAMESPACE_BEGIN

namespace container_internal
{

template<typename Key, typename Data, typename Compare, typename Alloc, int TargetNodeSize, bool IsMulti>
struct map_params;

} // namespace container_internal

// absl::btree_map<>
//
// An `absl::btree_map<K, V>` is an ordered associative container of
// unique keys and associated values designed to be a more efficient replacement
// for `std::map` (in most cases).
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_map<K, V>` uses a default allocator of
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
// nodes, and construct and destruct values within those nodes. You may
// instead specify a custom allocator `A` (which in turn requires specifying a
// custom comparator `C`) as in `absl::btree_map<K, V, C, A>`.
//
template<typename Key, typename Value, typename Compare = std::less<Key>, typename Alloc = std::allocator<std::pair<const Key, Value>>>
class btree_map : public container_internal::btree_map_container<container_internal::btree<container_internal::map_params<Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>>
{
using Base = typename btree_map::btree_map_container;

public:
// Constructors and Assignment Operators
//
// A `btree_map` supports the same overload set as `std::map`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_map<int, std::string> map1;
//
// * Initializer List constructor
//
// absl::btree_map<int, std::string> map2 =
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
//
// * Copy constructor
//
// absl::btree_map<int, std::string> map3(map2);
//
// * Copy assignment operator
//
// absl::btree_map<int, std::string> map4;
// map4 = map3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_map<int, std::string> map5(std::move(map4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_map<int, std::string> map6;
// map6 = std::move(map5);
//
// * Range constructor
//
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
// absl::btree_map<int, std::string> map7(v.begin(), v.end());
btree_map()
{
}
using Base::Base;

// btree_map::begin()
//
// Returns an iterator to the beginning of the `btree_map`.
using Base::begin;

// btree_map::cbegin()
//
// Returns a const iterator to the beginning of the `btree_map`.
using Base::cbegin;

// btree_map::end()
//
// Returns an iterator to the end of the `btree_map`.
using Base::end;

// btree_map::cend()
//
// Returns a const iterator to the end of the `btree_map`.
using Base::cend;

// btree_map::empty()
//
// Returns whether or not the `btree_map` is empty.
using Base::empty;

// btree_map::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_map` under current memory constraints. This value can be thought
// of as the largest value of `std::distance(begin(), end())` for a
// `btree_map<Key, T>`.
using Base::max_size;

// btree_map::size()
//
// Returns the number of elements currently within the `btree_map`.
using Base::size;

// btree_map::clear()
//
// Removes all elements from the `btree_map`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;

// btree_map::erase()
//
// Erases elements within the `btree_map`. If an erase occurs, any references,
// pointers, or iterators are invalidated.
// Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_map`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;

// btree_map::insert()
//
// Inserts an element of the specified value into the `btree_map`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If an insertion
// occurs, any references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// std::pair<iterator,bool> insert(const value_type& value):
//
// Inserts a value into the `btree_map`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(value_type&& value):
//
// Inserts a moveable value into the `btree_map`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;

// btree_map::insert_or_assign()
//
// Inserts an element of the specified value into the `btree_map` provided
// that a value with the given key does not already exist, or replaces the
// corresponding mapped type with the forwarded `obj` argument if a key for
// that value already exists, returning an iterator pointing to the newly
// inserted element. Overloads are listed below.
//
// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `btree_map`. If the returned bool is true, insertion took place, and if
// it's false, assignment took place.
//
// iterator insert_or_assign(const_iterator hint,
// const key_type& k, M&& obj):
// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `btree_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
using Base::insert_or_assign;

// btree_map::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace;

// btree_map::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace_hint;

// btree_map::try_emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_map`, provided that no element with the given key
// already exists. Unlike `emplace()`, if an element with the given key
// already exists, we guarantee that no element is constructed.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
//
// Overloads are listed below.
//
// std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
// std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `btree_map`.
//
// iterator try_emplace(const_iterator hint,
// const key_type& k, Args&&... args):
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `btree_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
using Base::try_emplace;

// btree_map::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_map`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;

// btree_map::merge()
//
// Extracts elements from a given `source` btree_map into this
// `btree_map`. If the destination `btree_map` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;

// btree_map::swap(btree_map& other)
//
// Exchanges the contents of this `btree_map` with those of the `other`
// btree_map, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `btree_map` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
using Base::swap;

// btree_map::at()
//
// Returns a reference to the mapped value of the element with key equivalent
// to the passed key.
using Base::at;

// btree_map::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_map`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::contains;

// btree_map::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_map`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::count;

// btree_map::equal_range()
//
// Returns a half-open range [first, last), defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the `btree_map`.
using Base::equal_range;

// btree_map::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::find;

// btree_map::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;

// btree_map::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;

// btree_map::operator[]()
//
// Returns a reference to the value mapped to the passed key within the
// `btree_map`, performing an `insert()` if the key does not already
// exist.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated. Otherwise iterators are not affected and references are not
// invalidated. Overloads are listed below.
//
// T& operator[](key_type&& key):
// T& operator[](const key_type& key):
//
// Inserts a value_type object constructed in-place if the element with the
// given key does not exist.
using Base::operator[];

// btree_map::get_allocator()
//
// Returns the allocator function associated with this `btree_map`.
using Base::get_allocator;

// btree_map::key_comp();
//
// Returns the key comparator associated with this `btree_map`.
using Base::key_comp;

// btree_map::value_comp();
//
// Returns the value comparator associated with this `btree_map`.
using Base::value_comp;
};

// absl::swap(absl::btree_map<>, absl::btree_map<>)
//
// Swaps the contents of two `absl::btree_map` containers.
template<typename K, typename V, typename C, typename A>
void swap(btree_map<K, V, C, A>& x, btree_map<K, V, C, A>& y)
{
return x.swap(y);
}

// absl::erase_if(absl::btree_map<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template<typename K, typename V, typename C, typename A, typename Pred>
typename btree_map<K, V, C, A>::size_type erase_if(
btree_map<K, V, C, A>& map, Pred pred
)
{
return container_internal::btree_access::erase_if(map, std::move(pred));
}

// absl::btree_multimap
//
// An `absl::btree_multimap<K, V>` is an ordered associative container of
// keys and associated values designed to be a more efficient replacement for
// `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap
// allows multiple elements with equivalent keys.
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_multimap<K, V>` uses a default allocator of
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
// nodes, and construct and destruct values within those nodes. You may
// instead specify a custom allocator `A` (which in turn requires specifying a
// custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`.
//
template<typename Key, typename Value, typename Compare = std::less<Key>, typename Alloc = std::allocator<std::pair<const Key, Value>>>
class btree_multimap : public container_internal::btree_multimap_container<container_internal::btree<container_internal::map_params<Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>>
{
using Base = typename btree_multimap::btree_multimap_container;

public:
// Constructors and Assignment Operators
//
// A `btree_multimap` supports the same overload set as `std::multimap`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_multimap<int, std::string> map1;
//
// * Initializer List constructor
//
// absl::btree_multimap<int, std::string> map2 =
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
//
// * Copy constructor
//
// absl::btree_multimap<int, std::string> map3(map2);
//
// * Copy assignment operator
//
// absl::btree_multimap<int, std::string> map4;
// map4 = map3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_multimap<int, std::string> map5(std::move(map4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_multimap<int, std::string> map6;
// map6 = std::move(map5);
//
// * Range constructor
//
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
// absl::btree_multimap<int, std::string> map7(v.begin(), v.end());
btree_multimap()
{
}
using Base::Base;

// btree_multimap::begin()
//
// Returns an iterator to the beginning of the `btree_multimap`.
using Base::begin;

// btree_multimap::cbegin()
//
// Returns a const iterator to the beginning of the `btree_multimap`.
using Base::cbegin;

// btree_multimap::end()
//
// Returns an iterator to the end of the `btree_multimap`.
using Base::end;

// btree_multimap::cend()
//
// Returns a const iterator to the end of the `btree_multimap`.
using Base::cend;

// btree_multimap::empty()
//
// Returns whether or not the `btree_multimap` is empty.
using Base::empty;

// btree_multimap::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_multimap` under current memory constraints. This value can be
// thought of as the largest value of `std::distance(begin(), end())` for a
// `btree_multimap<Key, T>`.
using Base::max_size;

// btree_multimap::size()
//
// Returns the number of elements currently within the `btree_multimap`.
using Base::size;

// btree_multimap::clear()
//
// Removes all elements from the `btree_multimap`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;

// btree_multimap::erase()
//
// Erases elements within the `btree_multimap`. If an erase occurs, any
// references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_multimap`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the elements matching the key, if any exist, returning the
// number of elements erased.
using Base::erase;

// btree_multimap::insert()
//
// Inserts an element of the specified value into the `btree_multimap`,
// returning an iterator pointing to the newly inserted element.
// Any references, pointers, or iterators are invalidated. Overloads are
// listed below.
//
// iterator insert(const value_type& value):
//
// Inserts a value into the `btree_multimap`, returning an iterator to the
// inserted element.
//
// iterator insert(value_type&& value):
//
// Inserts a moveable value into the `btree_multimap`, returning an iterator
// to the inserted element.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;

// btree_multimap::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multimap`. Any references, pointers, or iterators are
// invalidated.
using Base::emplace;

// btree_multimap::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multimap`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search.
//
// Any references, pointers, or iterators are invalidated.
using Base::emplace_hint;

// btree_multimap::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multimap`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;

// btree_multimap::merge()
//
// Extracts all elements from a given `source` btree_multimap into this
// `btree_multimap`.
using Base::merge;

// btree_multimap::swap(btree_multimap& other)
//
// Exchanges the contents of this `btree_multimap` with those of the `other`
// btree_multimap, avoiding invocation of any move, copy, or swap operations
// on individual elements.
//
// All iterators and references on the `btree_multimap` remain valid,
// excepting for the past-the-end iterator, which is invalidated.
using Base::swap;

// btree_multimap::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_multimap`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::contains;

// btree_multimap::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::count;

// btree_multimap::equal_range()
//
// Returns a half-open range [first, last), defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_multimap`.
using Base::equal_range;

// btree_multimap::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::find;

// btree_multimap::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;

// btree_multimap::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;

// btree_multimap::get_allocator()
//
// Returns the allocator function associated with this `btree_multimap`.
using Base::get_allocator;

// btree_multimap::key_comp();
//
// Returns the key comparator associated with this `btree_multimap`.
using Base::key_comp;

// btree_multimap::value_comp();
//
// Returns the value comparator associated with this `btree_multimap`.
using Base::value_comp;
};

// absl::swap(absl::btree_multimap<>, absl::btree_multimap<>)
//
// Swaps the contents of two `absl::btree_multimap` containers.
template<typename K, typename V, typename C, typename A>
void swap(btree_multimap<K, V, C, A>& x, btree_multimap<K, V, C, A>& y)
{
return x.swap(y);
}

// absl::erase_if(absl::btree_multimap<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template<typename K, typename V, typename C, typename A, typename Pred>
typename btree_multimap<K, V, C, A>::size_type erase_if(
btree_multimap<K, V, C, A>& map, Pred pred
)
{
return container_internal::btree_access::erase_if(map, std::move(pred));
}

namespace container_internal
{

// A parameters structure for holding the type parameters for a btree_map.
// Compare and Alloc should be nothrow copy-constructible.
template<typename Key, typename Data, typename Compare, typename Alloc, int TargetNodeSize, bool IsMulti>
struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/true,
map_slot_policy<Key, Data>>
{
using super_type = typename map_params::common_params;
using mapped_type = Data;
// This type allows us to move keys when it is safe to do so. It is safe
// for maps in which value_type and mutable_value_type are layout compatible.
using slot_policy = typename super_type::slot_policy;
using slot_type = typename super_type::slot_type;
using value_type = typename super_type::value_type;
using init_type = typename super_type::init_type;

template<typename V>
static auto key(const V& value) -> decltype(value.first)
{
return value.first;
}
static const Key& key(const slot_type* s)
{
return slot_policy::key(s);
}
static const Key& key(slot_type* s)
{
return slot_policy::key(s);
}
// For use in node handle.
static auto mutable_key(slot_type* s)
-> decltype(slot_policy::mutable_key(s))
{
return slot_policy::mutable_key(s);
}
static mapped_type& value(value_type* value)
{
return value->second;
}
};

} // namespace container_internal

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_BTREE_MAP_H_

+ 816
- 0
CAPI/cpp/grpc/include/absl/container/btree_set.h View File

@@ -0,0 +1,816 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: btree_set.h
// -----------------------------------------------------------------------------
//
// This header file defines B-tree sets: sorted associative containers of
// values.
//
// * `absl::btree_set<>`
// * `absl::btree_multiset<>`
//
// These B-tree types are similar to the corresponding types in the STL
// (`std::set` and `std::multiset`) and generally conform to the STL interfaces
// of those types. However, because they are implemented using B-trees, they
// are more efficient in most situations.
//
// Unlike `std::set` and `std::multiset`, which are commonly implemented using
// red-black tree nodes, B-tree sets use more generic B-tree nodes able to hold
// multiple values per node. Holding multiple values per node often makes
// B-tree sets perform better than their `std::set` counterparts, because
// multiple entries can be checked within the same cache hit.
//
// However, these types should not be considered drop-in replacements for
// `std::set` and `std::multiset` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
//
// Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only
// an issue if insertion and deletion operations are interleaved with the use of
// more than one iterator, pointer, or reference simultaneously. For this
// reason, `insert()` and `erase()` return a valid iterator at the current
// position.

#ifndef ABSL_CONTAINER_BTREE_SET_H_
#define ABSL_CONTAINER_BTREE_SET_H_

#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/btree_container.h" // IWYU pragma: export

namespace absl
{
ABSL_NAMESPACE_BEGIN

namespace container_internal
{

template<typename Key>
struct set_slot_policy;

template<typename Key, typename Compare, typename Alloc, int TargetNodeSize, bool IsMulti>
struct set_params;

} // namespace container_internal

// absl::btree_set<>
//
// An `absl::btree_set<K>` is an ordered associative container of unique key
// values designed to be a more efficient replacement for `std::set` (in most
// cases).
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_set<K>` uses a default allocator of `std::allocator<K>` to
// allocate (and deallocate) nodes, and construct and destruct values within
// those nodes. You may instead specify a custom allocator `A` (which in turn
// requires specifying a custom comparator `C`) as in
// `absl::btree_set<K, C, A>`.
//
template<typename Key, typename Compare = std::less<Key>, typename Alloc = std::allocator<Key>>
class btree_set : public container_internal::btree_set_container<container_internal::btree<container_internal::set_params<Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>>
{
using Base = typename btree_set::btree_set_container;

public:
// Constructors and Assignment Operators
//
// A `btree_set` supports the same overload set as `std::set`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_set<std::string> set1;
//
// * Initializer List constructor
//
// absl::btree_set<std::string> set2 =
// {{"huey"}, {"dewey"}, {"louie"},};
//
// * Copy constructor
//
// absl::btree_set<std::string> set3(set2);
//
// * Copy assignment operator
//
// absl::btree_set<std::string> set4;
// set4 = set3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_set<std::string> set5(std::move(set4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_set<std::string> set6;
// set6 = std::move(set5);
//
// * Range constructor
//
// std::vector<std::string> v = {"a", "b"};
// absl::btree_set<std::string> set7(v.begin(), v.end());
btree_set()
{
}
using Base::Base;

// btree_set::begin()
//
// Returns an iterator to the beginning of the `btree_set`.
using Base::begin;

// btree_set::cbegin()
//
// Returns a const iterator to the beginning of the `btree_set`.
using Base::cbegin;

// btree_set::end()
//
// Returns an iterator to the end of the `btree_set`.
using Base::end;

// btree_set::cend()
//
// Returns a const iterator to the end of the `btree_set`.
using Base::cend;

// btree_set::empty()
//
// Returns whether or not the `btree_set` is empty.
using Base::empty;

// btree_set::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_set` under current memory constraints. This value can be thought
// of as the largest value of `std::distance(begin(), end())` for a
// `btree_set<Key>`.
using Base::max_size;

// btree_set::size()
//
// Returns the number of elements currently within the `btree_set`.
using Base::size;

// btree_set::clear()
//
// Removes all elements from the `btree_set`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;

// btree_set::erase()
//
// Erases elements within the `btree_set`. Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_set`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;

// btree_set::insert()
//
// Inserts an element of the specified value into the `btree_set`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If an insertion
// occurs, any references, pointers, or iterators are invalidated.
// Overloads are listed below.
//
// std::pair<iterator,bool> insert(const value_type& value):
//
// Inserts a value into the `btree_set`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(value_type&& value):
//
// Inserts a moveable value into the `btree_set`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;

// btree_set::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_set`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace;

// btree_set::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_set`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If an insertion occurs, any references, pointers, or iterators are
// invalidated.
using Base::emplace_hint;

// btree_set::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_set`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;

// btree_set::merge()
//
// Extracts elements from a given `source` btree_set into this
// `btree_set`. If the destination `btree_set` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;

// btree_set::swap(btree_set& other)
//
// Exchanges the contents of this `btree_set` with those of the `other`
// btree_set, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `btree_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
using Base::swap;

// btree_set::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_set`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::contains;

// btree_set::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_set`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::count;

// btree_set::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_set`.
using Base::equal_range;

// btree_set::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::find;

// btree_set::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;

// btree_set::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;

// btree_set::get_allocator()
//
// Returns the allocator function associated with this `btree_set`.
using Base::get_allocator;

// btree_set::key_comp();
//
// Returns the key comparator associated with this `btree_set`.
using Base::key_comp;

// btree_set::value_comp();
//
// Returns the value comparator associated with this `btree_set`. The keys to
// sort the elements are the values themselves, therefore `value_comp` and its
// sibling member function `key_comp` are equivalent.
using Base::value_comp;
};

// absl::swap(absl::btree_set<>, absl::btree_set<>)
//
// Swaps the contents of two `absl::btree_set` containers.
template<typename K, typename C, typename A>
void swap(btree_set<K, C, A>& x, btree_set<K, C, A>& y)
{
return x.swap(y);
}

// absl::erase_if(absl::btree_set<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template<typename K, typename C, typename A, typename Pred>
typename btree_set<K, C, A>::size_type erase_if(btree_set<K, C, A>& set, Pred pred)
{
return container_internal::btree_access::erase_if(set, std::move(pred));
}

// absl::btree_multiset<>
//
// An `absl::btree_multiset<K>` is an ordered associative container of
// keys and associated values designed to be a more efficient replacement
// for `std::multiset` (in most cases). Unlike `absl::btree_set`, a B-tree
// multiset allows equivalent elements.
//
// Keys are sorted using an (optional) comparison function, which defaults to
// `std::less<K>`.
//
// An `absl::btree_multiset<K>` uses a default allocator of `std::allocator<K>`
// to allocate (and deallocate) nodes, and construct and destruct values within
// those nodes. You may instead specify a custom allocator `A` (which in turn
// requires specifying a custom comparator `C`) as in
// `absl::btree_multiset<K, C, A>`.
//
template<typename Key, typename Compare = std::less<Key>, typename Alloc = std::allocator<Key>>
class btree_multiset : public container_internal::btree_multiset_container<container_internal::btree<container_internal::set_params<Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>>
{
using Base = typename btree_multiset::btree_multiset_container;

public:
// Constructors and Assignment Operators
//
// A `btree_multiset` supports the same overload set as `std::set`
// for construction and assignment:
//
// * Default constructor
//
// absl::btree_multiset<std::string> set1;
//
// * Initializer List constructor
//
// absl::btree_multiset<std::string> set2 =
// {{"huey"}, {"dewey"}, {"louie"},};
//
// * Copy constructor
//
// absl::btree_multiset<std::string> set3(set2);
//
// * Copy assignment operator
//
// absl::btree_multiset<std::string> set4;
// set4 = set3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::btree_multiset<std::string> set5(std::move(set4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::btree_multiset<std::string> set6;
// set6 = std::move(set5);
//
// * Range constructor
//
// std::vector<std::string> v = {"a", "b"};
// absl::btree_multiset<std::string> set7(v.begin(), v.end());
btree_multiset()
{
}
using Base::Base;

// btree_multiset::begin()
//
// Returns an iterator to the beginning of the `btree_multiset`.
using Base::begin;

// btree_multiset::cbegin()
//
// Returns a const iterator to the beginning of the `btree_multiset`.
using Base::cbegin;

// btree_multiset::end()
//
// Returns an iterator to the end of the `btree_multiset`.
using Base::end;

// btree_multiset::cend()
//
// Returns a const iterator to the end of the `btree_multiset`.
using Base::cend;

// btree_multiset::empty()
//
// Returns whether or not the `btree_multiset` is empty.
using Base::empty;

// btree_multiset::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `btree_multiset` under current memory constraints. This value can be
// thought of as the largest value of `std::distance(begin(), end())` for a
// `btree_multiset<Key>`.
using Base::max_size;

// btree_multiset::size()
//
// Returns the number of elements currently within the `btree_multiset`.
using Base::size;

// btree_multiset::clear()
//
// Removes all elements from the `btree_multiset`. Invalidates any references,
// pointers, or iterators referring to contained elements.
using Base::clear;

// btree_multiset::erase()
//
// Erases elements within the `btree_multiset`. Overloads are listed below.
//
// iterator erase(iterator position):
// iterator erase(const_iterator position):
//
// Erases the element at `position` of the `btree_multiset`, returning
// the iterator pointing to the element after the one that was erased
// (or end() if none exists).
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning
// the iterator pointing to the element after the interval that was erased
// (or end() if none exists).
//
// template <typename K> size_type erase(const K& key):
//
// Erases the elements matching the key, if any exist, returning the
// number of elements erased.
using Base::erase;

// btree_multiset::insert()
//
// Inserts an element of the specified value into the `btree_multiset`,
// returning an iterator pointing to the newly inserted element.
// Any references, pointers, or iterators are invalidated. Overloads are
// listed below.
//
// iterator insert(const value_type& value):
//
// Inserts a value into the `btree_multiset`, returning an iterator to the
// inserted element.
//
// iterator insert(value_type&& value):
//
// Inserts a moveable value into the `btree_multiset`, returning an iterator
// to the inserted element.
//
// iterator insert(const_iterator hint, const value_type& value):
// iterator insert(const_iterator hint, value_type&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
using Base::insert;

// btree_multiset::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multiset`. Any references, pointers, or iterators are
// invalidated.
using Base::emplace;

// btree_multiset::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `btree_multiset`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search.
//
// Any references, pointers, or iterators are invalidated.
using Base::emplace_hint;

// btree_multiset::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// template <typename K> node_type extract(const K& k):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multiset`
// does not contain an element with a matching key, this function returns an
// empty node handle.
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
// It does NOT refer to the data layout of the underlying btree.
using Base::extract;

// btree_multiset::merge()
//
// Extracts all elements from a given `source` btree_multiset into this
// `btree_multiset`.
using Base::merge;

// btree_multiset::swap(btree_multiset& other)
//
// Exchanges the contents of this `btree_multiset` with those of the `other`
// btree_multiset, avoiding invocation of any move, copy, or swap operations
// on individual elements.
//
// All iterators and references on the `btree_multiset` remain valid,
// excepting for the past-the-end iterator, which is invalidated.
using Base::swap;

// btree_multiset::contains()
//
// template <typename K> bool contains(const K& key) const:
//
// Determines whether an element comparing equal to the given `key` exists
// within the `btree_multiset`, returning `true` if so or `false` otherwise.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::contains;

// btree_multiset::count()
//
// template <typename K> size_type count(const K& key) const:
//
// Returns the number of elements comparing equal to the given `key` within
// the `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::count;

// btree_multiset::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `btree_multiset`.
using Base::equal_range;

// btree_multiset::find()
//
// template <typename K> iterator find(const K& key):
// template <typename K> const_iterator find(const K& key) const:
//
// Finds an element with the passed `key` within the `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::find;

// btree_multiset::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;

// btree_multiset::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;

// btree_multiset::get_allocator()
//
// Returns the allocator function associated with this `btree_multiset`.
using Base::get_allocator;

// btree_multiset::key_comp();
//
// Returns the key comparator associated with this `btree_multiset`.
using Base::key_comp;

// btree_multiset::value_comp();
//
// Returns the value comparator associated with this `btree_multiset`. The
// keys to sort the elements are the values themselves, therefore `value_comp`
// and its sibling member function `key_comp` are equivalent.
using Base::value_comp;
};

// absl::swap(absl::btree_multiset<>, absl::btree_multiset<>)
//
// Swaps the contents of two `absl::btree_multiset` containers.
template<typename K, typename C, typename A>
void swap(btree_multiset<K, C, A>& x, btree_multiset<K, C, A>& y)
{
return x.swap(y);
}

// absl::erase_if(absl::btree_multiset<>, Pred)
//
// Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template<typename K, typename C, typename A, typename Pred>
typename btree_multiset<K, C, A>::size_type erase_if(
btree_multiset<K, C, A>& set, Pred pred
)
{
return container_internal::btree_access::erase_if(set, std::move(pred));
}

namespace container_internal
{

// This type implements the necessary functions from the
// absl::container_internal::slot_type interface for btree_(multi)set.
template<typename Key>
struct set_slot_policy
{
using slot_type = Key;
using value_type = Key;
using mutable_value_type = Key;

static value_type& element(slot_type* slot)
{
return *slot;
}
static const value_type& element(const slot_type* slot)
{
return *slot;
}

template<typename Alloc, class... Args>
static void construct(Alloc* alloc, slot_type* slot, Args&&... args)
{
absl::allocator_traits<Alloc>::construct(*alloc, slot, std::forward<Args>(args)...);
}

template<typename Alloc>
static void construct(Alloc* alloc, slot_type* slot, slot_type* other)
{
absl::allocator_traits<Alloc>::construct(*alloc, slot, std::move(*other));
}

template<typename Alloc>
static void construct(Alloc* alloc, slot_type* slot, const slot_type* other)
{
absl::allocator_traits<Alloc>::construct(*alloc, slot, *other);
}

template<typename Alloc>
static void destroy(Alloc* alloc, slot_type* slot)
{
absl::allocator_traits<Alloc>::destroy(*alloc, slot);
}

template<typename Alloc>
static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot)
{
construct(alloc, new_slot, old_slot);
destroy(alloc, old_slot);
}
};

// A parameters structure for holding the type parameters for a btree_set.
// Compare and Alloc should be nothrow copy-constructible.
template<typename Key, typename Compare, typename Alloc, int TargetNodeSize, bool IsMulti>
struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/false,
set_slot_policy<Key>>
{
using value_type = Key;
using slot_type = typename set_params::common_params::slot_type;

template<typename V>
static const V& key(const V& value)
{
return value;
}
static const Key& key(const slot_type* slot)
{
return *slot;
}
static const Key& key(slot_type* slot)
{
return *slot;
}
};

} // namespace container_internal

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_BTREE_SET_H_

+ 215
- 0
CAPI/cpp/grpc/include/absl/container/btree_test.h View File

@@ -0,0 +1,215 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_BTREE_TEST_H_
#define ABSL_CONTAINER_BTREE_TEST_H_

#include <algorithm>
#include <cassert>
#include <random>
#include <string>
#include <utility>
#include <vector>

#include "absl/container/btree_map.h"
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/cord.h"
#include "absl/time/time.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// Like remove_const but propagates the removal through std::pair.
template<typename T>
struct remove_pair_const
{
using type = typename std::remove_const<T>::type;
};
template<typename T, typename U>
struct remove_pair_const<std::pair<T, U>>
{
using type = std::pair<typename remove_pair_const<T>::type, typename remove_pair_const<U>::type>;
};

// Utility class to provide an accessor for a key given a value. The default
// behavior is to treat the value as a pair and return the first element.
template<typename K, typename V>
struct KeyOfValue
{
struct type
{
const K& operator()(const V& p) const
{
return p.first;
}
};
};

// Partial specialization of KeyOfValue class for when the key and value are
// the same type such as in set<> and btree_set<>.
template<typename K>
struct KeyOfValue<K, K>
{
struct type
{
const K& operator()(const K& k) const
{
return k;
}
};
};

inline char* GenerateDigits(char buf[16], unsigned val, unsigned maxval)
{
assert(val <= maxval);
constexpr unsigned kBase = 64; // avoid integer division.
unsigned p = 15;
buf[p--] = 0;
while (maxval > 0)
{
buf[p--] = ' ' + (val % kBase);
val /= kBase;
maxval /= kBase;
}
return buf + p + 1;
}

template<typename K>
struct Generator
{
int maxval;
explicit Generator(int m) :
maxval(m)
{
}
K operator()(int i) const
{
assert(i <= maxval);
return K(i);
}
};

template<>
struct Generator<absl::Time>
{
int maxval;
explicit Generator(int m) :
maxval(m)
{
}
absl::Time operator()(int i) const
{
return absl::FromUnixMillis(i);
}
};

template<>
struct Generator<std::string>
{
int maxval;
explicit Generator(int m) :
maxval(m)
{
}
std::string operator()(int i) const
{
char buf[16];
return GenerateDigits(buf, i, maxval);
}
};

template<>
struct Generator<Cord>
{
int maxval;
explicit Generator(int m) :
maxval(m)
{
}
Cord operator()(int i) const
{
char buf[16];
return Cord(GenerateDigits(buf, i, maxval));
}
};

template<typename T, typename U>
struct Generator<std::pair<T, U>>
{
Generator<typename remove_pair_const<T>::type> tgen;
Generator<typename remove_pair_const<U>::type> ugen;

explicit Generator(int m) :
tgen(m),
ugen(m)
{
}
std::pair<T, U> operator()(int i) const
{
return std::make_pair(tgen(i), ugen(i));
}
};

// Generate n values for our tests and benchmarks. Value range is [0, maxval].
inline std::vector<int> GenerateNumbersWithSeed(int n, int maxval, int seed)
{
// NOTE: Some tests rely on generated numbers not changing between test runs.
// We use std::minstd_rand0 because it is well-defined, but don't use
// std::uniform_int_distribution because platforms use different algorithms.
std::minstd_rand0 rng(seed);

std::vector<int> values;
absl::flat_hash_set<int> unique_values;
if (values.size() < n)
{
for (int i = values.size(); i < n; i++)
{
int value;
do
{
value = static_cast<int>(rng()) % (maxval + 1);
} while (!unique_values.insert(value).second);

values.push_back(value);
}
}
return values;
}

// Generates n values in the range [0, maxval].
template<typename V>
std::vector<V> GenerateValuesWithSeed(int n, int maxval, int seed)
{
const std::vector<int> nums = GenerateNumbersWithSeed(n, maxval, seed);
Generator<V> gen(maxval);
std::vector<V> vec;

vec.reserve(n);
for (int i = 0; i < n; i++)
{
vec.push_back(gen(nums[i]));
}

return vec;
}

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_BTREE_TEST_H_

+ 653
- 0
CAPI/cpp/grpc/include/absl/container/fixed_array.h View File

@@ -0,0 +1,653 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: fixed_array.h
// -----------------------------------------------------------------------------
//
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
// the array can be determined at run-time. It is a good replacement for
// non-standard and deprecated uses of `alloca()` and variable length arrays
// within the GCC extension. (See
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
//
// `FixedArray` allocates small arrays inline, keeping performance fast by
// avoiding heap operations. It also helps reduce the chances of
// accidentally overflowing your stack if large input is passed to
// your function.

#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
#define ABSL_CONTAINER_FIXED_ARRAY_H_

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <type_traits>

#include "absl/algorithm/algorithm.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/memory/memory.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN

constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);

// -----------------------------------------------------------------------------
// FixedArray
// -----------------------------------------------------------------------------
//
// A `FixedArray` provides a run-time fixed-size array, allocating a small array
// inline for efficiency.
//
// Most users should not specify an `inline_elements` argument and let
// `FixedArray` automatically determine the number of elements
// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the
// `FixedArray` implementation will use inline storage for arrays with a
// length <= `inline_elements`.
//
// Note that a `FixedArray` constructed with a `size_type` argument will
// default-initialize its values by leaving trivially constructible types
// uninitialized (e.g. int, int[4], double), and others default-constructed.
// This matches the behavior of c-style arrays and `std::array`, but not
// `std::vector`.
template<typename T, size_t N = kFixedArrayUseDefault, typename A = std::allocator<T>>
class FixedArray
{
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0, "Arrays with unknown bounds cannot be used with FixedArray.");

static constexpr size_t kInlineBytesDefault = 256;

using AllocatorTraits = std::allocator_traits<A>;
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
// but this seems to be mostly pedantic.
template<typename Iterator>
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>::value>;
static constexpr bool NoexceptCopyable()
{
return std::is_nothrow_copy_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool NoexceptMovable()
{
return std::is_nothrow_move_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool DefaultConstructorIsNonTrivial()
{
return !absl::is_trivially_default_constructible<StorageElement>::value;
}

public:
using allocator_type = typename AllocatorTraits::allocator_type;
using value_type = typename AllocatorTraits::value_type;
using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename AllocatorTraits::const_pointer;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = typename AllocatorTraits::size_type;
using difference_type = typename AllocatorTraits::difference_type;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;

static constexpr size_type inline_elements =
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type) : static_cast<size_type>(N));

FixedArray(
const FixedArray& other,
const allocator_type& a = allocator_type()
) noexcept(NoexceptCopyable()) :
FixedArray(other.begin(), other.end(), a)
{
}

FixedArray(
FixedArray&& other,
const allocator_type& a = allocator_type()
) noexcept(NoexceptMovable()) :
FixedArray(std::make_move_iterator(other.begin()), std::make_move_iterator(other.end()), a)
{
}

// Creates an array object that can store `n` elements.
// Note that trivially constructible elements will be uninitialized.
explicit FixedArray(size_type n, const allocator_type& a = allocator_type()) :
storage_(n, a)
{
if (DefaultConstructorIsNonTrivial())
{
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(), storage_.end());
}
}

// Creates an array initialized with `n` copies of `val`.
FixedArray(size_type n, const value_type& val, const allocator_type& a = allocator_type()) :
storage_(n, a)
{
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(), storage_.end(), val);
}

// Creates an array initialized with the size and contents of `init_list`.
FixedArray(std::initializer_list<value_type> init_list, const allocator_type& a = allocator_type()) :
FixedArray(init_list.begin(), init_list.end(), a)
{
}

// Creates an array initialized with the elements from the input
// range. The array's size will always be `std::distance(first, last)`.
// REQUIRES: Iterator must be a forward_iterator or better.
template<typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
FixedArray(Iterator first, Iterator last, const allocator_type& a = allocator_type()) :
storage_(std::distance(first, last), a)
{
memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
}

~FixedArray() noexcept
{
for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur)
{
AllocatorTraits::destroy(storage_.alloc(), cur);
}
}

// Assignments are deleted because they break the invariant that the size of a
// `FixedArray` never changes.
void operator=(FixedArray&&) = delete;
void operator=(const FixedArray&) = delete;

// FixedArray::size()
//
// Returns the length of the fixed array.
size_type size() const
{
return storage_.size();
}

// FixedArray::max_size()
//
// Returns the largest possible value of `std::distance(begin(), end())` for a
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
// over the number of bytes taken by T.
constexpr size_type max_size() const
{
return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
}

// FixedArray::empty()
//
// Returns whether or not the fixed array is empty.
bool empty() const
{
return size() == 0;
}

// FixedArray::memsize()
//
// Returns the memory size of the fixed array in bytes.
size_t memsize() const
{
return size() * sizeof(value_type);
}

// FixedArray::data()
//
// Returns a const T* pointer to elements of the `FixedArray`. This pointer
// can be used to access (but not modify) the contained elements.
const_pointer data() const
{
return AsValueType(storage_.begin());
}

// Overload of FixedArray::data() to return a T* pointer to elements of the
// fixed array. This pointer can be used to access and modify the contained
// elements.
pointer data()
{
return AsValueType(storage_.begin());
}

// FixedArray::operator[]
//
// Returns a reference the ith element of the fixed array.
// REQUIRES: 0 <= i < size()
reference operator[](size_type i)
{
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}

// Overload of FixedArray::operator()[] to return a const reference to the
// ith element of the fixed array.
// REQUIRES: 0 <= i < size()
const_reference operator[](size_type i) const
{
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}

// FixedArray::at
//
// Bounds-checked access. Returns a reference to the ith element of the fixed
// array, or throws std::out_of_range
reference at(size_type i)
{
if (ABSL_PREDICT_FALSE(i >= size()))
{
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
}
return data()[i];
}

// Overload of FixedArray::at() to return a const reference to the ith element
// of the fixed array.
const_reference at(size_type i) const
{
if (ABSL_PREDICT_FALSE(i >= size()))
{
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
}
return data()[i];
}

// FixedArray::front()
//
// Returns a reference to the first element of the fixed array.
reference front()
{
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}

// Overload of FixedArray::front() to return a reference to the first element
// of a fixed array of const values.
const_reference front() const
{
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}

// FixedArray::back()
//
// Returns a reference to the last element of the fixed array.
reference back()
{
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}

// Overload of FixedArray::back() to return a reference to the last element
// of a fixed array of const values.
const_reference back() const
{
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}

// FixedArray::begin()
//
// Returns an iterator to the beginning of the fixed array.
iterator begin()
{
return data();
}

// Overload of FixedArray::begin() to return a const iterator to the
// beginning of the fixed array.
const_iterator begin() const
{
return data();
}

// FixedArray::cbegin()
//
// Returns a const iterator to the beginning of the fixed array.
const_iterator cbegin() const
{
return begin();
}

// FixedArray::end()
//
// Returns an iterator to the end of the fixed array.
iterator end()
{
return data() + size();
}

// Overload of FixedArray::end() to return a const iterator to the end of the
// fixed array.
const_iterator end() const
{
return data() + size();
}

// FixedArray::cend()
//
// Returns a const iterator to the end of the fixed array.
const_iterator cend() const
{
return end();
}

// FixedArray::rbegin()
//
// Returns a reverse iterator from the end of the fixed array.
reverse_iterator rbegin()
{
return reverse_iterator(end());
}

// Overload of FixedArray::rbegin() to return a const reverse iterator from
// the end of the fixed array.
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}

// FixedArray::crbegin()
//
// Returns a const reverse iterator from the end of the fixed array.
const_reverse_iterator crbegin() const
{
return rbegin();
}

// FixedArray::rend()
//
// Returns a reverse iterator from the beginning of the fixed array.
reverse_iterator rend()
{
return reverse_iterator(begin());
}

// Overload of FixedArray::rend() for returning a const reverse iterator
// from the beginning of the fixed array.
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}

// FixedArray::crend()
//
// Returns a reverse iterator from the beginning of the fixed array.
const_reverse_iterator crend() const
{
return rend();
}

// FixedArray::fill()
//
// Assigns the given `value` to all elements in the fixed array.
void fill(const value_type& val)
{
std::fill(begin(), end(), val);
}

// Relational operators. Equality operators are elementwise using
// `operator==`, while order operators order FixedArrays lexicographically.
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs)
{
return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs)
{
return !(lhs == rhs);
}

friend bool operator<(const FixedArray& lhs, const FixedArray& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

friend bool operator>(const FixedArray& lhs, const FixedArray& rhs)
{
return rhs < lhs;
}

friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs)
{
return !(rhs < lhs);
}

friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs)
{
return !(lhs < rhs);
}

template<typename H>
friend H AbslHashValue(H h, const FixedArray& v)
{
return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()), v.size());
}

private:
// StorageElement
//
// For FixedArrays with a C-style-array value_type, StorageElement is a POD
// wrapper struct called StorageElementWrapper that holds the value_type
// instance inside. This is needed for construction and destruction of the
// entire array regardless of how many dimensions it has. For all other cases,
// StorageElement is just an alias of value_type.
//
// Maintainer's Note: The simpler solution would be to simply wrap value_type
// in a struct whether it's an array or not. That causes some paranoid
// diagnostics to misfire, believing that 'data()' returns a pointer to a
// single element, rather than the packed array that it really is.
// e.g.:
//
// FixedArray<char> buf(1);
// sprintf(buf.data(), "foo");
//
// error: call to int __builtin___sprintf_chk(etc...)
// will always overflow destination buffer [-Werror]
//
template<typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>, size_t InnerN = std::extent<OuterT>::value>
struct StorageElementWrapper
{
InnerT array[InnerN];
};

using StorageElement =
absl::conditional_t<std::is_array<value_type>::value, StorageElementWrapper<value_type>, value_type>;

static pointer AsValueType(pointer ptr)
{
return ptr;
}
static pointer AsValueType(StorageElementWrapper<value_type>* ptr)
{
return std::addressof(ptr->array);
}

static_assert(sizeof(StorageElement) == sizeof(value_type), "");
static_assert(alignof(StorageElement) == alignof(value_type), "");

class NonEmptyInlinedStorage
{
public:
StorageElement* data()
{
return reinterpret_cast<StorageElement*>(buff_);
}
void AnnotateConstruct(size_type n);
void AnnotateDestruct(size_type n);

#ifdef ABSL_HAVE_ADDRESS_SANITIZER
void* RedzoneBegin()
{
return &redzone_begin_;
}
void* RedzoneEnd()
{
return &redzone_end_ + 1;
}
#endif // ABSL_HAVE_ADDRESS_SANITIZER

private:
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
};

class EmptyInlinedStorage
{
public:
StorageElement* data()
{
return nullptr;
}
void AnnotateConstruct(size_type)
{
}
void AnnotateDestruct(size_type)
{
}
};

using InlinedStorage =
absl::conditional_t<inline_elements == 0, EmptyInlinedStorage, NonEmptyInlinedStorage>;

// Storage
//
// An instance of Storage manages the inline and out-of-line memory for
// instances of FixedArray. This guarantees that even when construction of
// individual elements fails in the FixedArray constructor body, the
// destructor for Storage will still be called and out-of-line memory will be
// properly deallocated.
//
class Storage : public InlinedStorage
{
public:
Storage(size_type n, const allocator_type& a) :
size_alloc_(n, a),
data_(InitializeData())
{
}

~Storage() noexcept
{
if (UsingInlinedStorage(size()))
{
InlinedStorage::AnnotateDestruct(size());
}
else
{
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
}
}

size_type size() const
{
return size_alloc_.template get<0>();
}
StorageElement* begin() const
{
return data_;
}
StorageElement* end() const
{
return begin() + size();
}
allocator_type& alloc()
{
return size_alloc_.template get<1>();
}

private:
static bool UsingInlinedStorage(size_type n)
{
return n <= inline_elements;
}

StorageElement* InitializeData()
{
if (UsingInlinedStorage(size()))
{
InlinedStorage::AnnotateConstruct(size());
return InlinedStorage::data();
}
else
{
return reinterpret_cast<StorageElement*>(
AllocatorTraits::allocate(alloc(), size())
);
}
}

// `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
StorageElement* data_;
};

Storage storage_;
};

#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
template<typename T, size_t N, typename A>
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;

template<typename T, size_t N, typename A>
constexpr typename FixedArray<T, N, A>::size_type
FixedArray<T, N, A>::inline_elements;
#endif

template<typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n
)
{
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n)
return;
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n);
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}

template<typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
typename FixedArray<T, N, A>::size_type n
)
{
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n)
return;
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd());
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_FIXED_ARRAY_H_

+ 634
- 0
CAPI/cpp/grpc/include/absl/container/flat_hash_map.h View File

@@ -0,0 +1,634 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: flat_hash_map.h
// -----------------------------------------------------------------------------
//
// An `absl::flat_hash_map<K, V>` is an unordered associative container of
// unique keys and associated values designed to be a more efficient replacement
// for `std::unordered_map`. Like `unordered_map`, search, insertion, and
// deletion of map elements can be done as an `O(1)` operation. However,
// `flat_hash_map` (and other unordered associative containers known as the
// collection of Abseil "Swiss tables") contain other optimizations that result
// in both memory and computation advantages.
//
// In most cases, your default choice for a hash map should be a map of type
// `flat_hash_map`.

#ifndef ABSL_CONTAINER_FLAT_HASH_MAP_H_
#define ABSL_CONTAINER_FLAT_HASH_MAP_H_

#include <cstddef>
#include <new>
#include <type_traits>
#include <utility>

#include "absl/algorithm/container.h"
#include "absl/base/macros.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
#include "absl/memory/memory.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{
template<class K, class V>
struct FlatHashMapPolicy;
} // namespace container_internal

// -----------------------------------------------------------------------------
// absl::flat_hash_map
// -----------------------------------------------------------------------------
//
// An `absl::flat_hash_map<K, V>` is an unordered associative container which
// has been optimized for both speed and memory footprint in most common use
// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
// the following notable differences:
//
// * Requires keys that are CopyConstructible
// * Requires values that are MoveConstructible
// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
// `insert()`, provided that the map is provided a compatible heterogeneous
// hashing function and equality operator.
// * Invalidates any references and pointers to elements within the table after
// `rehash()`.
// * Contains a `capacity()` member function indicating the number of element
// slots (open, deleted, and empty) within the hash map.
// * Returns `void` from the `erase(iterator)` overload.
//
// By default, `flat_hash_map` uses the `absl::Hash` hashing framework.
// All fundamental and Abseil types that support the `absl::Hash` framework have
// a compatible equality operator for comparing insertions into `flat_hash_map`.
// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
// Using `absl::flat_hash_map` at interface boundaries in dynamically loaded
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
// be randomized across dynamically loaded libraries.
//
// NOTE: A `flat_hash_map` stores its value types directly inside its
// implementation array to avoid memory indirection. Because a `flat_hash_map`
// is designed to move data when rehashed, map values will not retain pointer
// stability. If you require pointer stability, or if your values are large,
// consider using `absl::flat_hash_map<Key, std::unique_ptr<Value>>` instead.
// If your types are not moveable or you require pointer stability for keys,
// consider `absl::node_hash_map`.
//
// Example:
//
// // Create a flat hash map of three strings (that map to strings)
// absl::flat_hash_map<std::string, std::string> ducks =
// {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
//
// // Insert a new element into the flat hash map
// ducks.insert({"d", "donald"});
//
// // Force a rehash of the flat hash map
// ducks.rehash(0);
//
// // Find the element with the key "b"
// std::string search_key = "b";
// auto result = ducks.find(search_key);
// if (result != ducks.end()) {
// std::cout << "Result: " << result->second << std::endl;
// }
template<class K, class V, class Hash = absl::container_internal::hash_default_hash<K>, class Eq = absl::container_internal::hash_default_eq<K>, class Allocator = std::allocator<std::pair<const K, V>>>
class flat_hash_map : public absl::container_internal::raw_hash_map<absl::container_internal::FlatHashMapPolicy<K, V>, Hash, Eq, Allocator>
{
using Base = typename flat_hash_map::raw_hash_map;

public:
// Constructors and Assignment Operators
//
// A flat_hash_map supports the same overload set as `std::unordered_map`
// for construction and assignment:
//
// * Default constructor
//
// // No allocation for the table's elements is made.
// absl::flat_hash_map<int, std::string> map1;
//
// * Initializer List constructor
//
// absl::flat_hash_map<int, std::string> map2 =
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
//
// * Copy constructor
//
// absl::flat_hash_map<int, std::string> map3(map2);
//
// * Copy assignment operator
//
// // Hash functor and Comparator are copied as well
// absl::flat_hash_map<int, std::string> map4;
// map4 = map3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::flat_hash_map<int, std::string> map5(std::move(map4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::flat_hash_map<int, std::string> map6;
// map6 = std::move(map5);
//
// * Range constructor
//
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
// absl::flat_hash_map<int, std::string> map7(v.begin(), v.end());
flat_hash_map()
{
}
using Base::Base;

// flat_hash_map::begin()
//
// Returns an iterator to the beginning of the `flat_hash_map`.
using Base::begin;

// flat_hash_map::cbegin()
//
// Returns a const iterator to the beginning of the `flat_hash_map`.
using Base::cbegin;

// flat_hash_map::cend()
//
// Returns a const iterator to the end of the `flat_hash_map`.
using Base::cend;

// flat_hash_map::end()
//
// Returns an iterator to the end of the `flat_hash_map`.
using Base::end;

// flat_hash_map::capacity()
//
// Returns the number of element slots (assigned, deleted, and empty)
// available within the `flat_hash_map`.
//
// NOTE: this member function is particular to `absl::flat_hash_map` and is
// not provided in the `std::unordered_map` API.
using Base::capacity;

// flat_hash_map::empty()
//
// Returns whether or not the `flat_hash_map` is empty.
using Base::empty;

// flat_hash_map::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `flat_hash_map` under current memory constraints. This value can be thought
// of the largest value of `std::distance(begin(), end())` for a
// `flat_hash_map<K, V>`.
using Base::max_size;

// flat_hash_map::size()
//
// Returns the number of elements currently within the `flat_hash_map`.
using Base::size;

// flat_hash_map::clear()
//
// Removes all elements from the `flat_hash_map`. Invalidates any references,
// pointers, or iterators referring to contained elements.
//
// NOTE: this operation may shrink the underlying buffer. To avoid shrinking
// the underlying buffer call `erase(begin(), end())`.
using Base::clear;

// flat_hash_map::erase()
//
// Erases elements within the `flat_hash_map`. Erasing does not trigger a
// rehash. Overloads are listed below.
//
// void erase(const_iterator pos):
//
// Erases the element at `position` of the `flat_hash_map`, returning
// `void`.
//
// NOTE: returning `void` in this case is different than that of STL
// containers in general and `std::unordered_map` in particular (which
// return an iterator to the element following the erased element). If that
// iterator is needed, simply post increment the iterator:
//
// map.erase(it++);
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning an
// iterator pointing to `last`.
//
// size_type erase(const key_type& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;

// flat_hash_map::insert()
//
// Inserts an element of the specified value into the `flat_hash_map`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If rehashing occurs
// due to the insertion, all iterators are invalidated. Overloads are listed
// below.
//
// std::pair<iterator,bool> insert(const init_type& value):
//
// Inserts a value into the `flat_hash_map`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(T&& value):
// std::pair<iterator,bool> insert(init_type&& value):
//
// Inserts a moveable value into the `flat_hash_map`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const init_type& value):
// iterator insert(const_iterator hint, T&& value):
// iterator insert(const_iterator hint, init_type&& value);
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// NOTE: Although the STL does not specify which element may be inserted if
// multiple keys compare equivalently, for `flat_hash_map` we guarantee the
// first match is inserted.
//
// void insert(std::initializer_list<init_type> ilist):
//
// Inserts the elements within the initializer list `ilist`.
//
// NOTE: Although the STL does not specify which element may be inserted if
// multiple keys compare equivalently within the initializer list, for
// `flat_hash_map` we guarantee the first match is inserted.
using Base::insert;

// flat_hash_map::insert_or_assign()
//
// Inserts an element of the specified value into the `flat_hash_map` provided
// that a value with the given key does not already exist, or replaces it with
// the element value if a key for that value already exists, returning an
// iterator pointing to the newly inserted element. If rehashing occurs due
// to the insertion, all existing iterators are invalidated. Overloads are
// listed below.
//
// pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
// pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `flat_hash_map`.
//
// iterator insert_or_assign(const_iterator hint,
// const init_type& k, T&& obj):
// iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
//
// Inserts/Assigns (or moves) the element of the specified key into the
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
using Base::insert_or_assign;

// flat_hash_map::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `flat_hash_map`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;

// flat_hash_map::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `flat_hash_map`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately. Prefer `try_emplace()` unless your key is not
// copyable or moveable.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;

// flat_hash_map::try_emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `flat_hash_map`, provided that no element with the given key
// already exists. Unlike `emplace()`, if an element with the given key
// already exists, we guarantee that no element is constructed.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
// Overloads are listed below.
//
// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `flat_hash_map`.
//
// iterator try_emplace(const_iterator hint,
// const key_type& k, Args&&... args):
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
//
// Inserts (via copy or move) the element of the specified key into the
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search.
//
// All `try_emplace()` overloads make the same guarantees regarding rvalue
// arguments as `std::unordered_map::try_emplace()`, namely that these
// functions will not move from rvalue arguments if insertions do not happen.
using Base::try_emplace;

// flat_hash_map::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the key,value pair of the element at the indicated position and
// returns a node handle owning that extracted data.
//
// node_type extract(const key_type& x):
//
// Extracts the key,value pair of the element with a key matching the passed
// key value and returns a node handle owning that extracted data. If the
// `flat_hash_map` does not contain an element with a matching key, this
// function returns an empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
using Base::extract;

// flat_hash_map::merge()
//
// Extracts elements from a given `source` flat hash map into this
// `flat_hash_map`. If the destination `flat_hash_map` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;

// flat_hash_map::swap(flat_hash_map& other)
//
// Exchanges the contents of this `flat_hash_map` with those of the `other`
// flat hash map, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `flat_hash_map` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
//
// `swap()` requires that the flat hash map's hashing and key equivalence
// functions be Swappable, and are exchanged using unqualified calls to
// non-member `swap()`. If the map's allocator has
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
// set to `true`, the allocators are also exchanged using an unqualified call
// to non-member `swap()`; otherwise, the allocators are not swapped.
using Base::swap;

// flat_hash_map::rehash(count)
//
// Rehashes the `flat_hash_map`, setting the number of slots to be at least
// the passed value. If the new number of slots increases the load factor more
// than the current maximum load factor
// (`count` < `size()` / `max_load_factor()`), then the new number of slots
// will be at least `size()` / `max_load_factor()`.
//
// To force a rehash, pass rehash(0).
//
// NOTE: unlike behavior in `std::unordered_map`, references are also
// invalidated upon a `rehash()`.
using Base::rehash;

// flat_hash_map::reserve(count)
//
// Sets the number of slots in the `flat_hash_map` to the number needed to
// accommodate at least `count` total elements without exceeding the current
// maximum load factor, and may rehash the container if needed.
using Base::reserve;

// flat_hash_map::at()
//
// Returns a reference to the mapped value of the element with key equivalent
// to the passed key.
using Base::at;

// flat_hash_map::contains()
//
// Determines whether an element with a key comparing equal to the given `key`
// exists within the `flat_hash_map`, returning `true` if so or `false`
// otherwise.
using Base::contains;

// flat_hash_map::count(const Key& key) const
//
// Returns the number of elements with a key comparing equal to the given
// `key` within the `flat_hash_map`. note that this function will return
// either `1` or `0` since duplicate keys are not allowed within a
// `flat_hash_map`.
using Base::count;

// flat_hash_map::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `flat_hash_map`.
using Base::equal_range;

// flat_hash_map::find()
//
// Finds an element with the passed `key` within the `flat_hash_map`.
using Base::find;

// flat_hash_map::operator[]()
//
// Returns a reference to the value mapped to the passed key within the
// `flat_hash_map`, performing an `insert()` if the key does not already
// exist.
//
// If an insertion occurs and results in a rehashing of the container, all
// iterators are invalidated. Otherwise iterators are not affected and
// references are not invalidated. Overloads are listed below.
//
// T& operator[](const Key& key):
//
// Inserts an init_type object constructed in-place if the element with the
// given key does not exist.
//
// T& operator[](Key&& key):
//
// Inserts an init_type object constructed in-place provided that an element
// with the given key does not exist.
using Base::operator[];

// flat_hash_map::bucket_count()
//
// Returns the number of "buckets" within the `flat_hash_map`. Note that
// because a flat hash map contains all elements within its internal storage,
// this value simply equals the current capacity of the `flat_hash_map`.
using Base::bucket_count;

// flat_hash_map::load_factor()
//
// Returns the current load factor of the `flat_hash_map` (the average number
// of slots occupied with a value within the hash map).
using Base::load_factor;

// flat_hash_map::max_load_factor()
//
// Manages the maximum load factor of the `flat_hash_map`. Overloads are
// listed below.
//
// float flat_hash_map::max_load_factor()
//
// Returns the current maximum load factor of the `flat_hash_map`.
//
// void flat_hash_map::max_load_factor(float ml)
//
// Sets the maximum load factor of the `flat_hash_map` to the passed value.
//
// NOTE: This overload is provided only for API compatibility with the STL;
// `flat_hash_map` will ignore any set load factor and manage its rehashing
// internally as an implementation detail.
using Base::max_load_factor;

// flat_hash_map::get_allocator()
//
// Returns the allocator function associated with this `flat_hash_map`.
using Base::get_allocator;

// flat_hash_map::hash_function()
//
// Returns the hashing function used to hash the keys within this
// `flat_hash_map`.
using Base::hash_function;

// flat_hash_map::key_eq()
//
// Returns the function used for comparing keys equality.
using Base::key_eq;
};

// erase_if(flat_hash_map<>, Pred)
//
// Erases all elements that satisfy the predicate `pred` from the container `c`.
// Returns the number of erased elements.
template<typename K, typename V, typename H, typename E, typename A, typename Predicate>
typename flat_hash_map<K, V, H, E, A>::size_type erase_if(
flat_hash_map<K, V, H, E, A>& c, Predicate pred
)
{
return container_internal::EraseIf(pred, &c);
}

namespace container_internal
{

template<class K, class V>
struct FlatHashMapPolicy
{
using slot_policy = container_internal::map_slot_policy<K, V>;
using slot_type = typename slot_policy::slot_type;
using key_type = K;
using mapped_type = V;
using init_type = std::pair</*non const*/ key_type, mapped_type>;

template<class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args)
{
slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
}

template<class Allocator>
static void destroy(Allocator* alloc, slot_type* slot)
{
slot_policy::destroy(alloc, slot);
}

template<class Allocator>
static void transfer(Allocator* alloc, slot_type* new_slot, slot_type* old_slot)
{
slot_policy::transfer(alloc, new_slot, old_slot);
}

template<class F, class... Args>
static decltype(absl::container_internal::DecomposePair(
std::declval<F>(), std::declval<Args>()...
))
apply(F&& f, Args&&... args)
{
return absl::container_internal::DecomposePair(std::forward<F>(f), std::forward<Args>(args)...);
}

static size_t space_used(const slot_type*)
{
return 0;
}

static std::pair<const K, V>& element(slot_type* slot)
{
return slot->value;
}

static V& value(std::pair<const K, V>* kv)
{
return kv->second;
}
static const V& value(const std::pair<const K, V>* kv)
{
return kv->second;
}
};

} // namespace container_internal

namespace container_algorithm_internal
{

// Specialization of trait in absl/algorithm/container.h
template<class Key, class T, class Hash, class KeyEqual, class Allocator>
struct IsUnorderedContainer<
absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type
{
};

} // namespace container_algorithm_internal

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_

+ 527
- 0
CAPI/cpp/grpc/include/absl/container/flat_hash_set.h View File

@@ -0,0 +1,527 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: flat_hash_set.h
// -----------------------------------------------------------------------------
//
// An `absl::flat_hash_set<T>` is an unordered associative container designed to
// be a more efficient replacement for `std::unordered_set`. Like
// `unordered_set`, search, insertion, and deletion of set elements can be done
// as an `O(1)` operation. However, `flat_hash_set` (and other unordered
// associative containers known as the collection of Abseil "Swiss tables")
// contain other optimizations that result in both memory and computation
// advantages.
//
// In most cases, your default choice for a hash set should be a set of type
// `flat_hash_set`.
#ifndef ABSL_CONTAINER_FLAT_HASH_SET_H_
#define ABSL_CONTAINER_FLAT_HASH_SET_H_

#include <type_traits>
#include <utility>

#include "absl/algorithm/container.h"
#include "absl/base/macros.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
#include "absl/memory/memory.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{
template<typename T>
struct FlatHashSetPolicy;
} // namespace container_internal

// -----------------------------------------------------------------------------
// absl::flat_hash_set
// -----------------------------------------------------------------------------
//
// An `absl::flat_hash_set<T>` is an unordered associative container which has
// been optimized for both speed and memory footprint in most common use cases.
// Its interface is similar to that of `std::unordered_set<T>` with the
// following notable differences:
//
// * Requires keys that are CopyConstructible
// * Supports heterogeneous lookup, through `find()` and `insert()`, provided
// that the set is provided a compatible heterogeneous hashing function and
// equality operator.
// * Invalidates any references and pointers to elements within the table after
// `rehash()`.
// * Contains a `capacity()` member function indicating the number of element
// slots (open, deleted, and empty) within the hash set.
// * Returns `void` from the `erase(iterator)` overload.
//
// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
// fundamental and Abseil types that support the `absl::Hash` framework have a
// compatible equality operator for comparing insertions into `flat_hash_set`.
// If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types.
//
// Using `absl::flat_hash_set` at interface boundaries in dynamically loaded
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
// be randomized across dynamically loaded libraries.
//
// NOTE: A `flat_hash_set` stores its keys directly inside its implementation
// array to avoid memory indirection. Because a `flat_hash_set` is designed to
// move data when rehashed, set keys will not retain pointer stability. If you
// require pointer stability, consider using
// `absl::flat_hash_set<std::unique_ptr<T>>`. If your type is not moveable and
// you require pointer stability, consider `absl::node_hash_set` instead.
//
// Example:
//
// // Create a flat hash set of three strings
// absl::flat_hash_set<std::string> ducks =
// {"huey", "dewey", "louie"};
//
// // Insert a new element into the flat hash set
// ducks.insert("donald");
//
// // Force a rehash of the flat hash set
// ducks.rehash(0);
//
// // See if "dewey" is present
// if (ducks.contains("dewey")) {
// std::cout << "We found dewey!" << std::endl;
// }
template<class T, class Hash = absl::container_internal::hash_default_hash<T>, class Eq = absl::container_internal::hash_default_eq<T>, class Allocator = std::allocator<T>>
class flat_hash_set : public absl::container_internal::raw_hash_set<absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator>
{
using Base = typename flat_hash_set::raw_hash_set;

public:
// Constructors and Assignment Operators
//
// A flat_hash_set supports the same overload set as `std::unordered_set`
// for construction and assignment:
//
// * Default constructor
//
// // No allocation for the table's elements is made.
// absl::flat_hash_set<std::string> set1;
//
// * Initializer List constructor
//
// absl::flat_hash_set<std::string> set2 =
// {{"huey"}, {"dewey"}, {"louie"},};
//
// * Copy constructor
//
// absl::flat_hash_set<std::string> set3(set2);
//
// * Copy assignment operator
//
// // Hash functor and Comparator are copied as well
// absl::flat_hash_set<std::string> set4;
// set4 = set3;
//
// * Move constructor
//
// // Move is guaranteed efficient
// absl::flat_hash_set<std::string> set5(std::move(set4));
//
// * Move assignment operator
//
// // May be efficient if allocators are compatible
// absl::flat_hash_set<std::string> set6;
// set6 = std::move(set5);
//
// * Range constructor
//
// std::vector<std::string> v = {"a", "b"};
// absl::flat_hash_set<std::string> set7(v.begin(), v.end());
flat_hash_set()
{
}
using Base::Base;

// flat_hash_set::begin()
//
// Returns an iterator to the beginning of the `flat_hash_set`.
using Base::begin;

// flat_hash_set::cbegin()
//
// Returns a const iterator to the beginning of the `flat_hash_set`.
using Base::cbegin;

// flat_hash_set::cend()
//
// Returns a const iterator to the end of the `flat_hash_set`.
using Base::cend;

// flat_hash_set::end()
//
// Returns an iterator to the end of the `flat_hash_set`.
using Base::end;

// flat_hash_set::capacity()
//
// Returns the number of element slots (assigned, deleted, and empty)
// available within the `flat_hash_set`.
//
// NOTE: this member function is particular to `absl::flat_hash_set` and is
// not provided in the `std::unordered_set` API.
using Base::capacity;

// flat_hash_set::empty()
//
// Returns whether or not the `flat_hash_set` is empty.
using Base::empty;

// flat_hash_set::max_size()
//
// Returns the largest theoretical possible number of elements within a
// `flat_hash_set` under current memory constraints. This value can be thought
// of the largest value of `std::distance(begin(), end())` for a
// `flat_hash_set<T>`.
using Base::max_size;

// flat_hash_set::size()
//
// Returns the number of elements currently within the `flat_hash_set`.
using Base::size;

// flat_hash_set::clear()
//
// Removes all elements from the `flat_hash_set`. Invalidates any references,
// pointers, or iterators referring to contained elements.
//
// NOTE: this operation may shrink the underlying buffer. To avoid shrinking
// the underlying buffer call `erase(begin(), end())`.
using Base::clear;

// flat_hash_set::erase()
//
// Erases elements within the `flat_hash_set`. Erasing does not trigger a
// rehash. Overloads are listed below.
//
// void erase(const_iterator pos):
//
// Erases the element at `position` of the `flat_hash_set`, returning
// `void`.
//
// NOTE: returning `void` in this case is different than that of STL
// containers in general and `std::unordered_set` in particular (which
// return an iterator to the element following the erased element). If that
// iterator is needed, simply post increment the iterator:
//
// set.erase(it++);
//
// iterator erase(const_iterator first, const_iterator last):
//
// Erases the elements in the open interval [`first`, `last`), returning an
// iterator pointing to `last`.
//
// size_type erase(const key_type& key):
//
// Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase;

// flat_hash_set::insert()
//
// Inserts an element of the specified value into the `flat_hash_set`,
// returning an iterator pointing to the newly inserted element, provided that
// an element with the given key does not already exist. If rehashing occurs
// due to the insertion, all iterators are invalidated. Overloads are listed
// below.
//
// std::pair<iterator,bool> insert(const T& value):
//
// Inserts a value into the `flat_hash_set`. Returns a pair consisting of an
// iterator to the inserted element (or to the element that prevented the
// insertion) and a bool denoting whether the insertion took place.
//
// std::pair<iterator,bool> insert(T&& value):
//
// Inserts a moveable value into the `flat_hash_set`. Returns a pair
// consisting of an iterator to the inserted element (or to the element that
// prevented the insertion) and a bool denoting whether the insertion took
// place.
//
// iterator insert(const_iterator hint, const T& value):
// iterator insert(const_iterator hint, T&& value):
//
// Inserts a value, using the position of `hint` as a non-binding suggestion
// for where to begin the insertion search. Returns an iterator to the
// inserted element, or to the existing element that prevented the
// insertion.
//
// void insert(InputIterator first, InputIterator last):
//
// Inserts a range of values [`first`, `last`).
//
// NOTE: Although the STL does not specify which element may be inserted if
// multiple keys compare equivalently, for `flat_hash_set` we guarantee the
// first match is inserted.
//
// void insert(std::initializer_list<T> ilist):
//
// Inserts the elements within the initializer list `ilist`.
//
// NOTE: Although the STL does not specify which element may be inserted if
// multiple keys compare equivalently within the initializer list, for
// `flat_hash_set` we guarantee the first match is inserted.
using Base::insert;

// flat_hash_set::emplace()
//
// Inserts an element of the specified value by constructing it in-place
// within the `flat_hash_set`, provided that no element with the given key
// already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace;

// flat_hash_set::emplace_hint()
//
// Inserts an element of the specified value by constructing it in-place
// within the `flat_hash_set`, using the position of `hint` as a non-binding
// suggestion for where to begin the insertion search, and only inserts
// provided that no element with the given key already exists.
//
// The element may be constructed even if there already is an element with the
// key in the container, in which case the newly constructed element will be
// destroyed immediately.
//
// If rehashing occurs due to the insertion, all iterators are invalidated.
using Base::emplace_hint;

// flat_hash_set::extract()
//
// Extracts the indicated element, erasing it in the process, and returns it
// as a C++17-compatible node handle. Overloads are listed below.
//
// node_type extract(const_iterator position):
//
// Extracts the element at the indicated position and returns a node handle
// owning that extracted data.
//
// node_type extract(const key_type& x):
//
// Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `flat_hash_set`
// does not contain an element with a matching key, this function returns an
// empty node handle.
using Base::extract;

// flat_hash_set::merge()
//
// Extracts elements from a given `source` flat hash set into this
// `flat_hash_set`. If the destination `flat_hash_set` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge;

// flat_hash_set::swap(flat_hash_set& other)
//
// Exchanges the contents of this `flat_hash_set` with those of the `other`
// flat hash set, avoiding invocation of any move, copy, or swap operations on
// individual elements.
//
// All iterators and references on the `flat_hash_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
//
// `swap()` requires that the flat hash set's hashing and key equivalence
// functions be Swappable, and are exchaged using unqualified calls to
// non-member `swap()`. If the set's allocator has
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
// set to `true`, the allocators are also exchanged using an unqualified call
// to non-member `swap()`; otherwise, the allocators are not swapped.
using Base::swap;

// flat_hash_set::rehash(count)
//
// Rehashes the `flat_hash_set`, setting the number of slots to be at least
// the passed value. If the new number of slots increases the load factor more
// than the current maximum load factor
// (`count` < `size()` / `max_load_factor()`), then the new number of slots
// will be at least `size()` / `max_load_factor()`.
//
// To force a rehash, pass rehash(0).
//
// NOTE: unlike behavior in `std::unordered_set`, references are also
// invalidated upon a `rehash()`.
using Base::rehash;

// flat_hash_set::reserve(count)
//
// Sets the number of slots in the `flat_hash_set` to the number needed to
// accommodate at least `count` total elements without exceeding the current
// maximum load factor, and may rehash the container if needed.
using Base::reserve;

// flat_hash_set::contains()
//
// Determines whether an element comparing equal to the given `key` exists
// within the `flat_hash_set`, returning `true` if so or `false` otherwise.
using Base::contains;

// flat_hash_set::count(const Key& key) const
//
// Returns the number of elements comparing equal to the given `key` within
// the `flat_hash_set`. note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `flat_hash_set`.
using Base::count;

// flat_hash_set::equal_range()
//
// Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the
// `flat_hash_set`.
using Base::equal_range;

// flat_hash_set::find()
//
// Finds an element with the passed `key` within the `flat_hash_set`.
using Base::find;

// flat_hash_set::bucket_count()
//
// Returns the number of "buckets" within the `flat_hash_set`. Note that
// because a flat hash set contains all elements within its internal storage,
// this value simply equals the current capacity of the `flat_hash_set`.
using Base::bucket_count;

// flat_hash_set::load_factor()
//
// Returns the current load factor of the `flat_hash_set` (the average number
// of slots occupied with a value within the hash set).
using Base::load_factor;

// flat_hash_set::max_load_factor()
//
// Manages the maximum load factor of the `flat_hash_set`. Overloads are
// listed below.
//
// float flat_hash_set::max_load_factor()
//
// Returns the current maximum load factor of the `flat_hash_set`.
//
// void flat_hash_set::max_load_factor(float ml)
//
// Sets the maximum load factor of the `flat_hash_set` to the passed value.
//
// NOTE: This overload is provided only for API compatibility with the STL;
// `flat_hash_set` will ignore any set load factor and manage its rehashing
// internally as an implementation detail.
using Base::max_load_factor;

// flat_hash_set::get_allocator()
//
// Returns the allocator function associated with this `flat_hash_set`.
using Base::get_allocator;

// flat_hash_set::hash_function()
//
// Returns the hashing function used to hash the keys within this
// `flat_hash_set`.
using Base::hash_function;

// flat_hash_set::key_eq()
//
// Returns the function used for comparing keys equality.
using Base::key_eq;
};

// erase_if(flat_hash_set<>, Pred)
//
// Erases all elements that satisfy the predicate `pred` from the container `c`.
// Returns the number of erased elements.
template<typename T, typename H, typename E, typename A, typename Predicate>
typename flat_hash_set<T, H, E, A>::size_type erase_if(
flat_hash_set<T, H, E, A>& c, Predicate pred
)
{
return container_internal::EraseIf(pred, &c);
}

namespace container_internal
{

template<class T>
struct FlatHashSetPolicy
{
using slot_type = T;
using key_type = T;
using init_type = T;
using constant_iterators = std::true_type;

template<class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args)
{
absl::allocator_traits<Allocator>::construct(*alloc, slot, std::forward<Args>(args)...);
}

template<class Allocator>
static void destroy(Allocator* alloc, slot_type* slot)
{
absl::allocator_traits<Allocator>::destroy(*alloc, slot);
}

template<class Allocator>
static void transfer(Allocator* alloc, slot_type* new_slot, slot_type* old_slot)
{
construct(alloc, new_slot, std::move(*old_slot));
destroy(alloc, old_slot);
}

static T& element(slot_type* slot)
{
return *slot;
}

template<class F, class... Args>
static decltype(absl::container_internal::DecomposeValue(
std::declval<F>(), std::declval<Args>()...
))
apply(F&& f, Args&&... args)
{
return absl::container_internal::DecomposeValue(
std::forward<F>(f), std::forward<Args>(args)...
);
}

static size_t space_used(const T*)
{
return 0;
}
};
} // namespace container_internal

namespace container_algorithm_internal
{

// Specialization of trait in absl/algorithm/container.h
template<class Key, class Hash, class KeyEqual, class Allocator>
struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>> : std::true_type
{
};

} // namespace container_algorithm_internal

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_

+ 984
- 0
CAPI/cpp/grpc/include/absl/container/inlined_vector.h View File

@@ -0,0 +1,984 @@
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: inlined_vector.h
// -----------------------------------------------------------------------------
//
// This header file contains the declaration and definition of an "inlined
// vector" which behaves in an equivalent fashion to a `std::vector`, except
// that storage for small sequences of the vector are provided inline without
// requiring any heap allocation.
//
// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
// its template parameters. Instances where `size() <= N` hold contained
// elements in inline space. Typically `N` is very small so that sequences that
// are expected to be short do not require allocations.
//
// An `absl::InlinedVector` does not usually require a specific allocator. If
// the inlined vector grows beyond its initial constraints, it will need to
// allocate (as any normal `std::vector` would). This is usually performed with
// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.

#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
#define ABSL_CONTAINER_INLINED_VECTOR_H_

#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>

#include "absl/algorithm/algorithm.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/inlined_vector.h"
#include "absl/memory/memory.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
// -----------------------------------------------------------------------------
// InlinedVector
// -----------------------------------------------------------------------------
//
// An `absl::InlinedVector` is designed to be a drop-in replacement for
// `std::vector` for use cases where the vector's size is sufficiently small
// that it can be inlined. If the inlined vector does grow beyond its estimated
// capacity, it will trigger an initial allocation on the heap, and will behave
// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
// designed to cover the same API footprint as covered by `std::vector`.
template<typename T, size_t N, typename A = std::allocator<T>>
class InlinedVector
{
static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");

using Storage = inlined_vector_internal::Storage<T, N, A>;

template<typename TheA>
using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>;
template<typename TheA>
using MoveIterator = inlined_vector_internal::MoveIterator<TheA>;
template<typename TheA>
using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<TheA>;

template<typename TheA, typename Iterator>
using IteratorValueAdapter =
inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>;
template<typename TheA>
using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>;
template<typename TheA>
using DefaultValueAdapter =
inlined_vector_internal::DefaultValueAdapter<TheA>;

template<typename Iterator>
using EnableIfAtLeastForwardIterator = absl::enable_if_t<
inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value,
int>;
template<typename Iterator>
using DisableIfAtLeastForwardIterator = absl::enable_if_t<
!inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value,
int>;

public:
using allocator_type = A;
using value_type = inlined_vector_internal::ValueType<A>;
using pointer = inlined_vector_internal::Pointer<A>;
using const_pointer = inlined_vector_internal::ConstPointer<A>;
using size_type = inlined_vector_internal::SizeType<A>;
using difference_type = inlined_vector_internal::DifferenceType<A>;
using reference = inlined_vector_internal::Reference<A>;
using const_reference = inlined_vector_internal::ConstReference<A>;
using iterator = inlined_vector_internal::Iterator<A>;
using const_iterator = inlined_vector_internal::ConstIterator<A>;
using reverse_iterator = inlined_vector_internal::ReverseIterator<A>;
using const_reverse_iterator =
inlined_vector_internal::ConstReverseIterator<A>;

// ---------------------------------------------------------------------------
// InlinedVector Constructors and Destructor
// ---------------------------------------------------------------------------

// Creates an empty inlined vector with a value-initialized allocator.
InlinedVector() noexcept(noexcept(allocator_type())) :
storage_()
{
}

// Creates an empty inlined vector with a copy of `allocator`.
explicit InlinedVector(const allocator_type& allocator) noexcept
:
storage_(allocator)
{
}

// Creates an inlined vector with `n` copies of `value_type()`.
explicit InlinedVector(size_type n, const allocator_type& allocator = allocator_type()) :
storage_(allocator)
{
storage_.Initialize(DefaultValueAdapter<A>(), n);
}

// Creates an inlined vector with `n` copies of `v`.
InlinedVector(size_type n, const_reference v, const allocator_type& allocator = allocator_type()) :
storage_(allocator)
{
storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n);
}

// Creates an inlined vector with copies of the elements of `list`.
InlinedVector(std::initializer_list<value_type> list, const allocator_type& allocator = allocator_type()) :
InlinedVector(list.begin(), list.end(), allocator)
{
}

// Creates an inlined vector with elements constructed from the provided
// forward iterator range [`first`, `last`).
//
// NOTE: the `enable_if` prevents ambiguous interpretation between a call to
// this constructor with two integral arguments and a call to the above
// `InlinedVector(size_type, const_reference)` constructor.
template<typename ForwardIterator, EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
InlinedVector(ForwardIterator first, ForwardIterator last, const allocator_type& allocator = allocator_type()) :
storage_(allocator)
{
storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first), static_cast<size_t>(std::distance(first, last)));
}

// Creates an inlined vector with elements constructed from the provided input
// iterator range [`first`, `last`).
template<typename InputIterator, DisableIfAtLeastForwardIterator<InputIterator> = 0>
InlinedVector(InputIterator first, InputIterator last, const allocator_type& allocator = allocator_type()) :
storage_(allocator)
{
std::copy(first, last, std::back_inserter(*this));
}

// Creates an inlined vector by copying the contents of `other` using
// `other`'s allocator.
InlinedVector(const InlinedVector& other) :
InlinedVector(other, other.storage_.GetAllocator())
{
}

// Creates an inlined vector by copying the contents of `other` using the
// provided `allocator`.
InlinedVector(const InlinedVector& other, const allocator_type& allocator) :
storage_(allocator)
{
if (other.empty())
{
// Empty; nothing to do.
}
else if (IsMemcpyOk<A>::value && !other.storage_.GetIsAllocated())
{
// Memcpy-able and do not need allocation.
storage_.MemcpyFrom(other.storage_);
}
else
{
storage_.InitFrom(other.storage_);
}
}

// Creates an inlined vector by moving in the contents of `other` without
// allocating. If `other` contains allocated memory, the newly-created inlined
// vector will take ownership of that memory. However, if `other` does not
// contain allocated memory, the newly-created inlined vector will perform
// element-wise move construction of the contents of `other`.
//
// NOTE: since no allocation is performed for the inlined vector in either
// case, the `noexcept(...)` specification depends on whether moving the
// underlying objects can throw. It is assumed assumed that...
// a) move constructors should only throw due to allocation failure.
// b) if `value_type`'s move constructor allocates, it uses the same
// allocation function as the inlined vector's allocator.
// Thus, the move constructor is non-throwing if the allocator is non-throwing
// or `value_type`'s move constructor is specified as `noexcept`.
InlinedVector(InlinedVector&& other) noexcept(
absl::allocator_is_nothrow<allocator_type>::value ||
std::is_nothrow_move_constructible<value_type>::value
) :
storage_(other.storage_.GetAllocator())
{
if (IsMemcpyOk<A>::value)
{
storage_.MemcpyFrom(other.storage_);

other.storage_.SetInlinedSize(0);
}
else if (other.storage_.GetIsAllocated())
{
storage_.SetAllocation({other.storage_.GetAllocatedData(), other.storage_.GetAllocatedCapacity()});
storage_.SetAllocatedSize(other.storage_.GetSize());

other.storage_.SetInlinedSize(0);
}
else
{
IteratorValueAdapter<A, MoveIterator<A>> other_values(
MoveIterator<A>(other.storage_.GetInlinedData())
);

inlined_vector_internal::ConstructElements<A>(
storage_.GetAllocator(), storage_.GetInlinedData(), other_values, other.storage_.GetSize()
);

storage_.SetInlinedSize(other.storage_.GetSize());
}
}

// Creates an inlined vector by moving in the contents of `other` with a copy
// of `allocator`.
//
// NOTE: if `other`'s allocator is not equal to `allocator`, even if `other`
// contains allocated memory, this move constructor will still allocate. Since
// allocation is performed, this constructor can only be `noexcept` if the
// specified allocator is also `noexcept`.
InlinedVector(
InlinedVector&& other,
const allocator_type&
allocator
) noexcept(absl::allocator_is_nothrow<allocator_type>::value) :
storage_(allocator)
{
if (IsMemcpyOk<A>::value)
{
storage_.MemcpyFrom(other.storage_);

other.storage_.SetInlinedSize(0);
}
else if ((storage_.GetAllocator() == other.storage_.GetAllocator()) && other.storage_.GetIsAllocated())
{
storage_.SetAllocation({other.storage_.GetAllocatedData(), other.storage_.GetAllocatedCapacity()});
storage_.SetAllocatedSize(other.storage_.GetSize());

other.storage_.SetInlinedSize(0);
}
else
{
storage_.Initialize(IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(other.data())), other.size());
}
}

~InlinedVector()
{
}

// ---------------------------------------------------------------------------
// InlinedVector Member Accessors
// ---------------------------------------------------------------------------

// `InlinedVector::empty()`
//
// Returns whether the inlined vector contains no elements.
bool empty() const noexcept
{
return !size();
}

// `InlinedVector::size()`
//
// Returns the number of elements in the inlined vector.
size_type size() const noexcept
{
return storage_.GetSize();
}

// `InlinedVector::max_size()`
//
// Returns the maximum number of elements the inlined vector can hold.
size_type max_size() const noexcept
{
// One bit of the size storage is used to indicate whether the inlined
// vector contains allocated memory. As a result, the maximum size that the
// inlined vector can express is half of the max for `size_type`.
return (std::numeric_limits<size_type>::max)() / 2;
}

// `InlinedVector::capacity()`
//
// Returns the number of elements that could be stored in the inlined vector
// without requiring a reallocation.
//
// NOTE: for most inlined vectors, `capacity()` should be equal to the
// template parameter `N`. For inlined vectors which exceed this capacity,
// they will no longer be inlined and `capacity()` will equal the capactity of
// the allocated memory.
size_type capacity() const noexcept
{
return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity() : storage_.GetInlinedCapacity();
}

// `InlinedVector::data()`
//
// Returns a `pointer` to the elements of the inlined vector. This pointer
// can be used to access and modify the contained elements.
//
// NOTE: only elements within [`data()`, `data() + size()`) are valid.
pointer data() noexcept
{
return storage_.GetIsAllocated() ? storage_.GetAllocatedData() : storage_.GetInlinedData();
}

// Overload of `InlinedVector::data()` that returns a `const_pointer` to the
// elements of the inlined vector. This pointer can be used to access but not
// modify the contained elements.
//
// NOTE: only elements within [`data()`, `data() + size()`) are valid.
const_pointer data() const noexcept
{
return storage_.GetIsAllocated() ? storage_.GetAllocatedData() : storage_.GetInlinedData();
}

// `InlinedVector::operator[](...)`
//
// Returns a `reference` to the `i`th element of the inlined vector.
reference operator[](size_type i)
{
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}

// Overload of `InlinedVector::operator[](...)` that returns a
// `const_reference` to the `i`th element of the inlined vector.
const_reference operator[](size_type i) const
{
ABSL_HARDENING_ASSERT(i < size());
return data()[i];
}

// `InlinedVector::at(...)`
//
// Returns a `reference` to the `i`th element of the inlined vector.
//
// NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
// in both debug and non-debug builds, `std::out_of_range` will be thrown.
reference at(size_type i)
{
if (ABSL_PREDICT_FALSE(i >= size()))
{
base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type)` failed bounds check"
);
}
return data()[i];
}

// Overload of `InlinedVector::at(...)` that returns a `const_reference` to
// the `i`th element of the inlined vector.
//
// NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
// in both debug and non-debug builds, `std::out_of_range` will be thrown.
const_reference at(size_type i) const
{
if (ABSL_PREDICT_FALSE(i >= size()))
{
base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type) const` failed bounds check"
);
}
return data()[i];
}

// `InlinedVector::front()`
//
// Returns a `reference` to the first element of the inlined vector.
reference front()
{
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}

// Overload of `InlinedVector::front()` that returns a `const_reference` to
// the first element of the inlined vector.
const_reference front() const
{
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}

// `InlinedVector::back()`
//
// Returns a `reference` to the last element of the inlined vector.
reference back()
{
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}

// Overload of `InlinedVector::back()` that returns a `const_reference` to the
// last element of the inlined vector.
const_reference back() const
{
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}

// `InlinedVector::begin()`
//
// Returns an `iterator` to the beginning of the inlined vector.
iterator begin() noexcept
{
return data();
}

// Overload of `InlinedVector::begin()` that returns a `const_iterator` to
// the beginning of the inlined vector.
const_iterator begin() const noexcept
{
return data();
}

// `InlinedVector::end()`
//
// Returns an `iterator` to the end of the inlined vector.
iterator end() noexcept
{
return data() + size();
}

// Overload of `InlinedVector::end()` that returns a `const_iterator` to the
// end of the inlined vector.
const_iterator end() const noexcept
{
return data() + size();
}

// `InlinedVector::cbegin()`
//
// Returns a `const_iterator` to the beginning of the inlined vector.
const_iterator cbegin() const noexcept
{
return begin();
}

// `InlinedVector::cend()`
//
// Returns a `const_iterator` to the end of the inlined vector.
const_iterator cend() const noexcept
{
return end();
}

// `InlinedVector::rbegin()`
//
// Returns a `reverse_iterator` from the end of the inlined vector.
reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}

// Overload of `InlinedVector::rbegin()` that returns a
// `const_reverse_iterator` from the end of the inlined vector.
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}

// `InlinedVector::rend()`
//
// Returns a `reverse_iterator` from the beginning of the inlined vector.
reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}

// Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
// from the beginning of the inlined vector.
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}

// `InlinedVector::crbegin()`
//
// Returns a `const_reverse_iterator` from the end of the inlined vector.
const_reverse_iterator crbegin() const noexcept
{
return rbegin();
}

// `InlinedVector::crend()`
//
// Returns a `const_reverse_iterator` from the beginning of the inlined
// vector.
const_reverse_iterator crend() const noexcept
{
return rend();
}

// `InlinedVector::get_allocator()`
//
// Returns a copy of the inlined vector's allocator.
allocator_type get_allocator() const
{
return storage_.GetAllocator();
}

// ---------------------------------------------------------------------------
// InlinedVector Member Mutators
// ---------------------------------------------------------------------------

// `InlinedVector::operator=(...)`
//
// Replaces the elements of the inlined vector with copies of the elements of
// `list`.
InlinedVector& operator=(std::initializer_list<value_type> list)
{
assign(list.begin(), list.end());

return *this;
}

// Overload of `InlinedVector::operator=(...)` that replaces the elements of
// the inlined vector with copies of the elements of `other`.
InlinedVector& operator=(const InlinedVector& other)
{
if (ABSL_PREDICT_TRUE(this != std::addressof(other)))
{
const_pointer other_data = other.data();
assign(other_data, other_data + other.size());
}

return *this;
}

// Overload of `InlinedVector::operator=(...)` that moves the elements of
// `other` into the inlined vector.
//
// NOTE: as a result of calling this overload, `other` is left in a valid but
// unspecified state.
InlinedVector& operator=(InlinedVector&& other)
{
if (ABSL_PREDICT_TRUE(this != std::addressof(other)))
{
if (IsMemcpyOk<A>::value || other.storage_.GetIsAllocated())
{
inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
storage_.GetAllocator(), data(), size()
);
storage_.DeallocateIfAllocated();
storage_.MemcpyFrom(other.storage_);

other.storage_.SetInlinedSize(0);
}
else
{
storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(other.storage_.GetInlinedData())), other.size());
}
}

return *this;
}

// `InlinedVector::assign(...)`
//
// Replaces the contents of the inlined vector with `n` copies of `v`.
void assign(size_type n, const_reference v)
{
storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n);
}

// Overload of `InlinedVector::assign(...)` that replaces the contents of the
// inlined vector with copies of the elements of `list`.
void assign(std::initializer_list<value_type> list)
{
assign(list.begin(), list.end());
}

// Overload of `InlinedVector::assign(...)` to replace the contents of the
// inlined vector with the range [`first`, `last`).
//
// NOTE: this overload is for iterators that are "forward" category or better.
template<typename ForwardIterator, EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
void assign(ForwardIterator first, ForwardIterator last)
{
storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first), static_cast<size_t>(std::distance(first, last)));
}

// Overload of `InlinedVector::assign(...)` to replace the contents of the
// inlined vector with the range [`first`, `last`).
//
// NOTE: this overload is for iterators that are "input" category.
template<typename InputIterator, DisableIfAtLeastForwardIterator<InputIterator> = 0>
void assign(InputIterator first, InputIterator last)
{
size_type i = 0;
for (; i < size() && first != last; ++i, static_cast<void>(++first))
{
data()[i] = *first;
}

erase(data() + i, data() + size());
std::copy(first, last, std::back_inserter(*this));
}

// `InlinedVector::resize(...)`
//
// Resizes the inlined vector to contain `n` elements.
//
// NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are value-initialized.
void resize(size_type n)
{
ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(DefaultValueAdapter<A>(), n);
}

// Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
// contain `n` elements.
//
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are copied-constructed from `v`.
void resize(size_type n, const_reference v)
{
ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n);
}

// `InlinedVector::insert(...)`
//
// Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
// inserted element.
iterator insert(const_iterator pos, const_reference v)
{
return emplace(pos, v);
}

// Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
// move semantics, returning an `iterator` to the newly inserted element.
iterator insert(const_iterator pos, value_type&& v)
{
return emplace(pos, std::move(v));
}

// Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
// of `v` starting at `pos`, returning an `iterator` pointing to the first of
// the newly inserted elements.
iterator insert(const_iterator pos, size_type n, const_reference v)
{
ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end());

if (ABSL_PREDICT_TRUE(n != 0))
{
value_type dealias = v;
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
// It appears that GCC thinks that since `pos` is a const pointer and may
// point to uninitialized memory at this point, a warning should be
// issued. But `pos` is actually only used to compute an array index to
// write to.
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)), n);
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
}
else
{
return const_cast<iterator>(pos);
}
}

// Overload of `InlinedVector::insert(...)` that inserts copies of the
// elements of `list` starting at `pos`, returning an `iterator` pointing to
// the first of the newly inserted elements.
iterator insert(const_iterator pos, std::initializer_list<value_type> list)
{
return insert(pos, list.begin(), list.end());
}

// Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
// `last`) starting at `pos`, returning an `iterator` pointing to the first
// of the newly inserted elements.
//
// NOTE: this overload is for iterators that are "forward" category or better.
template<typename ForwardIterator, EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
iterator insert(const_iterator pos, ForwardIterator first, ForwardIterator last)
{
ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end());

if (ABSL_PREDICT_TRUE(first != last))
{
return storage_.Insert(pos, IteratorValueAdapter<A, ForwardIterator>(first), std::distance(first, last));
}
else
{
return const_cast<iterator>(pos);
}
}

// Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
// `last`) starting at `pos`, returning an `iterator` pointing to the first
// of the newly inserted elements.
//
// NOTE: this overload is for iterators that are "input" category.
template<typename InputIterator, DisableIfAtLeastForwardIterator<InputIterator> = 0>
iterator insert(const_iterator pos, InputIterator first, InputIterator last)
{
ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end());

size_type index = std::distance(cbegin(), pos);
for (size_type i = index; first != last; ++i, static_cast<void>(++first))
{
insert(data() + i, *first);
}

return iterator(data() + index);
}

// `InlinedVector::emplace(...)`
//
// Constructs and inserts an element using `args...` in the inlined vector at
// `pos`, returning an `iterator` pointing to the newly emplaced element.
template<typename... Args>
iterator emplace(const_iterator pos, Args&&... args)
{
ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end());

value_type dealias(std::forward<Args>(args)...);
return storage_.Insert(pos, IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(std::addressof(dealias))), 1);
}

// `InlinedVector::emplace_back(...)`
//
// Constructs and inserts an element using `args...` in the inlined vector at
// `end()`, returning a `reference` to the newly emplaced element.
template<typename... Args>
reference emplace_back(Args&&... args)
{
return storage_.EmplaceBack(std::forward<Args>(args)...);
}

// `InlinedVector::push_back(...)`
//
// Inserts a copy of `v` in the inlined vector at `end()`.
void push_back(const_reference v)
{
static_cast<void>(emplace_back(v));
}

// Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
// using move semantics.
void push_back(value_type&& v)
{
static_cast<void>(emplace_back(std::move(v)));
}

// `InlinedVector::pop_back()`
//
// Destroys the element at `back()`, reducing the size by `1`.
void pop_back() noexcept
{
ABSL_HARDENING_ASSERT(!empty());

AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1));
storage_.SubtractSize(1);
}

// `InlinedVector::erase(...)`
//
// Erases the element at `pos`, returning an `iterator` pointing to where the
// erased element was located.
//
// NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator pos)
{
ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos < end());

return storage_.Erase(pos, pos + 1);
}

// Overload of `InlinedVector::erase(...)` that erases every element in the
// range [`from`, `to`), returning an `iterator` pointing to where the first
// erased element was located.
//
// NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator from, const_iterator to)
{
ABSL_HARDENING_ASSERT(from >= begin());
ABSL_HARDENING_ASSERT(from <= to);
ABSL_HARDENING_ASSERT(to <= end());

if (ABSL_PREDICT_TRUE(from != to))
{
return storage_.Erase(from, to);
}
else
{
return const_cast<iterator>(from);
}
}

// `InlinedVector::clear()`
//
// Destroys all elements in the inlined vector, setting the size to `0` and
// deallocating any held memory.
void clear() noexcept
{
inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
storage_.GetAllocator(), data(), size()
);
storage_.DeallocateIfAllocated();

storage_.SetInlinedSize(0);
}

// `InlinedVector::reserve(...)`
//
// Ensures that there is enough room for at least `n` elements.
void reserve(size_type n)
{
storage_.Reserve(n);
}

// `InlinedVector::shrink_to_fit()`
//
// Attempts to reduce memory usage by moving elements to (or keeping elements
// in) the smallest available buffer sufficient for containing `size()`
// elements.
//
// If `size()` is sufficiently small, the elements will be moved into (or kept
// in) the inlined space.
void shrink_to_fit()
{
if (storage_.GetIsAllocated())
{
storage_.ShrinkToFit();
}
}

// `InlinedVector::swap(...)`
//
// Swaps the contents of the inlined vector with `other`.
void swap(InlinedVector& other)
{
if (ABSL_PREDICT_TRUE(this != std::addressof(other)))
{
storage_.Swap(std::addressof(other.storage_));
}
}

private:
template<typename H, typename TheT, size_t TheN, typename TheA>
friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);

Storage storage_;
};

// -----------------------------------------------------------------------------
// InlinedVector Non-Member Functions
// -----------------------------------------------------------------------------

// `swap(...)`
//
// Swaps the contents of two inlined vectors.
template<typename T, size_t N, typename A>
void swap(absl::InlinedVector<T, N, A>& a, absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b)))
{
a.swap(b);
}

// `operator==(...)`
//
// Tests for value-equality of two inlined vectors.
template<typename T, size_t N, typename A>
bool operator==(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
auto a_data = a.data();
auto b_data = b.data();
return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
}

// `operator!=(...)`
//
// Tests for value-inequality of two inlined vectors.
template<typename T, size_t N, typename A>
bool operator!=(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
return !(a == b);
}

// `operator<(...)`
//
// Tests whether the value of an inlined vector is less than the value of
// another inlined vector using a lexicographical comparison algorithm.
template<typename T, size_t N, typename A>
bool operator<(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
auto a_data = a.data();
auto b_data = b.data();
return std::lexicographical_compare(a_data, a_data + a.size(), b_data, b_data + b.size());
}

// `operator>(...)`
//
// Tests whether the value of an inlined vector is greater than the value of
// another inlined vector using a lexicographical comparison algorithm.
template<typename T, size_t N, typename A>
bool operator>(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
return b < a;
}

// `operator<=(...)`
//
// Tests whether the value of an inlined vector is less than or equal to the
// value of another inlined vector using a lexicographical comparison algorithm.
template<typename T, size_t N, typename A>
bool operator<=(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
return !(b < a);
}

// `operator>=(...)`
//
// Tests whether the value of an inlined vector is greater than or equal to the
// value of another inlined vector using a lexicographical comparison algorithm.
template<typename T, size_t N, typename A>
bool operator>=(const absl::InlinedVector<T, N, A>& a, const absl::InlinedVector<T, N, A>& b)
{
return !(a < b);
}

// `AbslHashValue(...)`
//
// Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
// call this directly.
template<typename H, typename T, size_t N, typename A>
H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a)
{
auto size = a.size();
return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
}

ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INLINED_VECTOR_H_

+ 3419
- 0
CAPI/cpp/grpc/include/absl/container/internal/btree.h
File diff suppressed because it is too large
View File


+ 863
- 0
CAPI/cpp/grpc/include/absl/container/internal/btree_container.h View File

@@ -0,0 +1,863 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_
#define ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_

#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <utility>

#include "absl/base/attributes.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/common.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// A common base class for btree_set, btree_map, btree_multiset, and
// btree_multimap.
template<typename Tree>
class btree_container
{
using params_type = typename Tree::params_type;

protected:
// Alias used for heterogeneous lookup functions.
// `key_arg<K>` evaluates to `K` when the functors are transparent and to
// `key_type` otherwise. It permits template argument deduction on `K` for the
// transparent case.
template<class K>
using key_arg =
typename KeyArg<params_type::kIsKeyCompareTransparent>::template type<
K,
typename Tree::key_type>;

public:
using key_type = typename Tree::key_type;
using value_type = typename Tree::value_type;
using size_type = typename Tree::size_type;
using difference_type = typename Tree::difference_type;
using key_compare = typename Tree::original_key_compare;
using value_compare = typename Tree::value_compare;
using allocator_type = typename Tree::allocator_type;
using reference = typename Tree::reference;
using const_reference = typename Tree::const_reference;
using pointer = typename Tree::pointer;
using const_pointer = typename Tree::const_pointer;
using iterator = typename Tree::iterator;
using const_iterator = typename Tree::const_iterator;
using reverse_iterator = typename Tree::reverse_iterator;
using const_reverse_iterator = typename Tree::const_reverse_iterator;
using node_type = typename Tree::node_handle_type;

// Constructors/assignments.
btree_container() :
tree_(key_compare(), allocator_type())
{
}
explicit btree_container(const key_compare& comp, const allocator_type& alloc = allocator_type()) :
tree_(comp, alloc)
{
}
explicit btree_container(const allocator_type& alloc) :
tree_(key_compare(), alloc)
{
}

btree_container(const btree_container& other) :
btree_container(other, absl::allocator_traits<allocator_type>::select_on_container_copy_construction(other.get_allocator()))
{
}
btree_container(const btree_container& other, const allocator_type& alloc) :
tree_(other.tree_, alloc)
{
}

btree_container(btree_container&& other) noexcept(
std::is_nothrow_move_constructible<Tree>::value
) = default;
btree_container(btree_container&& other, const allocator_type& alloc) :
tree_(std::move(other.tree_), alloc)
{
}

btree_container& operator=(const btree_container& other) = default;
btree_container& operator=(btree_container&& other) noexcept(
std::is_nothrow_move_assignable<Tree>::value
) = default;

// Iterator routines.
iterator begin()
{
return tree_.begin();
}
const_iterator begin() const
{
return tree_.begin();
}
const_iterator cbegin() const
{
return tree_.begin();
}
iterator end()
{
return tree_.end();
}
const_iterator end() const
{
return tree_.end();
}
const_iterator cend() const
{
return tree_.end();
}
reverse_iterator rbegin()
{
return tree_.rbegin();
}
const_reverse_iterator rbegin() const
{
return tree_.rbegin();
}
const_reverse_iterator crbegin() const
{
return tree_.rbegin();
}
reverse_iterator rend()
{
return tree_.rend();
}
const_reverse_iterator rend() const
{
return tree_.rend();
}
const_reverse_iterator crend() const
{
return tree_.rend();
}

// Lookup routines.
template<typename K = key_type>
size_type count(const key_arg<K>& key) const
{
auto equal_range = this->equal_range(key);
return std::distance(equal_range.first, equal_range.second);
}
template<typename K = key_type>
iterator find(const key_arg<K>& key)
{
return tree_.find(key);
}
template<typename K = key_type>
const_iterator find(const key_arg<K>& key) const
{
return tree_.find(key);
}
template<typename K = key_type>
bool contains(const key_arg<K>& key) const
{
return find(key) != end();
}
template<typename K = key_type>
iterator lower_bound(const key_arg<K>& key)
{
return tree_.lower_bound(key);
}
template<typename K = key_type>
const_iterator lower_bound(const key_arg<K>& key) const
{
return tree_.lower_bound(key);
}
template<typename K = key_type>
iterator upper_bound(const key_arg<K>& key)
{
return tree_.upper_bound(key);
}
template<typename K = key_type>
const_iterator upper_bound(const key_arg<K>& key) const
{
return tree_.upper_bound(key);
}
template<typename K = key_type>
std::pair<iterator, iterator> equal_range(const key_arg<K>& key)
{
return tree_.equal_range(key);
}
template<typename K = key_type>
std::pair<const_iterator, const_iterator> equal_range(
const key_arg<K>& key
) const
{
return tree_.equal_range(key);
}

// Deletion routines. Note that there is also a deletion routine that is
// specific to btree_set_container/btree_multiset_container.

// Erase the specified iterator from the btree. The iterator must be valid
// (i.e. not equal to end()). Return an iterator pointing to the node after
// the one that was erased (or end() if none exists).
iterator erase(const_iterator iter)
{
return tree_.erase(iterator(iter));
}
iterator erase(iterator iter)
{
return tree_.erase(iter);
}
iterator erase(const_iterator first, const_iterator last)
{
return tree_.erase_range(iterator(first), iterator(last)).second;
}
template<typename K = key_type>
size_type erase(const key_arg<K>& key)
{
auto equal_range = this->equal_range(key);
return tree_.erase_range(equal_range.first, equal_range.second).first;
}

// Extract routines.
node_type extract(iterator position)
{
// Use Construct instead of Transfer because the rebalancing code will
// destroy the slot later.
auto node =
CommonAccess::Construct<node_type>(get_allocator(), position.slot());
erase(position);
return node;
}
node_type extract(const_iterator position)
{
return extract(iterator(position));
}

// Utility routines.
ABSL_ATTRIBUTE_REINITIALIZES void clear()
{
tree_.clear();
}
void swap(btree_container& other)
{
tree_.swap(other.tree_);
}
void verify() const
{
tree_.verify();
}

// Size routines.
size_type size() const
{
return tree_.size();
}
size_type max_size() const
{
return tree_.max_size();
}
bool empty() const
{
return tree_.empty();
}

friend bool operator==(const btree_container& x, const btree_container& y)
{
if (x.size() != y.size())
return false;
return std::equal(x.begin(), x.end(), y.begin());
}

friend bool operator!=(const btree_container& x, const btree_container& y)
{
return !(x == y);
}

friend bool operator<(const btree_container& x, const btree_container& y)
{
return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}

friend bool operator>(const btree_container& x, const btree_container& y)
{
return y < x;
}

friend bool operator<=(const btree_container& x, const btree_container& y)
{
return !(y < x);
}

friend bool operator>=(const btree_container& x, const btree_container& y)
{
return !(x < y);
}

// The allocator used by the btree.
allocator_type get_allocator() const
{
return tree_.get_allocator();
}

// The key comparator used by the btree.
key_compare key_comp() const
{
return key_compare(tree_.key_comp());
}
value_compare value_comp() const
{
return tree_.value_comp();
}

// Support absl::Hash.
template<typename State>
friend State AbslHashValue(State h, const btree_container& b)
{
for (const auto& v : b)
{
h = State::combine(std::move(h), v);
}
return State::combine(std::move(h), b.size());
}

protected:
friend struct btree_access;
Tree tree_;
};

// A common base class for btree_set and btree_map.
template<typename Tree>
class btree_set_container : public btree_container<Tree>
{
using super_type = btree_container<Tree>;
using params_type = typename Tree::params_type;
using init_type = typename params_type::init_type;
using is_key_compare_to = typename params_type::is_key_compare_to;
friend class BtreeNodePeer;

protected:
template<class K>
using key_arg = typename super_type::template key_arg<K>;

public:
using key_type = typename Tree::key_type;
using value_type = typename Tree::value_type;
using size_type = typename Tree::size_type;
using key_compare = typename Tree::original_key_compare;
using allocator_type = typename Tree::allocator_type;
using iterator = typename Tree::iterator;
using const_iterator = typename Tree::const_iterator;
using node_type = typename super_type::node_type;
using insert_return_type = InsertReturnType<iterator, node_type>;

// Inherit constructors.
using super_type::super_type;
btree_set_container()
{
}

// Range constructors.
template<class InputIterator>
btree_set_container(InputIterator b, InputIterator e, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) :
super_type(comp, alloc)
{
insert(b, e);
}
template<class InputIterator>
btree_set_container(InputIterator b, InputIterator e, const allocator_type& alloc) :
btree_set_container(b, e, key_compare(), alloc)
{
}

// Initializer list constructors.
btree_set_container(std::initializer_list<init_type> init, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) :
btree_set_container(init.begin(), init.end(), comp, alloc)
{
}
btree_set_container(std::initializer_list<init_type> init, const allocator_type& alloc) :
btree_set_container(init.begin(), init.end(), alloc)
{
}

// Insertion routines.
std::pair<iterator, bool> insert(const value_type& v)
{
return this->tree_.insert_unique(params_type::key(v), v);
}
std::pair<iterator, bool> insert(value_type&& v)
{
return this->tree_.insert_unique(params_type::key(v), std::move(v));
}
template<typename... Args>
std::pair<iterator, bool> emplace(Args&&... args)
{
// Use a node handle to manage a temp slot.
auto node = CommonAccess::Construct<node_type>(this->get_allocator(), std::forward<Args>(args)...);
auto* slot = CommonAccess::GetSlot(node);
return this->tree_.insert_unique(params_type::key(slot), slot);
}
iterator insert(const_iterator hint, const value_type& v)
{
return this->tree_
.insert_hint_unique(iterator(hint), params_type::key(v), v)
.first;
}
iterator insert(const_iterator hint, value_type&& v)
{
return this->tree_
.insert_hint_unique(iterator(hint), params_type::key(v), std::move(v))
.first;
}
template<typename... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
// Use a node handle to manage a temp slot.
auto node = CommonAccess::Construct<node_type>(this->get_allocator(), std::forward<Args>(args)...);
auto* slot = CommonAccess::GetSlot(node);
return this->tree_
.insert_hint_unique(iterator(hint), params_type::key(slot), slot)
.first;
}
template<typename InputIterator>
void insert(InputIterator b, InputIterator e)
{
this->tree_.insert_iterator_unique(b, e, 0);
}
void insert(std::initializer_list<init_type> init)
{
this->tree_.insert_iterator_unique(init.begin(), init.end(), 0);
}
insert_return_type insert(node_type&& node)
{
if (!node)
return {this->end(), false, node_type()};
std::pair<iterator, bool> res =
this->tree_.insert_unique(params_type::key(CommonAccess::GetSlot(node)), CommonAccess::GetSlot(node));
if (res.second)
{
CommonAccess::Destroy(&node);
return {res.first, true, node_type()};
}
else
{
return {res.first, false, std::move(node)};
}
}
iterator insert(const_iterator hint, node_type&& node)
{
if (!node)
return this->end();
std::pair<iterator, bool> res = this->tree_.insert_hint_unique(
iterator(hint), params_type::key(CommonAccess::GetSlot(node)), CommonAccess::GetSlot(node)
);
if (res.second)
CommonAccess::Destroy(&node);
return res.first;
}

// Node extraction routines.
template<typename K = key_type>
node_type extract(const key_arg<K>& key)
{
const std::pair<iterator, bool> lower_and_equal =
this->tree_.lower_bound_equal(key);
return lower_and_equal.second ? extract(lower_and_equal.first) : node_type();
}
using super_type::extract;

// Merge routines.
// Moves elements from `src` into `this`. If the element already exists in
// `this`, it is left unmodified in `src`.
template<
typename T,
typename absl::enable_if_t<
absl::conjunction<
std::is_same<value_type, typename T::value_type>,
std::is_same<allocator_type, typename T::allocator_type>,
std::is_same<typename params_type::is_map_container, typename T::params_type::is_map_container>>::value,
int> = 0>
void merge(btree_container<T>& src)
{ // NOLINT
for (auto src_it = src.begin(); src_it != src.end();)
{
if (insert(std::move(params_type::element(src_it.slot()))).second)
{
src_it = src.erase(src_it);
}
else
{
++src_it;
}
}
}

template<
typename T,
typename absl::enable_if_t<
absl::conjunction<
std::is_same<value_type, typename T::value_type>,
std::is_same<allocator_type, typename T::allocator_type>,
std::is_same<typename params_type::is_map_container, typename T::params_type::is_map_container>>::value,
int> = 0>
void merge(btree_container<T>&& src)
{
merge(src);
}
};

// Base class for btree_map.
template<typename Tree>
class btree_map_container : public btree_set_container<Tree>
{
using super_type = btree_set_container<Tree>;
using params_type = typename Tree::params_type;
friend class BtreeNodePeer;

private:
template<class K>
using key_arg = typename super_type::template key_arg<K>;

public:
using key_type = typename Tree::key_type;
using mapped_type = typename params_type::mapped_type;
using value_type = typename Tree::value_type;
using key_compare = typename Tree::original_key_compare;
using allocator_type = typename Tree::allocator_type;
using iterator = typename Tree::iterator;
using const_iterator = typename Tree::const_iterator;

// Inherit constructors.
using super_type::super_type;
btree_map_container()
{
}

// Insertion routines.
// Note: the nullptr template arguments and extra `const M&` overloads allow
// for supporting bitfield arguments.
template<typename K = key_type, class M>
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const M& obj)
{
return insert_or_assign_impl(k, obj);
}
template<typename K = key_type, class M, K* = nullptr>
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const M& obj)
{
return insert_or_assign_impl(std::forward<K>(k), obj);
}
template<typename K = key_type, class M, M* = nullptr>
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, M&& obj)
{
return insert_or_assign_impl(k, std::forward<M>(obj));
}
template<typename K = key_type, class M, K* = nullptr, M* = nullptr>
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, M&& obj)
{
return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
}
template<typename K = key_type, class M>
iterator insert_or_assign(const_iterator hint, const key_arg<K>& k, const M& obj)
{
return insert_or_assign_hint_impl(hint, k, obj);
}
template<typename K = key_type, class M, K* = nullptr>
iterator insert_or_assign(const_iterator hint, key_arg<K>&& k, const M& obj)
{
return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
}
template<typename K = key_type, class M, M* = nullptr>
iterator insert_or_assign(const_iterator hint, const key_arg<K>& k, M&& obj)
{
return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
}
template<typename K = key_type, class M, K* = nullptr, M* = nullptr>
iterator insert_or_assign(const_iterator hint, key_arg<K>&& k, M&& obj)
{
return insert_or_assign_hint_impl(hint, std::forward<K>(k), std::forward<M>(obj));
}

template<typename K = key_type, typename... Args, typename absl::enable_if_t<!std::is_convertible<K, const_iterator>::value, int> = 0>
std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
{
return try_emplace_impl(k, std::forward<Args>(args)...);
}
template<typename K = key_type, typename... Args, typename absl::enable_if_t<!std::is_convertible<K, const_iterator>::value, int> = 0>
std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
{
return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
}
template<typename K = key_type, typename... Args>
iterator try_emplace(const_iterator hint, const key_arg<K>& k, Args&&... args)
{
return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
}
template<typename K = key_type, typename... Args>
iterator try_emplace(const_iterator hint, key_arg<K>&& k, Args&&... args)
{
return try_emplace_hint_impl(hint, std::forward<K>(k), std::forward<Args>(args)...);
}

template<typename K = key_type>
mapped_type& operator[](const key_arg<K>& k)
{
return try_emplace(k).first->second;
}
template<typename K = key_type>
mapped_type& operator[](key_arg<K>&& k)
{
return try_emplace(std::forward<K>(k)).first->second;
}

template<typename K = key_type>
mapped_type& at(const key_arg<K>& key)
{
auto it = this->find(key);
if (it == this->end())
base_internal::ThrowStdOutOfRange("absl::btree_map::at");
return it->second;
}
template<typename K = key_type>
const mapped_type& at(const key_arg<K>& key) const
{
auto it = this->find(key);
if (it == this->end())
base_internal::ThrowStdOutOfRange("absl::btree_map::at");
return it->second;
}

private:
// Note: when we call `std::forward<M>(obj)` twice, it's safe because
// insert_unique/insert_hint_unique are guaranteed to not consume `obj` when
// `ret.second` is false.
template<class K, class M>
std::pair<iterator, bool> insert_or_assign_impl(K&& k, M&& obj)
{
const std::pair<iterator, bool> ret =
this->tree_.insert_unique(k, std::forward<K>(k), std::forward<M>(obj));
if (!ret.second)
ret.first->second = std::forward<M>(obj);
return ret;
}
template<class K, class M>
iterator insert_or_assign_hint_impl(const_iterator hint, K&& k, M&& obj)
{
const std::pair<iterator, bool> ret = this->tree_.insert_hint_unique(
iterator(hint), k, std::forward<K>(k), std::forward<M>(obj)
);
if (!ret.second)
ret.first->second = std::forward<M>(obj);
return ret.first;
}

template<class K, class... Args>
std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args)
{
return this->tree_.insert_unique(
k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), std::forward_as_tuple(std::forward<Args>(args)...)
);
}
template<class K, class... Args>
iterator try_emplace_hint_impl(const_iterator hint, K&& k, Args&&... args)
{
return this->tree_
.insert_hint_unique(iterator(hint), k, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), std::forward_as_tuple(std::forward<Args>(args)...))
.first;
}
};

// A common base class for btree_multiset and btree_multimap.
template<typename Tree>
class btree_multiset_container : public btree_container<Tree>
{
using super_type = btree_container<Tree>;
using params_type = typename Tree::params_type;
using init_type = typename params_type::init_type;
using is_key_compare_to = typename params_type::is_key_compare_to;
friend class BtreeNodePeer;

template<class K>
using key_arg = typename super_type::template key_arg<K>;

public:
using key_type = typename Tree::key_type;
using value_type = typename Tree::value_type;
using size_type = typename Tree::size_type;
using key_compare = typename Tree::original_key_compare;
using allocator_type = typename Tree::allocator_type;
using iterator = typename Tree::iterator;
using const_iterator = typename Tree::const_iterator;
using node_type = typename super_type::node_type;

// Inherit constructors.
using super_type::super_type;
btree_multiset_container()
{
}

// Range constructors.
template<class InputIterator>
btree_multiset_container(InputIterator b, InputIterator e, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) :
super_type(comp, alloc)
{
insert(b, e);
}
template<class InputIterator>
btree_multiset_container(InputIterator b, InputIterator e, const allocator_type& alloc) :
btree_multiset_container(b, e, key_compare(), alloc)
{
}

// Initializer list constructors.
btree_multiset_container(std::initializer_list<init_type> init, const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type()) :
btree_multiset_container(init.begin(), init.end(), comp, alloc)
{
}
btree_multiset_container(std::initializer_list<init_type> init, const allocator_type& alloc) :
btree_multiset_container(init.begin(), init.end(), alloc)
{
}

// Insertion routines.
iterator insert(const value_type& v)
{
return this->tree_.insert_multi(v);
}
iterator insert(value_type&& v)
{
return this->tree_.insert_multi(std::move(v));
}
iterator insert(const_iterator hint, const value_type& v)
{
return this->tree_.insert_hint_multi(iterator(hint), v);
}
iterator insert(const_iterator hint, value_type&& v)
{
return this->tree_.insert_hint_multi(iterator(hint), std::move(v));
}
template<typename InputIterator>
void insert(InputIterator b, InputIterator e)
{
this->tree_.insert_iterator_multi(b, e);
}
void insert(std::initializer_list<init_type> init)
{
this->tree_.insert_iterator_multi(init.begin(), init.end());
}
template<typename... Args>
iterator emplace(Args&&... args)
{
// Use a node handle to manage a temp slot.
auto node = CommonAccess::Construct<node_type>(this->get_allocator(), std::forward<Args>(args)...);
return this->tree_.insert_multi(CommonAccess::GetSlot(node));
}
template<typename... Args>
iterator emplace_hint(const_iterator hint, Args&&... args)
{
// Use a node handle to manage a temp slot.
auto node = CommonAccess::Construct<node_type>(this->get_allocator(), std::forward<Args>(args)...);
return this->tree_.insert_hint_multi(iterator(hint), CommonAccess::GetSlot(node));
}
iterator insert(node_type&& node)
{
if (!node)
return this->end();
iterator res =
this->tree_.insert_multi(params_type::key(CommonAccess::GetSlot(node)), CommonAccess::GetSlot(node));
CommonAccess::Destroy(&node);
return res;
}
iterator insert(const_iterator hint, node_type&& node)
{
if (!node)
return this->end();
iterator res = this->tree_.insert_hint_multi(
iterator(hint),
std::move(params_type::element(CommonAccess::GetSlot(node)))
);
CommonAccess::Destroy(&node);
return res;
}

// Node extraction routines.
template<typename K = key_type>
node_type extract(const key_arg<K>& key)
{
const std::pair<iterator, bool> lower_and_equal =
this->tree_.lower_bound_equal(key);
return lower_and_equal.second ? extract(lower_and_equal.first) : node_type();
}
using super_type::extract;

// Merge routines.
// Moves all elements from `src` into `this`.
template<
typename T,
typename absl::enable_if_t<
absl::conjunction<
std::is_same<value_type, typename T::value_type>,
std::is_same<allocator_type, typename T::allocator_type>,
std::is_same<typename params_type::is_map_container, typename T::params_type::is_map_container>>::value,
int> = 0>
void merge(btree_container<T>& src)
{ // NOLINT
for (auto src_it = src.begin(), end = src.end(); src_it != end; ++src_it)
{
insert(std::move(params_type::element(src_it.slot())));
}
src.clear();
}

template<
typename T,
typename absl::enable_if_t<
absl::conjunction<
std::is_same<value_type, typename T::value_type>,
std::is_same<allocator_type, typename T::allocator_type>,
std::is_same<typename params_type::is_map_container, typename T::params_type::is_map_container>>::value,
int> = 0>
void merge(btree_container<T>&& src)
{
merge(src);
}
};

// A base class for btree_multimap.
template<typename Tree>
class btree_multimap_container : public btree_multiset_container<Tree>
{
using super_type = btree_multiset_container<Tree>;
using params_type = typename Tree::params_type;
friend class BtreeNodePeer;

public:
using mapped_type = typename params_type::mapped_type;

// Inherit constructors.
using super_type::super_type;
btree_multimap_container()
{
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_BTREE_CONTAINER_H_

+ 258
- 0
CAPI/cpp/grpc/include/absl/container/internal/common.h View File

@@ -0,0 +1,258 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_H_
#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_

#include <cassert>
#include <type_traits>

#include "absl/meta/type_traits.h"
#include "absl/types/optional.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class, class = void>
struct IsTransparent : std::false_type
{
};
template<class T>
struct IsTransparent<T, absl::void_t<typename T::is_transparent>> : std::true_type
{
};

template<bool is_transparent>
struct KeyArg
{
// Transparent. Forward `K`.
template<typename K, typename key_type>
using type = K;
};

template<>
struct KeyArg<false>
{
// Not transparent. Always use `key_type`.
template<typename K, typename key_type>
using type = key_type;
};

// The node_handle concept from C++17.
// We specialize node_handle for sets and maps. node_handle_base holds the
// common API of both.
template<typename PolicyTraits, typename Alloc>
class node_handle_base
{
protected:
using slot_type = typename PolicyTraits::slot_type;

public:
using allocator_type = Alloc;

constexpr node_handle_base() = default;
node_handle_base(node_handle_base&& other) noexcept
{
*this = std::move(other);
}
~node_handle_base()
{
destroy();
}
node_handle_base& operator=(node_handle_base&& other) noexcept
{
destroy();
if (!other.empty())
{
alloc_ = other.alloc_;
PolicyTraits::transfer(alloc(), slot(), other.slot());
other.reset();
}
return *this;
}

bool empty() const noexcept
{
return !alloc_;
}
explicit operator bool() const noexcept
{
return !empty();
}
allocator_type get_allocator() const
{
return *alloc_;
}

protected:
friend struct CommonAccess;

struct transfer_tag_t
{
};
node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s) :
alloc_(a)
{
PolicyTraits::transfer(alloc(), slot(), s);
}

struct construct_tag_t
{
};
template<typename... Args>
node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args) :
alloc_(a)
{
PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...);
}

void destroy()
{
if (!empty())
{
PolicyTraits::destroy(alloc(), slot());
reset();
}
}

void reset()
{
assert(alloc_.has_value());
alloc_ = absl::nullopt;
}

slot_type* slot() const
{
assert(!empty());
return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
}
allocator_type* alloc()
{
return std::addressof(*alloc_);
}

private:
absl::optional<allocator_type> alloc_ = {};
alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
};

// For sets.
template<typename Policy, typename PolicyTraits, typename Alloc, typename = void>
class node_handle : public node_handle_base<PolicyTraits, Alloc>
{
using Base = node_handle_base<PolicyTraits, Alloc>;

public:
using value_type = typename PolicyTraits::value_type;

constexpr node_handle()
{
}

value_type& value() const
{
return PolicyTraits::element(this->slot());
}

private:
friend struct CommonAccess;

using Base::Base;
};

// For maps.
template<typename Policy, typename PolicyTraits, typename Alloc>
class node_handle<Policy, PolicyTraits, Alloc, absl::void_t<typename Policy::mapped_type>> : public node_handle_base<PolicyTraits, Alloc>
{
using Base = node_handle_base<PolicyTraits, Alloc>;
using slot_type = typename PolicyTraits::slot_type;

public:
using key_type = typename Policy::key_type;
using mapped_type = typename Policy::mapped_type;

constexpr node_handle()
{
}

// When C++17 is available, we can use std::launder to provide mutable
// access to the key. Otherwise, we provide const access.
auto key() const
-> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>()))
{
return PolicyTraits::mutable_key(this->slot());
}

mapped_type& mapped() const
{
return PolicyTraits::value(&PolicyTraits::element(this->slot()));
}

private:
friend struct CommonAccess;

using Base::Base;
};

// Provide access to non-public node-handle functions.
struct CommonAccess
{
template<typename Node>
static auto GetSlot(const Node& node) -> decltype(node.slot())
{
return node.slot();
}

template<typename Node>
static void Destroy(Node* node)
{
node->destroy();
}

template<typename Node>
static void Reset(Node* node)
{
node->reset();
}

template<typename T, typename... Args>
static T Transfer(Args&&... args)
{
return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
}

template<typename T, typename... Args>
static T Construct(Args&&... args)
{
return T(typename T::construct_tag_t{}, std::forward<Args>(args)...);
}
};

// Implement the insert_return_type<> concept of C++17.
template<class Iterator, class NodeType>
struct InsertReturnType
{
Iterator position;
bool inserted;
NodeType node;
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_

+ 339
- 0
CAPI/cpp/grpc/include/absl/container/internal/compressed_tuple.h View File

@@ -0,0 +1,339 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Helper class to perform the Empty Base Optimization.
// Ts can contain classes and non-classes, empty or not. For the ones that
// are empty classes, we perform the optimization. If all types in Ts are empty
// classes, then CompressedTuple<Ts...> is itself an empty class.
//
// To access the members, use member get<N>() function.
//
// Eg:
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
// t3);
// assert(value.get<0>() == 7);
// T1& t1 = value.get<1>();
// const T2& t2 = value.get<2>();
// ...
//
// https://en.cppreference.com/w/cpp/language/ebo

#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_

#include <initializer_list>
#include <tuple>
#include <type_traits>
#include <utility>

#include "absl/utility/utility.h"

#if defined(_MSC_VER) && !defined(__NVCC__)
// We need to mark these classes with this declspec to ensure that
// CompressedTuple happens.
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
#else
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<typename... Ts>
class CompressedTuple;

namespace internal_compressed_tuple
{

template<typename D, size_t I>
struct Elem;
template<typename... B, size_t I>
struct Elem<CompressedTuple<B...>, I> : std::tuple_element<I, std::tuple<B...>>
{
};
template<typename D, size_t I>
using ElemT = typename Elem<D, I>::type;

// Use the __is_final intrinsic if available. Where it's not available, classes
// declared with the 'final' specifier cannot be used as CompressedTuple
// elements.
// TODO(sbenza): Replace this with std::is_final in C++14.
template<typename T>
constexpr bool IsFinal()
{
#if defined(__clang__) || defined(__GNUC__)
return __is_final(T);
#else
return false;
#endif
}

// We can't use EBCO on other CompressedTuples because that would mean that we
// derive from multiple Storage<> instantiations with the same I parameter,
// and potentially from multiple identical Storage<> instantiations. So anytime
// we use type inheritance rather than encapsulation, we mark
// CompressedTupleImpl, to make this easy to detect.
struct uses_inheritance
{
};

template<typename T>
constexpr bool ShouldUseBase()
{
return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>() &&
!std::is_base_of<uses_inheritance, T>::value;
}

// The storage class provides two specializations:
// - For empty classes, it stores T as a base class.
// - For everything else, it stores T as a member.
template<typename T, size_t I,
#if defined(_MSC_VER)
bool UseBase = ShouldUseBase<typename std::enable_if<true, T>::type>()>
#else
bool UseBase = ShouldUseBase<T>()>
#endif
struct Storage
{
T value;
constexpr Storage() = default;
template<typename V>
explicit constexpr Storage(absl::in_place_t, V&& v) :
value(absl::forward<V>(v))
{
}
constexpr const T& get() const&
{
return value;
}
T& get() &
{
return value;
}
constexpr const T&& get() const&&
{
return absl::move(*this).value;
}
T&& get() &&
{
return std::move(*this).value;
}
};

template<typename T, size_t I>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T
{
constexpr Storage() = default;

template<typename V>
explicit constexpr Storage(absl::in_place_t, V&& v) :
T(absl::forward<V>(v))
{
}

constexpr const T& get() const&
{
return *this;
}
T& get() &
{
return *this;
}
constexpr const T&& get() const&&
{
return absl::move(*this);
}
T&& get() &&
{
return std::move(*this);
}
};

template<typename D, typename I, bool ShouldAnyUseBase>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;

template<typename... Ts, size_t... I, bool ShouldAnyUseBase>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
CompressedTuple<Ts...>,
absl::index_sequence<I...>,
ShouldAnyUseBase>
// We use the dummy identity function through std::integral_constant to
// convince MSVC of accepting and expanding I in that context. Without it
// you would get:
// error C3548: 'I': parameter pack cannot be used in this context
: uses_inheritance, Storage<Ts, std::integral_constant<size_t, I>::value>...
{
constexpr CompressedTupleImpl() = default;
template<typename... Vs>
explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args) :
Storage<Ts, I>(absl::in_place, absl::forward<Vs>(args))...
{
}
friend CompressedTuple<Ts...>;
};

template<typename... Ts, size_t... I>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
CompressedTuple<Ts...>,
absl::index_sequence<I...>,
false>
// We use the dummy identity function as above...
: Storage<Ts, std::integral_constant<size_t, I>::value, false>...
{
constexpr CompressedTupleImpl() = default;
template<typename... Vs>
explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args) :
Storage<Ts, I, false>(absl::in_place, absl::forward<Vs>(args))...
{
}
friend CompressedTuple<Ts...>;
};

std::false_type Or(std::initializer_list<std::false_type>);
std::true_type Or(std::initializer_list<bool>);

// MSVC requires this to be done separately rather than within the declaration
// of CompressedTuple below.
template<typename... Ts>
constexpr bool ShouldAnyUseBase()
{
return decltype(Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){};
}

template<typename T, typename V>
using TupleElementMoveConstructible =
typename std::conditional<std::is_reference<T>::value, std::is_convertible<V, T>, std::is_constructible<T, V&&>>::type;

template<bool SizeMatches, class T, class... Vs>
struct TupleMoveConstructible : std::false_type
{
};

template<class... Ts, class... Vs>
struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...> : std::integral_constant<bool, absl::conjunction<TupleElementMoveConstructible<Ts, Vs&&>...>::value>
{
};

template<typename T>
struct compressed_tuple_size;

template<typename... Es>
struct compressed_tuple_size<CompressedTuple<Es...>> : public std::integral_constant<std::size_t, sizeof...(Es)>
{
};

template<class T, class... Vs>
struct TupleItemsMoveConstructible : std::integral_constant<bool, TupleMoveConstructible<compressed_tuple_size<T>::value == sizeof...(Vs), T, Vs...>::value>
{
};

} // namespace internal_compressed_tuple

// Helper class to perform the Empty Base Class Optimization.
// Ts can contain classes and non-classes, empty or not. For the ones that
// are empty classes, we perform the CompressedTuple. If all types in Ts are
// empty classes, then CompressedTuple<Ts...> is itself an empty class. (This
// does not apply when one or more of those empty classes is itself an empty
// CompressedTuple.)
//
// To access the members, use member .get<N>() function.
//
// Eg:
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
// t3);
// assert(value.get<0>() == 7);
// T1& t1 = value.get<1>();
// const T2& t2 = value.get<2>();
// ...
//
// https://en.cppreference.com/w/cpp/language/ebo
template<typename... Ts>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple : private internal_compressed_tuple::CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>, internal_compressed_tuple::ShouldAnyUseBase<Ts...>()>
{
private:
template<int I>
using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;

template<int I>
using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;

public:
// There seems to be a bug in MSVC dealing in which using '=default' here will
// cause the compiler to ignore the body of other constructors. The work-
// around is to explicitly implement the default constructor.
#if defined(_MSC_VER)
constexpr CompressedTuple() :
CompressedTuple::CompressedTupleImpl()
{
}
#else
constexpr CompressedTuple() = default;
#endif
explicit constexpr CompressedTuple(const Ts&... base) :
CompressedTuple::CompressedTupleImpl(absl::in_place, base...)
{
}

template<typename First, typename... Vs, absl::enable_if_t<absl::conjunction<
// Ensure we are not hiding default copy/move constructors.
absl::negation<std::is_same<void(CompressedTuple), void(absl::decay_t<First>)>>,
internal_compressed_tuple::TupleItemsMoveConstructible<CompressedTuple<Ts...>, First, Vs...>>::value,
bool> = true>
explicit constexpr CompressedTuple(First&& first, Vs&&... base) :
CompressedTuple::CompressedTupleImpl(absl::in_place, absl::forward<First>(first), absl::forward<Vs>(base)...)
{
}

template<int I>
ElemT<I>& get() &
{
return StorageT<I>::get();
}

template<int I>
constexpr const ElemT<I>& get() const&
{
return StorageT<I>::get();
}

template<int I>
ElemT<I>&& get() &&
{
return std::move(*this).StorageT<I>::get();
}

template<int I>
constexpr const ElemT<I>&& get() const&&
{
return absl::move(*this).StorageT<I>::get();
}
};

// Explicit specialization for a zero-element tuple
// (needed to avoid ambiguous overloads for the default constructor).
template<>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<>
{
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC

#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_

+ 499
- 0
CAPI/cpp/grpc/include/absl/container/internal/container_memory.h View File

@@ -0,0 +1,499 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_

#include <cassert>
#include <cstddef>
#include <memory>
#include <new>
#include <tuple>
#include <type_traits>
#include <utility>

#include "absl/base/config.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
#include "absl/utility/utility.h"

#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif

#ifdef ABSL_HAVE_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<size_t Alignment>
struct alignas(Alignment) AlignedType
{
};

// Allocates at least n bytes aligned to the specified alignment.
// Alignment must be a power of 2. It must be positive.
//
// Note that many allocators don't honor alignment requirements above certain
// threshold (usually either alignof(std::max_align_t) or alignof(void*)).
// Allocate() doesn't apply alignment corrections. If the underlying allocator
// returns insufficiently alignment pointer, that's what you are going to get.
template<size_t Alignment, class Alloc>
void* Allocate(Alloc* alloc, size_t n)
{
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
// On macOS, "mem_alloc" is a #define with one argument defined in
// rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
// with the "foo(bar)" syntax.
A my_mem_alloc(*alloc);
void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 && "allocator does not respect alignment");
return p;
}

// The pointer must have been previously obtained by calling
// Allocate<Alignment>(alloc, n).
template<size_t Alignment, class Alloc>
void Deallocate(Alloc* alloc, void* p, size_t n)
{
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
// On macOS, "mem_alloc" is a #define with one argument defined in
// rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
// with the "foo(bar)" syntax.
A my_mem_alloc(*alloc);
AT::deallocate(my_mem_alloc, static_cast<M*>(p), (n + sizeof(M) - 1) / sizeof(M));
}

namespace memory_internal
{

// Constructs T into uninitialized storage pointed by `ptr` using the args
// specified in the tuple.
template<class Alloc, class T, class Tuple, size_t... I>
void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t, absl::index_sequence<I...>)
{
absl::allocator_traits<Alloc>::construct(
*alloc, ptr, std::get<I>(std::forward<Tuple>(t))...
);
}

template<class T, class F>
struct WithConstructedImplF
{
template<class... Args>
decltype(std::declval<F>()(std::declval<T>())) operator()(
Args&&... args
) const
{
return std::forward<F>(f)(T(std::forward<Args>(args)...));
}
F&& f;
};

template<class T, class Tuple, size_t... Is, class F>
decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
Tuple&& t, absl::index_sequence<Is...>, F&& f
)
{
return WithConstructedImplF<T, F>{std::forward<F>(f)}(
std::get<Is>(std::forward<Tuple>(t))...
);
}

template<class T, size_t... Is>
auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...))
{
return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
}

// Returns a tuple of references to the elements of the input tuple. T must be a
// tuple.
template<class T>
auto TupleRef(T&& t) -> decltype(TupleRefImpl(std::forward<T>(t), absl::make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>()))
{
return TupleRefImpl(
std::forward<T>(t),
absl::make_index_sequence<
std::tuple_size<typename std::decay<T>::type>::value>()
);
}

template<class F, class K, class V>
decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct, std::declval<std::tuple<K>>(), std::declval<V>()))
DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p)
{
const auto& key = std::get<0>(p.first);
return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first), std::move(p.second));
}

} // namespace memory_internal

// Constructs T into uninitialized storage pointed by `ptr` using the args
// specified in the tuple.
template<class Alloc, class T, class Tuple>
void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t)
{
memory_internal::ConstructFromTupleImpl(
alloc, ptr, std::forward<Tuple>(t), absl::make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>()
);
}

// Constructs T using the args specified in the tuple and calls F with the
// constructed value.
template<class T, class Tuple, class F>
decltype(std::declval<F>()(std::declval<T>())) WithConstructed(
Tuple&& t, F&& f
)
{
return memory_internal::WithConstructedImpl<T>(
std::forward<Tuple>(t),
absl::make_index_sequence<
std::tuple_size<typename std::decay<Tuple>::type>::value>(),
std::forward<F>(f)
);
}

// Given arguments of an std::pair's consructor, PairArgs() returns a pair of
// tuples with references to the passed arguments. The tuples contain
// constructor arguments for the first and the second elements of the pair.
//
// The following two snippets are equivalent.
//
// 1. std::pair<F, S> p(args...);
//
// 2. auto a = PairArgs(args...);
// std::pair<F, S> p(std::piecewise_construct,
// std::move(a.first), std::move(a.second));
inline std::pair<std::tuple<>, std::tuple<>> PairArgs()
{
return {};
}
template<class F, class S>
std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s)
{
return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)), std::forward_as_tuple(std::forward<S>(s))};
}
template<class F, class S>
std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs(
const std::pair<F, S>& p
)
{
return PairArgs(p.first, p.second);
}
template<class F, class S>
std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p)
{
return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second));
}
template<class F, class S>
auto PairArgs(std::piecewise_construct_t, F&& f, S&& s)
-> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)), memory_internal::TupleRef(std::forward<S>(s))))
{
return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)), memory_internal::TupleRef(std::forward<S>(s)));
}

// A helper function for implementing apply() in map policies.
template<class F, class... Args>
auto DecomposePair(F&& f, Args&&... args)
-> decltype(memory_internal::DecomposePairImpl(
std::forward<F>(f), PairArgs(std::forward<Args>(args)...)
))
{
return memory_internal::DecomposePairImpl(
std::forward<F>(f), PairArgs(std::forward<Args>(args)...)
);
}

// A helper function for implementing apply() in set policies.
template<class F, class Arg>
decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>()))
DecomposeValue(F&& f, Arg&& arg)
{
const auto& key = arg;
return std::forward<F>(f)(key, std::forward<Arg>(arg));
}

// Helper functions for asan and msan.
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s)
{
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(m, s);
#endif
#ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_poison(m, s);
#endif
(void)m;
(void)s;
}

inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s)
{
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(m, s);
#endif
#ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_unpoison(m, s);
#endif
(void)m;
(void)s;
}

template<typename T>
inline void SanitizerPoisonObject(const T* object)
{
SanitizerPoisonMemoryRegion(object, sizeof(T));
}

template<typename T>
inline void SanitizerUnpoisonObject(const T* object)
{
SanitizerUnpoisonMemoryRegion(object, sizeof(T));
}

namespace memory_internal
{

// If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and
// OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and
// offsetof(Pair, second) respectively. Otherwise they are -1.
//
// The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout
// type, which is non-portable.
template<class Pair, class = std::true_type>
struct OffsetOf
{
static constexpr size_t kFirst = static_cast<size_t>(-1);
static constexpr size_t kSecond = static_cast<size_t>(-1);
};

template<class Pair>
struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type>
{
static constexpr size_t kFirst = offsetof(Pair, first);
static constexpr size_t kSecond = offsetof(Pair, second);
};

template<class K, class V>
struct IsLayoutCompatible
{
private:
struct Pair
{
K first;
V second;
};

// Is P layout-compatible with Pair?
template<class P>
static constexpr bool LayoutCompatible()
{
return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) &&
alignof(P) == alignof(Pair) &&
memory_internal::OffsetOf<P>::kFirst ==
memory_internal::OffsetOf<Pair>::kFirst &&
memory_internal::OffsetOf<P>::kSecond ==
memory_internal::OffsetOf<Pair>::kSecond;
}

public:
// Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are,
// then it is safe to store them in a union and read from either.
static constexpr bool value = std::is_standard_layout<K>() &&
std::is_standard_layout<Pair>() &&
memory_internal::OffsetOf<Pair>::kFirst == 0 &&
LayoutCompatible<std::pair<K, V>>() &&
LayoutCompatible<std::pair<const K, V>>();
};

} // namespace memory_internal

// The internal storage type for key-value containers like flat_hash_map.
//
// It is convenient for the value_type of a flat_hash_map<K, V> to be
// pair<const K, V>; the "const K" prevents accidental modification of the key
// when dealing with the reference returned from find() and similar methods.
// However, this creates other problems; we want to be able to emplace(K, V)
// efficiently with move operations, and similarly be able to move a
// pair<K, V> in insert().
//
// The solution is this union, which aliases the const and non-const versions
// of the pair. This also allows flat_hash_map<const K, V> to work, even though
// that has the same efficiency issues with move in emplace() and insert() -
// but people do it anyway.
//
// If kMutableKeys is false, only the value member can be accessed.
//
// If kMutableKeys is true, key can be accessed through all slots while value
// and mutable_value must be accessed only via INITIALIZED slots. Slots are
// created and destroyed via mutable_value so that the key can be moved later.
//
// Accessing one of the union fields while the other is active is safe as
// long as they are layout-compatible, which is guaranteed by the definition of
// kMutableKeys. For C++11, the relevant section of the standard is
// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
template<class K, class V>
union map_slot_type
{
map_slot_type()
{
}
~map_slot_type() = delete;
using value_type = std::pair<const K, V>;
using mutable_value_type =
std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;

value_type value;
mutable_value_type mutable_value;
absl::remove_const_t<K> key;
};

template<class K, class V>
struct map_slot_policy
{
using slot_type = map_slot_type<K, V>;
using value_type = std::pair<const K, V>;
using mutable_value_type = std::pair<K, V>;

private:
static void emplace(slot_type* slot)
{
// The construction of union doesn't do anything at runtime but it allows us
// to access its members without violating aliasing rules.
new (slot) slot_type;
}
// If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
// or the other via slot_type. We are also free to access the key via
// slot_type::key in this case.
using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;

public:
static value_type& element(slot_type* slot)
{
return slot->value;
}
static const value_type& element(const slot_type* slot)
{
return slot->value;
}

// When C++17 is available, we can use std::launder to provide mutable
// access to the key for use in node handle.
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
static K& mutable_key(slot_type* slot)
{
// Still check for kMutableKeys so that we can avoid calling std::launder
// unless necessary because it can interfere with optimizations.
return kMutableKeys::value ? slot->key : *std::launder(const_cast<K*>(std::addressof(slot->value.first)));
}
#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
static const K& mutable_key(slot_type* slot)
{
return key(slot);
}
#endif

static const K& key(const slot_type* slot)
{
return kMutableKeys::value ? slot->key : slot->value.first;
}

template<class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args)
{
emplace(slot);
if (kMutableKeys::value)
{
absl::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value, std::forward<Args>(args)...);
}
else
{
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, std::forward<Args>(args)...);
}
}

// Construct this slot by moving from another slot.
template<class Allocator>
static void construct(Allocator* alloc, slot_type* slot, slot_type* other)
{
emplace(slot);
if (kMutableKeys::value)
{
absl::allocator_traits<Allocator>::construct(
*alloc, &slot->mutable_value, std::move(other->mutable_value)
);
}
else
{
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, std::move(other->value));
}
}

// Construct this slot by copying from another slot.
template<class Allocator>
static void construct(Allocator* alloc, slot_type* slot, const slot_type* other)
{
emplace(slot);
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value, other->value);
}

template<class Allocator>
static void destroy(Allocator* alloc, slot_type* slot)
{
if (kMutableKeys::value)
{
absl::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value);
}
else
{
absl::allocator_traits<Allocator>::destroy(*alloc, &slot->value);
}
}

template<class Allocator>
static void transfer(Allocator* alloc, slot_type* new_slot, slot_type* old_slot)
{
emplace(new_slot);
if (kMutableKeys::value)
{
absl::allocator_traits<Allocator>::construct(
*alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value)
);
}
else
{
absl::allocator_traits<Allocator>::construct(*alloc, &new_slot->value, std::move(old_slot->value));
}
destroy(alloc, old_slot);
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_

+ 144
- 0
CAPI/cpp/grpc/include/absl/container/internal/counting_allocator.h View File

@@ -0,0 +1,144 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_

#include <cstdint>
#include <memory>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// This is a stateful allocator, but the state lives outside of the
// allocator (in whatever test is using the allocator). This is odd
// but helps in tests where the allocator is propagated into nested
// containers - that chain of allocators uses the same state and is
// thus easier to query for aggregate allocation information.
template<typename T>
class CountingAllocator
{
public:
using Allocator = std::allocator<T>;
using AllocatorTraits = std::allocator_traits<Allocator>;
using value_type = typename AllocatorTraits::value_type;
using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename AllocatorTraits::const_pointer;
using size_type = typename AllocatorTraits::size_type;
using difference_type = typename AllocatorTraits::difference_type;

CountingAllocator() = default;
explicit CountingAllocator(int64_t* bytes_used) :
bytes_used_(bytes_used)
{
}
CountingAllocator(int64_t* bytes_used, int64_t* instance_count) :
bytes_used_(bytes_used),
instance_count_(instance_count)
{
}

template<typename U>
CountingAllocator(const CountingAllocator<U>& x) :
bytes_used_(x.bytes_used_),
instance_count_(x.instance_count_)
{
}

pointer allocate(
size_type n,
typename AllocatorTraits::const_void_pointer hint = nullptr
)
{
Allocator allocator;
pointer ptr = AllocatorTraits::allocate(allocator, n, hint);
if (bytes_used_ != nullptr)
{
*bytes_used_ += n * sizeof(T);
}
return ptr;
}

void deallocate(pointer p, size_type n)
{
Allocator allocator;
AllocatorTraits::deallocate(allocator, p, n);
if (bytes_used_ != nullptr)
{
*bytes_used_ -= n * sizeof(T);
}
}

template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{
Allocator allocator;
AllocatorTraits::construct(allocator, p, std::forward<Args>(args)...);
if (instance_count_ != nullptr)
{
*instance_count_ += 1;
}
}

template<typename U>
void destroy(U* p)
{
Allocator allocator;
// Ignore GCC warning bug.
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuse-after-free"
#endif
AllocatorTraits::destroy(allocator, p);
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
#pragma GCC diagnostic pop
#endif
if (instance_count_ != nullptr)
{
*instance_count_ -= 1;
}
}

template<typename U>
class rebind
{
public:
using other = CountingAllocator<U>;
};

friend bool operator==(const CountingAllocator& a, const CountingAllocator& b)
{
return a.bytes_used_ == b.bytes_used_ &&
a.instance_count_ == b.instance_count_;
}

friend bool operator!=(const CountingAllocator& a, const CountingAllocator& b)
{
return !(a == b);
}

int64_t* bytes_used_ = nullptr;
int64_t* instance_count_ = nullptr;
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_

+ 195
- 0
CAPI/cpp/grpc/include/absl/container/internal/hash_function_defaults.h View File

@@ -0,0 +1,195 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Define the default Hash and Eq functions for SwissTable containers.
//
// std::hash<T> and std::equal_to<T> are not appropriate hash and equal
// functions for SwissTable containers. There are two reasons for this.
//
// SwissTable containers are power of 2 sized containers:
//
// This means they use the lower bits of the hash value to find the slot for
// each entry. The typical hash function for integral types is the identity.
// This is a very weak hash function for SwissTable and any power of 2 sized
// hashtable implementation which will lead to excessive collisions. For
// SwissTable we use murmur3 style mixing to reduce collisions to a minimum.
//
// SwissTable containers support heterogeneous lookup:
//
// In order to make heterogeneous lookup work, hash and equal functions must be
// polymorphic. At the same time they have to satisfy the same requirements the
// C++ standard imposes on hash functions and equality operators. That is:
//
// if hash_default_eq<T>(a, b) returns true for any a and b of type T, then
// hash_default_hash<T>(a) must equal hash_default_hash<T>(b)
//
// For SwissTable containers this requirement is relaxed to allow a and b of
// any and possibly different types. Note that like the standard the hash and
// equal functions are still bound to T. This is important because some type U
// can be hashed by/tested for equality differently depending on T. A notable
// example is `const char*`. `const char*` is treated as a c-style string when
// the hash function is hash<std::string> but as a pointer when the hash
// function is hash<void*>.
//
#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_

#include <stdint.h>
#include <cstddef>
#include <memory>
#include <string>
#include <type_traits>

#include "absl/base/config.h"
#include "absl/hash/hash.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// The hash of an object of type T is computed by using absl::Hash.
template<class T, class E = void>
struct HashEq
{
using Hash = absl::Hash<T>;
using Eq = std::equal_to<T>;
};

struct StringHash
{
using is_transparent = void;

size_t operator()(absl::string_view v) const
{
return absl::Hash<absl::string_view>{}(v);
}
size_t operator()(const absl::Cord& v) const
{
return absl::Hash<absl::Cord>{}(v);
}
};

struct StringEq
{
using is_transparent = void;
bool operator()(absl::string_view lhs, absl::string_view rhs) const
{
return lhs == rhs;
}
bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const
{
return lhs == rhs;
}
bool operator()(const absl::Cord& lhs, absl::string_view rhs) const
{
return lhs == rhs;
}
bool operator()(absl::string_view lhs, const absl::Cord& rhs) const
{
return lhs == rhs;
}
};

// Supports heterogeneous lookup for string-like elements.
struct StringHashEq
{
using Hash = StringHash;
using Eq = StringEq;
};

template<>
struct HashEq<std::string> : StringHashEq
{
};
template<>
struct HashEq<absl::string_view> : StringHashEq
{
};
template<>
struct HashEq<absl::Cord> : StringHashEq
{
};

// Supports heterogeneous lookup for pointers and smart pointers.
template<class T>
struct HashEq<T*>
{
struct Hash
{
using is_transparent = void;
template<class U>
size_t operator()(const U& ptr) const
{
return absl::Hash<const T*>{}(HashEq::ToPtr(ptr));
}
};
struct Eq
{
using is_transparent = void;
template<class A, class B>
bool operator()(const A& a, const B& b) const
{
return HashEq::ToPtr(a) == HashEq::ToPtr(b);
}
};

private:
static const T* ToPtr(const T* ptr)
{
return ptr;
}
template<class U, class D>
static const T* ToPtr(const std::unique_ptr<U, D>& ptr)
{
return ptr.get();
}
template<class U>
static const T* ToPtr(const std::shared_ptr<U>& ptr)
{
return ptr.get();
}
};

template<class T, class D>
struct HashEq<std::unique_ptr<T, D>> : HashEq<T*>
{
};
template<class T>
struct HashEq<std::shared_ptr<T>> : HashEq<T*>
{
};

// This header's visibility is restricted. If you need to access the default
// hasher please use the container's ::hasher alias instead.
//
// Example: typename Hash = typename absl::flat_hash_map<K, V>::hasher
template<class T>
using hash_default_hash = typename container_internal::HashEq<T>::Hash;

// This header's visibility is restricted. If you need to access the default
// key equal please use the container's ::key_equal alias instead.
//
// Example: typename Eq = typename absl::flat_hash_map<K, V, Hash>::key_equal
template<class T>
using hash_default_eq = typename container_internal::HashEq<T>::Eq;

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_

+ 209
- 0
CAPI/cpp/grpc/include/absl/container/internal/hash_generator_testing.h View File

@@ -0,0 +1,209 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Generates random values for testing. Specialized only for the few types we
// care about.

#ifndef ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
#define ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_

#include <stdint.h>

#include <algorithm>
#include <cassert>
#include <iosfwd>
#include <random>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

#include "absl/container/internal/hash_policy_testing.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{
namespace hash_internal
{
namespace generator_internal
{

template<class Container, class = void>
struct IsMap : std::false_type
{
};

template<class Map>
struct IsMap<Map, absl::void_t<typename Map::mapped_type>> : std::true_type
{
};

} // namespace generator_internal

std::mt19937_64* GetSharedRng();

enum Enum
{
kEnumEmpty,
kEnumDeleted,
};

enum class EnumClass : uint64_t
{
kEmpty,
kDeleted,
};

inline std::ostream& operator<<(std::ostream& o, const EnumClass& ec)
{
return o << static_cast<uint64_t>(ec);
}

template<class T, class E = void>
struct Generator;

template<class T>
struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
T operator()() const
{
std::uniform_int_distribution<T> dist;
return dist(*GetSharedRng());
}
};

template<>
struct Generator<Enum>
{
Enum operator()() const
{
std::uniform_int_distribution<typename std::underlying_type<Enum>::type>
dist;
while (true)
{
auto variate = dist(*GetSharedRng());
if (variate != kEnumEmpty && variate != kEnumDeleted)
return static_cast<Enum>(variate);
}
}
};

template<>
struct Generator<EnumClass>
{
EnumClass operator()() const
{
std::uniform_int_distribution<
typename std::underlying_type<EnumClass>::type>
dist;
while (true)
{
EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng()));
if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted)
return static_cast<EnumClass>(variate);
}
}
};

template<>
struct Generator<std::string>
{
std::string operator()() const;
};

template<>
struct Generator<absl::string_view>
{
absl::string_view operator()() const;
};

template<>
struct Generator<NonStandardLayout>
{
NonStandardLayout operator()() const
{
return NonStandardLayout(Generator<std::string>()());
}
};

template<class K, class V>
struct Generator<std::pair<K, V>>
{
std::pair<K, V> operator()() const
{
return std::pair<K, V>(Generator<typename std::decay<K>::type>()(), Generator<typename std::decay<V>::type>()());
}
};

template<class... Ts>
struct Generator<std::tuple<Ts...>>
{
std::tuple<Ts...> operator()() const
{
return std::tuple<Ts...>(Generator<typename std::decay<Ts>::type>()()...);
}
};

template<class T>
struct Generator<std::unique_ptr<T>>
{
std::unique_ptr<T> operator()() const
{
return absl::make_unique<T>(Generator<T>()());
}
};

template<class U>
struct Generator<U, absl::void_t<decltype(std::declval<U&>().key()), decltype(std::declval<U&>().value())>> : Generator<std::pair<typename std::decay<decltype(std::declval<U&>().key())>::type, typename std::decay<decltype(std::declval<U&>().value())>::type>>
{
};

template<class Container>
using GeneratedType = decltype(std::declval<const Generator<
typename std::conditional<generator_internal::IsMap<Container>::value, typename Container::value_type, typename Container::key_type>::type>&>()());

// Naive wrapper that performs a linear search of previous values.
// Beware this is O(SQR), which is reasonable for smaller kMaxValues.
template<class T, size_t kMaxValues = 64, class E = void>
struct UniqueGenerator
{
Generator<T, E> gen;
std::vector<T> values;

T operator()()
{
assert(values.size() < kMaxValues);
for (;;)
{
T value = gen();
if (std::find(values.begin(), values.end(), value) == values.end())
{
values.push_back(value);
return value;
}
}
}
};

} // namespace hash_internal
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_

+ 240
- 0
CAPI/cpp/grpc/include/absl/container/internal/hash_policy_testing.h View File

@@ -0,0 +1,240 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Utilities to help tests verify that hash tables properly handle stateful
// allocators and hash functions.

#ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_
#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_

#include <cstdlib>
#include <limits>
#include <memory>
#include <ostream>
#include <type_traits>
#include <utility>
#include <vector>

#include "absl/hash/hash.h"
#include "absl/strings/string_view.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{
namespace hash_testing_internal
{

template<class Derived>
struct WithId
{
WithId() :
id_(next_id<Derived>())
{
}
WithId(const WithId& that) :
id_(that.id_)
{
}
WithId(WithId&& that) :
id_(that.id_)
{
that.id_ = 0;
}
WithId& operator=(const WithId& that)
{
id_ = that.id_;
return *this;
}
WithId& operator=(WithId&& that)
{
id_ = that.id_;
that.id_ = 0;
return *this;
}

size_t id() const
{
return id_;
}

friend bool operator==(const WithId& a, const WithId& b)
{
return a.id_ == b.id_;
}
friend bool operator!=(const WithId& a, const WithId& b)
{
return !(a == b);
}

protected:
explicit WithId(size_t id) :
id_(id)
{
}

private:
size_t id_;

template<class T>
static size_t next_id()
{
// 0 is reserved for moved from state.
static size_t gId = 1;
return gId++;
}
};

} // namespace hash_testing_internal

struct NonStandardLayout
{
NonStandardLayout()
{
}
explicit NonStandardLayout(std::string s) :
value(std::move(s))
{
}
virtual ~NonStandardLayout()
{
}

friend bool operator==(const NonStandardLayout& a, const NonStandardLayout& b)
{
return a.value == b.value;
}
friend bool operator!=(const NonStandardLayout& a, const NonStandardLayout& b)
{
return a.value != b.value;
}

template<typename H>
friend H AbslHashValue(H h, const NonStandardLayout& v)
{
return H::combine(std::move(h), v.value);
}

std::string value;
};

struct StatefulTestingHash : absl::container_internal::hash_testing_internal::WithId<StatefulTestingHash>
{
template<class T>
size_t operator()(const T& t) const
{
return absl::Hash<T>{}(t);
}
};

struct StatefulTestingEqual : absl::container_internal::hash_testing_internal::WithId<StatefulTestingEqual>
{
template<class T, class U>
bool operator()(const T& t, const U& u) const
{
return t == u;
}
};

// It is expected that Alloc() == Alloc() for all allocators so we cannot use
// WithId base. We need to explicitly assign ids.
template<class T = int>
struct Alloc : std::allocator<T>
{
using propagate_on_container_swap = std::true_type;

// Using old paradigm for this to ensure compatibility.
explicit Alloc(size_t id = 0) :
id_(id)
{
}

Alloc(const Alloc&) = default;
Alloc& operator=(const Alloc&) = default;

template<class U>
Alloc(const Alloc<U>& that) :
std::allocator<T>(that),
id_(that.id())
{
}

template<class U>
struct rebind
{
using other = Alloc<U>;
};

size_t id() const
{
return id_;
}

friend bool operator==(const Alloc& a, const Alloc& b)
{
return a.id_ == b.id_;
}
friend bool operator!=(const Alloc& a, const Alloc& b)
{
return !(a == b);
}

private:
size_t id_ = (std::numeric_limits<size_t>::max)();
};

template<class Map>
auto items(const Map& m) -> std::vector<
std::pair<typename Map::key_type, typename Map::mapped_type>>
{
using std::get;
std::vector<std::pair<typename Map::key_type, typename Map::mapped_type>> res;
res.reserve(m.size());
for (const auto& v : m)
res.emplace_back(get<0>(v), get<1>(v));
return res;
}

template<class Set>
auto keys(const Set& s)
-> std::vector<typename std::decay<typename Set::key_type>::type>
{
std::vector<typename std::decay<typename Set::key_type>::type> res;
res.reserve(s.size());
for (const auto& v : s)
res.emplace_back(v);
return res;
}

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

// ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions
// where the unordered containers are missing certain constructors that
// take allocator arguments. This test is defined ad-hoc for the platforms
// we care about (notably Crosstool 17) because libstdcxx's useless
// versioning scheme precludes a more principled solution.
// From GCC-4.9 Changelog: (src: https://gcc.gnu.org/gcc-4.9/changes.html)
// "the unordered associative containers in <unordered_map> and <unordered_set>
// meet the allocator-aware container requirements;"
#if (defined(__GLIBCXX__) && __GLIBCXX__ <= 20140425) || \
(__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9))
#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 0
#else
#define ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS 1
#endif

#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TESTING_H_

+ 226
- 0
CAPI/cpp/grpc/include/absl/container/internal/hash_policy_traits.h View File

@@ -0,0 +1,226 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_

#include <cstddef>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>

#include "absl/meta/type_traits.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// Defines how slots are initialized/destroyed/moved.
template<class Policy, class = void>
struct hash_policy_traits
{
// The type of the keys stored in the hashtable.
using key_type = typename Policy::key_type;

private:
struct ReturnKey
{
// When C++17 is available, we can use std::launder to provide mutable
// access to the key for use in node handle.
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
template<class Key, absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
static key_type& Impl(Key&& k, int)
{
return *std::launder(
const_cast<key_type*>(std::addressof(std::forward<Key>(k)))
);
}
#endif

template<class Key>
static Key Impl(Key&& k, char)
{
return std::forward<Key>(k);
}

// When Key=T&, we forward the lvalue reference.
// When Key=T, we return by value to avoid a dangling reference.
// eg, for string_hash_map.
template<class Key, class... Args>
auto operator()(Key&& k, const Args&...) const
-> decltype(Impl(std::forward<Key>(k), 0))
{
return Impl(std::forward<Key>(k), 0);
}
};

template<class P = Policy, class = void>
struct ConstantIteratorsImpl : std::false_type
{
};

template<class P>
struct ConstantIteratorsImpl<P, absl::void_t<typename P::constant_iterators>> : P::constant_iterators
{
};

public:
// The actual object stored in the hash table.
using slot_type = typename Policy::slot_type;

// The argument type for insertions into the hashtable. This is different
// from value_type for increased performance. See initializer_list constructor
// and insert() member functions for more details.
using init_type = typename Policy::init_type;

using reference = decltype(Policy::element(std::declval<slot_type*>()));
using pointer = typename std::remove_reference<reference>::type*;
using value_type = typename std::remove_reference<reference>::type;

// Policies can set this variable to tell raw_hash_set that all iterators
// should be constant, even `iterator`. This is useful for set-like
// containers.
// Defaults to false if not provided by the policy.
using constant_iterators = ConstantIteratorsImpl<>;

// PRECONDITION: `slot` is UNINITIALIZED
// POSTCONDITION: `slot` is INITIALIZED
template<class Alloc, class... Args>
static void construct(Alloc* alloc, slot_type* slot, Args&&... args)
{
Policy::construct(alloc, slot, std::forward<Args>(args)...);
}

// PRECONDITION: `slot` is INITIALIZED
// POSTCONDITION: `slot` is UNINITIALIZED
template<class Alloc>
static void destroy(Alloc* alloc, slot_type* slot)
{
Policy::destroy(alloc, slot);
}

// Transfers the `old_slot` to `new_slot`. Any memory allocated by the
// allocator inside `old_slot` to `new_slot` can be transferred.
//
// OPTIONAL: defaults to:
//
// clone(new_slot, std::move(*old_slot));
// destroy(old_slot);
//
// PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
// POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
// UNINITIALIZED
template<class Alloc>
static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot)
{
transfer_impl(alloc, new_slot, old_slot, 0);
}

// PRECONDITION: `slot` is INITIALIZED
// POSTCONDITION: `slot` is INITIALIZED
template<class P = Policy>
static auto element(slot_type* slot) -> decltype(P::element(slot))
{
return P::element(slot);
}

// Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`.
//
// If `slot` is nullptr, returns the constant amount of memory owned by any
// full slot or -1 if slots own variable amounts of memory.
//
// PRECONDITION: `slot` is INITIALIZED or nullptr
template<class P = Policy>
static size_t space_used(const slot_type* slot)
{
return P::space_used(slot);
}

// Provides generalized access to the key for elements, both for elements in
// the table and for elements that have not yet been inserted (or even
// constructed). We would like an API that allows us to say: `key(args...)`
// but we cannot do that for all cases, so we use this more general API that
// can be used for many things, including the following:
//
// - Given an element in a table, get its key.
// - Given an element initializer, get its key.
// - Given `emplace()` arguments, get the element key.
//
// Implementations of this must adhere to a very strict technical
// specification around aliasing and consuming arguments:
//
// Let `value_type` be the result type of `element()` without ref- and
// cv-qualifiers. The first argument is a functor, the rest are constructor
// arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where
// `k` is the element key, and `xs...` are the new constructor arguments for
// `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias
// `ts...`. The key won't be touched once `xs...` are used to construct an
// element; `ts...` won't be touched at all, which allows `apply()` to consume
// any rvalues among them.
//
// If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not
// trigger a hard compile error unless it originates from `f`. In other words,
// `Policy::apply()` must be SFINAE-friendly. If `value_type` is not
// constructible from `Ts&&...`, either SFINAE or a hard compile error is OK.
//
// If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`,
// `Policy::apply()` must work. A compile error is not allowed, SFINAE or not.
template<class F, class... Ts, class P = Policy>
static auto apply(F&& f, Ts&&... ts)
-> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...))
{
return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);
}

// Returns the "key" portion of the slot.
// Used for node handle manipulation.
template<class P = Policy>
static auto mutable_key(slot_type* slot)
-> decltype(P::apply(ReturnKey(), element(slot)))
{
return P::apply(ReturnKey(), element(slot));
}

// Returns the "value" (as opposed to the "key") portion of the element. Used
// by maps to implement `operator[]`, `at()` and `insert_or_assign()`.
template<class T, class P = Policy>
static auto value(T* elem) -> decltype(P::value(elem))
{
return P::value(elem);
}

private:
// Use auto -> decltype as an enabler.
template<class Alloc, class P = Policy>
static auto transfer_impl(Alloc* alloc, slot_type* new_slot, slot_type* old_slot, int)
-> decltype((void)P::transfer(alloc, new_slot, old_slot))
{
P::transfer(alloc, new_slot, old_slot);
}
template<class Alloc>
static void transfer_impl(Alloc* alloc, slot_type* new_slot, slot_type* old_slot, char)
{
construct(alloc, new_slot, std::move(element(old_slot)));
destroy(alloc, old_slot);
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_

+ 122
- 0
CAPI/cpp/grpc/include/absl/container/internal/hashtable_debug.h View File

@@ -0,0 +1,122 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// This library provides APIs to debug the probing behavior of hash tables.
//
// In general, the probing behavior is a black box for users and only the
// side effects can be measured in the form of performance differences.
// These APIs give a glimpse on the actual behavior of the probing algorithms in
// these hashtables given a specified hash function and a set of elements.
//
// The probe count distribution can be used to assess the quality of the hash
// function for that particular hash table. Note that a hash function that
// performs well in one hash table implementation does not necessarily performs
// well in a different one.
//
// This library supports std::unordered_{set,map}, dense_hash_{set,map} and
// absl::{flat,node,string}_hash_{set,map}.

#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_

#include <cstddef>
#include <algorithm>
#include <type_traits>
#include <vector>

#include "absl/container/internal/hashtable_debug_hooks.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// Returns the number of probes required to lookup `key`. Returns 0 for a
// search with no collisions. Higher values mean more hash collisions occurred;
// however, the exact meaning of this number varies according to the container
// type.
template<typename C>
size_t GetHashtableDebugNumProbes(
const C& c, const typename C::key_type& key
)
{
return absl::container_internal::hashtable_debug_internal::
HashtableDebugAccess<C>::GetNumProbes(c, key);
}

// Gets a histogram of the number of probes for each elements in the container.
// The sum of all the values in the vector is equal to container.size().
template<typename C>
std::vector<size_t> GetHashtableDebugNumProbesHistogram(const C& container)
{
std::vector<size_t> v;
for (auto it = container.begin(); it != container.end(); ++it)
{
size_t num_probes = GetHashtableDebugNumProbes(
container,
absl::container_internal::hashtable_debug_internal::GetKey<C>(*it, 0)
);
v.resize((std::max)(v.size(), num_probes + 1));
v[num_probes]++;
}
return v;
}

struct HashtableDebugProbeSummary
{
size_t total_elements;
size_t total_num_probes;
double mean;
};

// Gets a summary of the probe count distribution for the elements in the
// container.
template<typename C>
HashtableDebugProbeSummary GetHashtableDebugProbeSummary(const C& container)
{
auto probes = GetHashtableDebugNumProbesHistogram(container);
HashtableDebugProbeSummary summary = {};
for (size_t i = 0; i < probes.size(); ++i)
{
summary.total_elements += probes[i];
summary.total_num_probes += probes[i] * i;
}
summary.mean = 1.0 * summary.total_num_probes / summary.total_elements;
return summary;
}

// Returns the number of bytes requested from the allocator by the container
// and not freed.
template<typename C>
size_t AllocatedByteSize(const C& c)
{
return absl::container_internal::hashtable_debug_internal::
HashtableDebugAccess<C>::AllocatedByteSize(c);
}

// Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type `C`
// and `c.size()` is equal to `num_elements`.
template<typename C>
size_t LowerBoundAllocatedByteSize(size_t num_elements)
{
return absl::container_internal::hashtable_debug_internal::
HashtableDebugAccess<C>::LowerBoundAllocatedByteSize(num_elements);
}

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_

+ 95
- 0
CAPI/cpp/grpc/include/absl/container/internal/hashtable_debug_hooks.h View File

@@ -0,0 +1,95 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Provides the internal API for hashtable_debug.h.

#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_

#include <cstddef>

#include <algorithm>
#include <type_traits>
#include <vector>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{
namespace hashtable_debug_internal
{

// If it is a map, call get<0>().
using std::get;
template<typename T, typename = typename T::mapped_type>
auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair))
{
return get<0>(pair);
}

// If it is not a map, return the value directly.
template<typename T>
const typename T::key_type& GetKey(const typename T::key_type& key, char)
{
return key;
}

// Containers should specialize this to provide debug information for that
// container.
template<class Container, typename Enabler = void>
struct HashtableDebugAccess
{
// Returns the number of probes required to find `key` in `c`. The "number of
// probes" is a concept that can vary by container. Implementations should
// return 0 when `key` was found in the minimum number of operations and
// should increment the result for each non-trivial operation required to find
// `key`.
//
// The default implementation uses the bucket api from the standard and thus
// works for `std::unordered_*` containers.
static size_t GetNumProbes(const Container& c, const typename Container::key_type& key)
{
if (!c.bucket_count())
return {};
size_t num_probes = 0;
size_t bucket = c.bucket(key);
for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes)
{
if (it == e)
return num_probes;
if (c.key_eq()(key, GetKey<Container>(*it, 0)))
return num_probes;
}
}

// Returns the number of bytes requested from the allocator by the container
// and not freed.
//
// static size_t AllocatedByteSize(const Container& c);

// Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type
// `Container` and `c.size()` is equal to `num_elements`.
//
// static size_t LowerBoundAllocatedByteSize(size_t num_elements);
};

} // namespace hashtable_debug_internal
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_

+ 353
- 0
CAPI/cpp/grpc/include/absl/container/internal/hashtablez_sampler.h View File

@@ -0,0 +1,353 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// File: hashtablez_sampler.h
// -----------------------------------------------------------------------------
//
// This header file defines the API for a low level library to sample hashtables
// and collect runtime statistics about them.
//
// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
// store information about a single sample.
//
// `Record*` methods store information into samples.
// `Sample()` and `Unsample()` make use of a single global sampler with
// properties controlled by the flags hashtablez_enabled,
// hashtablez_sample_rate, and hashtablez_max_samples.
//
// WARNING
//
// Using this sampling API may cause sampled Swiss tables to use the global
// allocator (operator `new`) in addition to any custom allocator. If you
// are using a table in an unusual circumstance where allocation or calling a
// linux syscall is unacceptable, this could interfere.
//
// This utility is internal-only. Use at your own risk.

#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_

#include <atomic>
#include <functional>
#include <memory>
#include <vector>

#include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h"
#include "absl/base/optimization.h"
#include "absl/profiling/internal/sample_recorder.h"
#include "absl/synchronization/mutex.h"
#include "absl/utility/utility.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// Stores information about a sampled hashtable. All mutations to this *must*
// be made through `Record*` functions below. All reads from this *must* only
// occur in the callback to `HashtablezSampler::Iterate`.
struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo>
{
// Constructs the object but does not fill in any fields.
HashtablezInfo();
~HashtablezInfo();
HashtablezInfo(const HashtablezInfo&) = delete;
HashtablezInfo& operator=(const HashtablezInfo&) = delete;

// Puts the object into a clean state, fills in the logically `const` members,
// blocking for any readers that are currently sampling the object.
void PrepareForSampling(int64_t stride, size_t inline_element_size_value)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);

// These fields are mutated by the various Record* APIs and need to be
// thread-safe.
std::atomic<size_t> capacity;
std::atomic<size_t> size;
std::atomic<size_t> num_erases;
std::atomic<size_t> num_rehashes;
std::atomic<size_t> max_probe_length;
std::atomic<size_t> total_probe_length;
std::atomic<size_t> hashes_bitwise_or;
std::atomic<size_t> hashes_bitwise_and;
std::atomic<size_t> hashes_bitwise_xor;
std::atomic<size_t> max_reserve;

// All of the fields below are set by `PrepareForSampling`, they must not be
// mutated in `Record*` functions. They are logically `const` in that sense.
// These are guarded by init_mu, but that is not externalized to clients,
// which can read them only during `SampleRecorder::Iterate` which will hold
// the lock.
static constexpr int kMaxStackDepth = 64;
absl::Time create_time;
int32_t depth;
void* stack[kMaxStackDepth];
size_t inline_element_size; // How big is the slot?
};

inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length)
{
#ifdef ABSL_INTERNAL_HAVE_SSE2
total_probe_length /= 16;
#else
total_probe_length /= 8;
#endif
info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
info->num_erases.store(0, std::memory_order_relaxed);
// There is only one concurrent writer, so `load` then `store` is sufficient
// instead of using `fetch_add`.
info->num_rehashes.store(
1 + info->num_rehashes.load(std::memory_order_relaxed),
std::memory_order_relaxed
);
}

inline void RecordReservationSlow(HashtablezInfo* info, size_t target_capacity)
{
info->max_reserve.store(
(std::max)(info->max_reserve.load(std::memory_order_relaxed), target_capacity),
std::memory_order_relaxed
);
}

inline void RecordClearedReservationSlow(HashtablezInfo* info)
{
info->max_reserve.store(0, std::memory_order_relaxed);
}

inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size, size_t capacity)
{
info->size.store(size, std::memory_order_relaxed);
info->capacity.store(capacity, std::memory_order_relaxed);
if (size == 0)
{
// This is a clear, reset the total/num_erases too.
info->total_probe_length.store(0, std::memory_order_relaxed);
info->num_erases.store(0, std::memory_order_relaxed);
}
}

void RecordInsertSlow(HashtablezInfo* info, size_t hash, size_t distance_from_desired);

inline void RecordEraseSlow(HashtablezInfo* info)
{
info->size.fetch_sub(1, std::memory_order_relaxed);
// There is only one concurrent writer, so `load` then `store` is sufficient
// instead of using `fetch_add`.
info->num_erases.store(
1 + info->num_erases.load(std::memory_order_relaxed),
std::memory_order_relaxed
);
}

struct SamplingState
{
int64_t next_sample;
// When we make a sampling decision, we record that distance so we can weight
// each sample.
int64_t sample_stride;
};

HashtablezInfo* SampleSlow(SamplingState& next_sample, size_t inline_element_size);
void UnsampleSlow(HashtablezInfo* info);

#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)

#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
class HashtablezInfoHandle
{
public:
explicit HashtablezInfoHandle() :
info_(nullptr)
{
}
explicit HashtablezInfoHandle(HashtablezInfo* info) :
info_(info)
{
}
~HashtablezInfoHandle()
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
UnsampleSlow(info_);
}

HashtablezInfoHandle(const HashtablezInfoHandle&) = delete;
HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;

HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept
:
info_(absl::exchange(o.info_, nullptr))
{
}
HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept
{
if (ABSL_PREDICT_FALSE(info_ != nullptr))
{
UnsampleSlow(info_);
}
info_ = absl::exchange(o.info_, nullptr);
return *this;
}

inline void RecordStorageChanged(size_t size, size_t capacity)
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordStorageChangedSlow(info_, size, capacity);
}

inline void RecordRehash(size_t total_probe_length)
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordRehashSlow(info_, total_probe_length);
}

inline void RecordReservation(size_t target_capacity)
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordReservationSlow(info_, target_capacity);
}

inline void RecordClearedReservation()
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordClearedReservationSlow(info_);
}

inline void RecordInsert(size_t hash, size_t distance_from_desired)
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordInsertSlow(info_, hash, distance_from_desired);
}

inline void RecordErase()
{
if (ABSL_PREDICT_TRUE(info_ == nullptr))
return;
RecordEraseSlow(info_);
}

friend inline void swap(HashtablezInfoHandle& lhs, HashtablezInfoHandle& rhs)
{
std::swap(lhs.info_, rhs.info_);
}

private:
friend class HashtablezInfoHandlePeer;
HashtablezInfo* info_;
};
#else
// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
// be removed by the linker, in order to reduce the binary size.
class HashtablezInfoHandle
{
public:
explicit HashtablezInfoHandle() = default;
explicit HashtablezInfoHandle(std::nullptr_t)
{
}

inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/)
{
}
inline void RecordRehash(size_t /*total_probe_length*/)
{
}
inline void RecordReservation(size_t /*target_capacity*/)
{
}
inline void RecordClearedReservation()
{
}
inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/)
{
}
inline void RecordErase()
{
}

friend inline void swap(HashtablezInfoHandle& /*lhs*/, HashtablezInfoHandle& /*rhs*/)
{
}
};
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)

#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
extern ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample;
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)

// Returns an RAII sampling handle that manages registration and unregistation
// with the global sampler.
inline HashtablezInfoHandle Sample(
size_t inline_element_size ABSL_ATTRIBUTE_UNUSED
)
{
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
if (ABSL_PREDICT_TRUE(--global_next_sample.next_sample > 0))
{
return HashtablezInfoHandle(nullptr);
}
return HashtablezInfoHandle(
SampleSlow(global_next_sample, inline_element_size)
);
#else
return HashtablezInfoHandle(nullptr);
#endif // !ABSL_PER_THREAD_TLS
}

using HashtablezSampler =
::absl::profiling_internal::SampleRecorder<HashtablezInfo>;

// Returns a global Sampler.
HashtablezSampler& GlobalHashtablezSampler();

using HashtablezConfigListener = void (*)();
void SetHashtablezConfigListener(HashtablezConfigListener l);

// Enables or disables sampling for Swiss tables.
bool IsHashtablezEnabled();
void SetHashtablezEnabled(bool enabled);
void SetHashtablezEnabledInternal(bool enabled);

// Sets the rate at which Swiss tables will be sampled.
int32_t GetHashtablezSampleParameter();
void SetHashtablezSampleParameter(int32_t rate);
void SetHashtablezSampleParameterInternal(int32_t rate);

// Sets a soft max for the number of samples that will be kept.
int32_t GetHashtablezMaxSamples();
void SetHashtablezMaxSamples(int32_t max);
void SetHashtablezMaxSamplesInternal(int32_t max);

// Configuration override.
// This allows process-wide sampling without depending on order of
// initialization of static storage duration objects.
// The definition of this constant is weak, which allows us to inject a
// different value for it at link time.
extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_

+ 1111
- 0
CAPI/cpp/grpc/include/absl/container/internal/inlined_vector.h
File diff suppressed because it is too large
View File


+ 809
- 0
CAPI/cpp/grpc/include/absl/container/internal/layout.h View File

@@ -0,0 +1,809 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// MOTIVATION AND TUTORIAL
//
// If you want to put in a single heap allocation N doubles followed by M ints,
// it's easy if N and M are known at compile time.
//
// struct S {
// double a[N];
// int b[M];
// };
//
// S* p = new S;
//
// But what if N and M are known only in run time? Class template Layout to the
// rescue! It's a portable generalization of the technique known as struct hack.
//
// // This object will tell us everything we need to know about the memory
// // layout of double[N] followed by int[M]. It's structurally identical to
// // size_t[2] that stores N and M. It's very cheap to create.
// const Layout<double, int> layout(N, M);
//
// // Allocate enough memory for both arrays. `AllocSize()` tells us how much
// // memory is needed. We are free to use any allocation function we want as
// // long as it returns aligned memory.
// std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]);
//
// // Obtain the pointer to the array of doubles.
// // Equivalent to `reinterpret_cast<double*>(p.get())`.
// //
// // We could have written layout.Pointer<0>(p) instead. If all the types are
// // unique you can use either form, but if some types are repeated you must
// // use the index form.
// double* a = layout.Pointer<double>(p.get());
//
// // Obtain the pointer to the array of ints.
// // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`.
// int* b = layout.Pointer<int>(p);
//
// If we are unable to specify sizes of all fields, we can pass as many sizes as
// we can to `Partial()`. In return, it'll allow us to access the fields whose
// locations and sizes can be computed from the provided information.
// `Partial()` comes in handy when the array sizes are embedded into the
// allocation.
//
// // size_t[1] containing N, size_t[1] containing M, double[N], int[M].
// using L = Layout<size_t, size_t, double, int>;
//
// unsigned char* Allocate(size_t n, size_t m) {
// const L layout(1, 1, n, m);
// unsigned char* p = new unsigned char[layout.AllocSize()];
// *layout.Pointer<0>(p) = n;
// *layout.Pointer<1>(p) = m;
// return p;
// }
//
// void Use(unsigned char* p) {
// // First, extract N and M.
// // Specify that the first array has only one element. Using `prefix` we
// // can access the first two arrays but not more.
// constexpr auto prefix = L::Partial(1);
// size_t n = *prefix.Pointer<0>(p);
// size_t m = *prefix.Pointer<1>(p);
//
// // Now we can get pointers to the payload.
// const L layout(1, 1, n, m);
// double* a = layout.Pointer<double>(p);
// int* b = layout.Pointer<int>(p);
// }
//
// The layout we used above combines fixed-size with dynamically-sized fields.
// This is quite common. Layout is optimized for this use case and generates
// optimal code. All computations that can be performed at compile time are
// indeed performed at compile time.
//
// Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to
// ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no
// padding in between arrays.
//
// You can manually override the alignment of an array by wrapping the type in
// `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
// and behavior as `Layout<..., T, ...>` except that the first element of the
// array of `T` is aligned to `N` (the rest of the elements follow without
// padding). `N` cannot be less than `alignof(T)`.
//
// `AllocSize()` and `Pointer()` are the most basic methods for dealing with
// memory layouts. Check out the reference or code below to discover more.
//
// EXAMPLE
//
// // Immutable move-only string with sizeof equal to sizeof(void*). The
// // string size and the characters are kept in the same heap allocation.
// class CompactString {
// public:
// CompactString(const char* s = "") {
// const size_t size = strlen(s);
// // size_t[1] followed by char[size + 1].
// const L layout(1, size + 1);
// p_.reset(new unsigned char[layout.AllocSize()]);
// // If running under ASAN, mark the padding bytes, if any, to catch
// // memory errors.
// layout.PoisonPadding(p_.get());
// // Store the size in the allocation.
// *layout.Pointer<size_t>(p_.get()) = size;
// // Store the characters in the allocation.
// memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
// }
//
// size_t size() const {
// // Equivalent to reinterpret_cast<size_t&>(*p).
// return *L::Partial().Pointer<size_t>(p_.get());
// }
//
// const char* c_str() const {
// // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
// // The argument in Partial(1) specifies that we have size_t[1] in front
// // of the characters.
// return L::Partial(1).Pointer<char>(p_.get());
// }
//
// private:
// // Our heap allocation contains a size_t followed by an array of chars.
// using L = Layout<size_t, char>;
// std::unique_ptr<unsigned char[]> p_;
// };
//
// int main() {
// CompactString s = "hello";
// assert(s.size() == 5);
// assert(strcmp(s.c_str(), "hello") == 0);
// }
//
// DOCUMENTATION
//
// The interface exported by this file consists of:
// - class `Layout<>` and its public members.
// - The public members of class `internal_layout::LayoutImpl<>`. That class
// isn't intended to be used directly, and its name and template parameter
// list are internal implementation details, but the class itself provides
// most of the functionality in this file. See comments on its members for
// detailed documentation.
//
// `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a
// `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`
// creates a `Layout` object, which exposes the same functionality by inheriting
// from `LayoutImpl<>`.

#ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
#define ABSL_CONTAINER_INTERNAL_LAYOUT_H_

#include <assert.h>
#include <stddef.h>
#include <stdint.h>

#include <ostream>
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <utility>

#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/str_cat.h"
#include "absl/types/span.h"
#include "absl/utility/utility.h"

#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif

#if defined(__GXX_RTTI)
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE
#endif

#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
#include <cxxabi.h>
#endif

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// A type wrapper that instructs `Layout` to use the specific alignment for the
// array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
// and behavior as `Layout<..., T, ...>` except that the first element of the
// array of `T` is aligned to `N` (the rest of the elements follow without
// padding).
//
// Requires: `N >= alignof(T)` and `N` is a power of 2.
template<class T, size_t N>
struct Aligned;

namespace internal_layout
{

template<class T>
struct NotAligned
{
};

template<class T, size_t N>
struct NotAligned<const Aligned<T, N>>
{
static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
};

template<size_t>
using IntToSize = size_t;

template<class>
using TypeToSize = size_t;

template<class T>
struct Type : NotAligned<T>
{
using type = T;
};

template<class T, size_t N>
struct Type<Aligned<T, N>>
{
using type = T;
};

template<class T>
struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)>
{
};

template<class T, size_t N>
struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)>
{
};

// Note: workaround for https://gcc.gnu.org/PR88115
template<class T>
struct AlignOf : NotAligned<T>
{
static constexpr size_t value = alignof(T);
};

template<class T, size_t N>
struct AlignOf<Aligned<T, N>>
{
static_assert(N % alignof(T) == 0, "Custom alignment can't be lower than the type's alignment");
static constexpr size_t value = N;
};

// Does `Ts...` contain `T`?
template<class T, class... Ts>
using Contains = absl::disjunction<std::is_same<T, Ts>...>;

template<class From, class To>
using CopyConst =
typename std::conditional<std::is_const<From>::value, const To, To>::type;

// Note: We're not qualifying this with absl:: because it doesn't compile under
// MSVC.
template<class T>
using SliceType = Span<T>;

// This namespace contains no types. It prevents functions defined in it from
// being found by ADL.
namespace adl_barrier
{

template<class Needle, class... Ts>
constexpr size_t Find(Needle, Needle, Ts...)
{
static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
return 0;
}

template<class Needle, class T, class... Ts>
constexpr size_t Find(Needle, T, Ts...)
{
return adl_barrier::Find(Needle(), Ts()...) + 1;
}

constexpr bool IsPow2(size_t n)
{
return !(n & (n - 1));
}

// Returns `q * m` for the smallest `q` such that `q * m >= n`.
// Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
constexpr size_t Align(size_t n, size_t m)
{
return (n + m - 1) & ~(m - 1);
}

constexpr size_t Min(size_t a, size_t b)
{
return b < a ? b : a;
}

constexpr size_t Max(size_t a)
{
return a;
}

template<class... Ts>
constexpr size_t Max(size_t a, size_t b, Ts... rest)
{
return adl_barrier::Max(b < a ? a : b, rest...);
}

template<class T>
std::string TypeName()
{
std::string out;
int status = 0;
char* demangled = nullptr;
#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
#endif
if (status == 0 && demangled != nullptr)
{ // Demangling succeeded.
absl::StrAppend(&out, "<", demangled, ">");
free(demangled);
}
else
{
#if defined(__GXX_RTTI) || defined(_CPPRTTI)
absl::StrAppend(&out, "<", typeid(T).name(), ">");
#endif
}
return out;
}

} // namespace adl_barrier

template<bool C>
using EnableIf = typename std::enable_if<C, int>::type;

// Can `T` be a template argument of `Layout`?
template<class T>
using IsLegalElementType = std::integral_constant<
bool,
!std::is_reference<T>::value && !std::is_volatile<T>::value &&
!std::is_reference<typename Type<T>::type>::value &&
!std::is_volatile<typename Type<T>::type>::value &&
adl_barrier::IsPow2(AlignOf<T>::value)>;

template<class Elements, class SizeSeq, class OffsetSeq>
class LayoutImpl;

// Public base class of `Layout` and the result type of `Layout::Partial()`.
//
// `Elements...` contains all template arguments of `Layout` that created this
// instance.
//
// `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments
// passed to `Layout::Partial()` or `Layout::Layout()`.
//
// `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
// `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
// can compute offsets).
template<class... Elements, size_t... SizeSeq, size_t... OffsetSeq>
class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>, absl::index_sequence<OffsetSeq...>>
{
private:
static_assert(sizeof...(Elements) > 0, "At least one field is required");
static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value, "Invalid element type (see IsLegalElementType)");

enum
{
NumTypes = sizeof...(Elements),
NumSizes = sizeof...(SizeSeq),
NumOffsets = sizeof...(OffsetSeq),
};

// These are guaranteed by `Layout`.
static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1), "Internal error");
static_assert(NumTypes > 0, "Internal error");

// Returns the index of `T` in `Elements...`. Results in a compilation error
// if `Elements...` doesn't contain exactly one instance of `T`.
template<class T>
static constexpr size_t ElementIndex()
{
static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(), "Type not found");
return adl_barrier::Find(Type<T>(), Type<typename Type<Elements>::type>()...);
}

template<size_t N>
using ElementAlignment =
AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;

public:
// Element types of all arrays packed in a tuple.
using ElementTypes = std::tuple<typename Type<Elements>::type...>;

// Element type of the Nth array.
template<size_t N>
using ElementType = typename std::tuple_element<N, ElementTypes>::type;

constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes) :
size_{sizes...}
{
}

// Alignment of the layout, equal to the strictest alignment of all elements.
// All pointers passed to the methods of layout must be aligned to this value.
static constexpr size_t Alignment()
{
return adl_barrier::Max(AlignOf<Elements>::value...);
}

// Offset in bytes of the Nth array.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// assert(x.Offset<0>() == 0); // The ints starts from 0.
// assert(x.Offset<1>() == 16); // The doubles starts from 16.
//
// Requires: `N <= NumSizes && N < sizeof...(Ts)`.
template<size_t N, EnableIf<N == 0> = 0>
constexpr size_t Offset() const
{
return 0;
}

template<size_t N, EnableIf<N != 0> = 0>
constexpr size_t Offset() const
{
static_assert(N < NumOffsets, "Index out of bounds");
return adl_barrier::Align(
Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
ElementAlignment<N>::value
);
}

// Offset in bytes of the array with the specified element type. There must
// be exactly one such array and its zero-based index must be at most
// `NumSizes`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// assert(x.Offset<int>() == 0); // The ints starts from 0.
// assert(x.Offset<double>() == 16); // The doubles starts from 16.
template<class T>
constexpr size_t Offset() const
{
return Offset<ElementIndex<T>()>();
}

// Offsets in bytes of all arrays for which the offsets are known.
constexpr std::array<size_t, NumOffsets> Offsets() const
{
return {{Offset<OffsetSeq>()...}};
}

// The number of elements in the Nth array. This is the Nth argument of
// `Layout::Partial()` or `Layout::Layout()` (zero-based).
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// assert(x.Size<0>() == 3);
// assert(x.Size<1>() == 4);
//
// Requires: `N < NumSizes`.
template<size_t N>
constexpr size_t Size() const
{
static_assert(N < NumSizes, "Index out of bounds");
return size_[N];
}

// The number of elements in the array with the specified element type.
// There must be exactly one such array and its zero-based index must be
// at most `NumSizes`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// assert(x.Size<int>() == 3);
// assert(x.Size<double>() == 4);
template<class T>
constexpr size_t Size() const
{
return Size<ElementIndex<T>()>();
}

// The number of elements of all arrays for which they are known.
constexpr std::array<size_t, NumSizes> Sizes() const
{
return {{Size<SizeSeq>()...}};
}

// Pointer to the beginning of the Nth array.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
// int* ints = x.Pointer<0>(p);
// double* doubles = x.Pointer<1>(p);
//
// Requires: `N <= NumSizes && N < sizeof...(Ts)`.
// Requires: `p` is aligned to `Alignment()`.
template<size_t N, class Char>
CopyConst<Char, ElementType<N>>* Pointer(Char* p) const
{
using C = typename std::remove_const<Char>::type;
static_assert(
std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
std::is_same<C, signed char>(),
"The argument must be a pointer to [const] [signed|unsigned] char"
);
constexpr size_t alignment = Alignment();
(void)alignment;
assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
}

// Pointer to the beginning of the array with the specified element type.
// There must be exactly one such array and its zero-based index must be at
// most `NumSizes`.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
// int* ints = x.Pointer<int>(p);
// double* doubles = x.Pointer<double>(p);
//
// Requires: `p` is aligned to `Alignment()`.
template<class T, class Char>
CopyConst<Char, T>* Pointer(Char* p) const
{
return Pointer<ElementIndex<T>()>(p);
}

// Pointers to all arrays for which pointers are known.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
//
// int* ints;
// double* doubles;
// std::tie(ints, doubles) = x.Pointers(p);
//
// Requires: `p` is aligned to `Alignment()`.
//
// Note: We're not using ElementType alias here because it does not compile
// under MSVC.
template<class Char>
std::tuple<CopyConst<
Char,
typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...>
Pointers(Char* p) const
{
return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
Pointer<OffsetSeq>(p)...
);
}

// The Nth array.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
// Span<int> ints = x.Slice<0>(p);
// Span<double> doubles = x.Slice<1>(p);
//
// Requires: `N < NumSizes`.
// Requires: `p` is aligned to `Alignment()`.
template<size_t N, class Char>
SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const
{
return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
}

// The array with the specified element type. There must be exactly one
// such array and its zero-based index must be less than `NumSizes`.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
// Span<int> ints = x.Slice<int>(p);
// Span<double> doubles = x.Slice<double>(p);
//
// Requires: `p` is aligned to `Alignment()`.
template<class T, class Char>
SliceType<CopyConst<Char, T>> Slice(Char* p) const
{
return Slice<ElementIndex<T>()>(p);
}

// All arrays with known sizes.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()];
//
// Span<int> ints;
// Span<double> doubles;
// std::tie(ints, doubles) = x.Slices(p);
//
// Requires: `p` is aligned to `Alignment()`.
//
// Note: We're not using ElementType alias here because it does not compile
// under MSVC.
template<class Char>
std::tuple<SliceType<CopyConst<
Char,
typename std::tuple_element<SizeSeq, ElementTypes>::type>>...>
Slices(Char* p) const
{
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed
// in 6.1).
(void)p;
return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
Slice<SizeSeq>(p)...
);
}

// The size of the allocation that fits all arrays.
//
// // int[3], 4 bytes of padding, double[4].
// Layout<int, double> x(3, 4);
// unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes
//
// Requires: `NumSizes == sizeof...(Ts)`.
constexpr size_t AllocSize() const
{
static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
return Offset<NumTypes - 1>() +
SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
}

// If built with --config=asan, poisons padding bytes (if any) in the
// allocation. The pointer must point to a memory block at least
// `AllocSize()` bytes in length.
//
// `Char` must be `[const] [signed|unsigned] char`.
//
// Requires: `p` is aligned to `Alignment()`.
template<class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
void PoisonPadding(const Char* p) const
{
Pointer<0>(p); // verify the requirements on `Char` and `p`
}

template<class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
void PoisonPadding(const Char* p) const
{
static_assert(N < NumOffsets, "Index out of bounds");
(void)p;
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
PoisonPadding<Char, N - 1>(p);
// The `if` is an optimization. It doesn't affect the observable behaviour.
if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value)
{
size_t start =
Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
}
#endif
}

// Human-readable description of the memory layout. Useful for debugging.
// Slow.
//
// // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
// // by an unknown number of doubles.
// auto x = Layout<char, int, double>::Partial(5, 3);
// assert(x.DebugString() ==
// "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
//
// Each field is in the following format: @offset<type>(sizeof)[size] (<type>
// may be missing depending on the target platform). For example,
// @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
// int is 4 bytes, and we have 3 of those ints. The size of the last field may
// be missing (as in the example above). Only fields with known offsets are
// described. Type names may differ across platforms: one compiler might
// produce "unsigned*" where another produces "unsigned int *".
std::string DebugString() const
{
const auto offsets = Offsets();
const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
const std::string types[] = {
adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
for (size_t i = 0; i != NumOffsets - 1; ++i)
{
absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1], "(", sizes[i + 1], ")");
}
// NumSizes is a constant that may be zero. Some compilers cannot see that
// inside the if statement "size_[NumSizes - 1]" must be valid.
int last = static_cast<int>(NumSizes) - 1;
if (NumTypes == NumSizes && last >= 0)
{
absl::StrAppend(&res, "[", size_[last], "]");
}
return res;
}

private:
// Arguments of `Layout::Partial()` or `Layout::Layout()`.
size_t size_[NumSizes > 0 ? NumSizes : 1];
};

template<size_t NumSizes, class... Ts>
using LayoutType = LayoutImpl<
std::tuple<Ts...>,
absl::make_index_sequence<NumSizes>,
absl::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>;

} // namespace internal_layout

// Descriptor of arrays of various types and sizes laid out in memory one after
// another. See the top of the file for documentation.
//
// Check out the public API of internal_layout::LayoutImpl above. The type is
// internal to the library but its methods are public, and they are inherited
// by `Layout`.
template<class... Ts>
class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...>
{
public:
static_assert(sizeof...(Ts) > 0, "At least one field is required");
static_assert(
absl::conjunction<internal_layout::IsLegalElementType<Ts>...>::value,
"Invalid element type (see IsLegalElementType)"
);

// The result type of `Partial()` with `NumSizes` arguments.
template<size_t NumSizes>
using PartialType = internal_layout::LayoutType<NumSizes, Ts...>;

// `Layout` knows the element types of the arrays we want to lay out in
// memory but not the number of elements in each array.
// `Partial(size1, ..., sizeN)` allows us to specify the latter. The
// resulting immutable object can be used to obtain pointers to the
// individual arrays.
//
// It's allowed to pass fewer array sizes than the number of arrays. E.g.,
// if all you need is to the offset of the second array, you only need to
// pass one argument -- the number of elements in the first array.
//
// // int[3] followed by 4 bytes of padding and an unknown number of
// // doubles.
// auto x = Layout<int, double>::Partial(3);
// // doubles start at byte 16.
// assert(x.Offset<1>() == 16);
//
// If you know the number of elements in all arrays, you can still call
// `Partial()` but it's more convenient to use the constructor of `Layout`.
//
// Layout<int, double> x(3, 5);
//
// Note: The sizes of the arrays must be specified in number of elements,
// not in bytes.
//
// Requires: `sizeof...(Sizes) <= sizeof...(Ts)`.
// Requires: all arguments are convertible to `size_t`.
template<class... Sizes>
static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes)
{
static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");
return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...);
}

// Creates a layout with the sizes of all arrays specified. If you know
// only the sizes of the first N arrays (where N can be zero), you can use
// `Partial()` defined above. The constructor is essentially equivalent to
// calling `Partial()` and passing in all array sizes; the constructor is
// provided as a convenient abbreviation.
//
// Note: The sizes of the arrays must be specified in number of elements,
// not in bytes.
constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes) :
internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...)
{
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_

+ 105
- 0
CAPI/cpp/grpc/include/absl/container/internal/node_slot_policy.h View File

@@ -0,0 +1,105 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapts a policy for nodes.
//
// The node policy should model:
//
// struct Policy {
// // Returns a new node allocated and constructed using the allocator, using
// // the specified arguments.
// template <class Alloc, class... Args>
// value_type* new_element(Alloc* alloc, Args&&... args) const;
//
// // Destroys and deallocates node using the allocator.
// template <class Alloc>
// void delete_element(Alloc* alloc, value_type* node) const;
// };
//
// It may also optionally define `value()` and `apply()`. For documentation on
// these, see hash_policy_traits.h.

#ifndef ABSL_CONTAINER_INTERNAL_NODE_SLOT_POLICY_H_
#define ABSL_CONTAINER_INTERNAL_NODE_SLOT_POLICY_H_

#include <cassert>
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class Reference, class Policy>
struct node_slot_policy
{
static_assert(std::is_lvalue_reference<Reference>::value, "");

using slot_type = typename std::remove_cv<
typename std::remove_reference<Reference>::type>::type*;

template<class Alloc, class... Args>
static void construct(Alloc* alloc, slot_type* slot, Args&&... args)
{
*slot = Policy::new_element(alloc, std::forward<Args>(args)...);
}

template<class Alloc>
static void destroy(Alloc* alloc, slot_type* slot)
{
Policy::delete_element(alloc, *slot);
}

template<class Alloc>
static void transfer(Alloc*, slot_type* new_slot, slot_type* old_slot)
{
*new_slot = *old_slot;
}

static size_t space_used(const slot_type* slot)
{
if (slot == nullptr)
return Policy::element_space_used(nullptr);
return Policy::element_space_used(*slot);
}

static Reference element(slot_type* slot)
{
return **slot;
}

template<class T, class P = Policy>
static auto value(T* elem) -> decltype(P::value(elem))
{
return P::value(elem);
}

template<class... Ts, class P = Policy>
static auto apply(Ts&&... ts) -> decltype(P::apply(std::forward<Ts>(ts)...))
{
return P::apply(std::forward<Ts>(ts)...);
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_NODE_SLOT_POLICY_H_

+ 218
- 0
CAPI/cpp/grpc/include/absl/container/internal/raw_hash_map.h View File

@@ -0,0 +1,218 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
#define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_

#include <tuple>
#include <type_traits>
#include <utility>

#include "absl/base/internal/throw_delegate.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class Policy, class Hash, class Eq, class Alloc>
class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc>
{
// P is Policy. It's passed as a template argument to support maps that have
// incomplete types as values, as in unordered_map<K, IncompleteType>.
// MappedReference<> may be a non-reference type.
template<class P>
using MappedReference = decltype(P::value(
std::addressof(std::declval<typename raw_hash_map::reference>())
));

// MappedConstReference<> may be a non-reference type.
template<class P>
using MappedConstReference = decltype(P::value(
std::addressof(std::declval<typename raw_hash_map::const_reference>())
));

using KeyArgImpl =
KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;

public:
using key_type = typename Policy::key_type;
using mapped_type = typename Policy::mapped_type;
template<class K>
using key_arg = typename KeyArgImpl::template type<K, key_type>;

static_assert(!std::is_reference<key_type>::value, "");

// TODO(b/187807849): Evaluate whether to support reference mapped_type and
// remove this assertion if/when it is supported.
static_assert(!std::is_reference<mapped_type>::value, "");

using iterator = typename raw_hash_map::raw_hash_set::iterator;
using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator;

raw_hash_map()
{
}
using raw_hash_map::raw_hash_set::raw_hash_set;

// The last two template parameters ensure that both arguments are rvalues
// (lvalue arguments are handled by the overloads below). This is necessary
// for supporting bitfield arguments.
//
// union { int n : 1; };
// flat_hash_map<int, int> m;
// m.insert_or_assign(n, n);
template<class K = key_type, class V = mapped_type, K* = nullptr, V* = nullptr>
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v)
{
return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
}

template<class K = key_type, class V = mapped_type, K* = nullptr>
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v)
{
return insert_or_assign_impl(std::forward<K>(k), v);
}

template<class K = key_type, class V = mapped_type, V* = nullptr>
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v)
{
return insert_or_assign_impl(k, std::forward<V>(v));
}

template<class K = key_type, class V = mapped_type>
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v)
{
return insert_or_assign_impl(k, v);
}

template<class K = key_type, class V = mapped_type, K* = nullptr, V* = nullptr>
iterator insert_or_assign(const_iterator, key_arg<K>&& k, V&& v)
{
return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
}

template<class K = key_type, class V = mapped_type, K* = nullptr>
iterator insert_or_assign(const_iterator, key_arg<K>&& k, const V& v)
{
return insert_or_assign(std::forward<K>(k), v).first;
}

template<class K = key_type, class V = mapped_type, V* = nullptr>
iterator insert_or_assign(const_iterator, const key_arg<K>& k, V&& v)
{
return insert_or_assign(k, std::forward<V>(v)).first;
}

template<class K = key_type, class V = mapped_type>
iterator insert_or_assign(const_iterator, const key_arg<K>& k, const V& v)
{
return insert_or_assign(k, v).first;
}

// All `try_emplace()` overloads make the same guarantees regarding rvalue
// arguments as `std::unordered_map::try_emplace()`, namely that these
// functions will not move from rvalue arguments if insertions do not happen.
template<class K = key_type, class... Args, typename std::enable_if<!std::is_convertible<K, const_iterator>::value, int>::type = 0, K* = nullptr>
std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
{
return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
}

template<class K = key_type, class... Args, typename std::enable_if<!std::is_convertible<K, const_iterator>::value, int>::type = 0>
std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
{
return try_emplace_impl(k, std::forward<Args>(args)...);
}

template<class K = key_type, class... Args, K* = nullptr>
iterator try_emplace(const_iterator, key_arg<K>&& k, Args&&... args)
{
return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
}

template<class K = key_type, class... Args>
iterator try_emplace(const_iterator, const key_arg<K>& k, Args&&... args)
{
return try_emplace(k, std::forward<Args>(args)...).first;
}

template<class K = key_type, class P = Policy>
MappedReference<P> at(const key_arg<K>& key)
{
auto it = this->find(key);
if (it == this->end())
{
base_internal::ThrowStdOutOfRange(
"absl::container_internal::raw_hash_map<>::at"
);
}
return Policy::value(&*it);
}

template<class K = key_type, class P = Policy>
MappedConstReference<P> at(const key_arg<K>& key) const
{
auto it = this->find(key);
if (it == this->end())
{
base_internal::ThrowStdOutOfRange(
"absl::container_internal::raw_hash_map<>::at"
);
}
return Policy::value(&*it);
}

template<class K = key_type, class P = Policy, K* = nullptr>
MappedReference<P> operator[](key_arg<K>&& key)
{
return Policy::value(&*try_emplace(std::forward<K>(key)).first);
}

template<class K = key_type, class P = Policy>
MappedReference<P> operator[](const key_arg<K>& key)
{
return Policy::value(&*try_emplace(key).first);
}

private:
template<class K, class V>
std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v)
{
auto res = this->find_or_prepare_insert(k);
if (res.second)
this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
else
Policy::value(&*this->iterator_at(res.first)) = std::forward<V>(v);
return {this->iterator_at(res.first), res.second};
}

template<class K = key_type, class... Args>
std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args)
{
auto res = this->find_or_prepare_insert(k);
if (res.second)
this->emplace_at(res.first, std::piecewise_construct, std::forward_as_tuple(std::forward<K>(k)), std::forward_as_tuple(std::forward<Args>(args)...));
return {this->iterator_at(res.first), res.second};
}
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_

+ 2748
- 0
CAPI/cpp/grpc/include/absl/container/internal/raw_hash_set.h
File diff suppressed because it is too large
View File


+ 340
- 0
CAPI/cpp/grpc/include/absl/container/internal/test_instance_tracker.h View File

@@ -0,0 +1,340 @@
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
#define ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_

#include <cstdlib>
#include <ostream>

#include "absl/types/compare.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace test_internal
{

// A type that counts number of occurrences of the type, the live occurrences of
// the type, as well as the number of copies, moves, swaps, and comparisons that
// have occurred on the type. This is used as a base class for the copyable,
// copyable+movable, and movable types below that are used in actual tests. Use
// InstanceTracker in tests to track the number of instances.
class BaseCountedInstance
{
public:
explicit BaseCountedInstance(int x) :
value_(x)
{
++num_instances_;
++num_live_instances_;
}
BaseCountedInstance(const BaseCountedInstance& x) :
value_(x.value_),
is_live_(x.is_live_)
{
++num_instances_;
if (is_live_)
++num_live_instances_;
++num_copies_;
}
BaseCountedInstance(BaseCountedInstance&& x) :
value_(x.value_),
is_live_(x.is_live_)
{
x.is_live_ = false;
++num_instances_;
++num_moves_;
}
~BaseCountedInstance()
{
--num_instances_;
if (is_live_)
--num_live_instances_;
}

BaseCountedInstance& operator=(const BaseCountedInstance& x)
{
value_ = x.value_;
if (is_live_)
--num_live_instances_;
is_live_ = x.is_live_;
if (is_live_)
++num_live_instances_;
++num_copies_;
return *this;
}
BaseCountedInstance& operator=(BaseCountedInstance&& x)
{
value_ = x.value_;
if (is_live_)
--num_live_instances_;
is_live_ = x.is_live_;
x.is_live_ = false;
++num_moves_;
return *this;
}

bool operator==(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ == x.value_;
}

bool operator!=(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ != x.value_;
}

bool operator<(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ < x.value_;
}

bool operator>(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ > x.value_;
}

bool operator<=(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ <= x.value_;
}

bool operator>=(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ >= x.value_;
}

absl::weak_ordering compare(const BaseCountedInstance& x) const
{
++num_comparisons_;
return value_ < x.value_ ? absl::weak_ordering::less : value_ == x.value_ ? absl::weak_ordering::equivalent :
absl::weak_ordering::greater;
}

int value() const
{
if (!is_live_)
std::abort();
return value_;
}

friend std::ostream& operator<<(std::ostream& o, const BaseCountedInstance& v)
{
return o << "[value:" << v.value() << "]";
}

// Implementation of efficient swap() that counts swaps.
static void SwapImpl(
BaseCountedInstance& lhs, // NOLINT(runtime/references)
BaseCountedInstance& rhs
)
{ // NOLINT(runtime/references)
using std::swap;
swap(lhs.value_, rhs.value_);
swap(lhs.is_live_, rhs.is_live_);
++BaseCountedInstance::num_swaps_;
}

private:
friend class InstanceTracker;

int value_;

// Indicates if the value is live, ie it hasn't been moved away from.
bool is_live_ = true;

// Number of instances.
static int num_instances_;

// Number of live instances (those that have not been moved away from.)
static int num_live_instances_;

// Number of times that BaseCountedInstance objects were moved.
static int num_moves_;

// Number of times that BaseCountedInstance objects were copied.
static int num_copies_;

// Number of times that BaseCountedInstance objects were swapped.
static int num_swaps_;

// Number of times that BaseCountedInstance objects were compared.
static int num_comparisons_;
};

// Helper to track the BaseCountedInstance instance counters. Expects that the
// number of instances and live_instances are the same when it is constructed
// and when it is destructed.
class InstanceTracker
{
public:
InstanceTracker() :
start_instances_(BaseCountedInstance::num_instances_),
start_live_instances_(BaseCountedInstance::num_live_instances_)
{
ResetCopiesMovesSwaps();
}
~InstanceTracker()
{
if (instances() != 0)
std::abort();
if (live_instances() != 0)
std::abort();
}

// Returns the number of BaseCountedInstance instances both containing valid
// values and those moved away from compared to when the InstanceTracker was
// constructed
int instances() const
{
return BaseCountedInstance::num_instances_ - start_instances_;
}

// Returns the number of live BaseCountedInstance instances compared to when
// the InstanceTracker was constructed
int live_instances() const
{
return BaseCountedInstance::num_live_instances_ - start_live_instances_;
}

// Returns the number of moves on BaseCountedInstance objects since
// construction or since the last call to ResetCopiesMovesSwaps().
int moves() const
{
return BaseCountedInstance::num_moves_ - start_moves_;
}

// Returns the number of copies on BaseCountedInstance objects since
// construction or the last call to ResetCopiesMovesSwaps().
int copies() const
{
return BaseCountedInstance::num_copies_ - start_copies_;
}

// Returns the number of swaps on BaseCountedInstance objects since
// construction or the last call to ResetCopiesMovesSwaps().
int swaps() const
{
return BaseCountedInstance::num_swaps_ - start_swaps_;
}

// Returns the number of comparisons on BaseCountedInstance objects since
// construction or the last call to ResetCopiesMovesSwaps().
int comparisons() const
{
return BaseCountedInstance::num_comparisons_ - start_comparisons_;
}

// Resets the base values for moves, copies, comparisons, and swaps to the
// current values, so that subsequent Get*() calls for moves, copies,
// comparisons, and swaps will compare to the situation at the point of this
// call.
void ResetCopiesMovesSwaps()
{
start_moves_ = BaseCountedInstance::num_moves_;
start_copies_ = BaseCountedInstance::num_copies_;
start_swaps_ = BaseCountedInstance::num_swaps_;
start_comparisons_ = BaseCountedInstance::num_comparisons_;
}

private:
int start_instances_;
int start_live_instances_;
int start_moves_;
int start_copies_;
int start_swaps_;
int start_comparisons_;
};

// Copyable, not movable.
class CopyableOnlyInstance : public BaseCountedInstance
{
public:
explicit CopyableOnlyInstance(int x) :
BaseCountedInstance(x)
{
}
CopyableOnlyInstance(const CopyableOnlyInstance& rhs) = default;
CopyableOnlyInstance& operator=(const CopyableOnlyInstance& rhs) = default;

friend void swap(CopyableOnlyInstance& lhs, CopyableOnlyInstance& rhs)
{
BaseCountedInstance::SwapImpl(lhs, rhs);
}

static bool supports_move()
{
return false;
}
};

// Copyable and movable.
class CopyableMovableInstance : public BaseCountedInstance
{
public:
explicit CopyableMovableInstance(int x) :
BaseCountedInstance(x)
{
}
CopyableMovableInstance(const CopyableMovableInstance& rhs) = default;
CopyableMovableInstance(CopyableMovableInstance&& rhs) = default;
CopyableMovableInstance& operator=(const CopyableMovableInstance& rhs) =
default;
CopyableMovableInstance& operator=(CopyableMovableInstance&& rhs) = default;

friend void swap(CopyableMovableInstance& lhs, CopyableMovableInstance& rhs)
{
BaseCountedInstance::SwapImpl(lhs, rhs);
}

static bool supports_move()
{
return true;
}
};

// Only movable, not default-constructible.
class MovableOnlyInstance : public BaseCountedInstance
{
public:
explicit MovableOnlyInstance(int x) :
BaseCountedInstance(x)
{
}
MovableOnlyInstance(MovableOnlyInstance&& other) = default;
MovableOnlyInstance& operator=(MovableOnlyInstance&& other) = default;

friend void swap(MovableOnlyInstance& lhs, MovableOnlyInstance& rhs)
{
BaseCountedInstance::SwapImpl(lhs, rhs);
}

static bool supports_move()
{
return true;
}
};

} // namespace test_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_

+ 106
- 0
CAPI/cpp/grpc/include/absl/container/internal/tracked.h View File

@@ -0,0 +1,106 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_TRACKED_H_
#define ABSL_CONTAINER_INTERNAL_TRACKED_H_

#include <stddef.h>

#include <memory>
#include <utility>

#include "absl/base/config.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

// A class that tracks its copies and moves so that it can be queried in tests.
template<class T>
class Tracked
{
public:
Tracked()
{
}
// NOLINTNEXTLINE(runtime/explicit)
Tracked(const T& val) :
val_(val)
{
}
Tracked(const Tracked& that) :
val_(that.val_),
num_moves_(that.num_moves_),
num_copies_(that.num_copies_)
{
++(*num_copies_);
}
Tracked(Tracked&& that) :
val_(std::move(that.val_)),
num_moves_(std::move(that.num_moves_)),
num_copies_(std::move(that.num_copies_))
{
++(*num_moves_);
}
Tracked& operator=(const Tracked& that)
{
val_ = that.val_;
num_moves_ = that.num_moves_;
num_copies_ = that.num_copies_;
++(*num_copies_);
}
Tracked& operator=(Tracked&& that)
{
val_ = std::move(that.val_);
num_moves_ = std::move(that.num_moves_);
num_copies_ = std::move(that.num_copies_);
++(*num_moves_);
}

const T& val() const
{
return val_;
}

friend bool operator==(const Tracked& a, const Tracked& b)
{
return a.val_ == b.val_;
}
friend bool operator!=(const Tracked& a, const Tracked& b)
{
return !(a == b);
}

size_t num_copies()
{
return *num_copies_;
}
size_t num_moves()
{
return *num_moves_;
}

private:
T val_;
std::shared_ptr<size_t> num_moves_ = std::make_shared<size_t>(0);
std::shared_ptr<size_t> num_copies_ = std::make_shared<size_t>(0);
};

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_TRACKED_H_

+ 546
- 0
CAPI/cpp/grpc/include/absl/container/internal/unordered_map_constructor_test.h View File

@@ -0,0 +1,546 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_

#include <algorithm>
#include <unordered_map>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class UnordMap>
class ConstructorTest : public ::testing::Test
{
};

TYPED_TEST_SUITE_P(ConstructorTest);

TYPED_TEST_P(ConstructorTest, NoArgs)
{
TypeParam m;
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
}

TYPED_TEST_P(ConstructorTest, BucketCount)
{
TypeParam m(123);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHash)
{
using H = typename TypeParam::hasher;
H hasher;
TypeParam m(123, hasher);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashEqual)
{
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
H hasher;
E equal;
TypeParam m(123, hasher, equal);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc)
{
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

template<typename T>
struct is_std_unordered_map : std::false_type
{
};

template<typename... T>
struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type
{
};

#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
using has_cxx14_std_apis = std::true_type;
#else
using has_cxx14_std_apis = std::false_type;
#endif

template<typename T>
using expect_cxx14_apis =
absl::disjunction<absl::negation<is_std_unordered_map<T>>, has_cxx14_std_apis>;

template<typename TypeParam>
void BucketCountAllocTest(std::false_type)
{
}

template<typename TypeParam>
void BucketCountAllocTest(std::true_type)
{
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountAlloc)
{
BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void BucketCountHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void BucketCountHashAllocTest(std::true_type)
{
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
TypeParam m(123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc)
{
BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
using has_alloc_std_constructors = std::true_type;
#else
using has_alloc_std_constructors = std::false_type;
#endif

template<typename T>
using expect_alloc_constructors =
absl::disjunction<absl::negation<is_std_unordered_map<T>>, has_alloc_std_constructors>;

template<typename TypeParam>
void AllocTest(std::false_type)
{
}

template<typename TypeParam>
void AllocTest(std::true_type)
{
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
}

TYPED_TEST_P(ConstructorTest, Alloc)
{
AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::UniqueGenerator<T>());
TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

template<typename TypeParam>
void InputIteratorBucketAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InputIteratorBucketAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::UniqueGenerator<T>());
TypeParam m(values.begin(), values.end(), 123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc)
{
InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void InputIteratorBucketHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InputIteratorBucketHashAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::UniqueGenerator<T>());
TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc)
{
InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, CopyConstructor)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(gen());
TypeParam n(m);
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

template<typename TypeParam>
void CopyConstructorAllocTest(std::false_type)
{
}

template<typename TypeParam>
void CopyConstructorAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(gen());
TypeParam n(m, A(11));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc)
{
CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

// TODO(alkis): Test non-propagating allocators on copy constructors.

TYPED_TEST_P(ConstructorTest, MoveConstructor)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(gen());
TypeParam t(m);
TypeParam n(std::move(t));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

template<typename TypeParam>
void MoveConstructorAllocTest(std::false_type)
{
}

template<typename TypeParam>
void MoveConstructorAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(gen());
TypeParam t(m);
TypeParam n(std::move(t), A(1));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc)
{
MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

// TODO(alkis): Test non-propagating allocators on move constructors.

TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(values, 123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

template<typename TypeParam>
void InitializerListBucketAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InitializerListBucketAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
A alloc(0);
TypeParam m(values, 123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc)
{
InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void InitializerListBucketHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InitializerListBucketHashAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m(values, 123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc)
{
InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, Assignment)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
TypeParam n;
n = m;
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m, n);
}

// TODO(alkis): Test [non-]propagating allocators on move/copy assignments
// (it depends on traits).

TYPED_TEST_P(ConstructorTest, MoveAssignment)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::UniqueGenerator<T> gen;
TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
TypeParam t(m);
TypeParam n;
n = std::move(t);
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m;
m = values;
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
}

TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
TypeParam m({gen(), gen(), gen()});
TypeParam n({gen()});
n = m;
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
TypeParam m({gen(), gen(), gen()});
TypeParam t(m);
TypeParam n({gen()});
n = std::move(t);
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m;
m = values;
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
}

TYPED_TEST_P(ConstructorTest, AssignmentOnSelf)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::UniqueGenerator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m(values);
m = *&m; // Avoid -Wself-assign
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
}

// We cannot test self move as standard states that it leaves standard
// containers in unspecified state (and in practice in causes memory-leak
// according to heap-checker!).

REGISTER_TYPED_TEST_SUITE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual, BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc, MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc, InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment, MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting, AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf
);

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_

+ 125
- 0
CAPI/cpp/grpc/include/absl/container/internal/unordered_map_lookup_test.h View File

@@ -0,0 +1,125 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_
#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class UnordMap>
class LookupTest : public ::testing::Test
{
};

TYPED_TEST_SUITE_P(LookupTest);

TYPED_TEST_P(LookupTest, At)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m(values.begin(), values.end());
for (const auto& p : values)
{
const auto& val = m.at(p.first);
EXPECT_EQ(p.second, val) << ::testing::PrintToString(p.first);
}
}

TYPED_TEST_P(LookupTest, OperatorBracket)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m;
for (const auto& p : values)
{
auto& val = m[p.first];
EXPECT_EQ(V(), val) << ::testing::PrintToString(p.first);
val = p.second;
}
for (const auto& p : values)
EXPECT_EQ(p.second, m[p.first]) << ::testing::PrintToString(p.first);
}

TYPED_TEST_P(LookupTest, Count)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m;
for (const auto& p : values)
EXPECT_EQ(0, m.count(p.first)) << ::testing::PrintToString(p.first);
m.insert(values.begin(), values.end());
for (const auto& p : values)
EXPECT_EQ(1, m.count(p.first)) << ::testing::PrintToString(p.first);
}

TYPED_TEST_P(LookupTest, Find)
{
using std::get;
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m;
for (const auto& p : values)
EXPECT_TRUE(m.end() == m.find(p.first))
<< ::testing::PrintToString(p.first);
m.insert(values.begin(), values.end());
for (const auto& p : values)
{
auto it = m.find(p.first);
EXPECT_TRUE(m.end() != it) << ::testing::PrintToString(p.first);
EXPECT_EQ(p.second, get<1>(*it)) << ::testing::PrintToString(p.first);
}
}

TYPED_TEST_P(LookupTest, EqualRange)
{
using std::get;
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m;
for (const auto& p : values)
{
auto r = m.equal_range(p.first);
ASSERT_EQ(0, std::distance(r.first, r.second));
}
m.insert(values.begin(), values.end());
for (const auto& p : values)
{
auto r = m.equal_range(p.first);
ASSERT_EQ(1, std::distance(r.first, r.second));
EXPECT_EQ(p.second, get<1>(*r.first)) << ::testing::PrintToString(p.first);
}
}

REGISTER_TYPED_TEST_SUITE_P(LookupTest, At, OperatorBracket, Count, Find, EqualRange);

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_

+ 90
- 0
CAPI/cpp/grpc/include/absl/container/internal/unordered_map_members_test.h View File

@@ -0,0 +1,90 @@
// Copyright 2019 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_

#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/meta/type_traits.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class UnordMap>
class MembersTest : public ::testing::Test
{
};

TYPED_TEST_SUITE_P(MembersTest);

template<typename T>
void UseType()
{
}

TYPED_TEST_P(MembersTest, Typedefs)
{
EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type, typename TypeParam::mapped_type>, typename TypeParam::value_type>()));
EXPECT_TRUE((absl::conjunction<
absl::negation<std::is_signed<typename TypeParam::size_type>>,
std::is_integral<typename TypeParam::size_type>>()));
EXPECT_TRUE((absl::conjunction<
std::is_signed<typename TypeParam::difference_type>,
std::is_integral<typename TypeParam::difference_type>>()));
EXPECT_TRUE((std::is_convertible<
decltype(std::declval<const typename TypeParam::hasher&>()(
std::declval<const typename TypeParam::key_type&>()
)),
size_t>()));
EXPECT_TRUE((std::is_convertible<
decltype(std::declval<const typename TypeParam::key_equal&>()(
std::declval<const typename TypeParam::key_type&>(),
std::declval<const typename TypeParam::key_type&>()
)),
bool>()));
EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type, typename TypeParam::value_type>()));
EXPECT_TRUE((std::is_same<typename TypeParam::value_type&, typename TypeParam::reference>()));
EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&, typename TypeParam::const_reference>()));
EXPECT_TRUE((std::is_same<typename std::allocator_traits<typename TypeParam::allocator_type>::pointer, typename TypeParam::pointer>()));
EXPECT_TRUE(
(std::is_same<typename std::allocator_traits<typename TypeParam::allocator_type>::const_pointer, typename TypeParam::const_pointer>())
);
}

TYPED_TEST_P(MembersTest, SimpleFunctions)
{
EXPECT_GT(TypeParam().max_size(), 0);
}

TYPED_TEST_P(MembersTest, BeginEnd)
{
TypeParam t = {typename TypeParam::value_type{}};
EXPECT_EQ(t.begin(), t.cbegin());
EXPECT_EQ(t.end(), t.cend());
EXPECT_NE(t.begin(), t.end());
EXPECT_NE(t.cbegin(), t.cend());
}

REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_

+ 370
- 0
CAPI/cpp/grpc/include/absl/container/internal/unordered_map_modifiers_test.h View File

@@ -0,0 +1,370 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_

#include <memory>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class UnordMap>
class ModifiersTest : public ::testing::Test
{
};

TYPED_TEST_SUITE_P(ModifiersTest);

TYPED_TEST_P(ModifiersTest, Clear)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m(values.begin(), values.end());
ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
m.clear();
EXPECT_THAT(items(m), ::testing::UnorderedElementsAre());
EXPECT_TRUE(m.empty());
}

TYPED_TEST_P(ModifiersTest, Insert)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
auto p = m.insert(val);
EXPECT_TRUE(p.second);
EXPECT_EQ(val, *p.first);
T val2 = {val.first, hash_internal::Generator<V>()()};
p = m.insert(val2);
EXPECT_FALSE(p.second);
EXPECT_EQ(val, *p.first);
}

TYPED_TEST_P(ModifiersTest, InsertHint)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
auto it = m.insert(m.end(), val);
EXPECT_TRUE(it != m.end());
EXPECT_EQ(val, *it);
T val2 = {val.first, hash_internal::Generator<V>()()};
it = m.insert(it, val2);
EXPECT_TRUE(it != m.end());
EXPECT_EQ(val, *it);
}

TYPED_TEST_P(ModifiersTest, InsertRange)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m;
m.insert(values.begin(), values.end());
ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
}

TYPED_TEST_P(ModifiersTest, InsertWithinCapacity)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
m.reserve(10);
const size_t original_capacity = m.bucket_count();
m.insert(val);
EXPECT_EQ(m.bucket_count(), original_capacity);
T val2 = {val.first, hash_internal::Generator<V>()()};
m.insert(val2);
EXPECT_EQ(m.bucket_count(), original_capacity);
}

TYPED_TEST_P(ModifiersTest, InsertRangeWithinCapacity)
{
#if !defined(__GLIBCXX__)
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> base_values;
std::generate_n(std::back_inserter(base_values), 10, hash_internal::Generator<T>());
std::vector<T> values;
while (values.size() != 100)
{
std::copy_n(base_values.begin(), 10, std::back_inserter(values));
}
TypeParam m;
m.reserve(10);
const size_t original_capacity = m.bucket_count();
m.insert(values.begin(), values.end());
EXPECT_EQ(m.bucket_count(), original_capacity);
#endif
}

TYPED_TEST_P(ModifiersTest, InsertOrAssign)
{
#ifdef UNORDERED_MAP_CXX17
using std::get;
using K = typename TypeParam::key_type;
using V = typename TypeParam::mapped_type;
K k = hash_internal::Generator<K>()();
V val = hash_internal::Generator<V>()();
TypeParam m;
auto p = m.insert_or_assign(k, val);
EXPECT_TRUE(p.second);
EXPECT_EQ(k, get<0>(*p.first));
EXPECT_EQ(val, get<1>(*p.first));
V val2 = hash_internal::Generator<V>()();
p = m.insert_or_assign(k, val2);
EXPECT_FALSE(p.second);
EXPECT_EQ(k, get<0>(*p.first));
EXPECT_EQ(val2, get<1>(*p.first));
#endif
}

TYPED_TEST_P(ModifiersTest, InsertOrAssignHint)
{
#ifdef UNORDERED_MAP_CXX17
using std::get;
using K = typename TypeParam::key_type;
using V = typename TypeParam::mapped_type;
K k = hash_internal::Generator<K>()();
V val = hash_internal::Generator<V>()();
TypeParam m;
auto it = m.insert_or_assign(m.end(), k, val);
EXPECT_TRUE(it != m.end());
EXPECT_EQ(k, get<0>(*it));
EXPECT_EQ(val, get<1>(*it));
V val2 = hash_internal::Generator<V>()();
it = m.insert_or_assign(it, k, val2);
EXPECT_EQ(k, get<0>(*it));
EXPECT_EQ(val2, get<1>(*it));
#endif
}

TYPED_TEST_P(ModifiersTest, Emplace)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
// TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
// with test traits/policy.
auto p = m.emplace(val);
EXPECT_TRUE(p.second);
EXPECT_EQ(val, *p.first);
T val2 = {val.first, hash_internal::Generator<V>()()};
p = m.emplace(val2);
EXPECT_FALSE(p.second);
EXPECT_EQ(val, *p.first);
}

TYPED_TEST_P(ModifiersTest, EmplaceHint)
{
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
// TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
// with test traits/policy.
auto it = m.emplace_hint(m.end(), val);
EXPECT_EQ(val, *it);
T val2 = {val.first, hash_internal::Generator<V>()()};
it = m.emplace_hint(it, val2);
EXPECT_EQ(val, *it);
}

TYPED_TEST_P(ModifiersTest, TryEmplace)
{
#ifdef UNORDERED_MAP_CXX17
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
// TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
// with test traits/policy.
auto p = m.try_emplace(val.first, val.second);
EXPECT_TRUE(p.second);
EXPECT_EQ(val, *p.first);
T val2 = {val.first, hash_internal::Generator<V>()()};
p = m.try_emplace(val2.first, val2.second);
EXPECT_FALSE(p.second);
EXPECT_EQ(val, *p.first);
#endif
}

TYPED_TEST_P(ModifiersTest, TryEmplaceHint)
{
#ifdef UNORDERED_MAP_CXX17
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
// TODO(alkis): We need a way to run emplace in a more meaningful way. Perhaps
// with test traits/policy.
auto it = m.try_emplace(m.end(), val.first, val.second);
EXPECT_EQ(val, *it);
T val2 = {val.first, hash_internal::Generator<V>()()};
it = m.try_emplace(it, val2.first, val2.second);
EXPECT_EQ(val, *it);
#endif
}

template<class V>
using IfNotVoid = typename std::enable_if<!std::is_void<V>::value, V>::type;

// In openmap we chose not to return the iterator from erase because that's
// more expensive. As such we adapt erase to return an iterator here.
struct EraseFirst
{
template<class Map>
auto operator()(Map* m, int) const
-> IfNotVoid<decltype(m->erase(m->begin()))>
{
return m->erase(m->begin());
}
template<class Map>
typename Map::iterator operator()(Map* m, ...) const
{
auto it = m->begin();
m->erase(it++);
return it;
}
};

TYPED_TEST_P(ModifiersTest, Erase)
{
using T = hash_internal::GeneratedType<TypeParam>;
using std::get;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m(values.begin(), values.end());
ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
auto& first = *m.begin();
std::vector<T> values2;
for (const auto& val : values)
if (get<0>(val) != get<0>(first))
values2.push_back(val);
auto it = EraseFirst()(&m, 0);
ASSERT_TRUE(it != m.end());
EXPECT_EQ(1, std::count(values2.begin(), values2.end(), *it));
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values2.begin(), values2.end()));
}

TYPED_TEST_P(ModifiersTest, EraseRange)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m(values.begin(), values.end());
ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
auto it = m.erase(m.begin(), m.end());
EXPECT_THAT(items(m), ::testing::UnorderedElementsAre());
EXPECT_TRUE(it == m.end());
}

TYPED_TEST_P(ModifiersTest, EraseKey)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> values;
std::generate_n(std::back_inserter(values), 10, hash_internal::Generator<T>());
TypeParam m(values.begin(), values.end());
ASSERT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_EQ(1, m.erase(values[0].first));
EXPECT_EQ(0, std::count(m.begin(), m.end(), values[0]));
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values.begin() + 1, values.end()));
}

TYPED_TEST_P(ModifiersTest, Swap)
{
using T = hash_internal::GeneratedType<TypeParam>;
std::vector<T> v1;
std::vector<T> v2;
std::generate_n(std::back_inserter(v1), 5, hash_internal::Generator<T>());
std::generate_n(std::back_inserter(v2), 5, hash_internal::Generator<T>());
TypeParam m1(v1.begin(), v1.end());
TypeParam m2(v2.begin(), v2.end());
EXPECT_THAT(items(m1), ::testing::UnorderedElementsAreArray(v1));
EXPECT_THAT(items(m2), ::testing::UnorderedElementsAreArray(v2));
m1.swap(m2);
EXPECT_THAT(items(m1), ::testing::UnorderedElementsAreArray(v2));
EXPECT_THAT(items(m2), ::testing::UnorderedElementsAreArray(v1));
}

// TODO(alkis): Write tests for extract.
// TODO(alkis): Write tests for merge.

REGISTER_TYPED_TEST_SUITE_P(ModifiersTest, Clear, Insert, InsertHint, InsertRange, InsertWithinCapacity, InsertRangeWithinCapacity, InsertOrAssign, InsertOrAssignHint, Emplace, EmplaceHint, TryEmplace, TryEmplaceHint, Erase, EraseRange, EraseKey, Swap);

template<typename Type>
struct is_unique_ptr : std::false_type
{
};

template<typename Type>
struct is_unique_ptr<std::unique_ptr<Type>> : std::true_type
{
};

template<class UnordMap>
class UniquePtrModifiersTest : public ::testing::Test
{
protected:
UniquePtrModifiersTest()
{
static_assert(is_unique_ptr<typename UnordMap::mapped_type>::value, "UniquePtrModifiersTyest may only be called with a "
"std::unique_ptr value type.");
}
};

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UniquePtrModifiersTest);

TYPED_TEST_SUITE_P(UniquePtrModifiersTest);

// Test that we do not move from rvalue arguments if an insertion does not
// happen.
TYPED_TEST_P(UniquePtrModifiersTest, TryEmplace)
{
#ifdef UNORDERED_MAP_CXX17
using T = hash_internal::GeneratedType<TypeParam>;
using V = typename TypeParam::mapped_type;
T val = hash_internal::Generator<T>()();
TypeParam m;
auto p = m.try_emplace(val.first, std::move(val.second));
EXPECT_TRUE(p.second);
// A moved from std::unique_ptr is guaranteed to be nullptr.
EXPECT_EQ(val.second, nullptr);
T val2 = {val.first, hash_internal::Generator<V>()()};
p = m.try_emplace(val2.first, std::move(val2.second));
EXPECT_FALSE(p.second);
EXPECT_NE(val2.second, nullptr);
#endif
}

REGISTER_TYPED_TEST_SUITE_P(UniquePtrModifiersTest, TryEmplace);

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_

+ 551
- 0
CAPI/cpp/grpc/include/absl/container/internal/unordered_set_constructor_test.h View File

@@ -0,0 +1,551 @@
// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_

#include <algorithm>
#include <unordered_set>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"
#include "absl/meta/type_traits.h"

namespace absl
{
ABSL_NAMESPACE_BEGIN
namespace container_internal
{

template<class UnordMap>
class ConstructorTest : public ::testing::Test
{
};

TYPED_TEST_SUITE_P(ConstructorTest);

TYPED_TEST_P(ConstructorTest, NoArgs)
{
TypeParam m;
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
}

TYPED_TEST_P(ConstructorTest, BucketCount)
{
TypeParam m(123);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHash)
{
using H = typename TypeParam::hasher;
H hasher;
TypeParam m(123, hasher);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashEqual)
{
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
H hasher;
E equal;
TypeParam m(123, hasher, equal);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc)
{
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);

const auto& cm = m;
EXPECT_EQ(cm.hash_function(), hasher);
EXPECT_EQ(cm.key_eq(), equal);
EXPECT_EQ(cm.get_allocator(), alloc);
EXPECT_TRUE(cm.empty());
EXPECT_THAT(keys(cm), ::testing::UnorderedElementsAre());
EXPECT_GE(cm.bucket_count(), 123);
}

template<typename T>
struct is_std_unordered_set : std::false_type
{
};

template<typename... T>
struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type
{
};

#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
using has_cxx14_std_apis = std::true_type;
#else
using has_cxx14_std_apis = std::false_type;
#endif

template<typename T>
using expect_cxx14_apis =
absl::disjunction<absl::negation<is_std_unordered_set<T>>, has_cxx14_std_apis>;

template<typename TypeParam>
void BucketCountAllocTest(std::false_type)
{
}

template<typename TypeParam>
void BucketCountAllocTest(std::true_type)
{
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountAlloc)
{
BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void BucketCountHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void BucketCountHashAllocTest(std::true_type)
{
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
TypeParam m(123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc)
{
BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
using has_alloc_std_constructors = std::true_type;
#else
using has_alloc_std_constructors = std::false_type;
#endif

template<typename T>
using expect_alloc_constructors =
absl::disjunction<absl::negation<is_std_unordered_set<T>>, has_alloc_std_constructors>;

template<typename TypeParam>
void AllocTest(std::false_type)
{
}

template<typename TypeParam>
void AllocTest(std::true_type)
{
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
}

TYPED_TEST_P(ConstructorTest, Alloc)
{
AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
std::vector<T> values;
for (size_t i = 0; i != 10; ++i)
values.push_back(hash_internal::Generator<T>()());
TypeParam m(values.begin(), values.end(), 123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

template<typename TypeParam>
void InputIteratorBucketAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InputIteratorBucketAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
std::vector<T> values;
for (size_t i = 0; i != 10; ++i)
values.push_back(hash_internal::Generator<T>()());
TypeParam m(values.begin(), values.end(), 123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc)
{
InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void InputIteratorBucketHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InputIteratorBucketHashAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
std::vector<T> values;
for (size_t i = 0; i != 10; ++i)
values.push_back(hash_internal::Generator<T>()());
TypeParam m(values.begin(), values.end(), 123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc)
{
InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, CopyConstructor)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(hash_internal::Generator<T>()());
TypeParam n(m);
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
EXPECT_NE(TypeParam(0, hasher, equal, alloc), n);
}

template<typename TypeParam>
void CopyConstructorAllocTest(std::false_type)
{
}

template<typename TypeParam>
void CopyConstructorAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(hash_internal::Generator<T>()());
TypeParam n(m, A(11));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc)
{
CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

// TODO(alkis): Test non-propagating allocators on copy constructors.

TYPED_TEST_P(ConstructorTest, MoveConstructor)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(hash_internal::Generator<T>()());
TypeParam t(m);
TypeParam n(std::move(t));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

template<typename TypeParam>
void MoveConstructorAllocTest(std::false_type)
{
}

template<typename TypeParam>
void MoveConstructorAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(123, hasher, equal, alloc);
for (size_t i = 0; i != 10; ++i)
m.insert(hash_internal::Generator<T>()());
TypeParam t(m);
TypeParam n(std::move(t), A(1));
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc)
{
MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}

// TODO(alkis): Test non-propagating allocators on move constructors.

TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
TypeParam m(values, 123, hasher, equal, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.key_eq(), equal);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

template<typename TypeParam>
void InitializerListBucketAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InitializerListBucketAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
A alloc(0);
TypeParam m(values, 123, alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc)
{
InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

template<typename TypeParam>
void InitializerListBucketHashAllocTest(std::false_type)
{
}

template<typename TypeParam>
void InitializerListBucketHashAllocTest(std::true_type)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
A alloc(0);
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m(values, 123, hasher, alloc);
EXPECT_EQ(m.hash_function(), hasher);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
}

TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc)
{
InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}

TYPED_TEST_P(ConstructorTest, CopyAssignment)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::Generator<T> gen;
TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
TypeParam n;
n = m;
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m, n);
}

// TODO(alkis): Test [non-]propagating allocators on move/copy assignments
// (it depends on traits).

TYPED_TEST_P(ConstructorTest, MoveAssignment)
{
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
using A = typename TypeParam::allocator_type;
H hasher;
E equal;
A alloc(0);
hash_internal::Generator<T> gen;
TypeParam m({gen(), gen(), gen()}, 123, hasher, equal, alloc);
TypeParam t(m);
TypeParam n;
n = std::move(t);
EXPECT_EQ(m.hash_function(), n.hash_function());
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerList)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m;
m = values;
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
}

TYPED_TEST_P(ConstructorTest, AssignmentOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
TypeParam m({gen(), gen(), gen()});
TypeParam n({gen()});
n = m;
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, MoveAssignmentOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
TypeParam m({gen(), gen(), gen()});
TypeParam t(m);
TypeParam n({gen()});
n = std::move(t);
EXPECT_EQ(m, n);
}

TYPED_TEST_P(ConstructorTest, AssignmentFromInitializerListOverwritesExisting)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m;
m = values;
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
}

TYPED_TEST_P(ConstructorTest, AssignmentOnSelf)
{
using T = hash_internal::GeneratedType<TypeParam>;
hash_internal::Generator<T> gen;
std::initializer_list<T> values = {gen(), gen(), gen(), gen(), gen()};
TypeParam m(values);
m = *&m; // Avoid -Wself-assign.
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
}

REGISTER_TYPED_TEST_SUITE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual, BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc, InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc, MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc, InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment, MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting, AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf
);

} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl

#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save