re2 1.22.2 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/README.md +60 -4
  2. package/binding.gyp +5 -1
  3. package/lib/addon.cc +4 -0
  4. package/lib/new.cc +1 -246
  5. package/lib/pattern.cc +252 -0
  6. package/lib/pattern.h +10 -0
  7. package/lib/set.cc +777 -0
  8. package/lib/wrapped_re2_set.h +42 -0
  9. package/package.json +21 -9
  10. package/re2.d.ts +46 -9
  11. package/vendor/abseil-cpp/CMake/AbseilDll.cmake +14 -24
  12. package/vendor/abseil-cpp/CMake/AbseilHelpers.cmake +3 -3
  13. package/vendor/abseil-cpp/CMake/README.md +2 -2
  14. package/vendor/abseil-cpp/CMakeLists.txt +3 -3
  15. package/vendor/abseil-cpp/MODULE.bazel +6 -9
  16. package/vendor/abseil-cpp/README.md +6 -8
  17. package/vendor/abseil-cpp/absl/abseil.podspec.gen.py +6 -4
  18. package/vendor/abseil-cpp/absl/algorithm/BUILD.bazel +3 -0
  19. package/vendor/abseil-cpp/absl/algorithm/CMakeLists.txt +1 -0
  20. package/vendor/abseil-cpp/absl/algorithm/container.h +2 -19
  21. package/vendor/abseil-cpp/absl/algorithm/container_test.cc +4 -11
  22. package/vendor/abseil-cpp/absl/base/BUILD.bazel +60 -45
  23. package/vendor/abseil-cpp/absl/base/CMakeLists.txt +57 -38
  24. package/vendor/abseil-cpp/absl/base/attributes.h +76 -7
  25. package/vendor/abseil-cpp/absl/base/attributes_test.cc +43 -0
  26. package/vendor/abseil-cpp/absl/base/call_once.h +11 -12
  27. package/vendor/abseil-cpp/absl/base/config.h +22 -129
  28. package/vendor/abseil-cpp/absl/base/exception_safety_testing_test.cc +0 -4
  29. package/vendor/abseil-cpp/absl/base/{internal/fast_type_id.h → fast_type_id.h} +11 -16
  30. package/vendor/abseil-cpp/absl/base/{internal/fast_type_id_test.cc → fast_type_id_test.cc} +34 -30
  31. package/vendor/abseil-cpp/absl/base/internal/cycleclock.cc +0 -5
  32. package/vendor/abseil-cpp/absl/base/internal/cycleclock_config.h +7 -7
  33. package/vendor/abseil-cpp/absl/base/internal/endian.h +34 -38
  34. package/vendor/abseil-cpp/absl/base/internal/iterator_traits.h +71 -0
  35. package/vendor/abseil-cpp/absl/base/internal/iterator_traits_test.cc +85 -0
  36. package/vendor/abseil-cpp/absl/base/internal/iterator_traits_test_helper.h +97 -0
  37. package/vendor/abseil-cpp/absl/base/internal/low_level_alloc.cc +39 -9
  38. package/vendor/abseil-cpp/absl/base/internal/low_level_alloc.h +6 -0
  39. package/vendor/abseil-cpp/absl/base/internal/poison.cc +7 -6
  40. package/vendor/abseil-cpp/absl/base/internal/spinlock.cc +15 -28
  41. package/vendor/abseil-cpp/absl/base/internal/spinlock.h +65 -35
  42. package/vendor/abseil-cpp/absl/base/internal/spinlock_benchmark.cc +2 -2
  43. package/vendor/abseil-cpp/absl/base/internal/sysinfo_test.cc +2 -2
  44. package/vendor/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc +1 -1
  45. package/vendor/abseil-cpp/absl/base/internal/thread_identity_test.cc +4 -4
  46. package/vendor/abseil-cpp/absl/base/internal/unaligned_access.h +6 -6
  47. package/vendor/abseil-cpp/absl/base/internal/unscaledcycleclock.cc +4 -0
  48. package/vendor/abseil-cpp/absl/base/internal/unscaledcycleclock.h +8 -3
  49. package/vendor/abseil-cpp/absl/base/no_destructor.h +11 -32
  50. package/vendor/abseil-cpp/absl/base/no_destructor_test.cc +0 -4
  51. package/vendor/abseil-cpp/absl/base/nullability.h +83 -72
  52. package/vendor/abseil-cpp/absl/base/nullability_test.cc +25 -64
  53. package/vendor/abseil-cpp/absl/base/options.h +3 -80
  54. package/vendor/abseil-cpp/absl/base/policy_checks.h +7 -7
  55. package/vendor/abseil-cpp/absl/base/raw_logging_test.cc +15 -0
  56. package/vendor/abseil-cpp/absl/base/spinlock_test_common.cc +50 -30
  57. package/vendor/abseil-cpp/absl/cleanup/BUILD.bazel +2 -1
  58. package/vendor/abseil-cpp/absl/cleanup/CMakeLists.txt +0 -1
  59. package/vendor/abseil-cpp/absl/cleanup/cleanup.h +1 -3
  60. package/vendor/abseil-cpp/absl/cleanup/cleanup_test.cc +0 -2
  61. package/vendor/abseil-cpp/absl/cleanup/internal/cleanup.h +3 -4
  62. package/vendor/abseil-cpp/absl/container/BUILD.bazel +74 -1
  63. package/vendor/abseil-cpp/absl/container/CMakeLists.txt +73 -0
  64. package/vendor/abseil-cpp/absl/container/btree_benchmark.cc +51 -9
  65. package/vendor/abseil-cpp/absl/container/btree_map.h +8 -6
  66. package/vendor/abseil-cpp/absl/container/btree_set.h +8 -6
  67. package/vendor/abseil-cpp/absl/container/btree_test.cc +89 -4
  68. package/vendor/abseil-cpp/absl/container/fixed_array.h +7 -15
  69. package/vendor/abseil-cpp/absl/container/fixed_array_test.cc +17 -0
  70. package/vendor/abseil-cpp/absl/container/flat_hash_map.h +20 -15
  71. package/vendor/abseil-cpp/absl/container/flat_hash_map_test.cc +8 -14
  72. package/vendor/abseil-cpp/absl/container/flat_hash_set.h +19 -14
  73. package/vendor/abseil-cpp/absl/container/flat_hash_set_test.cc +46 -0
  74. package/vendor/abseil-cpp/absl/container/inlined_vector.h +7 -6
  75. package/vendor/abseil-cpp/absl/container/inlined_vector_test.cc +28 -0
  76. package/vendor/abseil-cpp/absl/container/internal/btree.h +132 -29
  77. package/vendor/abseil-cpp/absl/container/internal/btree_container.h +175 -71
  78. package/vendor/abseil-cpp/absl/container/internal/common.h +43 -0
  79. package/vendor/abseil-cpp/absl/container/internal/common_policy_traits.h +1 -2
  80. package/vendor/abseil-cpp/absl/container/internal/compressed_tuple.h +28 -24
  81. package/vendor/abseil-cpp/absl/container/internal/compressed_tuple_test.cc +4 -17
  82. package/vendor/abseil-cpp/absl/container/internal/container_memory.h +80 -17
  83. package/vendor/abseil-cpp/absl/container/internal/container_memory_test.cc +32 -2
  84. package/vendor/abseil-cpp/absl/container/internal/hash_function_defaults.h +13 -8
  85. package/vendor/abseil-cpp/absl/container/internal/hash_function_defaults_test.cc +1 -52
  86. package/vendor/abseil-cpp/absl/container/internal/hash_generator_testing.cc +9 -31
  87. package/vendor/abseil-cpp/absl/container/internal/hash_generator_testing.h +23 -32
  88. package/vendor/abseil-cpp/absl/container/internal/hash_policy_testing.h +5 -1
  89. package/vendor/abseil-cpp/absl/container/internal/hash_policy_traits.h +11 -23
  90. package/vendor/abseil-cpp/absl/container/internal/hash_policy_traits_test.cc +14 -9
  91. package/vendor/abseil-cpp/absl/container/internal/hashtable_control_bytes.h +516 -0
  92. package/vendor/abseil-cpp/absl/container/internal/hashtable_control_bytes_test.cc +259 -0
  93. package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler.cc +23 -6
  94. package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler.h +32 -13
  95. package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc +8 -8
  96. package/vendor/abseil-cpp/absl/container/internal/inlined_vector.h +2 -7
  97. package/vendor/abseil-cpp/absl/container/internal/layout.h +26 -42
  98. package/vendor/abseil-cpp/absl/container/internal/raw_hash_map.h +199 -68
  99. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set.cc +1506 -213
  100. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set.h +1095 -1658
  101. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc +3 -2
  102. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc +31 -29
  103. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc +51 -20
  104. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_resize_impl.h +79 -0
  105. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_resize_impl_test.cc +66 -0
  106. package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +707 -363
  107. package/vendor/abseil-cpp/absl/container/node_hash_map.h +20 -15
  108. package/vendor/abseil-cpp/absl/container/node_hash_map_test.cc +0 -3
  109. package/vendor/abseil-cpp/absl/container/node_hash_set.h +18 -13
  110. package/vendor/abseil-cpp/absl/container/sample_element_size_test.cc +3 -8
  111. package/vendor/abseil-cpp/absl/copts/AbseilConfigureCopts.cmake +1 -1
  112. package/vendor/abseil-cpp/absl/copts/GENERATED_AbseilCopts.cmake +9 -20
  113. package/vendor/abseil-cpp/absl/copts/GENERATED_copts.bzl +9 -20
  114. package/vendor/abseil-cpp/absl/copts/copts.py +24 -15
  115. package/vendor/abseil-cpp/absl/crc/BUILD.bazel +3 -0
  116. package/vendor/abseil-cpp/absl/crc/crc32c.cc +0 -4
  117. package/vendor/abseil-cpp/absl/crc/crc32c.h +7 -5
  118. package/vendor/abseil-cpp/absl/crc/crc32c_benchmark.cc +17 -4
  119. package/vendor/abseil-cpp/absl/crc/crc32c_test.cc +30 -0
  120. package/vendor/abseil-cpp/absl/crc/internal/cpu_detect.cc +17 -0
  121. package/vendor/abseil-cpp/absl/crc/internal/cpu_detect.h +7 -1
  122. package/vendor/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h +0 -22
  123. package/vendor/abseil-cpp/absl/crc/internal/crc_memcpy_x86_arm_combined.cc +5 -0
  124. package/vendor/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc +136 -165
  125. package/vendor/abseil-cpp/absl/crc/internal/gen_crc32c_consts.py +90 -0
  126. package/vendor/abseil-cpp/absl/debugging/BUILD.bazel +7 -0
  127. package/vendor/abseil-cpp/absl/debugging/CMakeLists.txt +4 -0
  128. package/vendor/abseil-cpp/absl/debugging/internal/addresses.h +57 -0
  129. package/vendor/abseil-cpp/absl/debugging/internal/decode_rust_punycode.cc +1 -1
  130. package/vendor/abseil-cpp/absl/debugging/internal/decode_rust_punycode.h +5 -5
  131. package/vendor/abseil-cpp/absl/debugging/internal/demangle.cc +8 -35
  132. package/vendor/abseil-cpp/absl/debugging/internal/demangle_rust.cc +16 -16
  133. package/vendor/abseil-cpp/absl/debugging/internal/demangle_test.cc +11 -10
  134. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc +40 -37
  135. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc +16 -7
  136. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_config.h +6 -5
  137. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc +14 -5
  138. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc +10 -4
  139. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc +27 -16
  140. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc +13 -4
  141. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_unimplemented-inl.inc +4 -3
  142. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc +15 -28
  143. package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc +25 -14
  144. package/vendor/abseil-cpp/absl/debugging/internal/vdso_support.cc +4 -0
  145. package/vendor/abseil-cpp/absl/debugging/stacktrace.cc +161 -27
  146. package/vendor/abseil-cpp/absl/debugging/stacktrace.h +73 -5
  147. package/vendor/abseil-cpp/absl/debugging/stacktrace_test.cc +435 -1
  148. package/vendor/abseil-cpp/absl/debugging/symbolize_elf.inc +55 -63
  149. package/vendor/abseil-cpp/absl/debugging/symbolize_emscripten.inc +3 -2
  150. package/vendor/abseil-cpp/absl/debugging/symbolize_win32.inc +25 -6
  151. package/vendor/abseil-cpp/absl/flags/BUILD.bazel +6 -0
  152. package/vendor/abseil-cpp/absl/flags/CMakeLists.txt +3 -0
  153. package/vendor/abseil-cpp/absl/flags/commandlineflag.h +2 -2
  154. package/vendor/abseil-cpp/absl/flags/flag.h +4 -3
  155. package/vendor/abseil-cpp/absl/flags/internal/commandlineflag.h +2 -2
  156. package/vendor/abseil-cpp/absl/flags/internal/flag.cc +14 -13
  157. package/vendor/abseil-cpp/absl/flags/internal/flag.h +34 -34
  158. package/vendor/abseil-cpp/absl/flags/internal/program_name.cc +2 -2
  159. package/vendor/abseil-cpp/absl/flags/internal/registry.h +4 -3
  160. package/vendor/abseil-cpp/absl/flags/internal/usage.cc +2 -2
  161. package/vendor/abseil-cpp/absl/flags/parse.cc +10 -6
  162. package/vendor/abseil-cpp/absl/flags/reflection.cc +9 -7
  163. package/vendor/abseil-cpp/absl/flags/usage.cc +2 -2
  164. package/vendor/abseil-cpp/absl/flags/usage_config.cc +2 -2
  165. package/vendor/abseil-cpp/absl/functional/BUILD.bazel +7 -6
  166. package/vendor/abseil-cpp/absl/functional/CMakeLists.txt +2 -4
  167. package/vendor/abseil-cpp/absl/functional/any_invocable.h +15 -15
  168. package/vendor/abseil-cpp/absl/functional/any_invocable_test.cc +10 -42
  169. package/vendor/abseil-cpp/absl/functional/function_ref.h +2 -9
  170. package/vendor/abseil-cpp/absl/functional/function_ref_test.cc +10 -0
  171. package/vendor/abseil-cpp/absl/functional/function_type_benchmark.cc +1 -1
  172. package/vendor/abseil-cpp/absl/functional/internal/any_invocable.h +112 -227
  173. package/vendor/abseil-cpp/absl/functional/internal/front_binder.h +10 -12
  174. package/vendor/abseil-cpp/absl/functional/internal/function_ref.h +2 -5
  175. package/vendor/abseil-cpp/absl/functional/overload.h +0 -20
  176. package/vendor/abseil-cpp/absl/functional/overload_test.cc +1 -7
  177. package/vendor/abseil-cpp/absl/hash/BUILD.bazel +16 -9
  178. package/vendor/abseil-cpp/absl/hash/CMakeLists.txt +6 -9
  179. package/vendor/abseil-cpp/absl/hash/hash.h +18 -0
  180. package/vendor/abseil-cpp/absl/hash/hash_benchmark.cc +3 -0
  181. package/vendor/abseil-cpp/absl/hash/hash_instantiated_test.cc +1 -1
  182. package/vendor/abseil-cpp/absl/hash/hash_test.cc +131 -30
  183. package/vendor/abseil-cpp/absl/hash/hash_testing.h +20 -20
  184. package/vendor/abseil-cpp/absl/hash/internal/hash.cc +129 -17
  185. package/vendor/abseil-cpp/absl/hash/internal/hash.h +326 -362
  186. package/vendor/abseil-cpp/absl/hash/internal/low_level_hash_test.cc +54 -151
  187. package/vendor/abseil-cpp/absl/hash/internal/spy_hash_state.h +14 -2
  188. package/vendor/abseil-cpp/absl/{strings/cord_buffer.cc → hash/internal/weakly_mixed_integer.h} +14 -6
  189. package/vendor/abseil-cpp/absl/log/BUILD.bazel +4 -0
  190. package/vendor/abseil-cpp/absl/log/CMakeLists.txt +7 -0
  191. package/vendor/abseil-cpp/absl/log/check.h +2 -1
  192. package/vendor/abseil-cpp/absl/log/check_test_impl.inc +308 -14
  193. package/vendor/abseil-cpp/absl/log/die_if_null.h +2 -2
  194. package/vendor/abseil-cpp/absl/log/flags_test.cc +7 -0
  195. package/vendor/abseil-cpp/absl/log/globals.h +4 -5
  196. package/vendor/abseil-cpp/absl/log/internal/BUILD.bazel +13 -9
  197. package/vendor/abseil-cpp/absl/log/internal/append_truncated.h +28 -0
  198. package/vendor/abseil-cpp/absl/log/internal/check_op.cc +24 -22
  199. package/vendor/abseil-cpp/absl/log/internal/check_op.h +149 -94
  200. package/vendor/abseil-cpp/absl/log/internal/conditions.cc +5 -3
  201. package/vendor/abseil-cpp/absl/log/internal/conditions.h +7 -2
  202. package/vendor/abseil-cpp/absl/log/internal/fnmatch_test.cc +1 -0
  203. package/vendor/abseil-cpp/absl/log/internal/log_message.cc +85 -43
  204. package/vendor/abseil-cpp/absl/log/internal/log_message.h +84 -59
  205. package/vendor/abseil-cpp/absl/log/internal/log_sink_set.cc +4 -4
  206. package/vendor/abseil-cpp/absl/log/internal/nullstream.h +1 -0
  207. package/vendor/abseil-cpp/absl/log/internal/proto.cc +3 -2
  208. package/vendor/abseil-cpp/absl/log/internal/proto.h +3 -3
  209. package/vendor/abseil-cpp/absl/log/internal/strip.h +4 -12
  210. package/vendor/abseil-cpp/absl/log/internal/structured.h +3 -7
  211. package/vendor/abseil-cpp/absl/log/internal/vlog_config.cc +9 -9
  212. package/vendor/abseil-cpp/absl/log/internal/vlog_config.h +8 -6
  213. package/vendor/abseil-cpp/absl/log/internal/voidify.h +10 -4
  214. package/vendor/abseil-cpp/absl/log/log.h +48 -35
  215. package/vendor/abseil-cpp/absl/log/log_basic_test_impl.inc +45 -0
  216. package/vendor/abseil-cpp/absl/log/log_entry.cc +241 -19
  217. package/vendor/abseil-cpp/absl/log/log_entry.h +2 -0
  218. package/vendor/abseil-cpp/absl/log/log_format_test.cc +412 -6
  219. package/vendor/abseil-cpp/absl/log/log_modifier_methods_test.cc +20 -0
  220. package/vendor/abseil-cpp/absl/log/log_sink_registry.h +2 -2
  221. package/vendor/abseil-cpp/absl/log/log_streamer_test.cc +15 -2
  222. package/vendor/abseil-cpp/absl/log/scoped_mock_log.h +7 -1
  223. package/vendor/abseil-cpp/absl/log/structured_test.cc +1 -0
  224. package/vendor/abseil-cpp/absl/memory/BUILD.bazel +2 -0
  225. package/vendor/abseil-cpp/absl/meta/BUILD.bazel +2 -0
  226. package/vendor/abseil-cpp/absl/meta/type_traits.h +46 -175
  227. package/vendor/abseil-cpp/absl/meta/type_traits_test.cc +1 -478
  228. package/vendor/abseil-cpp/absl/numeric/BUILD.bazel +7 -3
  229. package/vendor/abseil-cpp/absl/numeric/CMakeLists.txt +2 -0
  230. package/vendor/abseil-cpp/absl/numeric/bits.h +68 -2
  231. package/vendor/abseil-cpp/absl/numeric/bits_benchmark.cc +1 -1
  232. package/vendor/abseil-cpp/absl/numeric/bits_test.cc +83 -0
  233. package/vendor/abseil-cpp/absl/numeric/int128.cc +0 -52
  234. package/vendor/abseil-cpp/absl/numeric/int128_benchmark.cc +14 -15
  235. package/vendor/abseil-cpp/absl/numeric/int128_test.cc +13 -8
  236. package/vendor/abseil-cpp/absl/numeric/internal/bits.h +39 -7
  237. package/vendor/abseil-cpp/absl/profiling/BUILD.bazel +47 -0
  238. package/vendor/abseil-cpp/absl/profiling/CMakeLists.txt +38 -0
  239. package/vendor/abseil-cpp/absl/profiling/hashtable.cc +124 -0
  240. package/vendor/abseil-cpp/absl/profiling/hashtable.h +40 -0
  241. package/vendor/abseil-cpp/absl/profiling/internal/exponential_biased.cc +1 -1
  242. package/vendor/abseil-cpp/absl/profiling/internal/profile_builder.cc +462 -0
  243. package/vendor/abseil-cpp/absl/profiling/internal/profile_builder.h +138 -0
  244. package/vendor/abseil-cpp/absl/profiling/internal/sample_recorder.h +9 -9
  245. package/vendor/abseil-cpp/absl/profiling/internal/sample_recorder_test.cc +7 -3
  246. package/vendor/abseil-cpp/absl/random/BUILD.bazel +6 -4
  247. package/vendor/abseil-cpp/absl/random/CMakeLists.txt +20 -19
  248. package/vendor/abseil-cpp/absl/random/benchmarks.cc +16 -23
  249. package/vendor/abseil-cpp/absl/random/bit_gen_ref.h +10 -11
  250. package/vendor/abseil-cpp/absl/random/bit_gen_ref_test.cc +7 -2
  251. package/vendor/abseil-cpp/absl/random/distributions.h +6 -8
  252. package/vendor/abseil-cpp/absl/random/gaussian_distribution.h +1 -1
  253. package/vendor/abseil-cpp/absl/random/internal/BUILD.bazel +19 -20
  254. package/vendor/abseil-cpp/absl/random/internal/distribution_caller.h +5 -6
  255. package/vendor/abseil-cpp/absl/random/internal/{pool_urbg.cc → entropy_pool.cc} +24 -92
  256. package/vendor/abseil-cpp/absl/{base/inline_variable_test_b.cc → random/internal/entropy_pool.h} +14 -6
  257. package/vendor/abseil-cpp/absl/random/internal/entropy_pool_test.cc +119 -0
  258. package/vendor/abseil-cpp/absl/random/internal/mock_helpers.h +6 -7
  259. package/vendor/abseil-cpp/absl/random/internal/nonsecure_base.h +5 -6
  260. package/vendor/abseil-cpp/absl/random/internal/nonsecure_base_test.cc +39 -0
  261. package/vendor/abseil-cpp/absl/random/internal/randen_benchmarks.cc +8 -6
  262. package/vendor/abseil-cpp/absl/random/internal/randen_detect.cc +1 -1
  263. package/vendor/abseil-cpp/absl/random/internal/seed_material.cc +20 -12
  264. package/vendor/abseil-cpp/absl/random/internal/seed_material.h +5 -5
  265. package/vendor/abseil-cpp/absl/random/internal/seed_material_test.cc +3 -0
  266. package/vendor/abseil-cpp/absl/random/mock_distributions_test.cc +5 -4
  267. package/vendor/abseil-cpp/absl/random/mocking_bit_gen.h +8 -10
  268. package/vendor/abseil-cpp/absl/random/random.h +88 -53
  269. package/vendor/abseil-cpp/absl/random/seed_sequences.cc +6 -2
  270. package/vendor/abseil-cpp/absl/status/BUILD.bazel +26 -0
  271. package/vendor/abseil-cpp/absl/status/internal/status_internal.cc +3 -4
  272. package/vendor/abseil-cpp/absl/status/internal/status_internal.h +3 -4
  273. package/vendor/abseil-cpp/absl/status/internal/status_matchers.cc +4 -3
  274. package/vendor/abseil-cpp/absl/status/internal/statusor_internal.h +194 -32
  275. package/vendor/abseil-cpp/absl/status/status.cc +4 -8
  276. package/vendor/abseil-cpp/absl/status/status.h +8 -8
  277. package/vendor/abseil-cpp/absl/{base/inline_variable_test_a.cc → status/status_benchmark.cc} +20 -10
  278. package/vendor/abseil-cpp/absl/status/status_matchers_test.cc +65 -0
  279. package/vendor/abseil-cpp/absl/status/status_payload_printer.h +2 -2
  280. package/vendor/abseil-cpp/absl/status/statusor.cc +2 -2
  281. package/vendor/abseil-cpp/absl/status/statusor.h +49 -102
  282. package/vendor/abseil-cpp/absl/status/statusor_benchmark.cc +480 -0
  283. package/vendor/abseil-cpp/absl/status/statusor_test.cc +323 -1
  284. package/vendor/abseil-cpp/absl/strings/BUILD.bazel +70 -34
  285. package/vendor/abseil-cpp/absl/strings/CMakeLists.txt +6 -3
  286. package/vendor/abseil-cpp/absl/strings/ascii.cc +9 -9
  287. package/vendor/abseil-cpp/absl/strings/ascii.h +18 -18
  288. package/vendor/abseil-cpp/absl/strings/ascii_benchmark.cc +5 -8
  289. package/vendor/abseil-cpp/absl/strings/charconv.cc +21 -22
  290. package/vendor/abseil-cpp/absl/strings/charconv.h +5 -5
  291. package/vendor/abseil-cpp/absl/strings/charconv_benchmark.cc +1 -2
  292. package/vendor/abseil-cpp/absl/strings/charset_benchmark.cc +1 -1
  293. package/vendor/abseil-cpp/absl/strings/cord.cc +54 -58
  294. package/vendor/abseil-cpp/absl/strings/cord.h +94 -84
  295. package/vendor/abseil-cpp/absl/strings/cord_analysis.cc +11 -11
  296. package/vendor/abseil-cpp/absl/strings/cord_analysis.h +3 -3
  297. package/vendor/abseil-cpp/absl/strings/cord_test.cc +23 -0
  298. package/vendor/abseil-cpp/absl/strings/cordz_test_helpers.h +4 -5
  299. package/vendor/abseil-cpp/absl/strings/escaping.cc +130 -149
  300. package/vendor/abseil-cpp/absl/strings/escaping.h +9 -10
  301. package/vendor/abseil-cpp/absl/strings/escaping_benchmark.cc +2 -3
  302. package/vendor/abseil-cpp/absl/strings/escaping_test.cc +19 -9
  303. package/vendor/abseil-cpp/absl/strings/internal/charconv_bigint.cc +1 -1
  304. package/vendor/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc +1 -1
  305. package/vendor/abseil-cpp/absl/strings/internal/cord_internal.h +6 -10
  306. package/vendor/abseil-cpp/absl/strings/internal/cord_rep_btree.cc +0 -4
  307. package/vendor/abseil-cpp/absl/strings/internal/cordz_handle.cc +6 -6
  308. package/vendor/abseil-cpp/absl/strings/internal/cordz_info.cc +5 -9
  309. package/vendor/abseil-cpp/absl/strings/internal/cordz_info.h +2 -4
  310. package/vendor/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc +56 -0
  311. package/vendor/abseil-cpp/absl/strings/internal/memutil_benchmark.cc +2 -3
  312. package/vendor/abseil-cpp/absl/strings/internal/ostringstream_benchmark.cc +1 -2
  313. package/vendor/abseil-cpp/absl/strings/internal/str_format/arg.cc +7 -63
  314. package/vendor/abseil-cpp/absl/strings/internal/str_format/arg.h +1 -11
  315. package/vendor/abseil-cpp/absl/strings/internal/str_format/convert_test.cc +1 -6
  316. package/vendor/abseil-cpp/absl/strings/internal/str_format/extension.cc +0 -22
  317. package/vendor/abseil-cpp/absl/strings/internal/str_format/extension_test.cc +3 -2
  318. package/vendor/abseil-cpp/absl/strings/internal/str_format/output.cc +5 -3
  319. package/vendor/abseil-cpp/absl/strings/internal/str_format/parser.h +4 -2
  320. package/vendor/abseil-cpp/absl/strings/internal/str_join_internal.h +3 -3
  321. package/vendor/abseil-cpp/absl/strings/internal/str_split_internal.h +7 -2
  322. package/vendor/abseil-cpp/absl/strings/internal/string_constant.h +0 -5
  323. package/vendor/abseil-cpp/absl/strings/internal/utf8.cc +96 -1
  324. package/vendor/abseil-cpp/absl/strings/internal/utf8.h +15 -1
  325. package/vendor/abseil-cpp/absl/strings/internal/utf8_test.cc +196 -3
  326. package/vendor/abseil-cpp/absl/strings/numbers.cc +53 -32
  327. package/vendor/abseil-cpp/absl/strings/numbers.h +87 -58
  328. package/vendor/abseil-cpp/absl/strings/numbers_benchmark.cc +1 -1
  329. package/vendor/abseil-cpp/absl/strings/numbers_test.cc +634 -120
  330. package/vendor/abseil-cpp/absl/strings/str_cat.cc +6 -7
  331. package/vendor/abseil-cpp/absl/strings/str_cat.h +32 -32
  332. package/vendor/abseil-cpp/absl/strings/str_cat_benchmark.cc +25 -1
  333. package/vendor/abseil-cpp/absl/strings/str_cat_test.cc +2 -7
  334. package/vendor/abseil-cpp/absl/strings/str_format.h +18 -18
  335. package/vendor/abseil-cpp/absl/strings/str_format_test.cc +8 -14
  336. package/vendor/abseil-cpp/absl/strings/str_join_benchmark.cc +2 -3
  337. package/vendor/abseil-cpp/absl/strings/str_replace.cc +3 -3
  338. package/vendor/abseil-cpp/absl/strings/str_replace.h +6 -6
  339. package/vendor/abseil-cpp/absl/strings/str_replace_benchmark.cc +2 -3
  340. package/vendor/abseil-cpp/absl/strings/str_split.h +2 -2
  341. package/vendor/abseil-cpp/absl/strings/str_split_benchmark.cc +2 -3
  342. package/vendor/abseil-cpp/absl/strings/string_view.cc +4 -9
  343. package/vendor/abseil-cpp/absl/strings/string_view.h +38 -39
  344. package/vendor/abseil-cpp/absl/strings/string_view_benchmark.cc +4 -6
  345. package/vendor/abseil-cpp/absl/strings/string_view_test.cc +2 -50
  346. package/vendor/abseil-cpp/absl/strings/strip.h +4 -4
  347. package/vendor/abseil-cpp/absl/strings/substitute.cc +5 -4
  348. package/vendor/abseil-cpp/absl/strings/substitute.h +66 -64
  349. package/vendor/abseil-cpp/absl/strings/substitute_benchmark.cc +158 -0
  350. package/vendor/abseil-cpp/absl/synchronization/BUILD.bazel +6 -1
  351. package/vendor/abseil-cpp/absl/synchronization/CMakeLists.txt +2 -1
  352. package/vendor/abseil-cpp/absl/synchronization/barrier.cc +1 -1
  353. package/vendor/abseil-cpp/absl/synchronization/barrier_test.cc +3 -3
  354. package/vendor/abseil-cpp/absl/synchronization/blocking_counter.cc +2 -2
  355. package/vendor/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc +3 -3
  356. package/vendor/abseil-cpp/absl/synchronization/internal/futex_waiter.cc +0 -4
  357. package/vendor/abseil-cpp/absl/synchronization/internal/graphcycles.cc +30 -33
  358. package/vendor/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc +2 -3
  359. package/vendor/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc +6 -5
  360. package/vendor/abseil-cpp/absl/synchronization/internal/kernel_timeout.cc +0 -5
  361. package/vendor/abseil-cpp/absl/synchronization/internal/pthread_waiter.cc +0 -4
  362. package/vendor/abseil-cpp/absl/synchronization/internal/sem_waiter.cc +0 -4
  363. package/vendor/abseil-cpp/absl/synchronization/internal/stdcpp_waiter.cc +0 -4
  364. package/vendor/abseil-cpp/absl/synchronization/internal/thread_pool.h +3 -3
  365. package/vendor/abseil-cpp/absl/synchronization/internal/waiter_base.cc +0 -4
  366. package/vendor/abseil-cpp/absl/synchronization/internal/waiter_test.cc +12 -3
  367. package/vendor/abseil-cpp/absl/synchronization/internal/win32_waiter.cc +0 -4
  368. package/vendor/abseil-cpp/absl/synchronization/lifetime_test.cc +4 -4
  369. package/vendor/abseil-cpp/absl/synchronization/mutex.cc +27 -29
  370. package/vendor/abseil-cpp/absl/synchronization/mutex.h +205 -126
  371. package/vendor/abseil-cpp/absl/synchronization/mutex_benchmark.cc +13 -31
  372. package/vendor/abseil-cpp/absl/synchronization/mutex_test.cc +183 -169
  373. package/vendor/abseil-cpp/absl/synchronization/notification.cc +5 -5
  374. package/vendor/abseil-cpp/absl/synchronization/notification.h +1 -1
  375. package/vendor/abseil-cpp/absl/synchronization/notification_test.cc +3 -3
  376. package/vendor/abseil-cpp/absl/time/BUILD.bazel +9 -1
  377. package/vendor/abseil-cpp/absl/time/CMakeLists.txt +3 -1
  378. package/vendor/abseil-cpp/absl/time/civil_time.cc +1 -0
  379. package/vendor/abseil-cpp/absl/time/civil_time_test.cc +134 -0
  380. package/vendor/abseil-cpp/absl/time/clock.cc +11 -14
  381. package/vendor/abseil-cpp/absl/time/duration.cc +14 -9
  382. package/vendor/abseil-cpp/absl/time/duration_test.cc +6 -7
  383. package/vendor/abseil-cpp/absl/time/internal/cctz/BUILD.bazel +14 -3
  384. package/vendor/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h +12 -0
  385. package/vendor/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h +1 -1
  386. package/vendor/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc +4 -490
  387. package/vendor/abseil-cpp/absl/time/internal/cctz/src/test_time_zone_names.cc +515 -0
  388. package/vendor/abseil-cpp/absl/time/internal/cctz/src/test_time_zone_names.h +33 -0
  389. package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc +41 -4
  390. package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc +22 -23
  391. package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc +90 -111
  392. package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc +1 -488
  393. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/version +1 -1
  394. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Coyhaique +0 -0
  395. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran +0 -0
  396. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran +0 -0
  397. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab +2 -1
  398. package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab +1 -1
  399. package/vendor/abseil-cpp/absl/time/time.h +24 -18
  400. package/vendor/abseil-cpp/absl/time/time_test.cc +26 -0
  401. package/vendor/abseil-cpp/absl/types/BUILD.bazel +11 -164
  402. package/vendor/abseil-cpp/absl/types/CMakeLists.txt +23 -167
  403. package/vendor/abseil-cpp/absl/types/any.h +9 -484
  404. package/vendor/abseil-cpp/absl/types/optional.h +7 -747
  405. package/vendor/abseil-cpp/absl/types/span.h +46 -19
  406. package/vendor/abseil-cpp/absl/types/span_test.cc +27 -0
  407. package/vendor/abseil-cpp/absl/types/variant.h +5 -784
  408. package/vendor/abseil-cpp/absl/types/variant_test.cc +43 -2597
  409. package/vendor/abseil-cpp/absl/utility/BUILD.bazel +1 -41
  410. package/vendor/abseil-cpp/absl/utility/CMakeLists.txt +0 -40
  411. package/vendor/abseil-cpp/absl/utility/utility.h +10 -185
  412. package/vendor/abseil-cpp/ci/absl_alternate_options.h +2 -3
  413. package/vendor/abseil-cpp/ci/cmake_common.sh +2 -2
  414. package/vendor/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh +12 -13
  415. package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh +24 -21
  416. package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh +12 -12
  417. package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh +23 -22
  418. package/vendor/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh +20 -19
  419. package/vendor/abseil-cpp/ci/linux_docker_containers.sh +4 -4
  420. package/vendor/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh +17 -17
  421. package/vendor/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh +10 -10
  422. package/vendor/abseil-cpp/ci/linux_gcc-latest_libstdcxx_cmake.sh +1 -1
  423. package/vendor/abseil-cpp/ci/linux_gcc_alpine_cmake.sh +1 -1
  424. package/vendor/abseil-cpp/ci/macos_xcode_bazel.sh +9 -10
  425. package/vendor/abseil-cpp/ci/macos_xcode_cmake.sh +9 -1
  426. package/vendor/abseil-cpp/ci/windows_clangcl_bazel.bat +14 -6
  427. package/vendor/abseil-cpp/ci/windows_msvc_bazel.bat +14 -6
  428. package/vendor/abseil-cpp/ci/windows_msvc_cmake.bat +1 -1
  429. package/vendor/re2/.bazelrc +4 -4
  430. package/vendor/re2/.bcr/metadata.template.json +16 -0
  431. package/vendor/re2/.bcr/presubmit.yml +57 -0
  432. package/vendor/re2/.bcr/source.template.json +5 -0
  433. package/vendor/re2/.github/bazel.sh +1 -7
  434. package/vendor/re2/.github/workflows/ci-bazel.yml +5 -5
  435. package/vendor/re2/.github/workflows/ci-cmake.yml +4 -4
  436. package/vendor/re2/.github/workflows/ci.yml +5 -6
  437. package/vendor/re2/.github/workflows/pages.yml +3 -3
  438. package/vendor/re2/.github/workflows/python.yml +29 -24
  439. package/vendor/re2/.github/workflows/release-bazel.yml +42 -0
  440. package/vendor/re2/.github/workflows/release.yml +15 -4
  441. package/vendor/re2/BUILD.bazel +25 -0
  442. package/vendor/re2/CMakeLists.txt +100 -85
  443. package/vendor/re2/CONTRIBUTING.md +0 -1
  444. package/vendor/re2/MODULE.bazel +10 -10
  445. package/vendor/re2/Makefile +1 -1
  446. package/vendor/re2/README.md +259 -0
  447. package/vendor/re2/python/BUILD.bazel +8 -0
  448. package/vendor/re2/python/re2.py +1 -1
  449. package/vendor/re2/python/re2_test.py +6 -0
  450. package/vendor/re2/python/setup.py +3 -3
  451. package/vendor/re2/re2/bitmap256.cc +3 -4
  452. package/vendor/re2/re2/bitstate.cc +15 -10
  453. package/vendor/re2/re2/dfa.cc +1 -2
  454. package/vendor/re2/re2/parse.cc +3 -4
  455. package/vendor/re2/re2/prog.cc +1 -2
  456. package/vendor/re2/re2/prog.h +1 -0
  457. package/vendor/re2/re2/re2.cc +5 -0
  458. package/vendor/re2/re2/re2.h +9 -9
  459. package/vendor/re2/re2/set.cc +6 -0
  460. package/vendor/re2/re2/set.h +5 -0
  461. package/vendor/re2/re2/testing/re2_arg_test.cc +3 -3
  462. package/vendor/re2/re2/testing/re2_test.cc +8 -0
  463. package/vendor/re2/re2/testing/set_test.cc +5 -0
  464. package/vendor/re2/re2/walker-inl.h +1 -1
  465. package/vendor/abseil-cpp/WORKSPACE +0 -76
  466. package/vendor/abseil-cpp/WORKSPACE.bzlmod +0 -19
  467. package/vendor/abseil-cpp/absl/base/inline_variable_test.cc +0 -64
  468. package/vendor/abseil-cpp/absl/base/internal/inline_variable.h +0 -108
  469. package/vendor/abseil-cpp/absl/base/internal/inline_variable_testing.h +0 -46
  470. package/vendor/abseil-cpp/absl/base/internal/invoke.h +0 -241
  471. package/vendor/abseil-cpp/absl/base/internal/nullability_impl.h +0 -69
  472. package/vendor/abseil-cpp/absl/base/invoke_test.cc +0 -331
  473. package/vendor/abseil-cpp/absl/hash/internal/low_level_hash.cc +0 -148
  474. package/vendor/abseil-cpp/absl/hash/internal/low_level_hash.h +0 -54
  475. package/vendor/abseil-cpp/absl/random/internal/pool_urbg.h +0 -131
  476. package/vendor/abseil-cpp/absl/random/internal/pool_urbg_test.cc +0 -182
  477. package/vendor/abseil-cpp/absl/types/any_exception_safety_test.cc +0 -173
  478. package/vendor/abseil-cpp/absl/types/any_test.cc +0 -778
  479. package/vendor/abseil-cpp/absl/types/bad_any_cast.cc +0 -64
  480. package/vendor/abseil-cpp/absl/types/bad_any_cast.h +0 -75
  481. package/vendor/abseil-cpp/absl/types/bad_optional_access.cc +0 -66
  482. package/vendor/abseil-cpp/absl/types/bad_optional_access.h +0 -78
  483. package/vendor/abseil-cpp/absl/types/bad_variant_access.cc +0 -82
  484. package/vendor/abseil-cpp/absl/types/bad_variant_access.h +0 -82
  485. package/vendor/abseil-cpp/absl/types/internal/optional.h +0 -352
  486. package/vendor/abseil-cpp/absl/types/internal/variant.h +0 -1622
  487. package/vendor/abseil-cpp/absl/types/optional_exception_safety_test.cc +0 -292
  488. package/vendor/abseil-cpp/absl/types/optional_test.cc +0 -1615
  489. package/vendor/abseil-cpp/absl/types/variant_benchmark.cc +0 -222
  490. package/vendor/abseil-cpp/absl/types/variant_exception_safety_test.cc +0 -532
  491. package/vendor/abseil-cpp/absl/utility/internal/if_constexpr.h +0 -70
  492. package/vendor/abseil-cpp/absl/utility/internal/if_constexpr_test.cc +0 -79
  493. package/vendor/abseil-cpp/absl/utility/utility_test.cc +0 -239
  494. package/vendor/re2/.github/workflows/pr.yml +0 -34
  495. package/vendor/re2/README +0 -47
@@ -19,6 +19,7 @@
19
19
  #include <cstddef>
20
20
  #include <cstdint>
21
21
  #include <cstring>
22
+ #include <utility>
22
23
 
23
24
  #include "absl/base/attributes.h"
24
25
  #include "absl/base/config.h"
@@ -27,9 +28,11 @@
27
28
  #include "absl/base/internal/raw_logging.h"
28
29
  #include "absl/base/optimization.h"
29
30
  #include "absl/container/internal/container_memory.h"
31
+ #include "absl/container/internal/hashtable_control_bytes.h"
30
32
  #include "absl/container/internal/hashtablez_sampler.h"
33
+ #include "absl/container/internal/raw_hash_set_resize_impl.h"
34
+ #include "absl/functional/function_ref.h"
31
35
  #include "absl/hash/hash.h"
32
- #include "absl/numeric/bits.h"
33
36
 
34
37
  namespace absl {
35
38
  ABSL_NAMESPACE_BEGIN
@@ -38,48 +41,39 @@ namespace container_internal {
38
41
  // Represents a control byte corresponding to a full slot with arbitrary hash.
39
42
  constexpr ctrl_t ZeroCtrlT() { return static_cast<ctrl_t>(0); }
40
43
 
41
- // We have space for `growth_info` before a single block of control bytes. A
42
- // single block of empty control bytes for tables without any slots allocated.
43
- // This enables removing a branch in the hot path of find(). In order to ensure
44
- // that the control bytes are aligned to 16, we have 16 bytes before the control
45
- // bytes even though growth_info only needs 8.
46
- alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = {
47
- ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
48
- ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
49
- ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
50
- ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
51
- ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
52
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
53
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
54
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty};
55
-
56
- // We need one full byte followed by a sentinel byte for iterator::operator++ to
57
- // work. We have a full group after kSentinel to be safe (in case operator++ is
58
- // changed to read a full group).
59
- ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[17] = {
60
- ZeroCtrlT(), ctrl_t::kSentinel, ZeroCtrlT(), ctrl_t::kEmpty,
61
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
62
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
63
- ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
64
- ctrl_t::kEmpty};
65
- static_assert(NumControlBytes(SooCapacity()) <= 17,
66
- "kSooControl capacity too small");
67
-
68
- #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
69
- constexpr size_t Group::kWidth;
70
- #endif
44
+ // A single control byte for default-constructed iterators. We leave it
45
+ // uninitialized because reading this memory is a bug.
46
+ ABSL_DLL ctrl_t kDefaultIterControl;
47
+
48
+ // We need one full byte followed by a sentinel byte for iterator::operator++.
49
+ ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[2] = {ZeroCtrlT(),
50
+ ctrl_t::kSentinel};
71
51
 
72
52
  namespace {
73
53
 
54
+ #ifdef ABSL_SWISSTABLE_ASSERT
55
+ #error ABSL_SWISSTABLE_ASSERT cannot be directly set
56
+ #else
57
+ // We use this macro for assertions that users may see when the table is in an
58
+ // invalid state that sanitizers may help diagnose.
59
+ #define ABSL_SWISSTABLE_ASSERT(CONDITION) \
60
+ assert((CONDITION) && "Try enabling sanitizers.")
61
+ #endif
62
+
63
+ [[noreturn]] ABSL_ATTRIBUTE_NOINLINE void HashTableSizeOverflow() {
64
+ ABSL_RAW_LOG(FATAL, "Hash table size overflow");
65
+ }
66
+
67
+ void ValidateMaxSize(size_t size, size_t slot_size) {
68
+ if (IsAboveValidSize(size, slot_size)) {
69
+ HashTableSizeOverflow();
70
+ }
71
+ }
72
+
74
73
  // Returns "random" seed.
75
74
  inline size_t RandomSeed() {
76
75
  #ifdef ABSL_HAVE_THREAD_LOCAL
77
76
  static thread_local size_t counter = 0;
78
- // On Linux kernels >= 5.4 the MSAN runtime has a false-positive when
79
- // accessing thread local storage data from loaded libraries
80
- // (https://github.com/google/sanitizers/issues/1265), for this reason counter
81
- // needs to be annotated as initialized.
82
- ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(&counter, sizeof(size_t));
83
77
  size_t value = ++counter;
84
78
  #else // ABSL_HAVE_THREAD_LOCAL
85
79
  static std::atomic<size_t> counter(0);
@@ -88,24 +82,43 @@ inline size_t RandomSeed() {
88
82
  return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
89
83
  }
90
84
 
91
- bool ShouldRehashForBugDetection(const ctrl_t* ctrl, size_t capacity) {
85
+ bool ShouldRehashForBugDetection(size_t capacity) {
92
86
  // Note: we can't use the abseil-random library because abseil-random
93
87
  // depends on swisstable. We want to return true with probability
94
88
  // `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
95
89
  // we probe based on a random hash and see if the offset is less than
96
90
  // RehashProbabilityConstant().
97
- return probe(ctrl, capacity, absl::HashOf(RandomSeed())).offset() <
91
+ return probe(capacity, absl::HashOf(RandomSeed())).offset() <
98
92
  RehashProbabilityConstant();
99
93
  }
100
94
 
101
95
  // Find a non-deterministic hash for single group table.
102
96
  // Last two bits are used to find a position for a newly inserted element after
103
97
  // resize.
104
- // This function is mixing all bits of hash and control pointer to maximize
105
- // entropy.
106
- size_t SingleGroupTableH1(size_t hash, ctrl_t* control) {
107
- return static_cast<size_t>(absl::popcount(
108
- hash ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(control))));
98
+ // This function basically using H2 last bits to save on shift operation.
99
+ size_t SingleGroupTableH1(size_t hash, PerTableSeed seed) {
100
+ return hash ^ seed.seed();
101
+ }
102
+
103
+ // Returns the offset of the new element after resize from capacity 1 to 3.
104
+ size_t Resize1To3NewOffset(size_t hash, PerTableSeed seed) {
105
+ // After resize from capacity 1 to 3, we always have exactly the slot with
106
+ // index 1 occupied, so we need to insert either at index 0 or index 2.
107
+ static_assert(SooSlotIndex() == 1);
108
+ return SingleGroupTableH1(hash, seed) & 2;
109
+ }
110
+
111
+ // Returns the address of the slot `i` iterations after `slot` assuming each
112
+ // slot has the specified size.
113
+ inline void* NextSlot(void* slot, size_t slot_size, size_t i = 1) {
114
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) +
115
+ slot_size * i);
116
+ }
117
+
118
+ // Returns the address of the slot just before `slot` assuming each slot has the
119
+ // specified size.
120
+ inline void* PrevSlot(void* slot, size_t slot_size) {
121
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
109
122
  }
110
123
 
111
124
  } // namespace
@@ -121,42 +134,116 @@ GenerationType* EmptyGeneration() {
121
134
  }
122
135
 
123
136
  bool CommonFieldsGenerationInfoEnabled::
124
- should_rehash_for_bug_detection_on_insert(const ctrl_t* ctrl,
125
- size_t capacity) const {
137
+ should_rehash_for_bug_detection_on_insert(size_t capacity) const {
126
138
  if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
127
139
  if (reserved_growth_ > 0) return false;
128
- return ShouldRehashForBugDetection(ctrl, capacity);
140
+ return ShouldRehashForBugDetection(capacity);
129
141
  }
130
142
 
131
143
  bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
132
- const ctrl_t* ctrl, size_t capacity) const {
133
- return ShouldRehashForBugDetection(ctrl, capacity);
144
+ size_t capacity) const {
145
+ return ShouldRehashForBugDetection(capacity);
134
146
  }
135
147
 
136
- bool ShouldInsertBackwardsForDebug(size_t capacity, size_t hash,
137
- const ctrl_t* ctrl) {
138
- // To avoid problems with weak hashes and single bit tests, we use % 13.
139
- // TODO(kfm,sbenza): revisit after we do unconditional mixing
140
- return !is_small(capacity) && (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
148
+ namespace {
149
+
150
+ FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1,
151
+ size_t capacity) {
152
+ auto seq = probe_h1(capacity, h1);
153
+ if (IsEmptyOrDeleted(ctrl[seq.offset()])) {
154
+ return {seq.offset(), /*probe_length=*/0};
155
+ }
156
+ while (true) {
157
+ GroupFullEmptyOrDeleted g{ctrl + seq.offset()};
158
+ auto mask = g.MaskEmptyOrDeleted();
159
+ if (mask) {
160
+ return {seq.offset(mask.LowestBitSet()), seq.index()};
161
+ }
162
+ seq.next();
163
+ ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity && "full table!");
164
+ }
141
165
  }
142
166
 
143
- size_t PrepareInsertAfterSoo(size_t hash, size_t slot_size,
144
- CommonFields& common) {
145
- assert(common.capacity() == NextCapacity(SooCapacity()));
146
- // After resize from capacity 1 to 3, we always have exactly the slot with
147
- // index 1 occupied, so we need to insert either at index 0 or index 2.
148
- assert(HashSetResizeHelper::SooSlotIndex() == 1);
149
- PrepareInsertCommon(common);
150
- const size_t offset = SingleGroupTableH1(hash, common.control()) & 2;
151
- common.growth_info().OverwriteEmptyAsFull();
152
- SetCtrlInSingleGroupTable(common, offset, H2(hash), slot_size);
153
- common.infoz().RecordInsert(hash, /*distance_from_desired=*/0);
154
- return offset;
167
+ // Probes an array of control bits using a probe sequence derived from `hash`,
168
+ // and returns the offset corresponding to the first deleted or empty slot.
169
+ //
170
+ // Behavior when the entire table is full is undefined.
171
+ //
172
+ // NOTE: this function must work with tables having both empty and deleted
173
+ // slots in the same group. Such tables appear during `erase()`.
174
+ FindInfo find_first_non_full(const CommonFields& common, size_t hash) {
175
+ return find_first_non_full_from_h1(common.control(), H1(hash),
176
+ common.capacity());
155
177
  }
156
178
 
179
+ // Whether a table fits in half a group. A half-group table fits entirely into a
180
+ // probing group, i.e., has a capacity < `Group::kWidth`.
181
+ //
182
+ // In half-group mode we are able to use the whole capacity. The extra control
183
+ // bytes give us at least one "empty" control byte to stop the iteration.
184
+ // This is important to make 1 a valid capacity.
185
+ //
186
+ // In half-group mode only the first `capacity` control bytes after the sentinel
187
+ // are valid. The rest contain dummy ctrl_t::kEmpty values that do not
188
+ // represent a real slot.
189
+ constexpr bool is_half_group(size_t capacity) {
190
+ return capacity < Group::kWidth - 1;
191
+ }
192
+
193
+ template <class Fn>
194
+ void IterateOverFullSlotsImpl(const CommonFields& c, size_t slot_size, Fn cb) {
195
+ const size_t cap = c.capacity();
196
+ ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(cap));
197
+ const ctrl_t* ctrl = c.control();
198
+ void* slot = c.slot_array();
199
+ if (is_half_group(cap)) {
200
+ // Mirrored/cloned control bytes in half-group table are also located in the
201
+ // first group (starting from position 0). We are taking group from position
202
+ // `capacity` in order to avoid duplicates.
203
+
204
+ // Half-group tables capacity fits into portable group, where
205
+ // GroupPortableImpl::MaskFull is more efficient for the
206
+ // capacity <= GroupPortableImpl::kWidth.
207
+ ABSL_SWISSTABLE_ASSERT(cap <= GroupPortableImpl::kWidth &&
208
+ "unexpectedly large half-group capacity");
209
+ static_assert(Group::kWidth >= GroupPortableImpl::kWidth,
210
+ "unexpected group width");
211
+ // Group starts from kSentinel slot, so indices in the mask will
212
+ // be increased by 1.
213
+ const auto mask = GroupPortableImpl(ctrl + cap).MaskFull();
214
+ --ctrl;
215
+ slot = PrevSlot(slot, slot_size);
216
+ for (uint32_t i : mask) {
217
+ cb(ctrl + i, SlotAddress(slot, i, slot_size));
218
+ }
219
+ return;
220
+ }
221
+ size_t remaining = c.size();
222
+ ABSL_ATTRIBUTE_UNUSED const size_t original_size_for_assert = remaining;
223
+ while (remaining != 0) {
224
+ for (uint32_t i : GroupFullEmptyOrDeleted(ctrl).MaskFull()) {
225
+ ABSL_SWISSTABLE_ASSERT(IsFull(ctrl[i]) &&
226
+ "hash table was modified unexpectedly");
227
+ cb(ctrl + i, SlotAddress(slot, i, slot_size));
228
+ --remaining;
229
+ }
230
+ ctrl += Group::kWidth;
231
+ slot = NextSlot(slot, slot_size, Group::kWidth);
232
+ ABSL_SWISSTABLE_ASSERT(
233
+ (remaining == 0 || *(ctrl - 1) != ctrl_t::kSentinel) &&
234
+ "hash table was modified unexpectedly");
235
+ }
236
+ // NOTE: erasure of the current element is allowed in callback for
237
+ // absl::erase_if specialization. So we use `>=`.
238
+ ABSL_SWISSTABLE_ASSERT(original_size_for_assert >= c.size() &&
239
+ "hash table was modified unexpectedly");
240
+ }
241
+
242
+ } // namespace
243
+
157
244
  void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
158
- assert(ctrl[capacity] == ctrl_t::kSentinel);
159
- assert(IsValidCapacity(capacity));
245
+ ABSL_SWISSTABLE_ASSERT(ctrl[capacity] == ctrl_t::kSentinel);
246
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
160
247
  for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) {
161
248
  Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
162
249
  }
@@ -164,26 +251,20 @@ void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
164
251
  std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes());
165
252
  ctrl[capacity] = ctrl_t::kSentinel;
166
253
  }
167
- // Extern template instantiation for inline function.
168
- template FindInfo find_first_non_full(const CommonFields&, size_t);
169
254
 
170
- FindInfo find_first_non_full_outofline(const CommonFields& common,
171
- size_t hash) {
172
- return find_first_non_full(common, hash);
255
+ void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
256
+ absl::FunctionRef<void(const ctrl_t*, void*)> cb) {
257
+ IterateOverFullSlotsImpl(c, slot_size, cb);
173
258
  }
174
259
 
175
260
  namespace {
176
261
 
177
- // Returns the address of the slot just after slot assuming each slot has the
178
- // specified size.
179
- static inline void* NextSlot(void* slot, size_t slot_size) {
180
- return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) + slot_size);
262
+ void ResetGrowthLeft(GrowthInfo& growth_info, size_t capacity, size_t size) {
263
+ growth_info.InitGrowthLeftNoDeleted(CapacityToGrowth(capacity) - size);
181
264
  }
182
265
 
183
- // Returns the address of the slot just before slot assuming each slot has the
184
- // specified size.
185
- static inline void* PrevSlot(void* slot, size_t slot_size) {
186
- return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
266
+ void ResetGrowthLeft(CommonFields& common) {
267
+ ResetGrowthLeft(common.growth_info(), common.capacity(), common.size());
187
268
  }
188
269
 
189
270
  // Finds guaranteed to exists empty slot from the given position.
@@ -196,17 +277,34 @@ size_t FindEmptySlot(size_t start, size_t end, const ctrl_t* ctrl) {
196
277
  return i;
197
278
  }
198
279
  }
199
- assert(false && "no empty slot");
200
- return ~size_t{};
280
+ ABSL_UNREACHABLE();
201
281
  }
202
282
 
203
- void DropDeletesWithoutResize(CommonFields& common,
204
- const PolicyFunctions& policy) {
283
+ // Finds guaranteed to exist full slot starting from the given position.
284
+ // NOTE: this function is only triggered for rehash(0), when we need to
285
+ // go back to SOO state, so we keep it simple.
286
+ size_t FindFirstFullSlot(size_t start, size_t end, const ctrl_t* ctrl) {
287
+ for (size_t i = start; i < end; ++i) {
288
+ if (IsFull(ctrl[i])) {
289
+ return i;
290
+ }
291
+ }
292
+ ABSL_UNREACHABLE();
293
+ }
294
+
295
+ void PrepareInsertCommon(CommonFields& common) {
296
+ common.increment_size();
297
+ common.maybe_increment_generation_on_insert();
298
+ }
299
+
300
+ size_t DropDeletesWithoutResizeAndPrepareInsert(
301
+ CommonFields& common, const PolicyFunctions& __restrict policy,
302
+ size_t new_hash) {
205
303
  void* set = &common;
206
304
  void* slot_array = common.slot_array();
207
305
  const size_t capacity = common.capacity();
208
- assert(IsValidCapacity(capacity));
209
- assert(!is_small(capacity));
306
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
307
+ ABSL_SWISSTABLE_ASSERT(!is_single_group(capacity));
210
308
  // Algorithm:
211
309
  // - mark all DELETED slots as EMPTY
212
310
  // - mark all FULL slots as DELETED
@@ -227,7 +325,7 @@ void DropDeletesWithoutResize(CommonFields& common,
227
325
  ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity);
228
326
  const void* hash_fn = policy.hash_fn(common);
229
327
  auto hasher = policy.hash_slot;
230
- auto transfer = policy.transfer;
328
+ auto transfer_n = policy.transfer_n;
231
329
  const size_t slot_size = policy.slot_size;
232
330
 
233
331
  size_t total_probe_length = 0;
@@ -240,13 +338,13 @@ void DropDeletesWithoutResize(CommonFields& common,
240
338
 
241
339
  for (size_t i = 0; i != capacity;
242
340
  ++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
243
- assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
341
+ ABSL_SWISSTABLE_ASSERT(slot_ptr == SlotAddress(slot_array, i, slot_size));
244
342
  if (IsEmpty(ctrl[i])) {
245
343
  tmp_space_id = i;
246
344
  continue;
247
345
  }
248
346
  if (!IsDeleted(ctrl[i])) continue;
249
- const size_t hash = (*hasher)(hash_fn, slot_ptr);
347
+ const size_t hash = (*hasher)(hash_fn, slot_ptr, common.seed().seed());
250
348
  const FindInfo target = find_first_non_full(common, hash);
251
349
  const size_t new_i = target.offset;
252
350
  total_probe_length += target.probe_length;
@@ -255,13 +353,14 @@ void DropDeletesWithoutResize(CommonFields& common,
255
353
  // If they do, we don't need to move the object as it falls already in the
256
354
  // best probe we can.
257
355
  const size_t probe_offset = probe(common, hash).offset();
356
+ const h2_t h2 = H2(hash);
258
357
  const auto probe_index = [probe_offset, capacity](size_t pos) {
259
358
  return ((pos - probe_offset) & capacity) / Group::kWidth;
260
359
  };
261
360
 
262
361
  // Element doesn't move.
263
362
  if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
264
- SetCtrl(common, i, H2(hash), slot_size);
363
+ SetCtrlInLargeTable(common, i, h2, slot_size);
265
364
  continue;
266
365
  }
267
366
 
@@ -270,14 +369,14 @@ void DropDeletesWithoutResize(CommonFields& common,
270
369
  // Transfer element to the empty spot.
271
370
  // SetCtrl poisons/unpoisons the slots so we have to call it at the
272
371
  // right time.
273
- SetCtrl(common, new_i, H2(hash), slot_size);
274
- (*transfer)(set, new_slot_ptr, slot_ptr);
275
- SetCtrl(common, i, ctrl_t::kEmpty, slot_size);
372
+ SetCtrlInLargeTable(common, new_i, h2, slot_size);
373
+ (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
374
+ SetCtrlInLargeTable(common, i, ctrl_t::kEmpty, slot_size);
276
375
  // Initialize or change empty space id.
277
376
  tmp_space_id = i;
278
377
  } else {
279
- assert(IsDeleted(ctrl[new_i]));
280
- SetCtrl(common, new_i, H2(hash), slot_size);
378
+ ABSL_SWISSTABLE_ASSERT(IsDeleted(ctrl[new_i]));
379
+ SetCtrlInLargeTable(common, new_i, h2, slot_size);
281
380
  // Until we are done rehashing, DELETED marks previously FULL slots.
282
381
 
283
382
  if (tmp_space_id == kUnknownId) {
@@ -287,9 +386,9 @@ void DropDeletesWithoutResize(CommonFields& common,
287
386
  SanitizerUnpoisonMemoryRegion(tmp_space, slot_size);
288
387
 
289
388
  // Swap i and new_i elements.
290
- (*transfer)(set, tmp_space, new_slot_ptr);
291
- (*transfer)(set, new_slot_ptr, slot_ptr);
292
- (*transfer)(set, slot_ptr, tmp_space);
389
+ (*transfer_n)(set, tmp_space, new_slot_ptr, 1);
390
+ (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
391
+ (*transfer_n)(set, slot_ptr, tmp_space, 1);
293
392
 
294
393
  SanitizerPoisonMemoryRegion(tmp_space, slot_size);
295
394
 
@@ -298,11 +397,17 @@ void DropDeletesWithoutResize(CommonFields& common,
298
397
  slot_ptr = PrevSlot(slot_ptr, slot_size);
299
398
  }
300
399
  }
400
+ // Prepare insert for the new element.
401
+ PrepareInsertCommon(common);
301
402
  ResetGrowthLeft(common);
403
+ FindInfo find_info = find_first_non_full(common, new_hash);
404
+ SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), slot_size);
405
+ common.infoz().RecordInsert(new_hash, find_info.probe_length);
302
406
  common.infoz().RecordRehash(total_probe_length);
407
+ return find_info.offset;
303
408
  }
304
409
 
305
- static bool WasNeverFull(CommonFields& c, size_t index) {
410
+ bool WasNeverFull(CommonFields& c, size_t index) {
306
411
  if (is_single_group(c.capacity())) {
307
412
  return true;
308
413
  }
@@ -319,13 +424,116 @@ static bool WasNeverFull(CommonFields& c, size_t index) {
319
424
  Group::kWidth;
320
425
  }
321
426
 
427
+ // Updates the control bytes to indicate a completely empty table such that all
428
+ // control bytes are kEmpty except for the kSentinel byte.
429
+ void ResetCtrl(CommonFields& common, size_t slot_size) {
430
+ const size_t capacity = common.capacity();
431
+ ctrl_t* ctrl = common.control();
432
+ static constexpr size_t kTwoGroupCapacity = 2 * Group::kWidth - 1;
433
+ if (ABSL_PREDICT_TRUE(capacity <= kTwoGroupCapacity)) {
434
+ if (IsSmallCapacity(capacity)) return;
435
+ std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
436
+ std::memset(ctrl + capacity, static_cast<int8_t>(ctrl_t::kEmpty),
437
+ Group::kWidth);
438
+ if (capacity == kTwoGroupCapacity) {
439
+ std::memset(ctrl + Group::kWidth, static_cast<int8_t>(ctrl_t::kEmpty),
440
+ Group::kWidth);
441
+ }
442
+ } else {
443
+ std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
444
+ capacity + 1 + NumClonedBytes());
445
+ }
446
+ ctrl[capacity] = ctrl_t::kSentinel;
447
+ SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity);
448
+ }
449
+
450
+ // Initializes control bytes for growing from capacity 1 to 3.
451
+ // `orig_h2` is placed in the position `SooSlotIndex()`.
452
+ // `new_h2` is placed in the position `new_offset`.
453
+ ABSL_ATTRIBUTE_ALWAYS_INLINE inline void InitializeThreeElementsControlBytes(
454
+ h2_t orig_h2, h2_t new_h2, size_t new_offset, ctrl_t* new_ctrl) {
455
+ static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
456
+ static_assert(kNewCapacity == 3);
457
+ static_assert(is_single_group(kNewCapacity));
458
+ static_assert(SooSlotIndex() == 1);
459
+ ABSL_SWISSTABLE_ASSERT(new_offset == 0 || new_offset == 2);
460
+
461
+ static constexpr uint64_t kEmptyXorSentinel =
462
+ static_cast<uint8_t>(ctrl_t::kEmpty) ^
463
+ static_cast<uint8_t>(ctrl_t::kSentinel);
464
+ static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
465
+ static constexpr size_t kMirroredSooSlotIndex =
466
+ SooSlotIndex() + kNewCapacity + 1;
467
+ // The first 8 bytes, where SOO slot original and mirrored positions are
468
+ // replaced with 0.
469
+ // Result will look like: E0ESE0EE
470
+ static constexpr uint64_t kFirstCtrlBytesWithZeroes =
471
+ k8EmptyBytes ^ (kEmpty64 << (8 * SooSlotIndex())) ^
472
+ (kEmptyXorSentinel << (8 * kNewCapacity)) ^
473
+ (kEmpty64 << (8 * kMirroredSooSlotIndex));
474
+
475
+ const uint64_t soo_h2 = static_cast<uint64_t>(orig_h2);
476
+ const uint64_t new_h2_xor_empty =
477
+ static_cast<uint64_t>(new_h2 ^ static_cast<uint8_t>(ctrl_t::kEmpty));
478
+ // Fill the original and mirrored bytes for SOO slot.
479
+ // Result will look like:
480
+ // EHESEHEE
481
+ // Where H = soo_h2, E = kEmpty, S = kSentinel.
482
+ uint64_t first_ctrl_bytes =
483
+ ((soo_h2 << (8 * SooSlotIndex())) | kFirstCtrlBytesWithZeroes) |
484
+ (soo_h2 << (8 * kMirroredSooSlotIndex));
485
+ // Replace original and mirrored empty bytes for the new position.
486
+ // Result for new_offset 0 will look like:
487
+ // NHESNHEE
488
+ // Where H = soo_h2, N = H2(new_hash), E = kEmpty, S = kSentinel.
489
+ // Result for new_offset 2 will look like:
490
+ // EHNSEHNE
491
+ first_ctrl_bytes ^= (new_h2_xor_empty << (8 * new_offset));
492
+ size_t new_mirrored_offset = new_offset + kNewCapacity + 1;
493
+ first_ctrl_bytes ^= (new_h2_xor_empty << (8 * new_mirrored_offset));
494
+
495
+ // Fill last bytes with kEmpty.
496
+ std::memset(new_ctrl + kNewCapacity, static_cast<int8_t>(ctrl_t::kEmpty),
497
+ Group::kWidth);
498
+ // Overwrite the first 8 bytes with first_ctrl_bytes.
499
+ absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
500
+
501
+ // Example for group size 16:
502
+ // new_ctrl after 1st memset = ???EEEEEEEEEEEEEEEE
503
+ // new_offset 0:
504
+ // new_ctrl after 2nd store = NHESNHEEEEEEEEEEEEE
505
+ // new_offset 2:
506
+ // new_ctrl after 2nd store = EHNSEHNEEEEEEEEEEEE
507
+
508
+ // Example for group size 8:
509
+ // new_ctrl after 1st memset = ???EEEEEEEE
510
+ // new_offset 0:
511
+ // new_ctrl after 2nd store = NHESNHEEEEE
512
+ // new_offset 2:
513
+ // new_ctrl after 2nd store = EHNSEHNEEEE
514
+ }
515
+
322
516
  } // namespace
323
517
 
324
- void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
325
- assert(IsFull(c.control()[index]) && "erasing a dangling iterator");
518
+ void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size) {
519
+ ABSL_SWISSTABLE_ASSERT(c.is_small());
520
+ if (soo_enabled) {
521
+ c.set_empty_soo();
522
+ return;
523
+ }
524
+ c.decrement_size();
525
+ c.infoz().RecordErase();
526
+ SanitizerPoisonMemoryRegion(c.slot_array(), slot_size);
527
+ }
528
+
529
+ void EraseMetaOnlyLarge(CommonFields& c, const ctrl_t* ctrl, size_t slot_size) {
530
+ ABSL_SWISSTABLE_ASSERT(!c.is_small());
531
+ ABSL_SWISSTABLE_ASSERT(IsFull(*ctrl) && "erasing a dangling iterator");
326
532
  c.decrement_size();
327
533
  c.infoz().RecordErase();
328
534
 
535
+ size_t index = static_cast<size_t>(ctrl - c.control());
536
+
329
537
  if (WasNeverFull(c, index)) {
330
538
  SetCtrl(c, index, ctrl_t::kEmpty, slot_size);
331
539
  c.growth_info().OverwriteFullAsEmpty();
@@ -333,14 +541,15 @@ void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
333
541
  }
334
542
 
335
543
  c.growth_info().OverwriteFullAsDeleted();
336
- SetCtrl(c, index, ctrl_t::kDeleted, slot_size);
544
+ SetCtrlInLargeTable(c, index, ctrl_t::kDeleted, slot_size);
337
545
  }
338
546
 
339
- void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
547
+ void ClearBackingArray(CommonFields& c,
548
+ const PolicyFunctions& __restrict policy, void* alloc,
340
549
  bool reuse, bool soo_enabled) {
341
- c.set_size(0);
342
550
  if (reuse) {
343
- assert(!soo_enabled || c.capacity() > SooCapacity());
551
+ c.set_size_to_zero();
552
+ ABSL_SWISSTABLE_ASSERT(!soo_enabled || c.capacity() > SooCapacity());
344
553
  ResetCtrl(c, policy.slot_size);
345
554
  ResetGrowthLeft(c);
346
555
  c.infoz().RecordStorageChanged(0, c.capacity());
@@ -349,17 +558,280 @@ void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
349
558
  // infoz.
350
559
  c.infoz().RecordClearedReservation();
351
560
  c.infoz().RecordStorageChanged(0, soo_enabled ? SooCapacity() : 0);
352
- (*policy.dealloc)(c, policy);
561
+ c.infoz().Unregister();
562
+ (*policy.dealloc)(alloc, c.capacity(), c.control(), policy.slot_size,
563
+ policy.slot_align, c.has_infoz());
353
564
  c = soo_enabled ? CommonFields{soo_tag_t{}} : CommonFields{non_soo_tag_t{}};
354
565
  }
355
566
  }
356
567
 
357
- void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
358
- ctrl_t* __restrict new_ctrl, size_t new_capacity) const {
359
- assert(is_single_group(new_capacity));
568
+ namespace {
569
+
570
+ enum class ResizeNonSooMode {
571
+ kGuaranteedEmpty,
572
+ kGuaranteedAllocated,
573
+ };
574
+
575
+ // Iterates over full slots in old table, finds new positions for them and
576
+ // transfers the slots.
577
+ // This function is used for reserving or rehashing non-empty tables.
578
+ // This use case is rare so the function is type erased.
579
+ // Returns the total probe length.
580
+ size_t FindNewPositionsAndTransferSlots(
581
+ CommonFields& common, const PolicyFunctions& __restrict policy,
582
+ ctrl_t* old_ctrl, void* old_slots, size_t old_capacity) {
583
+ void* new_slots = common.slot_array();
584
+ const void* hash_fn = policy.hash_fn(common);
585
+ const size_t slot_size = policy.slot_size;
586
+ const size_t seed = common.seed().seed();
587
+
588
+ const auto insert_slot = [&](void* slot) {
589
+ size_t hash = policy.hash_slot(hash_fn, slot, seed);
590
+ FindInfo target;
591
+ if (common.is_small()) {
592
+ target = FindInfo{0, 0};
593
+ } else {
594
+ target = find_first_non_full(common, hash);
595
+ SetCtrl(common, target.offset, H2(hash), slot_size);
596
+ }
597
+ policy.transfer_n(&common, SlotAddress(new_slots, target.offset, slot_size),
598
+ slot, 1);
599
+ return target.probe_length;
600
+ };
601
+ if (IsSmallCapacity(old_capacity)) {
602
+ if (common.size() == 1) insert_slot(old_slots);
603
+ return 0;
604
+ }
605
+ size_t total_probe_length = 0;
606
+ for (size_t i = 0; i < old_capacity; ++i) {
607
+ if (IsFull(old_ctrl[i])) {
608
+ total_probe_length += insert_slot(old_slots);
609
+ }
610
+ old_slots = NextSlot(old_slots, slot_size);
611
+ }
612
+ return total_probe_length;
613
+ }
614
+
615
+ void ReportGrowthToInfozImpl(CommonFields& common, HashtablezInfoHandle infoz,
616
+ size_t hash, size_t total_probe_length,
617
+ size_t distance_from_desired) {
618
+ ABSL_SWISSTABLE_ASSERT(infoz.IsSampled());
619
+ infoz.RecordStorageChanged(common.size() - 1, common.capacity());
620
+ infoz.RecordRehash(total_probe_length);
621
+ infoz.RecordInsert(hash, distance_from_desired);
622
+ common.set_has_infoz();
623
+ // TODO(b/413062340): we could potentially store infoz in place of the
624
+ // control pointer for the capacity 1 case.
625
+ common.set_infoz(infoz);
626
+ }
627
+
628
+ // Specialization to avoid passing two 0s from hot function.
629
+ ABSL_ATTRIBUTE_NOINLINE void ReportSingleGroupTableGrowthToInfoz(
630
+ CommonFields& common, HashtablezInfoHandle infoz, size_t hash) {
631
+ ReportGrowthToInfozImpl(common, infoz, hash, /*total_probe_length=*/0,
632
+ /*distance_from_desired=*/0);
633
+ }
634
+
635
+ ABSL_ATTRIBUTE_NOINLINE void ReportGrowthToInfoz(CommonFields& common,
636
+ HashtablezInfoHandle infoz,
637
+ size_t hash,
638
+ size_t total_probe_length,
639
+ size_t distance_from_desired) {
640
+ ReportGrowthToInfozImpl(common, infoz, hash, total_probe_length,
641
+ distance_from_desired);
642
+ }
643
+
644
+ ABSL_ATTRIBUTE_NOINLINE void ReportResizeToInfoz(CommonFields& common,
645
+ HashtablezInfoHandle infoz,
646
+ size_t total_probe_length) {
647
+ ABSL_SWISSTABLE_ASSERT(infoz.IsSampled());
648
+ infoz.RecordStorageChanged(common.size(), common.capacity());
649
+ infoz.RecordRehash(total_probe_length);
650
+ common.set_has_infoz();
651
+ common.set_infoz(infoz);
652
+ }
653
+
654
+ struct BackingArrayPtrs {
655
+ ctrl_t* ctrl;
656
+ void* slots;
657
+ };
658
+
659
+ BackingArrayPtrs AllocBackingArray(CommonFields& common,
660
+ const PolicyFunctions& __restrict policy,
661
+ size_t new_capacity, bool has_infoz,
662
+ void* alloc) {
663
+ RawHashSetLayout layout(new_capacity, policy.slot_size, policy.slot_align,
664
+ has_infoz);
665
+ char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
666
+ const GenerationType old_generation = common.generation();
667
+ common.set_generation_ptr(
668
+ reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
669
+ common.set_generation(NextGeneration(old_generation));
670
+
671
+ return {reinterpret_cast<ctrl_t*>(mem + layout.control_offset()),
672
+ mem + layout.slot_offset()};
673
+ }
674
+
675
+ template <ResizeNonSooMode kMode>
676
+ void ResizeNonSooImpl(CommonFields& common,
677
+ const PolicyFunctions& __restrict policy,
678
+ size_t new_capacity, HashtablezInfoHandle infoz) {
679
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
680
+ ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
681
+
682
+ [[maybe_unused]] const size_t old_capacity = common.capacity();
683
+ [[maybe_unused]] ctrl_t* old_ctrl;
684
+ [[maybe_unused]] void* old_slots;
685
+ if constexpr (kMode == ResizeNonSooMode::kGuaranteedAllocated) {
686
+ old_ctrl = common.control();
687
+ old_slots = common.slot_array();
688
+ }
689
+
690
+ const size_t slot_size = policy.slot_size;
691
+ [[maybe_unused]] const size_t slot_align = policy.slot_align;
692
+ const bool has_infoz = infoz.IsSampled();
693
+ void* alloc = policy.get_char_alloc(common);
694
+
695
+ common.set_capacity(new_capacity);
696
+ const auto [new_ctrl, new_slots] =
697
+ AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
698
+ common.set_control(new_ctrl);
699
+ common.set_slots(new_slots);
700
+ common.generate_new_seed(has_infoz);
701
+
702
+ size_t total_probe_length = 0;
703
+ ResetCtrl(common, slot_size);
704
+ ABSL_SWISSTABLE_ASSERT(kMode != ResizeNonSooMode::kGuaranteedEmpty ||
705
+ old_capacity == policy.soo_capacity());
706
+ ABSL_SWISSTABLE_ASSERT(kMode != ResizeNonSooMode::kGuaranteedAllocated ||
707
+ old_capacity > 0);
708
+ if constexpr (kMode == ResizeNonSooMode::kGuaranteedAllocated) {
709
+ total_probe_length = FindNewPositionsAndTransferSlots(
710
+ common, policy, old_ctrl, old_slots, old_capacity);
711
+ (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
712
+ has_infoz);
713
+ ResetGrowthLeft(GetGrowthInfoFromControl(new_ctrl), new_capacity,
714
+ common.size());
715
+ } else {
716
+ GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(
717
+ CapacityToGrowth(new_capacity));
718
+ }
719
+
720
+ if (ABSL_PREDICT_FALSE(has_infoz)) {
721
+ ReportResizeToInfoz(common, infoz, total_probe_length);
722
+ }
723
+ }
724
+
725
+ void ResizeEmptyNonAllocatedTableImpl(CommonFields& common,
726
+ const PolicyFunctions& __restrict policy,
727
+ size_t new_capacity, bool force_infoz) {
728
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
729
+ ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
730
+ ABSL_SWISSTABLE_ASSERT(!force_infoz || policy.soo_enabled);
731
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= policy.soo_capacity());
732
+ ABSL_SWISSTABLE_ASSERT(common.empty());
733
+ const size_t slot_size = policy.slot_size;
734
+ HashtablezInfoHandle infoz;
735
+ const bool should_sample =
736
+ policy.is_hashtablez_eligible && (force_infoz || ShouldSampleNextTable());
737
+ if (ABSL_PREDICT_FALSE(should_sample)) {
738
+ infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
739
+ policy.soo_capacity());
740
+ }
741
+ ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedEmpty>(common, policy,
742
+ new_capacity, infoz);
743
+ }
744
+
745
+ // If the table was SOO, initializes new control bytes and transfers slot.
746
+ // After transferring the slot, sets control and slots in CommonFields.
747
+ // It is rare to resize an SOO table with one element to a large size.
748
+ // Requires: `c` contains SOO data.
749
+ void InsertOldSooSlotAndInitializeControlBytes(
750
+ CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* new_ctrl,
751
+ void* new_slots, bool has_infoz) {
752
+ ABSL_SWISSTABLE_ASSERT(c.size() == policy.soo_capacity());
753
+ ABSL_SWISSTABLE_ASSERT(policy.soo_enabled);
754
+ size_t new_capacity = c.capacity();
755
+
756
+ c.generate_new_seed(has_infoz);
757
+
758
+ const size_t soo_slot_hash =
759
+ policy.hash_slot(policy.hash_fn(c), c.soo_data(), c.seed().seed());
760
+ size_t offset = probe(new_capacity, soo_slot_hash).offset();
761
+ offset = offset == new_capacity ? 0 : offset;
762
+ SanitizerPoisonMemoryRegion(new_slots, policy.slot_size * new_capacity);
763
+ void* target_slot = SlotAddress(new_slots, offset, policy.slot_size);
764
+ SanitizerUnpoisonMemoryRegion(target_slot, policy.slot_size);
765
+ policy.transfer_n(&c, target_slot, c.soo_data(), 1);
766
+ c.set_control(new_ctrl);
767
+ c.set_slots(new_slots);
768
+ ResetCtrl(c, policy.slot_size);
769
+ SetCtrl(c, offset, H2(soo_slot_hash), policy.slot_size);
770
+ }
771
+
772
+ enum class ResizeFullSooTableSamplingMode {
773
+ kNoSampling,
774
+ // Force sampling. If the table was still not sampled, do not resize.
775
+ kForceSampleNoResizeIfUnsampled,
776
+ };
777
+
778
+ void AssertSoo([[maybe_unused]] CommonFields& common,
779
+ [[maybe_unused]] const PolicyFunctions& policy) {
780
+ ABSL_SWISSTABLE_ASSERT(policy.soo_enabled);
781
+ ABSL_SWISSTABLE_ASSERT(common.capacity() == policy.soo_capacity());
782
+ }
783
+ void AssertFullSoo([[maybe_unused]] CommonFields& common,
784
+ [[maybe_unused]] const PolicyFunctions& policy) {
785
+ AssertSoo(common, policy);
786
+ ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity());
787
+ }
788
+
789
+ void ResizeFullSooTable(CommonFields& common,
790
+ const PolicyFunctions& __restrict policy,
791
+ size_t new_capacity,
792
+ ResizeFullSooTableSamplingMode sampling_mode) {
793
+ AssertFullSoo(common, policy);
794
+ const size_t slot_size = policy.slot_size;
795
+ void* alloc = policy.get_char_alloc(common);
796
+
797
+ HashtablezInfoHandle infoz;
798
+ bool has_infoz = false;
799
+ if (sampling_mode ==
800
+ ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled) {
801
+ if (ABSL_PREDICT_FALSE(policy.is_hashtablez_eligible)) {
802
+ infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
803
+ policy.soo_capacity());
804
+ }
805
+
806
+ if (!infoz.IsSampled()) return;
807
+ has_infoz = true;
808
+ }
809
+
810
+ common.set_capacity(new_capacity);
811
+
812
+ // We do not set control and slots in CommonFields yet to avoid overriding
813
+ // SOO data.
814
+ const auto [new_ctrl, new_slots] =
815
+ AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
816
+
817
+ InsertOldSooSlotAndInitializeControlBytes(common, policy, new_ctrl, new_slots,
818
+ has_infoz);
819
+ ResetGrowthLeft(common);
820
+ if (has_infoz) {
821
+ common.set_has_infoz();
822
+ common.set_infoz(infoz);
823
+ infoz.RecordStorageChanged(common.size(), new_capacity);
824
+ }
825
+ }
826
+
827
+ void GrowIntoSingleGroupShuffleControlBytes(ctrl_t* __restrict old_ctrl,
828
+ size_t old_capacity,
829
+ ctrl_t* __restrict new_ctrl,
830
+ size_t new_capacity) {
831
+ ABSL_SWISSTABLE_ASSERT(is_single_group(new_capacity));
360
832
  constexpr size_t kHalfWidth = Group::kWidth / 2;
361
- ABSL_ASSUME(old_capacity_ < kHalfWidth);
362
- ABSL_ASSUME(old_capacity_ > 0);
833
+ ABSL_ASSUME(old_capacity < kHalfWidth);
834
+ ABSL_ASSUME(old_capacity > 0);
363
835
  static_assert(Group::kWidth == 8 || Group::kWidth == 16,
364
836
  "Group size is not supported.");
365
837
 
@@ -373,8 +845,7 @@ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
373
845
  // Example:
374
846
  // old_ctrl = 012S012EEEEEEEEE...
375
847
  // copied_bytes = S012EEEE
376
- uint64_t copied_bytes =
377
- absl::little_endian::Load64(old_ctrl() + old_capacity_);
848
+ uint64_t copied_bytes = absl::little_endian::Load64(old_ctrl + old_capacity);
378
849
 
379
850
  // We change the sentinel byte to kEmpty before storing to both the start of
380
851
  // the new_ctrl, and past the end of the new_ctrl later for the new cloned
@@ -395,7 +866,8 @@ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
395
866
 
396
867
  if (Group::kWidth == 8) {
397
868
  // With group size 8, we can grow with two write operations.
398
- assert(old_capacity_ < 8 && "old_capacity_ is too large for group size 8");
869
+ ABSL_SWISSTABLE_ASSERT(old_capacity < 8 &&
870
+ "old_capacity is too large for group size 8");
399
871
  absl::little_endian::Store64(new_ctrl, copied_bytes);
400
872
 
401
873
  static constexpr uint64_t kSentinal64 =
@@ -421,7 +893,7 @@ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
421
893
  return;
422
894
  }
423
895
 
424
- assert(Group::kWidth == 16);
896
+ ABSL_SWISSTABLE_ASSERT(Group::kWidth == 16); // NOLINT(misc-static-assert)
425
897
 
426
898
  // Fill the second half of the main control bytes with kEmpty.
427
899
  // For small capacity that may write into mirrored control bytes.
@@ -463,7 +935,6 @@ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
463
935
  // >!
464
936
  // new_ctrl after 2nd store = E012EEESE012EEEEEEEEEEE
465
937
 
466
-
467
938
  // Example for growth capacity 7->15:
468
939
  // old_ctrl = 0123456S0123456EEEEEEEE
469
940
  // new_ctrl at the end = E0123456EEEEEEESE0123456EEEEEEE
@@ -478,58 +949,520 @@ void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
478
949
  // new_ctrl after 2nd store = E0123456EEEEEEESE0123456EEEEEEE
479
950
  }
480
951
 
481
- void HashSetResizeHelper::InitControlBytesAfterSoo(ctrl_t* new_ctrl, ctrl_t h2,
482
- size_t new_capacity) {
483
- assert(is_single_group(new_capacity));
484
- std::memset(new_ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
485
- NumControlBytes(new_capacity));
486
- assert(HashSetResizeHelper::SooSlotIndex() == 1);
487
- // This allows us to avoid branching on had_soo_slot_.
488
- assert(had_soo_slot_ || h2 == ctrl_t::kEmpty);
489
- new_ctrl[1] = new_ctrl[new_capacity + 2] = h2;
952
+ // Size of the buffer we allocate on stack for storing probed elements in
953
+ // GrowToNextCapacity algorithm.
954
+ constexpr size_t kProbedElementsBufferSize = 512;
955
+
956
+ // Decodes information about probed elements from contiguous memory.
957
+ // Finds new position for each element and transfers it to the new slots.
958
+ // Returns the total probe length.
959
+ template <typename ProbedItem>
960
+ ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl(
961
+ CommonFields& c, const PolicyFunctions& __restrict policy,
962
+ const ProbedItem* start, const ProbedItem* end, void* old_slots) {
963
+ const size_t new_capacity = c.capacity();
964
+
965
+ void* new_slots = c.slot_array();
966
+ ctrl_t* new_ctrl = c.control();
967
+ size_t total_probe_length = 0;
968
+
969
+ const size_t slot_size = policy.slot_size;
970
+ auto transfer_n = policy.transfer_n;
971
+
972
+ for (; start < end; ++start) {
973
+ const FindInfo target = find_first_non_full_from_h1(
974
+ new_ctrl, static_cast<size_t>(start->h1), new_capacity);
975
+ total_probe_length += target.probe_length;
976
+ const size_t old_index = static_cast<size_t>(start->source_offset);
977
+ const size_t new_i = target.offset;
978
+ ABSL_SWISSTABLE_ASSERT(old_index < new_capacity / 2);
979
+ ABSL_SWISSTABLE_ASSERT(new_i < new_capacity);
980
+ ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_i]));
981
+ void* src_slot = SlotAddress(old_slots, old_index, slot_size);
982
+ void* dst_slot = SlotAddress(new_slots, new_i, slot_size);
983
+ SanitizerUnpoisonMemoryRegion(dst_slot, slot_size);
984
+ transfer_n(&c, dst_slot, src_slot, 1);
985
+ SetCtrlInLargeTable(c, new_i, static_cast<h2_t>(start->h2), slot_size);
986
+ }
987
+ return total_probe_length;
988
+ }
989
+
990
+ // Sentinel value for the start of marked elements.
991
+ // Signals that there are no marked elements.
992
+ constexpr size_t kNoMarkedElementsSentinel = ~size_t{};
993
+
994
+ // Process probed elements that did not fit into available buffers.
995
+ // We marked them in control bytes as kSentinel.
996
+ // Hash recomputation and full probing is done here.
997
+ // This use case should be extremely rare.
998
+ ABSL_ATTRIBUTE_NOINLINE size_t ProcessProbedMarkedElements(
999
+ CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl,
1000
+ void* old_slots, size_t start) {
1001
+ size_t old_capacity = PreviousCapacity(c.capacity());
1002
+ const size_t slot_size = policy.slot_size;
1003
+ void* new_slots = c.slot_array();
1004
+ size_t total_probe_length = 0;
1005
+ const void* hash_fn = policy.hash_fn(c);
1006
+ auto hash_slot = policy.hash_slot;
1007
+ auto transfer_n = policy.transfer_n;
1008
+ const size_t seed = c.seed().seed();
1009
+ for (size_t old_index = start; old_index < old_capacity; ++old_index) {
1010
+ if (old_ctrl[old_index] != ctrl_t::kSentinel) {
1011
+ continue;
1012
+ }
1013
+ void* src_slot = SlotAddress(old_slots, old_index, slot_size);
1014
+ const size_t hash = hash_slot(hash_fn, src_slot, seed);
1015
+ const FindInfo target = find_first_non_full(c, hash);
1016
+ total_probe_length += target.probe_length;
1017
+ const size_t new_i = target.offset;
1018
+ void* dst_slot = SlotAddress(new_slots, new_i, slot_size);
1019
+ SetCtrlInLargeTable(c, new_i, H2(hash), slot_size);
1020
+ transfer_n(&c, dst_slot, src_slot, 1);
1021
+ }
1022
+ return total_probe_length;
1023
+ }
1024
+
1025
+ // The largest old capacity for which it is guaranteed that all probed elements
1026
+ // fit in ProbedItemEncoder's local buffer.
1027
+ // For such tables, `encode_probed_element` is trivial.
1028
+ constexpr size_t kMaxLocalBufferOldCapacity =
1029
+ kProbedElementsBufferSize / sizeof(ProbedItem4Bytes) - 1;
1030
+ static_assert(IsValidCapacity(kMaxLocalBufferOldCapacity));
1031
+ constexpr size_t kMaxLocalBufferNewCapacity =
1032
+ NextCapacity(kMaxLocalBufferOldCapacity);
1033
+ static_assert(kMaxLocalBufferNewCapacity <= ProbedItem4Bytes::kMaxNewCapacity);
1034
+ static_assert(NextCapacity(kMaxLocalBufferNewCapacity) <=
1035
+ ProbedItem4Bytes::kMaxNewCapacity);
1036
+
1037
+ // Initializes mirrored control bytes after
1038
+ // transfer_unprobed_elements_to_next_capacity.
1039
+ void InitializeMirroredControlBytes(ctrl_t* new_ctrl, size_t new_capacity) {
1040
+ std::memcpy(new_ctrl + new_capacity,
1041
+ // We own GrowthInfo just before control bytes. So it is ok
1042
+ // to read one byte from it.
1043
+ new_ctrl - 1, Group::kWidth);
490
1044
  new_ctrl[new_capacity] = ctrl_t::kSentinel;
491
1045
  }
492
1046
 
493
- void HashSetResizeHelper::GrowIntoSingleGroupShuffleTransferableSlots(
494
- void* new_slots, size_t slot_size) const {
495
- ABSL_ASSUME(old_capacity_ > 0);
496
- SanitizerUnpoisonMemoryRegion(old_slots(), slot_size * old_capacity_);
497
- std::memcpy(SlotAddress(new_slots, 1, slot_size), old_slots(),
498
- slot_size * old_capacity_);
1047
+ // Encodes probed elements into available memory.
1048
+ // At first, a local (on stack) buffer is used. The size of the buffer is
1049
+ // kProbedElementsBufferSize bytes.
1050
+ // When the local buffer is full, we switch to `control_` buffer. We are allowed
1051
+ // to overwrite `control_` buffer till the `source_offset` byte. In case we have
1052
+ // no space in `control_` buffer, we fallback to a naive algorithm for all the
1053
+ // rest of the probed elements. We mark elements as kSentinel in control bytes
1054
+ // and later process them fully. See ProcessMarkedElements for details. It
1055
+ // should be extremely rare.
1056
+ template <typename ProbedItemType,
1057
+ // If true, we only use the local buffer and never switch to the
1058
+ // control buffer.
1059
+ bool kGuaranteedFitToBuffer = false>
1060
+ class ProbedItemEncoder {
1061
+ public:
1062
+ using ProbedItem = ProbedItemType;
1063
+ explicit ProbedItemEncoder(ctrl_t* control) : control_(control) {}
1064
+
1065
+ // Encode item into the best available location.
1066
+ void EncodeItem(ProbedItem item) {
1067
+ if (ABSL_PREDICT_FALSE(!kGuaranteedFitToBuffer && pos_ >= end_)) {
1068
+ return ProcessEncodeWithOverflow(item);
1069
+ }
1070
+ ABSL_SWISSTABLE_ASSERT(pos_ < end_);
1071
+ *pos_ = item;
1072
+ ++pos_;
1073
+ }
1074
+
1075
+ // Decodes information about probed elements from all available sources.
1076
+ // Finds new position for each element and transfers it to the new slots.
1077
+ // Returns the total probe length.
1078
+ size_t DecodeAndInsertToTable(CommonFields& common,
1079
+ const PolicyFunctions& __restrict policy,
1080
+ void* old_slots) const {
1081
+ if (pos_ == buffer_) {
1082
+ return 0;
1083
+ }
1084
+ if constexpr (kGuaranteedFitToBuffer) {
1085
+ return DecodeAndInsertImpl(common, policy, buffer_, pos_, old_slots);
1086
+ }
1087
+ size_t total_probe_length = DecodeAndInsertImpl(
1088
+ common, policy, buffer_,
1089
+ local_buffer_full_ ? buffer_ + kBufferSize : pos_, old_slots);
1090
+ if (!local_buffer_full_) {
1091
+ return total_probe_length;
1092
+ }
1093
+ total_probe_length +=
1094
+ DecodeAndInsertToTableOverflow(common, policy, old_slots);
1095
+ return total_probe_length;
1096
+ }
1097
+
1098
+ private:
1099
+ static ProbedItem* AlignToNextItem(void* ptr) {
1100
+ return reinterpret_cast<ProbedItem*>(AlignUpTo(
1101
+ reinterpret_cast<uintptr_t>(ptr), alignof(ProbedItem)));
1102
+ }
1103
+
1104
+ ProbedItem* OverflowBufferStart() const {
1105
+ // We reuse GrowthInfo memory as well.
1106
+ return AlignToNextItem(control_ - ControlOffset(/*has_infoz=*/false));
1107
+ }
1108
+
1109
+ // Encodes item when previously allocated buffer is full.
1110
+ // At first that happens when local buffer is full.
1111
+ // We switch from the local buffer to the control buffer.
1112
+ // Every time this function is called, the available buffer is extended till
1113
+ // `item.source_offset` byte in the control buffer.
1114
+ // After the buffer is extended, this function wouldn't be called till the
1115
+ // buffer is exhausted.
1116
+ //
1117
+ // If there's no space in the control buffer, we fallback to naive algorithm
1118
+ // and mark probed elements as kSentinel in the control buffer. In this case,
1119
+ // we will call this function for every subsequent probed element.
1120
+ ABSL_ATTRIBUTE_NOINLINE void ProcessEncodeWithOverflow(ProbedItem item) {
1121
+ if (!local_buffer_full_) {
1122
+ local_buffer_full_ = true;
1123
+ pos_ = OverflowBufferStart();
1124
+ }
1125
+ const size_t source_offset = static_cast<size_t>(item.source_offset);
1126
+ // We are in fallback mode so we can't reuse control buffer anymore.
1127
+ // Probed elements are marked as kSentinel in the control buffer.
1128
+ if (ABSL_PREDICT_FALSE(marked_elements_starting_position_ !=
1129
+ kNoMarkedElementsSentinel)) {
1130
+ control_[source_offset] = ctrl_t::kSentinel;
1131
+ return;
1132
+ }
1133
+ // Refresh the end pointer to the new available position.
1134
+ // Invariant: if pos < end, then we have at least sizeof(ProbedItem) bytes
1135
+ // to write.
1136
+ end_ = control_ + source_offset + 1 - sizeof(ProbedItem);
1137
+ if (ABSL_PREDICT_TRUE(pos_ < end_)) {
1138
+ *pos_ = item;
1139
+ ++pos_;
1140
+ return;
1141
+ }
1142
+ control_[source_offset] = ctrl_t::kSentinel;
1143
+ marked_elements_starting_position_ = source_offset;
1144
+ // Now we will always fall down to `ProcessEncodeWithOverflow`.
1145
+ ABSL_SWISSTABLE_ASSERT(pos_ >= end_);
1146
+ }
1147
+
1148
+ // Decodes information about probed elements from control buffer and processes
1149
+ // marked elements.
1150
+ // Finds new position for each element and transfers it to the new slots.
1151
+ // Returns the total probe length.
1152
+ ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertToTableOverflow(
1153
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1154
+ void* old_slots) const {
1155
+ ABSL_SWISSTABLE_ASSERT(local_buffer_full_ &&
1156
+ "must not be called when local buffer is not full");
1157
+ size_t total_probe_length = DecodeAndInsertImpl(
1158
+ common, policy, OverflowBufferStart(), pos_, old_slots);
1159
+ if (ABSL_PREDICT_TRUE(marked_elements_starting_position_ ==
1160
+ kNoMarkedElementsSentinel)) {
1161
+ return total_probe_length;
1162
+ }
1163
+ total_probe_length +=
1164
+ ProcessProbedMarkedElements(common, policy, control_, old_slots,
1165
+ marked_elements_starting_position_);
1166
+ return total_probe_length;
1167
+ }
1168
+
1169
+ static constexpr size_t kBufferSize =
1170
+ kProbedElementsBufferSize / sizeof(ProbedItem);
1171
+ ProbedItem buffer_[kBufferSize];
1172
+ // If local_buffer_full_ is false, then pos_/end_ are in the local buffer,
1173
+ // otherwise, they're in the overflow buffer.
1174
+ ProbedItem* pos_ = buffer_;
1175
+ const void* end_ = buffer_ + kBufferSize;
1176
+ ctrl_t* const control_;
1177
+ size_t marked_elements_starting_position_ = kNoMarkedElementsSentinel;
1178
+ bool local_buffer_full_ = false;
1179
+ };
1180
+
1181
+ // Grows to next capacity with specified encoder type.
1182
+ // Encoder is used to store probed elements that are processed later.
1183
+ // Different encoder is used depending on the capacity of the table.
1184
+ // Returns total probe length.
1185
+ template <typename Encoder>
1186
+ size_t GrowToNextCapacity(CommonFields& common,
1187
+ const PolicyFunctions& __restrict policy,
1188
+ ctrl_t* old_ctrl, void* old_slots) {
1189
+ using ProbedItem = typename Encoder::ProbedItem;
1190
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= ProbedItem::kMaxNewCapacity);
1191
+ Encoder encoder(old_ctrl);
1192
+ policy.transfer_unprobed_elements_to_next_capacity(
1193
+ common, old_ctrl, old_slots, &encoder,
1194
+ [](void* probed_storage, h2_t h2, size_t source_offset, size_t h1) {
1195
+ auto encoder_ptr = static_cast<Encoder*>(probed_storage);
1196
+ encoder_ptr->EncodeItem(ProbedItem(h2, source_offset, h1));
1197
+ });
1198
+ InitializeMirroredControlBytes(common.control(), common.capacity());
1199
+ return encoder.DecodeAndInsertToTable(common, policy, old_slots);
499
1200
  }
500
1201
 
501
- void HashSetResizeHelper::GrowSizeIntoSingleGroupTransferable(
502
- CommonFields& c, size_t slot_size) {
503
- assert(old_capacity_ < Group::kWidth / 2);
504
- assert(is_single_group(c.capacity()));
505
- assert(IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()));
1202
+ // Grows to next capacity for relatively small tables so that even if all
1203
+ // elements are probed, we don't need to overflow the local buffer.
1204
+ // Returns total probe length.
1205
+ size_t GrowToNextCapacityThatFitsInLocalBuffer(
1206
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1207
+ ctrl_t* old_ctrl, void* old_slots) {
1208
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= kMaxLocalBufferNewCapacity);
1209
+ return GrowToNextCapacity<
1210
+ ProbedItemEncoder<ProbedItem4Bytes, /*kGuaranteedFitToBuffer=*/true>>(
1211
+ common, policy, old_ctrl, old_slots);
1212
+ }
506
1213
 
507
- GrowIntoSingleGroupShuffleControlBytes(c.control(), c.capacity());
508
- GrowIntoSingleGroupShuffleTransferableSlots(c.slot_array(), slot_size);
1214
+ // Grows to next capacity with different encodings. Returns total probe length.
1215
+ // These functions are useful to simplify profile analysis.
1216
+ size_t GrowToNextCapacity4BytesEncoder(CommonFields& common,
1217
+ const PolicyFunctions& __restrict policy,
1218
+ ctrl_t* old_ctrl, void* old_slots) {
1219
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem4Bytes>>(
1220
+ common, policy, old_ctrl, old_slots);
1221
+ }
1222
+ size_t GrowToNextCapacity8BytesEncoder(CommonFields& common,
1223
+ const PolicyFunctions& __restrict policy,
1224
+ ctrl_t* old_ctrl, void* old_slots) {
1225
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem8Bytes>>(
1226
+ common, policy, old_ctrl, old_slots);
1227
+ }
1228
+ size_t GrowToNextCapacity16BytesEncoder(
1229
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1230
+ ctrl_t* old_ctrl, void* old_slots) {
1231
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem16Bytes>>(
1232
+ common, policy, old_ctrl, old_slots);
1233
+ }
509
1234
 
510
- // We poison since GrowIntoSingleGroupShuffleTransferableSlots
511
- // may leave empty slots unpoisoned.
512
- PoisonSingleGroupEmptySlots(c, slot_size);
1235
+ // Grows to next capacity for tables with relatively large capacity so that we
1236
+ // can't guarantee that all probed elements fit in the local buffer. Returns
1237
+ // total probe length.
1238
+ size_t GrowToNextCapacityOverflowLocalBuffer(
1239
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1240
+ ctrl_t* old_ctrl, void* old_slots) {
1241
+ const size_t new_capacity = common.capacity();
1242
+ if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem4Bytes::kMaxNewCapacity)) {
1243
+ return GrowToNextCapacity4BytesEncoder(common, policy, old_ctrl, old_slots);
1244
+ }
1245
+ if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem8Bytes::kMaxNewCapacity)) {
1246
+ return GrowToNextCapacity8BytesEncoder(common, policy, old_ctrl, old_slots);
1247
+ }
1248
+ // 16 bytes encoding supports the maximum swisstable capacity.
1249
+ return GrowToNextCapacity16BytesEncoder(common, policy, old_ctrl, old_slots);
513
1250
  }
514
1251
 
515
- void HashSetResizeHelper::TransferSlotAfterSoo(CommonFields& c,
516
- size_t slot_size) {
517
- assert(was_soo_);
518
- assert(had_soo_slot_);
519
- assert(is_single_group(c.capacity()));
520
- std::memcpy(SlotAddress(c.slot_array(), SooSlotIndex(), slot_size),
521
- old_soo_data(), slot_size);
522
- PoisonSingleGroupEmptySlots(c, slot_size);
1252
+ // Dispatches to the appropriate `GrowToNextCapacity*` function based on the
1253
+ // capacity of the table. Returns total probe length.
1254
+ ABSL_ATTRIBUTE_NOINLINE
1255
+ size_t GrowToNextCapacityDispatch(CommonFields& common,
1256
+ const PolicyFunctions& __restrict policy,
1257
+ ctrl_t* old_ctrl, void* old_slots) {
1258
+ const size_t new_capacity = common.capacity();
1259
+ if (ABSL_PREDICT_TRUE(new_capacity <= kMaxLocalBufferNewCapacity)) {
1260
+ return GrowToNextCapacityThatFitsInLocalBuffer(common, policy, old_ctrl,
1261
+ old_slots);
1262
+ } else {
1263
+ return GrowToNextCapacityOverflowLocalBuffer(common, policy, old_ctrl,
1264
+ old_slots);
1265
+ }
1266
+ }
1267
+
1268
+ void IncrementSmallSizeNonSoo(CommonFields& common,
1269
+ const PolicyFunctions& __restrict policy) {
1270
+ ABSL_SWISSTABLE_ASSERT(common.is_small());
1271
+ common.increment_size();
1272
+ SanitizerUnpoisonMemoryRegion(common.slot_array(), policy.slot_size);
1273
+ }
1274
+
1275
+ void IncrementSmallSize(CommonFields& common,
1276
+ const PolicyFunctions& __restrict policy) {
1277
+ ABSL_SWISSTABLE_ASSERT(common.is_small());
1278
+ if (policy.soo_enabled) {
1279
+ common.set_full_soo();
1280
+ } else {
1281
+ IncrementSmallSizeNonSoo(common, policy);
1282
+ }
1283
+ }
1284
+
1285
+ std::pair<ctrl_t*, void*> Grow1To3AndPrepareInsert(
1286
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1287
+ absl::FunctionRef<size_t(size_t)> get_hash) {
1288
+ // TODO(b/413062340): Refactor to reuse more code with
1289
+ // GrowSooTableToNextCapacityAndPrepareInsert.
1290
+ ABSL_SWISSTABLE_ASSERT(common.capacity() == 1);
1291
+ ABSL_SWISSTABLE_ASSERT(!common.empty());
1292
+ ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled);
1293
+ constexpr size_t kOldCapacity = 1;
1294
+ constexpr size_t kNewCapacity = NextCapacity(kOldCapacity);
1295
+ ctrl_t* old_ctrl = common.control();
1296
+ void* old_slots = common.slot_array();
1297
+
1298
+ common.set_capacity(kNewCapacity);
1299
+ const size_t slot_size = policy.slot_size;
1300
+ const size_t slot_align = policy.slot_align;
1301
+ void* alloc = policy.get_char_alloc(common);
1302
+ HashtablezInfoHandle infoz = common.infoz();
1303
+ const bool has_infoz = infoz.IsSampled();
1304
+
1305
+ const auto [new_ctrl, new_slots] =
1306
+ AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc);
1307
+ common.set_control(new_ctrl);
1308
+ common.set_slots(new_slots);
1309
+ SanitizerPoisonMemoryRegion(new_slots, kNewCapacity * slot_size);
1310
+
1311
+ if (ABSL_PREDICT_TRUE(!has_infoz)) {
1312
+ // When we're sampled, we already have a seed.
1313
+ common.generate_new_seed(/*has_infoz=*/false);
1314
+ }
1315
+ const size_t new_hash = get_hash(common.seed().seed());
1316
+ h2_t new_h2 = H2(new_hash);
1317
+ size_t orig_hash =
1318
+ policy.hash_slot(policy.hash_fn(common), old_slots, common.seed().seed());
1319
+ size_t offset = Resize1To3NewOffset(new_hash, common.seed());
1320
+ InitializeThreeElementsControlBytes(H2(orig_hash), new_h2, offset, new_ctrl);
1321
+
1322
+ void* old_element_target = NextSlot(new_slots, slot_size);
1323
+ SanitizerUnpoisonMemoryRegion(old_element_target, slot_size);
1324
+ policy.transfer_n(&common, old_element_target, old_slots, 1);
1325
+
1326
+ void* new_element_target_slot = SlotAddress(new_slots, offset, slot_size);
1327
+ SanitizerUnpoisonMemoryRegion(new_element_target_slot, slot_size);
1328
+
1329
+ policy.dealloc(alloc, kOldCapacity, old_ctrl, slot_size, slot_align,
1330
+ has_infoz);
1331
+ PrepareInsertCommon(common);
1332
+ ABSL_SWISSTABLE_ASSERT(common.size() == 2);
1333
+ GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(kNewCapacity - 2);
1334
+
1335
+ if (ABSL_PREDICT_FALSE(has_infoz)) {
1336
+ ReportSingleGroupTableGrowthToInfoz(common, infoz, new_hash);
1337
+ }
1338
+ return {new_ctrl + offset, new_element_target_slot};
1339
+ }
1340
+
1341
+ // Grows to next capacity and prepares insert for the given new_hash.
1342
+ // Returns the offset of the new element.
1343
+ size_t GrowToNextCapacityAndPrepareInsert(
1344
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1345
+ size_t new_hash) {
1346
+ ABSL_SWISSTABLE_ASSERT(common.growth_left() == 0);
1347
+ const size_t old_capacity = common.capacity();
1348
+ ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
1349
+ ABSL_SWISSTABLE_ASSERT(!IsSmallCapacity(old_capacity));
1350
+
1351
+ const size_t new_capacity = NextCapacity(old_capacity);
1352
+ ctrl_t* old_ctrl = common.control();
1353
+ void* old_slots = common.slot_array();
1354
+
1355
+ common.set_capacity(new_capacity);
1356
+ const size_t slot_size = policy.slot_size;
1357
+ const size_t slot_align = policy.slot_align;
1358
+ void* alloc = policy.get_char_alloc(common);
1359
+ HashtablezInfoHandle infoz = common.infoz();
1360
+ const bool has_infoz = infoz.IsSampled();
1361
+
1362
+ const auto [new_ctrl, new_slots] =
1363
+ AllocBackingArray(common, policy, new_capacity, has_infoz, alloc);
1364
+ common.set_control(new_ctrl);
1365
+ common.set_slots(new_slots);
1366
+ SanitizerPoisonMemoryRegion(new_slots, new_capacity * slot_size);
1367
+
1368
+ h2_t new_h2 = H2(new_hash);
1369
+ size_t total_probe_length = 0;
1370
+ FindInfo find_info;
1371
+ if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) {
1372
+ size_t offset;
1373
+ GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, new_ctrl,
1374
+ new_capacity);
1375
+ // We put the new element either at the beginning or at the end of the
1376
+ // table with approximately equal probability.
1377
+ offset =
1378
+ SingleGroupTableH1(new_hash, common.seed()) & 1 ? 0 : new_capacity - 1;
1379
+
1380
+ ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[offset]));
1381
+ SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size);
1382
+ find_info = FindInfo{offset, 0};
1383
+ // Single group tables have all slots full on resize. So we can transfer
1384
+ // all slots without checking the control bytes.
1385
+ ABSL_SWISSTABLE_ASSERT(common.size() == old_capacity);
1386
+ void* target = NextSlot(new_slots, slot_size);
1387
+ SanitizerUnpoisonMemoryRegion(target, old_capacity * slot_size);
1388
+ policy.transfer_n(&common, target, old_slots, old_capacity);
1389
+ } else {
1390
+ total_probe_length =
1391
+ GrowToNextCapacityDispatch(common, policy, old_ctrl, old_slots);
1392
+ find_info = find_first_non_full(common, new_hash);
1393
+ SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size);
1394
+ }
1395
+ ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
1396
+ (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
1397
+ has_infoz);
1398
+ PrepareInsertCommon(common);
1399
+ ResetGrowthLeft(GetGrowthInfoFromControl(new_ctrl), new_capacity,
1400
+ common.size());
1401
+
1402
+ if (ABSL_PREDICT_FALSE(has_infoz)) {
1403
+ ReportGrowthToInfoz(common, infoz, new_hash, total_probe_length,
1404
+ find_info.probe_length);
1405
+ }
1406
+ return find_info.offset;
1407
+ }
1408
+
1409
+ } // namespace
1410
+
1411
+ std::pair<ctrl_t*, void*> PrepareInsertSmallNonSoo(
1412
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1413
+ absl::FunctionRef<size_t(size_t)> get_hash) {
1414
+ ABSL_SWISSTABLE_ASSERT(common.is_small());
1415
+ ABSL_SWISSTABLE_ASSERT(!policy.soo_enabled);
1416
+ if (common.capacity() == 1) {
1417
+ if (common.empty()) {
1418
+ IncrementSmallSizeNonSoo(common, policy);
1419
+ return {SooControl(), common.slot_array()};
1420
+ } else {
1421
+ return Grow1To3AndPrepareInsert(common, policy, get_hash);
1422
+ }
1423
+ }
1424
+
1425
+ // Growing from 0 to 1 capacity.
1426
+ ABSL_SWISSTABLE_ASSERT(common.capacity() == 0);
1427
+ constexpr size_t kNewCapacity = 1;
1428
+
1429
+ common.set_capacity(kNewCapacity);
1430
+ HashtablezInfoHandle infoz;
1431
+ const bool should_sample =
1432
+ policy.is_hashtablez_eligible && ShouldSampleNextTable();
1433
+ if (ABSL_PREDICT_FALSE(should_sample)) {
1434
+ infoz = ForcedTrySample(policy.slot_size, policy.key_size,
1435
+ policy.value_size, policy.soo_capacity());
1436
+ }
1437
+ const bool has_infoz = infoz.IsSampled();
1438
+ void* alloc = policy.get_char_alloc(common);
1439
+
1440
+ const auto [new_ctrl, new_slots] =
1441
+ AllocBackingArray(common, policy, kNewCapacity, has_infoz, alloc);
1442
+ common.set_control(new_ctrl);
1443
+ common.set_slots(new_slots);
1444
+
1445
+ static_assert(NextCapacity(0) == 1);
1446
+ PrepareInsertCommon(common);
1447
+
1448
+ if (ABSL_PREDICT_FALSE(has_infoz)) {
1449
+ common.generate_new_seed(/*has_infoz=*/true);
1450
+ ReportSingleGroupTableGrowthToInfoz(common, infoz,
1451
+ get_hash(common.seed().seed()));
1452
+ }
1453
+ return {SooControl(), new_slots};
523
1454
  }
524
1455
 
525
1456
  namespace {
526
1457
 
527
1458
  // Called whenever the table needs to vacate empty slots either by removing
528
- // tombstones via rehash or growth.
1459
+ // tombstones via rehash or growth to next capacity.
529
1460
  ABSL_ATTRIBUTE_NOINLINE
530
- FindInfo FindInsertPositionWithGrowthOrRehash(CommonFields& common, size_t hash,
531
- const PolicyFunctions& policy) {
1461
+ size_t RehashOrGrowToNextCapacityAndPrepareInsert(
1462
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1463
+ size_t new_hash) {
532
1464
  const size_t cap = common.capacity();
1465
+ ABSL_ASSUME(cap > 0);
533
1466
  if (cap > Group::kWidth &&
534
1467
  // Do these calculations in 64-bit to avoid overflow.
535
1468
  common.size() * uint64_t{32} <= cap * uint64_t{25}) {
@@ -574,98 +1507,458 @@ FindInfo FindInsertPositionWithGrowthOrRehash(CommonFields& common, size_t hash,
574
1507
  // 762 | 149836 0.37 13 | 148559 0.74 190
575
1508
  // 807 | 149736 0.39 14 | 151107 0.39 14
576
1509
  // 852 | 150204 0.42 15 | 151019 0.42 15
577
- DropDeletesWithoutResize(common, policy);
1510
+ return DropDeletesWithoutResizeAndPrepareInsert(common, policy, new_hash);
578
1511
  } else {
579
1512
  // Otherwise grow the container.
580
- policy.resize(common, NextCapacity(cap), HashtablezInfoHandle{});
1513
+ return GrowToNextCapacityAndPrepareInsert(common, policy, new_hash);
1514
+ }
1515
+ }
1516
+
1517
+ // Slow path for PrepareInsertLarge that is called when the table has deleted
1518
+ // slots or need to be resized or rehashed.
1519
+ size_t PrepareInsertLargeSlow(CommonFields& common,
1520
+ const PolicyFunctions& __restrict policy,
1521
+ size_t hash) {
1522
+ const GrowthInfo growth_info = common.growth_info();
1523
+ ABSL_SWISSTABLE_ASSERT(!growth_info.HasNoDeletedAndGrowthLeft());
1524
+ if (ABSL_PREDICT_TRUE(growth_info.HasNoGrowthLeftAndNoDeleted())) {
1525
+ // Table without deleted slots (>95% cases) that needs to be resized.
1526
+ ABSL_SWISSTABLE_ASSERT(growth_info.HasNoDeleted() &&
1527
+ growth_info.GetGrowthLeft() == 0);
1528
+ return GrowToNextCapacityAndPrepareInsert(common, policy, hash);
1529
+ }
1530
+ if (ABSL_PREDICT_FALSE(growth_info.HasNoGrowthLeftAssumingMayHaveDeleted())) {
1531
+ // Table with deleted slots that needs to be rehashed or resized.
1532
+ return RehashOrGrowToNextCapacityAndPrepareInsert(common, policy, hash);
1533
+ }
1534
+ // Table with deleted slots that has space for the inserting element.
1535
+ FindInfo target = find_first_non_full(common, hash);
1536
+ PrepareInsertCommon(common);
1537
+ common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
1538
+ SetCtrlInLargeTable(common, target.offset, H2(hash), policy.slot_size);
1539
+ common.infoz().RecordInsert(hash, target.probe_length);
1540
+ return target.offset;
1541
+ }
1542
+
1543
+ // Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()),
1544
+ // forces the table to be sampled and prepares the insert.
1545
+ // SOO tables need to switch from SOO to heap in order to store the infoz.
1546
+ // Requires:
1547
+ // 1. `c.capacity() == SooCapacity()`.
1548
+ // 2. `c.empty()`.
1549
+ ABSL_ATTRIBUTE_NOINLINE size_t
1550
+ GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
1551
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1552
+ absl::FunctionRef<size_t(size_t)> get_hash) {
1553
+ ResizeEmptyNonAllocatedTableImpl(common, policy, NextCapacity(SooCapacity()),
1554
+ /*force_infoz=*/true);
1555
+ PrepareInsertCommon(common);
1556
+ common.growth_info().OverwriteEmptyAsFull();
1557
+ const size_t new_hash = get_hash(common.seed().seed());
1558
+ SetCtrlInSingleGroupTable(common, SooSlotIndex(), H2(new_hash),
1559
+ policy.slot_size);
1560
+ common.infoz().RecordInsert(new_hash, /*distance_from_desired=*/0);
1561
+ return SooSlotIndex();
1562
+ }
1563
+
1564
+ // Resizes empty non-allocated table to the capacity to fit new_size elements.
1565
+ // Requires:
1566
+ // 1. `c.capacity() == policy.soo_capacity()`.
1567
+ // 2. `c.empty()`.
1568
+ // 3. `new_size > policy.soo_capacity()`.
1569
+ // The table will be attempted to be sampled.
1570
+ void ReserveEmptyNonAllocatedTableToFitNewSize(
1571
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1572
+ size_t new_size) {
1573
+ ValidateMaxSize(new_size, policy.slot_size);
1574
+ ABSL_ASSUME(new_size > 0);
1575
+ ResizeEmptyNonAllocatedTableImpl(common, policy, SizeToCapacity(new_size),
1576
+ /*force_infoz=*/false);
1577
+ // This is after resize, to ensure that we have completed the allocation
1578
+ // and have potentially sampled the hashtable.
1579
+ common.infoz().RecordReservation(new_size);
1580
+ }
1581
+
1582
+ // Type erased version of raw_hash_set::reserve for tables that have an
1583
+ // allocated backing array.
1584
+ //
1585
+ // Requires:
1586
+ // 1. `c.capacity() > policy.soo_capacity()` OR `!c.empty()`.
1587
+ // Reserving already allocated tables is considered to be a rare case.
1588
+ ABSL_ATTRIBUTE_NOINLINE void ReserveAllocatedTable(
1589
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1590
+ size_t new_size) {
1591
+ const size_t cap = common.capacity();
1592
+ ValidateMaxSize(new_size, policy.slot_size);
1593
+ ABSL_ASSUME(new_size > 0);
1594
+ const size_t new_capacity = SizeToCapacity(new_size);
1595
+ if (cap == policy.soo_capacity()) {
1596
+ ABSL_SWISSTABLE_ASSERT(!common.empty());
1597
+ ResizeFullSooTable(common, policy, new_capacity,
1598
+ ResizeFullSooTableSamplingMode::kNoSampling);
1599
+ } else {
1600
+ ABSL_SWISSTABLE_ASSERT(cap > policy.soo_capacity());
1601
+ // TODO(b/382423690): consider using GrowToNextCapacity, when applicable.
1602
+ ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
581
1603
  }
582
- // This function is typically called with tables containing deleted slots.
583
- // The table will be big and `FindFirstNonFullAfterResize` will always
584
- // fallback to `find_first_non_full`. So using `find_first_non_full` directly.
585
- return find_first_non_full(common, hash);
1604
+ common.infoz().RecordReservation(new_size);
1605
+ }
1606
+
1607
+ // As `ResizeFullSooTableToNextCapacity`, except that we also force the SOO
1608
+ // table to be sampled. SOO tables need to switch from SOO to heap in order to
1609
+ // store the infoz. No-op if sampling is disabled or not possible.
1610
+ void GrowFullSooTableToNextCapacityForceSampling(
1611
+ CommonFields& common, const PolicyFunctions& __restrict policy) {
1612
+ AssertFullSoo(common, policy);
1613
+ ResizeFullSooTable(
1614
+ common, policy, NextCapacity(SooCapacity()),
1615
+ ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled);
586
1616
  }
587
1617
 
588
1618
  } // namespace
589
1619
 
590
- const void* GetHashRefForEmptyHasher(const CommonFields& common) {
1620
+ void* GetRefForEmptyClass(CommonFields& common) {
591
1621
  // Empty base optimization typically make the empty base class address to be
592
1622
  // the same as the first address of the derived class object.
593
- // But we generally assume that for empty hasher we can return any valid
1623
+ // But we generally assume that for empty classes we can return any valid
594
1624
  // pointer.
595
1625
  return &common;
596
1626
  }
597
1627
 
598
- FindInfo HashSetResizeHelper::FindFirstNonFullAfterResize(const CommonFields& c,
599
- size_t old_capacity,
600
- size_t hash) {
601
- size_t new_capacity = c.capacity();
602
- if (!IsGrowingIntoSingleGroupApplicable(old_capacity, new_capacity)) {
603
- return find_first_non_full(c, hash);
1628
+ void ResizeAllocatedTableWithSeedChange(
1629
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1630
+ size_t new_capacity) {
1631
+ ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedAllocated>(
1632
+ common, policy, new_capacity, common.infoz());
1633
+ }
1634
+
1635
+ void ReserveEmptyNonAllocatedTableToFitBucketCount(
1636
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1637
+ size_t bucket_count) {
1638
+ size_t new_capacity = NormalizeCapacity(bucket_count);
1639
+ ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size);
1640
+ ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
1641
+ /*force_infoz=*/false);
1642
+ }
1643
+
1644
+ // Resizes a full SOO table to the NextCapacity(SooCapacity()).
1645
+ template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
1646
+ size_t GrowSooTableToNextCapacityAndPrepareInsert(
1647
+ CommonFields& common, const PolicyFunctions& __restrict policy,
1648
+ absl::FunctionRef<size_t(size_t)> get_hash, bool force_sampling) {
1649
+ AssertSoo(common, policy);
1650
+ if (ABSL_PREDICT_FALSE(force_sampling)) {
1651
+ // The table is empty, it is only used for forced sampling of SOO tables.
1652
+ return GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
1653
+ common, policy, get_hash);
604
1654
  }
1655
+ ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity());
1656
+ static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
1657
+ const size_t slot_size = policy.slot_size;
1658
+ void* alloc = policy.get_char_alloc(common);
1659
+ common.set_capacity(kNewCapacity);
605
1660
 
606
- // We put the new element either at the beginning or at the end of the table
607
- // with approximately equal probability.
608
- size_t offset =
609
- SingleGroupTableH1(hash, c.control()) & 1 ? 0 : new_capacity - 1;
1661
+ // Since the table is not empty, it will not be sampled.
1662
+ // The decision to sample was already made during the first insertion.
1663
+ //
1664
+ // We do not set control and slots in CommonFields yet to avoid overriding
1665
+ // SOO data.
1666
+ const auto [new_ctrl, new_slots] = AllocBackingArray(
1667
+ common, policy, kNewCapacity, /*has_infoz=*/false, alloc);
610
1668
 
611
- assert(IsEmpty(c.control()[offset]));
612
- return FindInfo{offset, 0};
1669
+ PrepareInsertCommon(common);
1670
+ ABSL_SWISSTABLE_ASSERT(common.size() == 2);
1671
+ GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(kNewCapacity - 2);
1672
+ common.generate_new_seed(/*has_infoz=*/false);
1673
+ const h2_t soo_slot_h2 = H2(policy.hash_slot(
1674
+ policy.hash_fn(common), common.soo_data(), common.seed().seed()));
1675
+ const size_t new_hash = get_hash(common.seed().seed());
1676
+
1677
+ const size_t offset = Resize1To3NewOffset(new_hash, common.seed());
1678
+ InitializeThreeElementsControlBytes(soo_slot_h2, H2(new_hash), offset,
1679
+ new_ctrl);
1680
+
1681
+ SanitizerPoisonMemoryRegion(new_slots, slot_size * kNewCapacity);
1682
+ void* target_slot = SlotAddress(new_slots, SooSlotIndex(), slot_size);
1683
+ SanitizerUnpoisonMemoryRegion(target_slot, slot_size);
1684
+ if constexpr (TransferUsesMemcpy) {
1685
+ // Target slot is placed at index 1, but capacity is at
1686
+ // minimum 3. So we are allowed to copy at least twice as much
1687
+ // memory.
1688
+ static_assert(SooSlotIndex() == 1);
1689
+ static_assert(SooSlotMemcpySize > 0);
1690
+ static_assert(SooSlotMemcpySize <= MaxSooSlotSize());
1691
+ ABSL_SWISSTABLE_ASSERT(SooSlotMemcpySize <= 2 * slot_size);
1692
+ ABSL_SWISSTABLE_ASSERT(SooSlotMemcpySize >= slot_size);
1693
+ void* next_slot = SlotAddress(target_slot, 1, slot_size);
1694
+ SanitizerUnpoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
1695
+ std::memcpy(target_slot, common.soo_data(), SooSlotMemcpySize);
1696
+ SanitizerPoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
1697
+ } else {
1698
+ static_assert(SooSlotMemcpySize == 0);
1699
+ policy.transfer_n(&common, target_slot, common.soo_data(), 1);
1700
+ }
1701
+ common.set_control(new_ctrl);
1702
+ common.set_slots(new_slots);
1703
+
1704
+ // Full SOO table couldn't be sampled. If SOO table is sampled, it would
1705
+ // have been resized to the next capacity.
1706
+ ABSL_SWISSTABLE_ASSERT(!common.infoz().IsSampled());
1707
+ SanitizerUnpoisonMemoryRegion(SlotAddress(new_slots, offset, slot_size),
1708
+ slot_size);
1709
+ return offset;
613
1710
  }
614
1711
 
615
- size_t PrepareInsertNonSoo(CommonFields& common, size_t hash, FindInfo target,
616
- const PolicyFunctions& policy) {
617
- // When there are no deleted slots in the table
618
- // and growth_left is positive, we can insert at the first
619
- // empty slot in the probe sequence (target).
620
- const bool use_target_hint =
621
- // Optimization is disabled when generations are enabled.
622
- // We have to rehash even sparse tables randomly in such mode.
623
- !SwisstableGenerationsEnabled() &&
624
- common.growth_info().HasNoDeletedAndGrowthLeft();
625
- if (ABSL_PREDICT_FALSE(!use_target_hint)) {
626
- // Notes about optimized mode when generations are disabled:
627
- // We do not enter this branch if table has no deleted slots
628
- // and growth_left is positive.
629
- // We enter this branch in the following cases listed in decreasing
630
- // frequency:
631
- // 1. Table without deleted slots (>95% cases) that needs to be resized.
632
- // 2. Table with deleted slots that has space for the inserting element.
633
- // 3. Table with deleted slots that needs to be rehashed or resized.
634
- if (ABSL_PREDICT_TRUE(common.growth_info().HasNoGrowthLeftAndNoDeleted())) {
635
- const size_t old_capacity = common.capacity();
636
- policy.resize(common, NextCapacity(old_capacity), HashtablezInfoHandle{});
637
- target = HashSetResizeHelper::FindFirstNonFullAfterResize(
638
- common, old_capacity, hash);
639
- } else {
640
- // Note: the table may have no deleted slots here when generations
641
- // are enabled.
642
- const bool rehash_for_bug_detection =
643
- common.should_rehash_for_bug_detection_on_insert();
644
- if (rehash_for_bug_detection) {
645
- // Move to a different heap allocation in order to detect bugs.
646
- const size_t cap = common.capacity();
647
- policy.resize(common,
648
- common.growth_left() > 0 ? cap : NextCapacity(cap),
649
- HashtablezInfoHandle{});
1712
+ void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy,
1713
+ size_t n) {
1714
+ const size_t cap = common.capacity();
1715
+
1716
+ auto clear_backing_array = [&]() {
1717
+ ClearBackingArray(common, policy, policy.get_char_alloc(common),
1718
+ /*reuse=*/false, policy.soo_enabled);
1719
+ };
1720
+
1721
+ const size_t slot_size = policy.slot_size;
1722
+
1723
+ if (n == 0) {
1724
+ if (cap <= policy.soo_capacity()) return;
1725
+ if (common.empty()) {
1726
+ clear_backing_array();
1727
+ return;
1728
+ }
1729
+ if (common.size() <= policy.soo_capacity()) {
1730
+ // When the table is already sampled, we keep it sampled.
1731
+ if (common.infoz().IsSampled()) {
1732
+ static constexpr size_t kInitialSampledCapacity =
1733
+ NextCapacity(SooCapacity());
1734
+ if (cap > kInitialSampledCapacity) {
1735
+ ResizeAllocatedTableWithSeedChange(common, policy,
1736
+ kInitialSampledCapacity);
1737
+ }
1738
+ // This asserts that we didn't lose sampling coverage in `resize`.
1739
+ ABSL_SWISSTABLE_ASSERT(common.infoz().IsSampled());
1740
+ return;
650
1741
  }
651
- if (ABSL_PREDICT_TRUE(common.growth_left() > 0)) {
652
- target = find_first_non_full(common, hash);
1742
+ ABSL_SWISSTABLE_ASSERT(slot_size <= sizeof(HeapOrSoo));
1743
+ ABSL_SWISSTABLE_ASSERT(policy.slot_align <= alignof(HeapOrSoo));
1744
+ HeapOrSoo tmp_slot;
1745
+ size_t begin_offset = FindFirstFullSlot(0, cap, common.control());
1746
+ policy.transfer_n(
1747
+ &common, &tmp_slot,
1748
+ SlotAddress(common.slot_array(), begin_offset, slot_size), 1);
1749
+ clear_backing_array();
1750
+ policy.transfer_n(&common, common.soo_data(), &tmp_slot, 1);
1751
+ common.set_full_soo();
1752
+ return;
1753
+ }
1754
+ }
1755
+
1756
+ ValidateMaxSize(n, policy.slot_size);
1757
+ // bitor is a faster way of doing `max` here. We will round up to the next
1758
+ // power-of-2-minus-1, so bitor is good enough.
1759
+ const size_t new_capacity =
1760
+ NormalizeCapacity(n | SizeToCapacity(common.size()));
1761
+ // n == 0 unconditionally rehashes as per the standard.
1762
+ if (n == 0 || new_capacity > cap) {
1763
+ if (cap == policy.soo_capacity()) {
1764
+ if (common.empty()) {
1765
+ ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
1766
+ /*force_infoz=*/false);
653
1767
  } else {
654
- target = FindInsertPositionWithGrowthOrRehash(common, hash, policy);
1768
+ ResizeFullSooTable(common, policy, new_capacity,
1769
+ ResizeFullSooTableSamplingMode::kNoSampling);
655
1770
  }
1771
+ } else {
1772
+ ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
656
1773
  }
1774
+ // This is after resize, to ensure that we have completed the allocation
1775
+ // and have potentially sampled the hashtable.
1776
+ common.infoz().RecordReservation(n);
1777
+ }
1778
+ }
1779
+
1780
+ void Copy(CommonFields& common, const PolicyFunctions& __restrict policy,
1781
+ const CommonFields& other,
1782
+ absl::FunctionRef<void(void*, const void*)> copy_fn) {
1783
+ const size_t size = other.size();
1784
+ ABSL_SWISSTABLE_ASSERT(size > 0);
1785
+ const size_t soo_capacity = policy.soo_capacity();
1786
+ const size_t slot_size = policy.slot_size;
1787
+ const bool soo_enabled = policy.soo_enabled;
1788
+ if (size == 1) {
1789
+ if (!soo_enabled) ReserveTableToFitNewSize(common, policy, 1);
1790
+ IncrementSmallSize(common, policy);
1791
+ const size_t other_capacity = other.capacity();
1792
+ const void* other_slot =
1793
+ other_capacity <= soo_capacity ? other.soo_data()
1794
+ : other.is_small()
1795
+ ? other.slot_array()
1796
+ : SlotAddress(other.slot_array(),
1797
+ FindFirstFullSlot(0, other_capacity, other.control()),
1798
+ slot_size);
1799
+ copy_fn(soo_enabled ? common.soo_data() : common.slot_array(), other_slot);
1800
+
1801
+ if (soo_enabled && policy.is_hashtablez_eligible &&
1802
+ ShouldSampleNextTable()) {
1803
+ GrowFullSooTableToNextCapacityForceSampling(common, policy);
1804
+ }
1805
+ return;
1806
+ }
1807
+
1808
+ ReserveTableToFitNewSize(common, policy, size);
1809
+ auto infoz = common.infoz();
1810
+ ABSL_SWISSTABLE_ASSERT(other.capacity() > soo_capacity);
1811
+ const size_t cap = common.capacity();
1812
+ ABSL_SWISSTABLE_ASSERT(cap > soo_capacity);
1813
+ size_t offset = cap;
1814
+ const void* hash_fn = policy.hash_fn(common);
1815
+ auto hasher = policy.hash_slot;
1816
+ const size_t seed = common.seed().seed();
1817
+ IterateOverFullSlotsImpl(
1818
+ other, slot_size, [&](const ctrl_t*, void* that_slot) {
1819
+ // The table is guaranteed to be empty, so we can do faster than
1820
+ // a full `insert`.
1821
+ const size_t hash = (*hasher)(hash_fn, that_slot, seed);
1822
+ FindInfo target = find_first_non_full(common, hash);
1823
+ infoz.RecordInsert(hash, target.probe_length);
1824
+ offset = target.offset;
1825
+ SetCtrl(common, offset, H2(hash), slot_size);
1826
+ copy_fn(SlotAddress(common.slot_array(), offset, slot_size), that_slot);
1827
+ common.maybe_increment_generation_on_insert();
1828
+ });
1829
+ common.increment_size(size);
1830
+ common.growth_info().OverwriteManyEmptyAsFull(size);
1831
+ }
1832
+
1833
+ void ReserveTableToFitNewSize(CommonFields& common,
1834
+ const PolicyFunctions& __restrict policy,
1835
+ size_t new_size) {
1836
+ common.reset_reserved_growth(new_size);
1837
+ common.set_reservation_size(new_size);
1838
+ ABSL_SWISSTABLE_ASSERT(new_size > policy.soo_capacity());
1839
+ const size_t cap = common.capacity();
1840
+ if (ABSL_PREDICT_TRUE(common.empty() && cap <= policy.soo_capacity())) {
1841
+ return ReserveEmptyNonAllocatedTableToFitNewSize(common, policy, new_size);
1842
+ }
1843
+
1844
+ ABSL_SWISSTABLE_ASSERT(!common.empty() || cap > policy.soo_capacity());
1845
+ ABSL_SWISSTABLE_ASSERT(cap > 0);
1846
+ const size_t max_size_before_growth =
1847
+ IsSmallCapacity(cap) ? cap : common.size() + common.growth_left();
1848
+ if (new_size <= max_size_before_growth) {
1849
+ return;
1850
+ }
1851
+ ReserveAllocatedTable(common, policy, new_size);
1852
+ }
1853
+
1854
+ namespace {
1855
+ size_t PrepareInsertLargeImpl(CommonFields& common,
1856
+ const PolicyFunctions& __restrict policy,
1857
+ size_t hash, FindInfo target) {
1858
+ ABSL_SWISSTABLE_ASSERT(!common.is_small());
1859
+ const GrowthInfo growth_info = common.growth_info();
1860
+ // When there are no deleted slots in the table
1861
+ // and growth_left is positive, we can insert at the first
1862
+ // empty slot in the probe sequence (target).
1863
+ if (ABSL_PREDICT_FALSE(!growth_info.HasNoDeletedAndGrowthLeft())) {
1864
+ return PrepareInsertLargeSlow(common, policy, hash);
657
1865
  }
658
1866
  PrepareInsertCommon(common);
659
- common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
1867
+ common.growth_info().OverwriteEmptyAsFull();
660
1868
  SetCtrl(common, target.offset, H2(hash), policy.slot_size);
661
1869
  common.infoz().RecordInsert(hash, target.probe_length);
662
1870
  return target.offset;
663
1871
  }
1872
+ } // namespace
1873
+
1874
+ size_t PrepareInsertLarge(CommonFields& common,
1875
+ const PolicyFunctions& __restrict policy, size_t hash,
1876
+ FindInfo target) {
1877
+ // NOLINTNEXTLINE(misc-static-assert)
1878
+ ABSL_SWISSTABLE_ASSERT(!SwisstableGenerationsEnabled());
1879
+ return PrepareInsertLargeImpl(common, policy, hash, target);
1880
+ }
664
1881
 
665
- void HashTableSizeOverflow() {
666
- ABSL_RAW_LOG(FATAL, "Hash table size overflow");
1882
+ size_t PrepareInsertLargeGenerationsEnabled(
1883
+ CommonFields& common, const PolicyFunctions& policy, size_t hash,
1884
+ FindInfo target, absl::FunctionRef<size_t(size_t)> recompute_hash) {
1885
+ // NOLINTNEXTLINE(misc-static-assert)
1886
+ ABSL_SWISSTABLE_ASSERT(SwisstableGenerationsEnabled());
1887
+ if (common.should_rehash_for_bug_detection_on_insert()) {
1888
+ // Move to a different heap allocation in order to detect bugs.
1889
+ const size_t cap = common.capacity();
1890
+ ResizeAllocatedTableWithSeedChange(
1891
+ common, policy, common.growth_left() > 0 ? cap : NextCapacity(cap));
1892
+ hash = recompute_hash(common.seed().seed());
1893
+ target = find_first_non_full(common, hash);
1894
+ }
1895
+ return PrepareInsertLargeImpl(common, policy, hash, target);
667
1896
  }
668
1897
 
1898
+ namespace {
1899
+ // Returns true if the following is true
1900
+ // 1. OptimalMemcpySizeForSooSlotTransfer(left) >
1901
+ // OptimalMemcpySizeForSooSlotTransfer(left - 1)
1902
+ // 2. OptimalMemcpySizeForSooSlotTransfer(left) are equal for all i in [left,
1903
+ // right].
1904
+ // This function is used to verify that we have all the possible template
1905
+ // instantiations for GrowFullSooTableToNextCapacity.
1906
+ // With this verification the problem may be detected at compile time instead of
1907
+ // link time.
1908
+ constexpr bool VerifyOptimalMemcpySizeForSooSlotTransferRange(size_t left,
1909
+ size_t right) {
1910
+ size_t optimal_size_for_range = OptimalMemcpySizeForSooSlotTransfer(left);
1911
+ if (optimal_size_for_range <= OptimalMemcpySizeForSooSlotTransfer(left - 1)) {
1912
+ return false;
1913
+ }
1914
+ for (size_t i = left + 1; i <= right; ++i) {
1915
+ if (OptimalMemcpySizeForSooSlotTransfer(i) != optimal_size_for_range) {
1916
+ return false;
1917
+ }
1918
+ }
1919
+ return true;
1920
+ }
1921
+ } // namespace
1922
+
1923
+ // Extern template instantiation for inline function.
1924
+ template size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index,
1925
+ size_t old_capacity,
1926
+ ctrl_t* new_ctrl,
1927
+ size_t new_capacity);
1928
+
1929
+ // We need to instantiate ALL possible template combinations because we define
1930
+ // the function in the cc file.
1931
+ template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
1932
+ CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
1933
+ bool);
1934
+ template size_t GrowSooTableToNextCapacityAndPrepareInsert<
1935
+ OptimalMemcpySizeForSooSlotTransfer(1), true>(
1936
+ CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
1937
+ bool);
1938
+
1939
+ static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 3));
1940
+ template size_t GrowSooTableToNextCapacityAndPrepareInsert<
1941
+ OptimalMemcpySizeForSooSlotTransfer(3), true>(
1942
+ CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
1943
+ bool);
1944
+
1945
+ static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(4, 8));
1946
+ template size_t GrowSooTableToNextCapacityAndPrepareInsert<
1947
+ OptimalMemcpySizeForSooSlotTransfer(8), true>(
1948
+ CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
1949
+ bool);
1950
+
1951
+ #if UINTPTR_MAX == UINT32_MAX
1952
+ static_assert(MaxSooSlotSize() == 8);
1953
+ #else
1954
+ static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(9, 16));
1955
+ template size_t GrowSooTableToNextCapacityAndPrepareInsert<
1956
+ OptimalMemcpySizeForSooSlotTransfer(16), true>(
1957
+ CommonFields&, const PolicyFunctions&, absl::FunctionRef<size_t(size_t)>,
1958
+ bool);
1959
+ static_assert(MaxSooSlotSize() == 16);
1960
+ #endif
1961
+
669
1962
  } // namespace container_internal
670
1963
  ABSL_NAMESPACE_END
671
1964
  } // namespace absl