re2 1.24.0 → 1.25.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.
- package/LICENSE +15 -20
- package/README.md +63 -4
- package/binding.gyp +1 -2
- package/lib/addon.cc +9 -5
- package/lib/exec.cc +4 -4
- package/lib/match.cc +4 -4
- package/lib/new.cc +6 -6
- package/lib/pattern.cc +148 -1
- package/lib/replace.cc +5 -4
- package/lib/search.cc +1 -1
- package/lib/set.cc +85 -10
- package/lib/test.cc +1 -1
- package/lib/unicode_properties.h +15840 -0
- package/lib/wrapped_re2.h +40 -4
- package/lib/wrapped_re2_set.h +3 -1
- package/llms-full.txt +497 -0
- package/llms.txt +135 -0
- package/package.json +19 -11
- package/re2.d.ts +2 -0
- package/re2.js +1 -0
- package/vendor/abseil-cpp/CMake/AbseilDll.cmake +87 -74
- package/vendor/abseil-cpp/CMakeLists.txt +3 -3
- package/vendor/abseil-cpp/FAQ.md +130 -79
- package/vendor/abseil-cpp/MODULE.bazel +6 -7
- package/vendor/abseil-cpp/absl/BUILD.bazel +6 -0
- package/vendor/abseil-cpp/absl/algorithm/BUILD.bazel +4 -0
- package/vendor/abseil-cpp/absl/algorithm/CMakeLists.txt +4 -0
- package/vendor/abseil-cpp/absl/algorithm/algorithm.h +34 -2
- package/vendor/abseil-cpp/absl/algorithm/container.h +164 -17
- package/vendor/abseil-cpp/absl/algorithm/container_test.cc +390 -13
- package/vendor/abseil-cpp/absl/base/BUILD.bazel +53 -6
- package/vendor/abseil-cpp/absl/base/CMakeLists.txt +28 -4
- package/vendor/abseil-cpp/absl/base/attributes.h +61 -42
- package/vendor/abseil-cpp/absl/base/call_once.h +1 -0
- package/vendor/abseil-cpp/absl/base/casts.h +8 -1
- package/vendor/abseil-cpp/absl/base/casts_test.cc +3 -6
- package/vendor/abseil-cpp/absl/base/config.h +53 -9
- package/vendor/abseil-cpp/absl/base/exception_safety_testing_test.cc +9 -9
- package/vendor/abseil-cpp/absl/base/fast_type_id.h +30 -2
- package/vendor/abseil-cpp/absl/base/fast_type_id_test.cc +3 -0
- package/vendor/abseil-cpp/absl/base/internal/exception_safety_testing.h +15 -12
- package/vendor/abseil-cpp/absl/base/internal/hardening.h +136 -0
- package/vendor/abseil-cpp/absl/base/internal/hardening_test.cc +168 -0
- package/vendor/abseil-cpp/absl/base/internal/iterator_traits.h +2 -2
- package/vendor/abseil-cpp/absl/base/internal/low_level_alloc.cc +6 -0
- package/vendor/abseil-cpp/absl/base/internal/low_level_scheduling.h +77 -15
- package/vendor/abseil-cpp/absl/base/internal/sysinfo.cc +1 -2
- package/vendor/abseil-cpp/absl/base/internal/thread_identity.h +52 -0
- package/vendor/abseil-cpp/absl/base/internal/unscaledcycleclock.h +5 -0
- package/vendor/abseil-cpp/absl/base/macros.h +36 -20
- package/vendor/abseil-cpp/absl/base/nullability.h +4 -3
- package/vendor/abseil-cpp/absl/base/optimization.h +3 -2
- package/vendor/abseil-cpp/absl/base/optimization_test.cc +4 -3
- package/vendor/abseil-cpp/absl/base/options.h +55 -1
- package/vendor/abseil-cpp/absl/base/policy_checks.h +5 -5
- package/vendor/abseil-cpp/absl/base/{internal/throw_delegate.cc → throw_delegate.cc} +9 -7
- package/vendor/abseil-cpp/absl/base/{internal/throw_delegate.h → throw_delegate.h} +4 -14
- package/vendor/abseil-cpp/absl/base/throw_delegate_test.cc +19 -28
- package/vendor/abseil-cpp/absl/cleanup/BUILD.bazel +2 -0
- package/vendor/abseil-cpp/absl/cleanup/CMakeLists.txt +2 -0
- package/vendor/abseil-cpp/absl/cleanup/cleanup.h +3 -2
- package/vendor/abseil-cpp/absl/cleanup/internal/cleanup.h +3 -2
- package/vendor/abseil-cpp/absl/container/BUILD.bazel +19 -7
- package/vendor/abseil-cpp/absl/container/CMakeLists.txt +6 -5
- package/vendor/abseil-cpp/absl/container/btree_benchmark.cc +3 -5
- package/vendor/abseil-cpp/absl/container/btree_set.h +5 -5
- package/vendor/abseil-cpp/absl/container/btree_test.cc +11 -14
- package/vendor/abseil-cpp/absl/container/chunked_queue.h +8 -6
- package/vendor/abseil-cpp/absl/container/chunked_queue_test.cc +5 -5
- package/vendor/abseil-cpp/absl/container/fixed_array.h +14 -13
- package/vendor/abseil-cpp/absl/container/fixed_array_test.cc +3 -3
- package/vendor/abseil-cpp/absl/container/flat_hash_map.h +18 -6
- package/vendor/abseil-cpp/absl/container/flat_hash_map_test.cc +34 -1
- package/vendor/abseil-cpp/absl/container/flat_hash_set.h +21 -7
- package/vendor/abseil-cpp/absl/container/flat_hash_set_test.cc +39 -7
- package/vendor/abseil-cpp/absl/container/inlined_vector.h +29 -29
- package/vendor/abseil-cpp/absl/container/inlined_vector_test.cc +2 -2
- package/vendor/abseil-cpp/absl/container/internal/btree.h +32 -24
- package/vendor/abseil-cpp/absl/container/internal/btree_container.h +16 -17
- package/vendor/abseil-cpp/absl/container/internal/common.h +6 -5
- package/vendor/abseil-cpp/absl/container/internal/common_policy_traits.h +1 -1
- package/vendor/abseil-cpp/absl/container/internal/compressed_tuple.h +16 -16
- package/vendor/abseil-cpp/absl/container/internal/compressed_tuple_test.cc +13 -13
- package/vendor/abseil-cpp/absl/container/internal/container_memory.h +41 -31
- package/vendor/abseil-cpp/absl/container/internal/hash_function_defaults.h +2 -2
- package/vendor/abseil-cpp/absl/container/internal/hash_generator_testing.h +4 -4
- package/vendor/abseil-cpp/absl/container/internal/hash_policy_traits.h +3 -3
- package/vendor/abseil-cpp/absl/container/internal/hashtable_control_bytes.h +27 -19
- package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler.cc +2 -2
- package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler.h +0 -17
- package/vendor/abseil-cpp/absl/container/internal/hashtablez_sampler_test.cc +12 -30
- package/vendor/abseil-cpp/absl/container/internal/inlined_vector.h +28 -28
- package/vendor/abseil-cpp/absl/container/internal/layout.h +13 -13
- package/vendor/abseil-cpp/absl/container/internal/layout_test.cc +3 -2
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_map.h +60 -62
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_set.cc +59 -39
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_set.h +619 -326
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_benchmark.cc +25 -2
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_probe_benchmark.cc +4 -4
- package/vendor/abseil-cpp/absl/container/internal/raw_hash_set_test.cc +575 -159
- package/vendor/abseil-cpp/absl/container/linked_hash_map.h +2 -2
- package/vendor/abseil-cpp/absl/container/node_hash_map.h +27 -15
- package/vendor/abseil-cpp/absl/container/node_hash_map_test.cc +34 -0
- package/vendor/abseil-cpp/absl/container/node_hash_set.h +25 -11
- package/vendor/abseil-cpp/absl/container/node_hash_set_test.cc +39 -7
- package/vendor/abseil-cpp/absl/container/sample_element_size_test.cc +7 -4
- package/vendor/abseil-cpp/absl/crc/BUILD.bazel +0 -1
- package/vendor/abseil-cpp/absl/crc/CMakeLists.txt +2 -3
- package/vendor/abseil-cpp/absl/crc/crc32c_benchmark.cc +2 -1
- package/vendor/abseil-cpp/absl/crc/internal/cpu_detect.cc +6 -6
- package/vendor/abseil-cpp/absl/crc/internal/crc.cc +4 -6
- package/vendor/abseil-cpp/absl/crc/internal/crc32_x86_arm_combined_simd.h +41 -0
- package/vendor/abseil-cpp/absl/crc/internal/crc_internal.h +0 -16
- package/vendor/abseil-cpp/absl/crc/internal/crc_x86_arm_combined.cc +143 -81
- package/vendor/abseil-cpp/absl/debugging/BUILD.bazel +9 -31
- package/vendor/abseil-cpp/absl/debugging/CMakeLists.txt +3 -33
- package/vendor/abseil-cpp/absl/debugging/internal/demangle_rust.h +8 -0
- package/vendor/abseil-cpp/absl/debugging/internal/demangle_test.cc +2 -1
- package/vendor/abseil-cpp/absl/debugging/internal/examine_stack.cc +12 -2
- package/vendor/abseil-cpp/absl/debugging/internal/examine_stack.h +2 -3
- package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc +11 -0
- package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_emscripten-inl.inc +13 -4
- package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc +14 -7
- package/vendor/abseil-cpp/absl/debugging/internal/stacktrace_riscv-inl.inc +4 -0
- package/vendor/abseil-cpp/absl/debugging/internal/symbolize.h +46 -36
- package/vendor/abseil-cpp/absl/debugging/stacktrace.cc +18 -58
- package/vendor/abseil-cpp/absl/debugging/stacktrace.h +5 -48
- package/vendor/abseil-cpp/absl/debugging/stacktrace_test.cc +10 -124
- package/vendor/abseil-cpp/absl/debugging/symbolize.cc +20 -2
- package/vendor/abseil-cpp/absl/debugging/symbolize_elf.inc +58 -106
- package/vendor/abseil-cpp/absl/debugging/symbolize_test.cc +37 -36
- package/vendor/abseil-cpp/absl/debugging/symbolize_unimplemented.inc +4 -4
- package/vendor/abseil-cpp/absl/flags/BUILD.bazel +6 -3
- package/vendor/abseil-cpp/absl/flags/CMakeLists.txt +1 -1
- package/vendor/abseil-cpp/absl/flags/commandlineflag.h +8 -6
- package/vendor/abseil-cpp/absl/flags/commandlineflag_test.cc +1 -1
- package/vendor/abseil-cpp/absl/flags/flag_benchmark.cc +5 -5
- package/vendor/abseil-cpp/absl/flags/flag_test.cc +30 -30
- package/vendor/abseil-cpp/absl/flags/internal/flag.cc +4 -4
- package/vendor/abseil-cpp/absl/flags/internal/flag.h +6 -6
- package/vendor/abseil-cpp/absl/flags/marshalling.h +2 -28
- package/vendor/abseil-cpp/absl/flags/marshalling_test.cc +12 -11
- package/vendor/abseil-cpp/absl/flags/reflection_test.cc +1 -1
- package/vendor/abseil-cpp/absl/functional/BUILD.bazel +26 -1
- package/vendor/abseil-cpp/absl/functional/CMakeLists.txt +29 -1
- package/vendor/abseil-cpp/absl/functional/any_invocable.h +13 -14
- package/vendor/abseil-cpp/absl/functional/any_invocable_test.cc +46 -47
- package/vendor/abseil-cpp/absl/functional/bind_back.h +79 -0
- package/vendor/abseil-cpp/absl/functional/bind_back_test.cc +237 -0
- package/vendor/abseil-cpp/absl/functional/bind_front.h +7 -1
- package/vendor/abseil-cpp/absl/functional/bind_front_test.cc +4 -4
- package/vendor/abseil-cpp/absl/functional/function_ref_test.cc +2 -2
- package/vendor/abseil-cpp/absl/functional/internal/any_invocable.h +28 -28
- package/vendor/abseil-cpp/absl/functional/internal/back_binder.h +95 -0
- package/vendor/abseil-cpp/absl/functional/internal/front_binder.h +4 -4
- package/vendor/abseil-cpp/absl/functional/internal/function_ref.h +2 -2
- package/vendor/abseil-cpp/absl/functional/overload_test.cc +13 -13
- package/vendor/abseil-cpp/absl/hash/BUILD.bazel +1 -2
- package/vendor/abseil-cpp/absl/hash/CMakeLists.txt +1 -2
- package/vendor/abseil-cpp/absl/hash/hash.h +1 -1
- package/vendor/abseil-cpp/absl/hash/hash_test.cc +14 -20
- package/vendor/abseil-cpp/absl/hash/hash_testing.h +11 -9
- package/vendor/abseil-cpp/absl/hash/internal/city.cc +39 -51
- package/vendor/abseil-cpp/absl/hash/internal/hash.cc +165 -47
- package/vendor/abseil-cpp/absl/hash/internal/hash.h +86 -27
- package/vendor/abseil-cpp/absl/hash/internal/low_level_hash_test.cc +36 -1
- package/vendor/abseil-cpp/absl/hash/internal/spy_hash_state.h +8 -5
- package/vendor/abseil-cpp/absl/log/BUILD.bazel +5 -2
- package/vendor/abseil-cpp/absl/log/CMakeLists.txt +5 -3
- package/vendor/abseil-cpp/absl/log/absl_vlog_is_on.h +0 -2
- package/vendor/abseil-cpp/absl/log/internal/BUILD.bazel +15 -1
- package/vendor/abseil-cpp/absl/log/internal/log_message.cc +5 -4
- package/vendor/abseil-cpp/absl/log/internal/log_message.h +14 -0
- package/vendor/abseil-cpp/absl/log/internal/nullstream.h +1 -1
- package/vendor/abseil-cpp/absl/log/internal/proto.cc +13 -0
- package/vendor/abseil-cpp/absl/log/internal/structured_proto.cc +5 -5
- package/vendor/abseil-cpp/absl/log/internal/structured_proto.h +6 -5
- package/vendor/abseil-cpp/absl/log/internal/structured_proto_test.cc +3 -3
- package/vendor/abseil-cpp/absl/log/internal/vlog_config.cc +2 -2
- package/vendor/abseil-cpp/absl/log/internal/vlog_config_benchmark.cc +3 -3
- package/vendor/abseil-cpp/absl/log/log_format_test.cc +19 -2
- package/vendor/abseil-cpp/absl/log/log_modifier_methods_test.cc +18 -0
- package/vendor/abseil-cpp/absl/log/log_streamer.h +29 -2
- package/vendor/abseil-cpp/absl/log/log_streamer_test.cc +18 -0
- package/vendor/abseil-cpp/absl/log/scoped_mock_log_test.cc +1 -1
- package/vendor/abseil-cpp/absl/log/vlog_is_on.h +0 -2
- package/vendor/abseil-cpp/absl/log/vlog_is_on_test.cc +6 -5
- package/vendor/abseil-cpp/absl/memory/memory.h +55 -5
- package/vendor/abseil-cpp/absl/memory/memory_test.cc +55 -1
- package/vendor/abseil-cpp/absl/meta/BUILD.bazel +2 -0
- package/vendor/abseil-cpp/absl/meta/internal/requires.h +1 -1
- package/vendor/abseil-cpp/absl/meta/type_traits.h +119 -55
- package/vendor/abseil-cpp/absl/meta/type_traits_test.cc +7 -7
- package/vendor/abseil-cpp/absl/numeric/int128_test.cc +6 -6
- package/vendor/abseil-cpp/absl/profiling/BUILD.bazel +3 -1
- package/vendor/abseil-cpp/absl/profiling/hashtable.cc +0 -4
- package/vendor/abseil-cpp/absl/profiling/internal/profile_builder.cc +32 -33
- package/vendor/abseil-cpp/absl/profiling/internal/profile_builder.h +25 -2
- package/vendor/abseil-cpp/absl/profiling/internal/sample_recorder_test.cc +8 -5
- package/vendor/abseil-cpp/absl/random/BUILD.bazel +13 -1
- package/vendor/abseil-cpp/absl/random/CMakeLists.txt +23 -2
- package/vendor/abseil-cpp/absl/random/benchmarks.cc +1 -1
- package/vendor/abseil-cpp/absl/random/beta_distribution.h +2 -2
- package/vendor/abseil-cpp/absl/random/bit_gen_ref.h +26 -53
- package/vendor/abseil-cpp/absl/random/bit_gen_ref_test.cc +43 -0
- package/vendor/abseil-cpp/absl/random/discrete_distribution.h +1 -1
- package/vendor/abseil-cpp/absl/random/distributions.h +17 -17
- package/vendor/abseil-cpp/absl/random/distributions_test.cc +4 -4
- package/vendor/abseil-cpp/absl/random/exponential_distribution.h +1 -1
- package/vendor/abseil-cpp/absl/random/internal/BUILD.bazel +4 -2
- package/vendor/abseil-cpp/absl/random/internal/distribution_caller.h +8 -21
- package/vendor/abseil-cpp/absl/random/internal/fast_uniform_bits.h +1 -1
- package/vendor/abseil-cpp/absl/random/internal/generate_real.h +1 -1
- package/vendor/abseil-cpp/absl/random/internal/iostream_state_saver.h +2 -2
- package/vendor/abseil-cpp/absl/random/internal/iostream_state_saver_test.cc +3 -2
- package/vendor/abseil-cpp/absl/random/internal/mock_helpers.h +14 -40
- package/vendor/abseil-cpp/absl/random/internal/nonsecure_base.h +2 -2
- package/vendor/abseil-cpp/absl/random/internal/nonsecure_base_test.cc +2 -2
- package/vendor/abseil-cpp/absl/random/internal/pcg_engine.h +6 -6
- package/vendor/abseil-cpp/absl/random/internal/pcg_engine_test.cc +3 -2
- package/vendor/abseil-cpp/absl/random/internal/randen_detect.cc +6 -6
- package/vendor/abseil-cpp/absl/random/internal/randen_engine.h +2 -2
- package/vendor/abseil-cpp/absl/random/internal/randen_engine_test.cc +3 -2
- package/vendor/abseil-cpp/absl/random/internal/randen_test.cc +3 -2
- package/vendor/abseil-cpp/absl/random/internal/salted_seed_seq.h +6 -5
- package/vendor/abseil-cpp/absl/random/internal/seed_material.cc +4 -4
- package/vendor/abseil-cpp/absl/random/internal/seed_material.h +2 -1
- package/vendor/abseil-cpp/absl/random/internal/traits.h +21 -0
- package/vendor/abseil-cpp/absl/random/internal/traits_test.cc +5 -0
- package/vendor/abseil-cpp/absl/random/internal/uniform_helper.h +23 -23
- package/vendor/abseil-cpp/absl/random/internal/uniform_helper_test.cc +2 -1
- package/vendor/abseil-cpp/absl/random/mocking_access.h +74 -0
- package/vendor/abseil-cpp/absl/random/mocking_bit_gen.h +9 -19
- package/vendor/abseil-cpp/absl/random/uniform_real_distribution.h +1 -1
- package/vendor/abseil-cpp/absl/status/BUILD.bazel +81 -0
- package/vendor/abseil-cpp/absl/status/CMakeLists.txt +91 -0
- package/vendor/abseil-cpp/absl/status/internal/status_internal.cc +63 -18
- package/vendor/abseil-cpp/absl/status/internal/status_internal.h +26 -2
- package/vendor/abseil-cpp/absl/status/internal/status_matchers.h +22 -8
- package/vendor/abseil-cpp/absl/status/internal/statusor_internal.h +43 -43
- package/vendor/abseil-cpp/absl/status/status.cc +62 -70
- package/vendor/abseil-cpp/absl/status/status.h +249 -23
- package/vendor/abseil-cpp/absl/status/status_benchmark.cc +12 -0
- package/vendor/abseil-cpp/absl/status/status_builder.cc +196 -0
- package/vendor/abseil-cpp/absl/status/status_builder.h +978 -0
- package/vendor/abseil-cpp/absl/status/status_builder_test.cc +380 -0
- package/vendor/abseil-cpp/absl/status/status_macros.h +484 -0
- package/vendor/abseil-cpp/absl/status/status_macros_test.cc +634 -0
- package/vendor/abseil-cpp/absl/status/status_matchers.h +2 -1
- package/vendor/abseil-cpp/absl/status/status_matchers_test.cc +3 -4
- package/vendor/abseil-cpp/absl/status/status_payload_printer.h +3 -2
- package/vendor/abseil-cpp/absl/status/status_test.cc +443 -13
- package/vendor/abseil-cpp/absl/status/statusor.h +69 -36
- package/vendor/abseil-cpp/absl/status/statusor_test.cc +132 -35
- package/vendor/abseil-cpp/absl/strings/BUILD.bazel +42 -7
- package/vendor/abseil-cpp/absl/strings/CMakeLists.txt +33 -4
- package/vendor/abseil-cpp/absl/strings/ascii.h +1 -2
- package/vendor/abseil-cpp/absl/strings/atod_manual_test.cc +5 -5
- package/vendor/abseil-cpp/absl/strings/cord.cc +26 -7
- package/vendor/abseil-cpp/absl/strings/cord.h +23 -13
- package/vendor/abseil-cpp/absl/strings/cord_buffer.h +4 -2
- package/vendor/abseil-cpp/absl/strings/cord_test.cc +85 -9
- package/vendor/abseil-cpp/absl/strings/escaping.cc +183 -35
- package/vendor/abseil-cpp/absl/strings/escaping.h +12 -2
- package/vendor/abseil-cpp/absl/strings/escaping_benchmark.cc +1 -3
- package/vendor/abseil-cpp/absl/strings/escaping_test.cc +22 -18
- package/vendor/abseil-cpp/absl/strings/has_absl_stringify_test.cc +2 -2
- package/vendor/abseil-cpp/absl/strings/has_ostream_operator_test.cc +2 -2
- package/vendor/abseil-cpp/absl/strings/internal/append_and_overwrite.h +10 -10
- package/vendor/abseil-cpp/absl/strings/internal/cordz_sample_token_test.cc +1 -1
- package/vendor/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.cc +6 -0
- package/vendor/abseil-cpp/absl/strings/internal/damerau_levenshtein_distance.h +1 -0
- package/vendor/abseil-cpp/absl/strings/internal/escaping.cc +0 -141
- package/vendor/abseil-cpp/absl/strings/internal/escaping.h +2 -26
- package/vendor/abseil-cpp/absl/strings/internal/generic_printer_internal.h +23 -2
- package/vendor/abseil-cpp/absl/strings/internal/generic_printer_test.cc +6 -2
- package/vendor/abseil-cpp/absl/strings/internal/resize_uninitialized.h +31 -24
- package/vendor/abseil-cpp/absl/strings/internal/resize_uninitialized_test.cc +16 -41
- package/vendor/abseil-cpp/absl/strings/internal/stl_type_traits.h +39 -39
- package/vendor/abseil-cpp/absl/strings/internal/str_format/arg.h +14 -22
- package/vendor/abseil-cpp/absl/strings/internal/str_format/bind.h +2 -2
- package/vendor/abseil-cpp/absl/strings/internal/str_format/convert_test.cc +12 -20
- package/vendor/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc +510 -307
- package/vendor/abseil-cpp/absl/strings/internal/str_join_internal.h +0 -1
- package/vendor/abseil-cpp/absl/strings/internal/str_split_internal.h +9 -10
- package/vendor/abseil-cpp/absl/strings/internal/string_constant_test.cc +6 -5
- package/vendor/abseil-cpp/absl/strings/internal/stringify_sink.h +12 -0
- package/vendor/abseil-cpp/absl/strings/internal/stringify_stream.h +119 -0
- package/vendor/abseil-cpp/absl/strings/internal/stringify_stream_test.cc +111 -0
- package/vendor/abseil-cpp/absl/strings/numbers.cc +406 -0
- package/vendor/abseil-cpp/absl/strings/numbers.h +4 -0
- package/vendor/abseil-cpp/absl/strings/numbers_test.cc +33 -0
- package/vendor/abseil-cpp/absl/strings/resize_and_overwrite.h +10 -6
- package/vendor/abseil-cpp/absl/strings/str_cat.h +36 -1
- package/vendor/abseil-cpp/absl/strings/str_cat_benchmark.cc +1 -2
- package/vendor/abseil-cpp/absl/strings/str_cat_test.cc +28 -0
- package/vendor/abseil-cpp/absl/strings/str_join_test.cc +4 -4
- package/vendor/abseil-cpp/absl/strings/str_split.h +11 -6
- package/vendor/abseil-cpp/absl/strings/str_split_test.cc +13 -0
- package/vendor/abseil-cpp/absl/strings/substitute.h +2 -2
- package/vendor/abseil-cpp/absl/synchronization/BUILD.bazel +3 -0
- package/vendor/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc +21 -0
- package/vendor/abseil-cpp/absl/synchronization/internal/per_thread_sem.h +5 -0
- package/vendor/abseil-cpp/absl/synchronization/mutex.cc +13 -0
- package/vendor/abseil-cpp/absl/synchronization/mutex.h +32 -2
- package/vendor/abseil-cpp/absl/synchronization/mutex_test.cc +17 -3
- package/vendor/abseil-cpp/absl/time/BUILD.bazel +80 -0
- package/vendor/abseil-cpp/absl/time/CMakeLists.txt +73 -0
- package/vendor/abseil-cpp/absl/time/clock.h +3 -0
- package/vendor/abseil-cpp/absl/time/clock_interface.cc +71 -0
- package/vendor/abseil-cpp/absl/time/clock_interface.h +93 -0
- package/vendor/abseil-cpp/absl/time/clock_interface_test.cc +128 -0
- package/vendor/abseil-cpp/absl/time/format.cc +3 -10
- package/vendor/abseil-cpp/absl/time/format_test.cc +12 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc +90 -89
- package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc +80 -5
- package/vendor/abseil-cpp/absl/time/internal/cctz/src/time_zone_name_win.cc +1 -2
- package/vendor/abseil-cpp/absl/time/internal/cctz/src/tzfile.h +10 -15
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/version +1 -1
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol +0 -0
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab +1 -1
- package/vendor/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab +3 -3
- package/vendor/abseil-cpp/absl/time/simulated_clock.cc +225 -0
- package/vendor/abseil-cpp/absl/time/simulated_clock.h +109 -0
- package/vendor/abseil-cpp/absl/time/simulated_clock_test.cc +614 -0
- package/vendor/abseil-cpp/absl/types/BUILD.bazel +116 -0
- package/vendor/abseil-cpp/absl/types/CMakeLists.txt +100 -0
- package/vendor/abseil-cpp/absl/types/any.h +26 -4
- package/vendor/abseil-cpp/absl/types/any_span.h +1067 -0
- package/vendor/abseil-cpp/absl/types/any_span_benchmark.cc +258 -0
- package/vendor/abseil-cpp/absl/types/any_span_test.cc +1210 -0
- package/vendor/abseil-cpp/absl/types/compare.h +4 -4
- package/vendor/abseil-cpp/absl/types/internal/any_span.h +477 -0
- package/vendor/abseil-cpp/absl/types/internal/span.h +5 -6
- package/vendor/abseil-cpp/absl/types/optional.h +30 -3
- package/vendor/abseil-cpp/absl/types/optional_ref.h +295 -0
- package/vendor/abseil-cpp/absl/types/optional_ref_test.cc +370 -0
- package/vendor/abseil-cpp/absl/types/source_location.cc +18 -0
- package/vendor/abseil-cpp/absl/types/source_location.h +172 -0
- package/vendor/abseil-cpp/absl/types/source_location_test.cc +139 -0
- package/vendor/abseil-cpp/absl/types/span.h +19 -23
- package/vendor/abseil-cpp/absl/types/variant.h +75 -18
- package/vendor/abseil-cpp/absl/types/variant_test.cc +23 -23
- package/vendor/abseil-cpp/absl/utility/BUILD.bazel +1 -0
- package/vendor/abseil-cpp/absl/utility/CMakeLists.txt +1 -0
- package/vendor/abseil-cpp/absl/utility/utility.h +99 -16
- package/vendor/abseil-cpp/ci/absl_alternate_options.h +2 -0
- package/vendor/abseil-cpp/ci/linux_arm_clang-latest_libcxx_bazel.sh +10 -4
- package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_asan_bazel.sh +13 -6
- package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_bazel.sh +10 -4
- package/vendor/abseil-cpp/ci/linux_clang-latest_libcxx_tsan_bazel.sh +12 -5
- package/vendor/abseil-cpp/ci/linux_clang-latest_libstdcxx_bazel.sh +9 -2
- package/vendor/abseil-cpp/ci/linux_docker_containers.sh +4 -4
- package/vendor/abseil-cpp/ci/linux_gcc-floor_libstdcxx_bazel.sh +10 -3
- package/vendor/abseil-cpp/ci/linux_gcc-latest_libstdcxx_bazel.sh +8 -2
- package/vendor/abseil-cpp/ci/macos_xcode_bazel.sh +4 -3
- package/vendor/abseil-cpp/ci/macos_xcode_cmake.sh +2 -2
- package/vendor/abseil-cpp/ci/windows_clangcl_bazel.bat +1 -1
- package/vendor/abseil-cpp/ci/windows_msvc_bazel.bat +1 -1
- package/vendor/abseil-cpp/absl/debugging/internal/borrowed_fixup_buffer.cc +0 -118
- package/vendor/abseil-cpp/absl/debugging/internal/borrowed_fixup_buffer.h +0 -71
- package/vendor/abseil-cpp/absl/debugging/internal/borrowed_fixup_buffer_test.cc +0 -97
|
@@ -221,6 +221,14 @@
|
|
|
221
221
|
#include "absl/numeric/bits.h"
|
|
222
222
|
#include "absl/utility/utility.h"
|
|
223
223
|
|
|
224
|
+
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
|
|
225
|
+
#include <ranges> // NOLINT(build/c++20)
|
|
226
|
+
#endif
|
|
227
|
+
|
|
228
|
+
#ifdef __BMI2__
|
|
229
|
+
#include <bmi2intrin.h>
|
|
230
|
+
#endif // __BMI2__
|
|
231
|
+
|
|
224
232
|
namespace absl {
|
|
225
233
|
ABSL_NAMESPACE_BEGIN
|
|
226
234
|
namespace container_internal {
|
|
@@ -297,57 +305,6 @@ void CopyAlloc(AllocType& lhs, AllocType& rhs,
|
|
|
297
305
|
template <typename AllocType>
|
|
298
306
|
void CopyAlloc(AllocType&, AllocType&, std::false_type /* propagate_alloc */) {}
|
|
299
307
|
|
|
300
|
-
// The state for a probe sequence.
|
|
301
|
-
//
|
|
302
|
-
// Currently, the sequence is a triangular progression of the form
|
|
303
|
-
//
|
|
304
|
-
// p(i) := Width * (i^2 + i)/2 + hash (mod mask + 1)
|
|
305
|
-
//
|
|
306
|
-
// The use of `Width` ensures that each probe step does not overlap groups;
|
|
307
|
-
// the sequence effectively outputs the addresses of *groups* (although not
|
|
308
|
-
// necessarily aligned to any boundary). The `Group` machinery allows us
|
|
309
|
-
// to check an entire group with minimal branching.
|
|
310
|
-
//
|
|
311
|
-
// Wrapping around at `mask + 1` is important, but not for the obvious reason.
|
|
312
|
-
// As described above, the first few entries of the control byte array
|
|
313
|
-
// are mirrored at the end of the array, which `Group` will find and use
|
|
314
|
-
// for selecting candidates. However, when those candidates' slots are
|
|
315
|
-
// actually inspected, there are no corresponding slots for the cloned bytes,
|
|
316
|
-
// so we need to make sure we've treated those offsets as "wrapping around".
|
|
317
|
-
//
|
|
318
|
-
// It turns out that this probe sequence visits every group exactly once if the
|
|
319
|
-
// number of groups is a power of two, since (i^2+i)/2 is a bijection in
|
|
320
|
-
// Z/(2^m). See https://en.wikipedia.org/wiki/Quadratic_probing
|
|
321
|
-
template <size_t Width>
|
|
322
|
-
class probe_seq {
|
|
323
|
-
public:
|
|
324
|
-
// Creates a new probe sequence using `hash` as the initial value of the
|
|
325
|
-
// sequence and `mask` (usually the capacity of the table) as the mask to
|
|
326
|
-
// apply to each value in the progression.
|
|
327
|
-
probe_seq(size_t hash, size_t mask) {
|
|
328
|
-
ABSL_SWISSTABLE_ASSERT(((mask + 1) & mask) == 0 && "not a mask");
|
|
329
|
-
mask_ = mask;
|
|
330
|
-
offset_ = hash & mask_;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// The offset within the table, i.e., the value `p(i)` above.
|
|
334
|
-
size_t offset() const { return offset_; }
|
|
335
|
-
size_t offset(size_t i) const { return (offset_ + i) & mask_; }
|
|
336
|
-
|
|
337
|
-
void next() {
|
|
338
|
-
index_ += Width;
|
|
339
|
-
offset_ += index_;
|
|
340
|
-
offset_ &= mask_;
|
|
341
|
-
}
|
|
342
|
-
// 0-based probe index, a multiple of `Width`.
|
|
343
|
-
size_t index() const { return index_; }
|
|
344
|
-
|
|
345
|
-
private:
|
|
346
|
-
size_t mask_;
|
|
347
|
-
size_t offset_;
|
|
348
|
-
size_t index_ = 0;
|
|
349
|
-
};
|
|
350
|
-
|
|
351
308
|
template <class ContainerKey, class Hash, class Eq>
|
|
352
309
|
struct RequireUsableKey {
|
|
353
310
|
template <class PassedKey, class... Args>
|
|
@@ -363,25 +320,13 @@ struct IsDecomposable : std::false_type {};
|
|
|
363
320
|
|
|
364
321
|
template <class Policy, class Hash, class Eq, class... Ts>
|
|
365
322
|
struct IsDecomposable<
|
|
366
|
-
|
|
323
|
+
std::void_t<decltype(Policy::apply(
|
|
367
324
|
RequireUsableKey<typename Policy::key_type, Hash, Eq>(),
|
|
368
325
|
std::declval<Ts>()...))>,
|
|
369
326
|
Policy, Hash, Eq, Ts...> : std::true_type {};
|
|
370
327
|
|
|
371
328
|
ABSL_DLL extern ctrl_t kDefaultIterControl;
|
|
372
329
|
|
|
373
|
-
// We use these sentinel capacity values in debug mode to indicate different
|
|
374
|
-
// classes of bugs.
|
|
375
|
-
enum InvalidCapacity : size_t {
|
|
376
|
-
kAboveMaxValidCapacity = ~size_t{} - 100,
|
|
377
|
-
kReentrance,
|
|
378
|
-
kDestroyed,
|
|
379
|
-
|
|
380
|
-
// These two must be last because we use `>= kMovedFrom` to mean moved-from.
|
|
381
|
-
kMovedFrom,
|
|
382
|
-
kSelfMovedFrom,
|
|
383
|
-
};
|
|
384
|
-
|
|
385
330
|
// Returns a pointer to a control byte that can be used by default-constructed
|
|
386
331
|
// iterators. We don't expect this pointer to be dereferenced.
|
|
387
332
|
inline ctrl_t* DefaultIterControl() { return &kDefaultIterControl; }
|
|
@@ -417,6 +362,8 @@ inline bool IsEmptyGeneration(const GenerationType* generation) {
|
|
|
417
362
|
// - In order to prevent user code from depending on iteration order for small
|
|
418
363
|
// tables, we would need to randomize the iteration order somehow.
|
|
419
364
|
constexpr size_t SooCapacity() { return 1; }
|
|
365
|
+
// Maximum capacity of a table where we don't need to hash any keys.
|
|
366
|
+
constexpr size_t MaxSmallCapacity() { return 1; }
|
|
420
367
|
// Sentinel type to indicate SOO CommonFields construction.
|
|
421
368
|
struct soo_tag_t {};
|
|
422
369
|
// Sentinel type to indicate SOO CommonFields construction with full size.
|
|
@@ -428,74 +375,308 @@ struct uninitialized_tag_t {};
|
|
|
428
375
|
// Sentinel value to indicate creation of an empty table without a seed.
|
|
429
376
|
struct no_seed_empty_tag_t {};
|
|
430
377
|
|
|
378
|
+
// Returns whether `n` is a valid capacity (i.e., number of slots).
|
|
379
|
+
//
|
|
380
|
+
// A valid capacity is a non-zero integer `2^m - 1`.
|
|
381
|
+
constexpr bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
|
|
382
|
+
|
|
383
|
+
// Whether a table is small enough that we don't need to hash any keys.
|
|
384
|
+
constexpr bool IsSmallCapacity(size_t capacity) {
|
|
385
|
+
return capacity <= MaxSmallCapacity();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Converts `n` into the next valid capacity, per `IsValidCapacity`.
|
|
389
|
+
constexpr size_t NormalizeCapacity(size_t n) {
|
|
390
|
+
return n ? ~size_t{} >> countl_zero(n) : 1;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Returns the next valid capacity after `n`.
|
|
394
|
+
constexpr size_t NextCapacity(size_t n) {
|
|
395
|
+
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n) || n == 0);
|
|
396
|
+
return n * 2 + 1;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Returns the previous valid capacity before `n`.
|
|
400
|
+
constexpr size_t PreviousCapacity(size_t n) {
|
|
401
|
+
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n));
|
|
402
|
+
return n / 2;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// General notes on capacity/growth methods below:
|
|
406
|
+
// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
|
|
407
|
+
// average of two empty slots per group.
|
|
408
|
+
// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
|
|
409
|
+
// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
|
|
410
|
+
// never need to probe (the whole table fits in one group) so we don't need a
|
|
411
|
+
// load factor less than 1.
|
|
412
|
+
|
|
413
|
+
// Given `capacity`, applies the load factor; i.e., it returns the maximum
|
|
414
|
+
// number of values we should put into the table before a resizing rehash.
|
|
415
|
+
constexpr size_t CapacityToGrowth(size_t capacity) {
|
|
416
|
+
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
|
|
417
|
+
// `capacity*7/8`
|
|
418
|
+
if (Group::kWidth == 8 && capacity == 7) {
|
|
419
|
+
// x-x/8 does not work when x==7.
|
|
420
|
+
return 6;
|
|
421
|
+
}
|
|
422
|
+
return capacity - capacity / 8;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Given `size`, "unapplies" the load factor to find how large the capacity
|
|
426
|
+
// should be to stay within the load factor.
|
|
427
|
+
//
|
|
428
|
+
// For size == 0, returns 0.
|
|
429
|
+
// For other values, returns the same as `NormalizeCapacity(size*8/7)`.
|
|
430
|
+
constexpr size_t SizeToCapacity(size_t size) {
|
|
431
|
+
if (size == 0) {
|
|
432
|
+
return 0;
|
|
433
|
+
}
|
|
434
|
+
// The minimum possible capacity is NormalizeCapacity(size).
|
|
435
|
+
// Shifting right `~size_t{}` by `leading_zeros` yields
|
|
436
|
+
// NormalizeCapacity(size).
|
|
437
|
+
int leading_zeros = absl::countl_zero(size);
|
|
438
|
+
constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
|
|
439
|
+
// max_size_for_next_capacity = max_load_factor * next_capacity
|
|
440
|
+
// = (7/8) * (~size_t{} >> leading_zeros)
|
|
441
|
+
// = (7/8*~size_t{}) >> leading_zeros
|
|
442
|
+
// = kLast3Bits >> leading_zeros
|
|
443
|
+
size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
|
|
444
|
+
// Decrease shift if size is too big for the minimum capacity.
|
|
445
|
+
leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
|
|
446
|
+
if constexpr (Group::kWidth == 8) {
|
|
447
|
+
// Formula doesn't work when size==7 for 8-wide groups.
|
|
448
|
+
leading_zeros -= (size == 7);
|
|
449
|
+
}
|
|
450
|
+
return (~size_t{}) >> leading_zeros;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// The mode we store capacity in the table.
|
|
454
|
+
enum HashtableCapacityStorageMode {
|
|
455
|
+
// Capacity stored as size_t as a full number.
|
|
456
|
+
kCapacityByValue,
|
|
457
|
+
// Capacity stored as uint8_t as log2, i.e. capacity = 2^capacity_ - 1.
|
|
458
|
+
kCapacityByLog,
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
// The number of slots in the backing array. This is always 2^N-1 for an
|
|
462
|
+
// integer N.
|
|
463
|
+
// NOTE: this class exists to simplify experiments with different ways to store
|
|
464
|
+
// capacity within size.
|
|
465
|
+
// NOTE: we tried experimenting with compressing the capacity and storing it
|
|
466
|
+
// together with size_: (a) using 6 bits to store the corresponding power (N in
|
|
467
|
+
// 2^N-1), and (b) storing 2^N as the most significant bit of size_ and storing
|
|
468
|
+
// size in the low bits. Both of these experiments were regressions, presumably
|
|
469
|
+
// because we need capacity to do find operations.
|
|
470
|
+
template <HashtableCapacityStorageMode StorageMode>
|
|
471
|
+
class HashtableCapacityImpl {
|
|
472
|
+
using IntType =
|
|
473
|
+
std::conditional_t<StorageMode == kCapacityByValue, size_t, uint8_t>;
|
|
474
|
+
|
|
475
|
+
public:
|
|
476
|
+
static constexpr HashtableCapacityImpl CreateDestroyed() {
|
|
477
|
+
return HashtableCapacityImpl(kDestroyed);
|
|
478
|
+
}
|
|
479
|
+
static constexpr HashtableCapacityImpl CreateReentrance() {
|
|
480
|
+
return HashtableCapacityImpl(kReentrance);
|
|
481
|
+
}
|
|
482
|
+
static constexpr HashtableCapacityImpl CreateMovedFrom() {
|
|
483
|
+
return HashtableCapacityImpl(kMovedFrom);
|
|
484
|
+
}
|
|
485
|
+
static constexpr HashtableCapacityImpl CreateSelfMovedFrom() {
|
|
486
|
+
return HashtableCapacityImpl(kSelfMovedFrom);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
explicit HashtableCapacityImpl(uninitialized_tag_t) {}
|
|
490
|
+
explicit constexpr HashtableCapacityImpl(size_t capacity)
|
|
491
|
+
: capacity_data_(static_cast<IntType>(
|
|
492
|
+
StorageMode == kCapacityByValue ? capacity
|
|
493
|
+
: TrailingZeros(capacity + 1))) {
|
|
494
|
+
ABSL_SWISSTABLE_ASSERT(capacity == 0 || IsValidCapacity(capacity));
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Creates capacity from the value that was returned by `ToRawData()`.
|
|
498
|
+
// This is needed to use bitfield for capacity.
|
|
499
|
+
// At least on Windows combination uint8_t and uint64_t bitfield in one struct
|
|
500
|
+
// is not optimized by compiler.
|
|
501
|
+
static HashtableCapacityImpl FromRawData(uint64_t capacity) {
|
|
502
|
+
auto cap = HashtableCapacityImpl(uninitialized_tag_t{});
|
|
503
|
+
cap.capacity_data_ = static_cast<IntType>(capacity);
|
|
504
|
+
return cap;
|
|
505
|
+
}
|
|
506
|
+
IntType ToRawData() const { return capacity_data_; }
|
|
507
|
+
|
|
508
|
+
constexpr bool IsValid() const {
|
|
509
|
+
return capacity_data_ <= kAboveMaxValidCapacity;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
constexpr bool IsDestroyed() const { return capacity_data_ == kDestroyed; }
|
|
513
|
+
constexpr bool IsReentrance() const { return capacity_data_ == kReentrance; }
|
|
514
|
+
// Returns true if the table is moved-from including self moved-from.
|
|
515
|
+
constexpr bool IsMovedFrom() const { return capacity_data_ >= kMovedFrom; }
|
|
516
|
+
constexpr bool IsSelfMovedFrom() const {
|
|
517
|
+
return capacity_data_ == kSelfMovedFrom;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
constexpr size_t capacity() const {
|
|
521
|
+
ABSL_SWISSTABLE_ASSERT(IsValid());
|
|
522
|
+
return StorageMode == kCapacityByValue ? capacity_data_
|
|
523
|
+
: (size_t{1} << capacity_data_) - 1;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
constexpr bool is_small() const {
|
|
527
|
+
// Small tables have capacity 0 or 1. This expression is valid for both
|
|
528
|
+
// capacity storage modes.
|
|
529
|
+
// Comparing capacity_data_ directly leads to a better generated code.
|
|
530
|
+
// One byte comparison is used before computing the capacity in order to
|
|
531
|
+
// detect small tables faster for critical path.
|
|
532
|
+
static_assert(MaxSmallCapacity() == 1);
|
|
533
|
+
return capacity_data_ <= 1;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
constexpr size_t mask(size_t value) const {
|
|
537
|
+
#ifdef __BMI2__
|
|
538
|
+
if constexpr (StorageMode == kCapacityByLog) {
|
|
539
|
+
if constexpr (sizeof(size_t) == 8) {
|
|
540
|
+
return _bzhi_u64(value, capacity_data_);
|
|
541
|
+
} else {
|
|
542
|
+
return _bzhi_u32(value, capacity_data_);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
#endif // __BMI2__
|
|
546
|
+
return value & capacity();
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
private:
|
|
550
|
+
// We use these sentinel capacity values in debug mode to indicate different
|
|
551
|
+
// classes of bugs.
|
|
552
|
+
enum InvalidCapacity : IntType {
|
|
553
|
+
kAboveMaxValidCapacity = (std::numeric_limits<IntType>::max)() - 100,
|
|
554
|
+
kReentrance,
|
|
555
|
+
kDestroyed,
|
|
556
|
+
|
|
557
|
+
// These two must be last because we use `>= kMovedFrom` to mean moved-from.
|
|
558
|
+
kMovedFrom,
|
|
559
|
+
kSelfMovedFrom,
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
explicit constexpr HashtableCapacityImpl(InvalidCapacity capacity)
|
|
563
|
+
: capacity_data_(capacity) {
|
|
564
|
+
ABSL_SWISSTABLE_ASSERT(capacity_data_ > kAboveMaxValidCapacity);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Capacity is stored as a value or as a log2 depending on `StorageMode`.
|
|
568
|
+
IntType capacity_data_;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
template <HashtableCapacityStorageMode StorageMode>
|
|
572
|
+
class HashtableInlineDataImpl;
|
|
573
|
+
|
|
574
|
+
// Returns next per-table seed.
|
|
575
|
+
uint16_t NextHashTableSeed();
|
|
576
|
+
|
|
431
577
|
// Per table hash salt. This gets mixed into H1 to randomize iteration order
|
|
432
578
|
// per-table.
|
|
433
579
|
// The seed is needed to ensure non-determinism of iteration order.
|
|
434
|
-
|
|
580
|
+
template <typename StorageType>
|
|
581
|
+
class PerTableSeedImpl {
|
|
435
582
|
public:
|
|
583
|
+
using IntType = StorageType;
|
|
584
|
+
|
|
436
585
|
// The number of bits in the seed.
|
|
437
586
|
// It is big enough to ensure non-determinism of iteration order.
|
|
438
587
|
// We store the seed inside a uint64_t together with size and other metadata.
|
|
439
|
-
// Using 16 bits allows us to save one `and` instruction in H1 (we use
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
static constexpr size_t
|
|
588
|
+
// Using 8 or 16 bits allows us to save one `and` instruction in H1 (we use
|
|
589
|
+
// zero-extended move instead of mov+and). When absl::Hash is inlined, it can
|
|
590
|
+
// also have lower latency knowing that the high bits of the seed are zero.
|
|
591
|
+
static constexpr size_t kBitCount = sizeof(IntType) * 8;
|
|
592
|
+
|
|
593
|
+
// We need to use a constant seed when the table is sampled so that sampled
|
|
594
|
+
// hashes use the same seed and can e.g. identify stuck bits accurately.
|
|
595
|
+
static constexpr IntType kSampledSeed = static_cast<IntType>(~IntType{0});
|
|
443
596
|
|
|
444
597
|
// Returns the seed for the table.
|
|
445
|
-
size_t seed() const {
|
|
446
|
-
// We use a sign-extended load to ensure high bits are non-zero.
|
|
447
|
-
int16_t seed_signed = absl::bit_cast<int16_t>(seed_);
|
|
448
|
-
auto seed_sign_extended =
|
|
449
|
-
static_cast<std::make_signed_t<size_t>>(seed_signed);
|
|
450
|
-
return absl::bit_cast<size_t>(seed_sign_extended);
|
|
451
|
-
}
|
|
598
|
+
size_t seed() const { return seed_; }
|
|
452
599
|
|
|
453
600
|
private:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
601
|
+
template <HashtableCapacityStorageMode StorageMode>
|
|
602
|
+
friend class HashtableInlineDataImpl;
|
|
603
|
+
|
|
604
|
+
explicit PerTableSeedImpl(uint64_t seed)
|
|
605
|
+
: seed_(static_cast<IntType>(seed)) {}
|
|
458
606
|
|
|
459
|
-
|
|
460
|
-
// seed. This way, when sign-extended the seed has non-zero high bits.
|
|
461
|
-
const uint16_t seed_;
|
|
607
|
+
const IntType seed_;
|
|
462
608
|
};
|
|
463
609
|
|
|
464
|
-
//
|
|
610
|
+
// Capacity, size and also has additionally
|
|
465
611
|
// 1) one bit that stores whether we have infoz.
|
|
466
|
-
// 2) PerTableSeed::kBitCount bits for the seed.
|
|
467
|
-
|
|
612
|
+
// 2) PerTableSeed::kBitCount bits for the seed. (For SOO tables, the lowest
|
|
613
|
+
// bit of the seed is repurposed to track if sampling has been tried).
|
|
614
|
+
template <HashtableCapacityStorageMode StorageMode>
|
|
615
|
+
class HashtableInlineDataImpl {
|
|
468
616
|
public:
|
|
469
|
-
static constexpr
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
617
|
+
static constexpr HashtableCapacityStorageMode kStorageMode = StorageMode;
|
|
618
|
+
using PerTableSeed = PerTableSeedImpl<
|
|
619
|
+
std::conditional_t<StorageMode == kCapacityByValue, uint16_t, uint8_t>>;
|
|
620
|
+
using HashtableCapacity = HashtableCapacityImpl<StorageMode>;
|
|
621
|
+
static constexpr size_t kSizeBitCount =
|
|
622
|
+
StorageMode == kCapacityByValue
|
|
623
|
+
? 64 - PerTableSeed::kBitCount - 1
|
|
624
|
+
: 64 - PerTableSeed::kBitCount - sizeof(HashtableCapacity) * 8 - 1;
|
|
625
|
+
|
|
626
|
+
explicit HashtableInlineDataImpl(uninitialized_tag_t) {}
|
|
627
|
+
explicit HashtableInlineDataImpl(HashtableCapacity capacity,
|
|
628
|
+
no_seed_empty_tag_t)
|
|
629
|
+
: capacity_internal_(capacity.ToRawData()), data_(0) {}
|
|
630
|
+
HashtableInlineDataImpl(HashtableCapacity capacity, full_soo_tag_t,
|
|
631
|
+
bool has_tried_sampling)
|
|
632
|
+
: capacity_internal_(capacity.ToRawData()),
|
|
633
|
+
data_(kSizeOneNoMetadata |
|
|
634
|
+
(has_tried_sampling ? kSooHasTriedSamplingMask : 0)) {}
|
|
635
|
+
|
|
636
|
+
HashtableCapacity capacity() const {
|
|
637
|
+
return HashtableCapacity::FromRawData(capacity_internal_);
|
|
638
|
+
}
|
|
639
|
+
bool is_small() const { return capacity().is_small(); }
|
|
640
|
+
|
|
641
|
+
void set_capacity(HashtableCapacity c) { capacity_internal_ = c.ToRawData(); }
|
|
642
|
+
void set_capacity(size_t c) { set_capacity(HashtableCapacity(c)); }
|
|
474
643
|
|
|
475
644
|
// Returns actual size of the table.
|
|
476
645
|
size_t size() const { return static_cast<size_t>(data_ >> kSizeShift); }
|
|
477
646
|
void increment_size() { data_ += kSizeOneNoMetadata; }
|
|
478
647
|
void increment_size(size_t size) {
|
|
479
|
-
data_ += static_cast<uint64_t>(size)
|
|
648
|
+
data_ += static_cast<uint64_t>(size) << kSizeShift;
|
|
480
649
|
}
|
|
481
650
|
void decrement_size() { data_ -= kSizeOneNoMetadata; }
|
|
482
651
|
// Returns true if the table is empty.
|
|
483
652
|
bool empty() const { return data_ < kSizeOneNoMetadata; }
|
|
484
|
-
// Sets the size to zero, but keeps all the metadata bits.
|
|
485
|
-
void set_size_to_zero_keep_metadata() { data_ = data_ & kMetadataMask; }
|
|
486
653
|
|
|
487
|
-
|
|
488
|
-
|
|
654
|
+
// Returns true if an empty SOO table has already queried should_sample_soo().
|
|
655
|
+
bool soo_has_tried_sampling() const {
|
|
656
|
+
return (data_ & kSooHasTriedSamplingMask) != 0;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Records that an empty SOO table has tried sampling.
|
|
660
|
+
void set_soo_has_tried_sampling() { data_ |= kSooHasTriedSamplingMask; }
|
|
661
|
+
|
|
662
|
+
// Sets the size, but keeps all the metadata bits.
|
|
663
|
+
void set_size(size_t size) {
|
|
664
|
+
data_ =
|
|
665
|
+
(data_ & kMetadataMask) | (static_cast<uint64_t>(size) << kSizeShift);
|
|
489
666
|
}
|
|
490
667
|
|
|
491
|
-
|
|
668
|
+
PerTableSeed seed() const { return PerTableSeed(data_ & kSeedMask); }
|
|
669
|
+
|
|
670
|
+
void generate_new_seed() {
|
|
671
|
+
set_seed(static_cast<typename PerTableSeed::IntType>(NextHashTableSeed()));
|
|
672
|
+
}
|
|
492
673
|
|
|
493
674
|
// We need to use a constant seed when the table is sampled so that sampled
|
|
494
675
|
// hashes use the same seed and can e.g. identify stuck bits accurately.
|
|
495
|
-
void set_sampled_seed() { set_seed(PerTableSeed::
|
|
676
|
+
void set_sampled_seed() { set_seed(PerTableSeed::kSampledSeed); }
|
|
496
677
|
|
|
497
678
|
bool is_sampled_seed() const {
|
|
498
|
-
return (
|
|
679
|
+
return seed().seed() == PerTableSeed::kSampledSeed;
|
|
499
680
|
}
|
|
500
681
|
|
|
501
682
|
// Returns true if the table has infoz.
|
|
@@ -508,23 +689,53 @@ class HashtableSize {
|
|
|
508
689
|
|
|
509
690
|
void set_no_seed_for_testing() { data_ &= ~kSeedMask; }
|
|
510
691
|
|
|
511
|
-
// Returns next per-table seed.
|
|
512
|
-
static uint16_t NextSeed();
|
|
513
|
-
|
|
514
692
|
private:
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
693
|
+
// Bit layout of `data_` from MSB to LSB:
|
|
694
|
+
// (47 bits) : size
|
|
695
|
+
// (1 bit) : has_infoz
|
|
696
|
+
// (16 or 8 bits) : seed
|
|
697
|
+
// We don't split these components of `data_` into separate bit field elements
|
|
698
|
+
// because we get worse generated code that way.
|
|
699
|
+
static constexpr size_t kDataBitCount =
|
|
700
|
+
PerTableSeed::kBitCount + 1 + kSizeBitCount;
|
|
701
|
+
static constexpr size_t kSizeShift = kDataBitCount - kSizeBitCount;
|
|
519
702
|
static constexpr uint64_t kSizeOneNoMetadata = uint64_t{1} << kSizeShift;
|
|
520
703
|
static constexpr uint64_t kMetadataMask = kSizeOneNoMetadata - 1;
|
|
521
704
|
static constexpr uint64_t kSeedMask =
|
|
522
705
|
(uint64_t{1} << PerTableSeed::kBitCount) - 1;
|
|
523
706
|
// The next bit after the seed.
|
|
524
707
|
static constexpr uint64_t kHasInfozMask = kSeedMask + 1;
|
|
525
|
-
|
|
708
|
+
// For SOO tables, the seed is unused, and bit 0 is repurposed to track
|
|
709
|
+
// whether the table has already queried should_sample_soo().
|
|
710
|
+
static constexpr uint64_t kSooHasTriedSamplingMask = 1;
|
|
711
|
+
|
|
712
|
+
void set_seed(typename PerTableSeed::IntType seed) {
|
|
713
|
+
data_ = (data_ & ~kSeedMask) | seed;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
uint64_t capacity_internal_ : sizeof(HashtableCapacity) * 8;
|
|
717
|
+
uint64_t data_ : kDataBitCount;
|
|
526
718
|
};
|
|
527
719
|
|
|
720
|
+
static_assert(
|
|
721
|
+
sizeof(HashtableInlineDataImpl<kCapacityByValue>::HashtableCapacity) ==
|
|
722
|
+
sizeof(size_t));
|
|
723
|
+
// NOTE: some platforms have this size to be equal to 12 for two reasons:
|
|
724
|
+
// 1) alignof(uint64_t) == 4.
|
|
725
|
+
// 2) sizeof(size_t) == sizeof(HashtableCapacityImpl<kCapacityByValue>) == 4.
|
|
726
|
+
static_assert(sizeof(HashtableInlineDataImpl<kCapacityByValue>) <= 16);
|
|
727
|
+
static_assert(
|
|
728
|
+
sizeof(HashtableInlineDataImpl<kCapacityByLog>::HashtableCapacity) == 1);
|
|
729
|
+
static_assert(sizeof(HashtableInlineDataImpl<kCapacityByLog>) == 8);
|
|
730
|
+
|
|
731
|
+
#ifndef ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE
|
|
732
|
+
using HashtableInlineData = HashtableInlineDataImpl<kCapacityByLog>;
|
|
733
|
+
#else
|
|
734
|
+
using HashtableInlineData = HashtableInlineDataImpl<kCapacityByValue>;
|
|
735
|
+
#endif // ABSL_SWISSTABLE_INTERNAL_ENABLE_CAPACITY_BY_VALUE
|
|
736
|
+
using PerTableSeed = HashtableInlineData::PerTableSeed;
|
|
737
|
+
using HashtableCapacity = HashtableInlineData::HashtableCapacity;
|
|
738
|
+
|
|
528
739
|
// H1 is just the low bits of the hash.
|
|
529
740
|
inline size_t H1(size_t hash) { return hash; }
|
|
530
741
|
|
|
@@ -766,14 +977,6 @@ class GrowthInfo {
|
|
|
766
977
|
static_assert(sizeof(GrowthInfo) == sizeof(size_t), "");
|
|
767
978
|
static_assert(alignof(GrowthInfo) == alignof(size_t), "");
|
|
768
979
|
|
|
769
|
-
// Returns whether `n` is a valid capacity (i.e., number of slots).
|
|
770
|
-
//
|
|
771
|
-
// A valid capacity is a non-zero integer `2^m - 1`.
|
|
772
|
-
constexpr bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
|
|
773
|
-
|
|
774
|
-
// Whether a table is small enough that we don't need to hash any keys.
|
|
775
|
-
constexpr bool IsSmallCapacity(size_t capacity) { return capacity <= 1; }
|
|
776
|
-
|
|
777
980
|
// Returns the number of "cloned control bytes".
|
|
778
981
|
//
|
|
779
982
|
// This is the number of control bytes that are present both at the beginning
|
|
@@ -786,10 +989,20 @@ constexpr size_t NumControlBytes(size_t capacity) {
|
|
|
786
989
|
return IsSmallCapacity(capacity) ? 0 : capacity + 1 + NumClonedBytes();
|
|
787
990
|
}
|
|
788
991
|
|
|
992
|
+
// Returns whether table with the given capacity has a GrowthInfo.
|
|
993
|
+
constexpr bool HasGrowthInfoForCapacity(size_t capacity) {
|
|
994
|
+
return !IsSmallCapacity(capacity);
|
|
995
|
+
}
|
|
996
|
+
|
|
789
997
|
// Computes the offset from the start of the backing allocation of control.
|
|
790
998
|
// infoz and growth_info are stored at the beginning of the backing array.
|
|
791
|
-
constexpr size_t ControlOffset(bool has_infoz) {
|
|
792
|
-
|
|
999
|
+
constexpr size_t ControlOffset(bool has_infoz, bool has_growth_info) {
|
|
1000
|
+
if (ABSL_PREDICT_FALSE(has_infoz)) {
|
|
1001
|
+
// We always allocate GrowthInfo for sampled tables to allow branchless
|
|
1002
|
+
// access to infoz pointer.
|
|
1003
|
+
return sizeof(HashtablezInfoHandle) + sizeof(GrowthInfo);
|
|
1004
|
+
}
|
|
1005
|
+
return has_growth_info ? sizeof(GrowthInfo) : 0;
|
|
793
1006
|
}
|
|
794
1007
|
|
|
795
1008
|
// Returns the offset of the next item after `offset` that is aligned to `align`
|
|
@@ -801,12 +1014,10 @@ constexpr size_t AlignUpTo(size_t offset, size_t align) {
|
|
|
801
1014
|
// Helper class for computing offsets and allocation size of hash set fields.
|
|
802
1015
|
class RawHashSetLayout {
|
|
803
1016
|
public:
|
|
804
|
-
// TODO(b/413062340): maybe don't allocate growth info for capacity 1 tables.
|
|
805
|
-
// Doing so may require additional branches/complexity so it might not be
|
|
806
|
-
// worth it.
|
|
807
1017
|
explicit RawHashSetLayout(size_t capacity, size_t slot_size,
|
|
808
1018
|
size_t slot_align, bool has_infoz)
|
|
809
|
-
: control_offset_(
|
|
1019
|
+
: control_offset_(
|
|
1020
|
+
ControlOffset(has_infoz, HasGrowthInfoForCapacity(capacity))),
|
|
810
1021
|
generation_offset_(control_offset_ + NumControlBytes(capacity)),
|
|
811
1022
|
slot_offset_(
|
|
812
1023
|
AlignUpTo(generation_offset_ + NumGenerationBytes(), slot_align)),
|
|
@@ -912,13 +1123,15 @@ inline GrowthInfo& GetGrowthInfoFromControl(ctrl_t* control) {
|
|
|
912
1123
|
class CommonFields : public CommonFieldsGenerationInfo {
|
|
913
1124
|
public:
|
|
914
1125
|
explicit CommonFields(soo_tag_t)
|
|
915
|
-
:
|
|
916
|
-
explicit CommonFields(full_soo_tag_t)
|
|
917
|
-
:
|
|
1126
|
+
: inline_data_(HashtableCapacity(SooCapacity()), no_seed_empty_tag_t{}) {}
|
|
1127
|
+
explicit CommonFields(full_soo_tag_t, bool has_tried_sampling)
|
|
1128
|
+
: inline_data_(HashtableCapacity(SooCapacity()), full_soo_tag_t{},
|
|
1129
|
+
has_tried_sampling) {}
|
|
918
1130
|
explicit CommonFields(non_soo_tag_t)
|
|
919
|
-
:
|
|
1131
|
+
: inline_data_(HashtableCapacity(0), no_seed_empty_tag_t{}) {}
|
|
920
1132
|
// For use in swapping.
|
|
921
|
-
explicit CommonFields(uninitialized_tag_t)
|
|
1133
|
+
explicit CommonFields(uninitialized_tag_t)
|
|
1134
|
+
: inline_data_(uninitialized_tag_t{}) {}
|
|
922
1135
|
|
|
923
1136
|
// Not copyable
|
|
924
1137
|
CommonFields(const CommonFields&) = delete;
|
|
@@ -926,10 +1139,7 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
926
1139
|
|
|
927
1140
|
// Copy with guarantee that it is not SOO.
|
|
928
1141
|
CommonFields(non_soo_tag_t, const CommonFields& that)
|
|
929
|
-
:
|
|
930
|
-
size_(that.size_),
|
|
931
|
-
heap_or_soo_(that.heap_or_soo_) {
|
|
932
|
-
}
|
|
1142
|
+
: inline_data_(that.inline_data_), heap_or_soo_(that.heap_or_soo_) {}
|
|
933
1143
|
|
|
934
1144
|
// Movable
|
|
935
1145
|
CommonFields(CommonFields&& that) = default;
|
|
@@ -967,33 +1177,39 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
967
1177
|
void set_slots(void* s) { heap_or_soo_.slot_array().set(s); }
|
|
968
1178
|
|
|
969
1179
|
// The number of filled slots.
|
|
970
|
-
size_t size() const { return
|
|
1180
|
+
size_t size() const { return inline_data_.size(); }
|
|
971
1181
|
// Sets the size to zero, but keeps hashinfoz bit and seed.
|
|
972
|
-
void set_size_to_zero() {
|
|
1182
|
+
void set_size_to_zero() { inline_data_.set_size(0); }
|
|
973
1183
|
void set_empty_soo() {
|
|
974
1184
|
AssertInSooMode();
|
|
975
|
-
|
|
1185
|
+
inline_data_.set_size(0);
|
|
976
1186
|
}
|
|
977
1187
|
void set_full_soo() {
|
|
978
1188
|
AssertInSooMode();
|
|
979
|
-
|
|
1189
|
+
inline_data_.set_size(1);
|
|
980
1190
|
}
|
|
981
1191
|
void increment_size() {
|
|
982
1192
|
ABSL_SWISSTABLE_ASSERT(size() < capacity());
|
|
983
|
-
|
|
1193
|
+
inline_data_.increment_size();
|
|
984
1194
|
}
|
|
985
1195
|
void increment_size(size_t n) {
|
|
986
1196
|
ABSL_SWISSTABLE_ASSERT(size() + n <= capacity());
|
|
987
|
-
|
|
1197
|
+
inline_data_.increment_size(n);
|
|
988
1198
|
}
|
|
989
1199
|
void decrement_size() {
|
|
990
1200
|
ABSL_SWISSTABLE_ASSERT(!empty());
|
|
991
|
-
|
|
1201
|
+
inline_data_.decrement_size();
|
|
1202
|
+
}
|
|
1203
|
+
bool empty() const { return inline_data_.empty(); }
|
|
1204
|
+
void set_soo_has_tried_sampling() {
|
|
1205
|
+
inline_data_.set_soo_has_tried_sampling();
|
|
1206
|
+
}
|
|
1207
|
+
bool soo_has_tried_sampling() const {
|
|
1208
|
+
return inline_data_.soo_has_tried_sampling();
|
|
992
1209
|
}
|
|
993
|
-
bool empty() const { return size_.empty(); }
|
|
994
1210
|
|
|
995
1211
|
// The seed used for the hash function.
|
|
996
|
-
PerTableSeed seed() const { return
|
|
1212
|
+
PerTableSeed seed() const { return inline_data_.seed(); }
|
|
997
1213
|
// Generates a new seed the hash function.
|
|
998
1214
|
// The table will be invalidated if `!empty()` because hash is being changed.
|
|
999
1215
|
// In such cases, we will need to rehash the table.
|
|
@@ -1001,22 +1217,29 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1001
1217
|
// Note: we can't use has_infoz() here because we set has_infoz later than
|
|
1002
1218
|
// we generate the seed.
|
|
1003
1219
|
if (ABSL_PREDICT_FALSE(has_infoz)) {
|
|
1004
|
-
|
|
1220
|
+
inline_data_.set_sampled_seed();
|
|
1005
1221
|
return;
|
|
1006
1222
|
}
|
|
1007
|
-
|
|
1223
|
+
inline_data_.generate_new_seed();
|
|
1008
1224
|
}
|
|
1009
|
-
void set_no_seed_for_testing() {
|
|
1225
|
+
void set_no_seed_for_testing() { inline_data_.set_no_seed_for_testing(); }
|
|
1010
1226
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1227
|
+
HashtableCapacity capacity_impl() const {
|
|
1228
|
+
HashtableCapacity cap = inline_data_.capacity();
|
|
1229
|
+
ABSL_SWISSTABLE_ASSERT(cap.IsValid());
|
|
1230
|
+
return cap;
|
|
1231
|
+
}
|
|
1232
|
+
size_t capacity() const { return capacity_impl().capacity(); }
|
|
1233
|
+
// We have a separate alias for callsites in which the capacity may be
|
|
1234
|
+
// invalid.
|
|
1235
|
+
HashtableCapacity maybe_invalid_capacity() const {
|
|
1236
|
+
return inline_data_.capacity();
|
|
1237
|
+
}
|
|
1238
|
+
void set_capacity(HashtableCapacity c) { inline_data_.set_capacity(c); }
|
|
1013
1239
|
void set_capacity(size_t c) {
|
|
1014
|
-
|
|
1015
|
-
ABSL_SWISSTABLE_ASSERT(c == 0 || IsValidCapacity(c) ||
|
|
1016
|
-
c > kAboveMaxValidCapacity);
|
|
1017
|
-
capacity_ = c;
|
|
1240
|
+
set_capacity(HashtableCapacity(c));
|
|
1018
1241
|
}
|
|
1019
|
-
bool is_small() const { return
|
|
1242
|
+
bool is_small() const { return inline_data_.is_small(); }
|
|
1020
1243
|
|
|
1021
1244
|
// The number of slots we can still fill without needing to rehash.
|
|
1022
1245
|
// This is stored in the heap allocation before the control bytes.
|
|
@@ -1025,17 +1248,17 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1025
1248
|
size_t growth_left() const { return growth_info().GetGrowthLeft(); }
|
|
1026
1249
|
|
|
1027
1250
|
GrowthInfo& growth_info() {
|
|
1028
|
-
ABSL_SWISSTABLE_ASSERT(
|
|
1251
|
+
ABSL_SWISSTABLE_ASSERT(HasGrowthInfoForCapacity(capacity()));
|
|
1029
1252
|
return GetGrowthInfoFromControl(control());
|
|
1030
1253
|
}
|
|
1031
1254
|
GrowthInfo growth_info() const {
|
|
1032
1255
|
return const_cast<CommonFields*>(this)->growth_info();
|
|
1033
1256
|
}
|
|
1034
1257
|
|
|
1035
|
-
bool has_infoz() const { return
|
|
1258
|
+
bool has_infoz() const { return inline_data_.has_infoz(); }
|
|
1036
1259
|
void set_has_infoz() {
|
|
1037
|
-
ABSL_SWISSTABLE_ASSERT(
|
|
1038
|
-
|
|
1260
|
+
ABSL_SWISSTABLE_ASSERT(inline_data_.is_sampled_seed());
|
|
1261
|
+
inline_data_.set_has_infoz();
|
|
1039
1262
|
}
|
|
1040
1263
|
|
|
1041
1264
|
HashtablezInfoHandle* infoz_ptr() const {
|
|
@@ -1044,7 +1267,8 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1044
1267
|
reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
|
|
1045
1268
|
ABSL_SWISSTABLE_ASSERT(has_infoz());
|
|
1046
1269
|
return reinterpret_cast<HashtablezInfoHandle*>(
|
|
1047
|
-
control() - ControlOffset(/*has_infoz=*/true
|
|
1270
|
+
control() - ControlOffset(/*has_infoz=*/true,
|
|
1271
|
+
HasGrowthInfoForCapacity(capacity())));
|
|
1048
1272
|
}
|
|
1049
1273
|
|
|
1050
1274
|
HashtablezInfoHandle infoz() {
|
|
@@ -1083,8 +1307,7 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1083
1307
|
void move_non_heap_or_soo_fields(CommonFields& that) {
|
|
1084
1308
|
static_cast<CommonFieldsGenerationInfo&>(*this) =
|
|
1085
1309
|
std::move(static_cast<CommonFieldsGenerationInfo&>(that));
|
|
1086
|
-
|
|
1087
|
-
size_ = that.size_;
|
|
1310
|
+
inline_data_ = that.inline_data_;
|
|
1088
1311
|
}
|
|
1089
1312
|
|
|
1090
1313
|
// Returns the number of control bytes set to kDeleted. For testing only.
|
|
@@ -1101,8 +1324,8 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1101
1324
|
f();
|
|
1102
1325
|
return;
|
|
1103
1326
|
#endif
|
|
1104
|
-
const
|
|
1105
|
-
set_capacity(
|
|
1327
|
+
const HashtableCapacity cap = maybe_invalid_capacity();
|
|
1328
|
+
set_capacity(HashtableCapacity::CreateReentrance());
|
|
1106
1329
|
f();
|
|
1107
1330
|
set_capacity(cap);
|
|
1108
1331
|
}
|
|
@@ -1121,18 +1344,10 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1121
1344
|
ABSL_SWISSTABLE_ASSERT(!has_infoz());
|
|
1122
1345
|
}
|
|
1123
1346
|
|
|
1124
|
-
// The number of slots in the backing array. This is always 2^N-1 for an
|
|
1125
|
-
// integer N. NOTE: we tried experimenting with compressing the capacity and
|
|
1126
|
-
// storing it together with size_: (a) using 6 bits to store the corresponding
|
|
1127
|
-
// power (N in 2^N-1), and (b) storing 2^N as the most significant bit of
|
|
1128
|
-
// size_ and storing size in the low bits. Both of these experiments were
|
|
1129
|
-
// regressions, presumably because we need capacity to do find operations.
|
|
1130
|
-
size_t capacity_;
|
|
1131
|
-
|
|
1132
1347
|
// TODO(b/289225379): we could put size_ into HeapOrSoo and make capacity_
|
|
1133
1348
|
// encode the size in SOO case. We would be making size()/capacity() more
|
|
1134
1349
|
// expensive in order to have more SOO space.
|
|
1135
|
-
|
|
1350
|
+
HashtableInlineData inline_data_;
|
|
1136
1351
|
|
|
1137
1352
|
// Either the control/slots pointers or the SOO slot.
|
|
1138
1353
|
HeapOrSoo heap_or_soo_;
|
|
@@ -1141,18 +1356,6 @@ class CommonFields : public CommonFieldsGenerationInfo {
|
|
|
1141
1356
|
template <class Policy, class... Params>
|
|
1142
1357
|
class raw_hash_set;
|
|
1143
1358
|
|
|
1144
|
-
// Returns the next valid capacity after `n`.
|
|
1145
|
-
constexpr size_t NextCapacity(size_t n) {
|
|
1146
|
-
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n) || n == 0);
|
|
1147
|
-
return n * 2 + 1;
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
// Returns the previous valid capacity before `n`.
|
|
1151
|
-
constexpr size_t PreviousCapacity(size_t n) {
|
|
1152
|
-
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n));
|
|
1153
|
-
return n / 2;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
1359
|
// Applies the following mapping to every byte in the control array:
|
|
1157
1360
|
// * kDeleted -> kEmpty
|
|
1158
1361
|
// * kEmpty -> kEmpty
|
|
@@ -1163,59 +1366,6 @@ constexpr size_t PreviousCapacity(size_t n) {
|
|
|
1163
1366
|
// ctrl[i] != ctrl_t::kSentinel for all i < capacity
|
|
1164
1367
|
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
|
|
1165
1368
|
|
|
1166
|
-
// Converts `n` into the next valid capacity, per `IsValidCapacity`.
|
|
1167
|
-
constexpr size_t NormalizeCapacity(size_t n) {
|
|
1168
|
-
return n ? ~size_t{} >> countl_zero(n) : 1;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
// General notes on capacity/growth methods below:
|
|
1172
|
-
// - We use 7/8th as maximum load factor. For 16-wide groups, that gives an
|
|
1173
|
-
// average of two empty slots per group.
|
|
1174
|
-
// - For (capacity+1) >= Group::kWidth, growth is 7/8*capacity.
|
|
1175
|
-
// - For (capacity+1) < Group::kWidth, growth == capacity. In this case, we
|
|
1176
|
-
// never need to probe (the whole table fits in one group) so we don't need a
|
|
1177
|
-
// load factor less than 1.
|
|
1178
|
-
|
|
1179
|
-
// Given `capacity`, applies the load factor; i.e., it returns the maximum
|
|
1180
|
-
// number of values we should put into the table before a resizing rehash.
|
|
1181
|
-
constexpr size_t CapacityToGrowth(size_t capacity) {
|
|
1182
|
-
ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
|
|
1183
|
-
// `capacity*7/8`
|
|
1184
|
-
if (Group::kWidth == 8 && capacity == 7) {
|
|
1185
|
-
// x-x/8 does not work when x==7.
|
|
1186
|
-
return 6;
|
|
1187
|
-
}
|
|
1188
|
-
return capacity - capacity / 8;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
// Given `size`, "unapplies" the load factor to find how large the capacity
|
|
1192
|
-
// should be to stay within the load factor.
|
|
1193
|
-
//
|
|
1194
|
-
// For size == 0, returns 0.
|
|
1195
|
-
// For other values, returns the same as `NormalizeCapacity(size*8/7)`.
|
|
1196
|
-
constexpr size_t SizeToCapacity(size_t size) {
|
|
1197
|
-
if (size == 0) {
|
|
1198
|
-
return 0;
|
|
1199
|
-
}
|
|
1200
|
-
// The minimum possible capacity is NormalizeCapacity(size).
|
|
1201
|
-
// Shifting right `~size_t{}` by `leading_zeros` yields
|
|
1202
|
-
// NormalizeCapacity(size).
|
|
1203
|
-
int leading_zeros = absl::countl_zero(size);
|
|
1204
|
-
constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
|
|
1205
|
-
// max_size_for_next_capacity = max_load_factor * next_capacity
|
|
1206
|
-
// = (7/8) * (~size_t{} >> leading_zeros)
|
|
1207
|
-
// = (7/8*~size_t{}) >> leading_zeros
|
|
1208
|
-
// = kLast3Bits >> leading_zeros
|
|
1209
|
-
size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
|
|
1210
|
-
// Decrease shift if size is too big for the minimum capacity.
|
|
1211
|
-
leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
|
|
1212
|
-
if constexpr (Group::kWidth == 8) {
|
|
1213
|
-
// Formula doesn't work when size==7 for 8-wide groups.
|
|
1214
|
-
leading_zeros -= (size == 7);
|
|
1215
|
-
}
|
|
1216
|
-
return (~size_t{}) >> leading_zeros;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
1369
|
template <class InputIter>
|
|
1220
1370
|
size_t SelectBucketCountForIterRange(InputIter first, InputIter last,
|
|
1221
1371
|
size_t bucket_count) {
|
|
@@ -1238,6 +1388,26 @@ constexpr bool SwisstableDebugEnabled() {
|
|
|
1238
1388
|
#endif
|
|
1239
1389
|
}
|
|
1240
1390
|
|
|
1391
|
+
// Dereferences `ptr`. The function is named in order to provide a helpful error
|
|
1392
|
+
// message when users see crashing stack traces. Note that this function is not
|
|
1393
|
+
// guaranteed to crash when `ptr` is invalid if sanitizer mode is not enabled.
|
|
1394
|
+
template <typename T>
|
|
1395
|
+
T CrashIfIteratorIsInvalid(const T* ptr) {
|
|
1396
|
+
// If the following line(s) crash, then it's likely that `ptr` is from a
|
|
1397
|
+
// backing array that has been deallocated. If you see a crash here, it likely
|
|
1398
|
+
// means that you are comparing an invalid iterator from a table that has
|
|
1399
|
+
// rehashed, moved, or been destroyed. In such cases, it is often helpful to
|
|
1400
|
+
// reproduce the issue with --config=asan and (assuming there's a crash here)
|
|
1401
|
+
// examine the corresponding deallocation stack trace.
|
|
1402
|
+
T ret = *ptr;
|
|
1403
|
+
// Force a read with inline asm to make sure that a crash happens here, rather
|
|
1404
|
+
// than later when the value is used.
|
|
1405
|
+
#ifdef __clang__
|
|
1406
|
+
asm("" : "+r"(ret));
|
|
1407
|
+
#endif
|
|
1408
|
+
return ret;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1241
1411
|
inline void AssertIsFull(const ctrl_t* ctrl, GenerationType generation,
|
|
1242
1412
|
const GenerationType* generation_ptr,
|
|
1243
1413
|
const char* operation) {
|
|
@@ -1255,20 +1425,21 @@ inline void AssertIsFull(const ctrl_t* ctrl, GenerationType generation,
|
|
|
1255
1425
|
operation);
|
|
1256
1426
|
}
|
|
1257
1427
|
if (SwisstableGenerationsEnabled()) {
|
|
1258
|
-
if (ABSL_PREDICT_FALSE(generation !=
|
|
1428
|
+
if (ABSL_PREDICT_FALSE(generation !=
|
|
1429
|
+
CrashIfIteratorIsInvalid(generation_ptr))) {
|
|
1259
1430
|
ABSL_RAW_LOG(FATAL,
|
|
1260
1431
|
"%s called on invalid iterator. The table could have "
|
|
1261
1432
|
"rehashed or moved since this iterator was initialized.",
|
|
1262
1433
|
operation);
|
|
1263
1434
|
}
|
|
1264
|
-
if (ABSL_PREDICT_FALSE(!IsFull(
|
|
1435
|
+
if (ABSL_PREDICT_FALSE(!IsFull(CrashIfIteratorIsInvalid(ctrl)))) {
|
|
1265
1436
|
ABSL_RAW_LOG(
|
|
1266
1437
|
FATAL,
|
|
1267
1438
|
"%s called on invalid iterator. The element was likely erased.",
|
|
1268
1439
|
operation);
|
|
1269
1440
|
}
|
|
1270
1441
|
} else {
|
|
1271
|
-
if (ABSL_PREDICT_FALSE(!IsFull(
|
|
1442
|
+
if (ABSL_PREDICT_FALSE(!IsFull(CrashIfIteratorIsInvalid(ctrl)))) {
|
|
1272
1443
|
ABSL_RAW_LOG(
|
|
1273
1444
|
FATAL,
|
|
1274
1445
|
"%s called on invalid iterator. The element might have been erased "
|
|
@@ -1285,12 +1456,19 @@ inline void AssertIsValidForComparison(const ctrl_t* ctrl,
|
|
|
1285
1456
|
const GenerationType* generation_ptr) {
|
|
1286
1457
|
if (!SwisstableDebugEnabled()) return;
|
|
1287
1458
|
const bool ctrl_is_valid_for_comparison =
|
|
1288
|
-
ctrl == nullptr || ctrl == DefaultIterControl() ||
|
|
1459
|
+
ctrl == nullptr || ctrl == DefaultIterControl() ||
|
|
1460
|
+
IsFull(CrashIfIteratorIsInvalid(ctrl));
|
|
1289
1461
|
if (SwisstableGenerationsEnabled()) {
|
|
1290
|
-
if (ABSL_PREDICT_FALSE(generation !=
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1462
|
+
if (ABSL_PREDICT_FALSE(generation !=
|
|
1463
|
+
CrashIfIteratorIsInvalid(generation_ptr))) {
|
|
1464
|
+
// Note: in the case of a rehash, we would expect to see a sanitizer crash
|
|
1465
|
+
// in CrashIfIteratorIsInvalid so this assertion will only catch moved
|
|
1466
|
+
// table cases, unless we're using a custom allocator that does not
|
|
1467
|
+
// deallocate the old backing array (e.g. an arena allocator).
|
|
1468
|
+
ABSL_RAW_LOG(
|
|
1469
|
+
FATAL,
|
|
1470
|
+
"Invalid iterator comparison. The table was likely moved (or "
|
|
1471
|
+
"possibly rehashed) since this iterator was initialized.");
|
|
1294
1472
|
}
|
|
1295
1473
|
if (ABSL_PREDICT_FALSE(!ctrl_is_valid_for_comparison)) {
|
|
1296
1474
|
ABSL_RAW_LOG(
|
|
@@ -1394,15 +1572,64 @@ constexpr bool is_single_group(size_t capacity) {
|
|
|
1394
1572
|
return capacity <= Group::kWidth;
|
|
1395
1573
|
}
|
|
1396
1574
|
|
|
1575
|
+
// The state for a probe sequence.
|
|
1576
|
+
//
|
|
1577
|
+
// Currently, the sequence is a triangular progression of the form
|
|
1578
|
+
//
|
|
1579
|
+
// p(i) := Width * (i^2 + i)/2 + hash (mod mask + 1)
|
|
1580
|
+
//
|
|
1581
|
+
// The use of `Width` ensures that each probe step does not overlap groups;
|
|
1582
|
+
// the sequence effectively outputs the addresses of *groups* (although not
|
|
1583
|
+
// necessarily aligned to any boundary). The `Group` machinery allows us
|
|
1584
|
+
// to check an entire group with minimal branching.
|
|
1585
|
+
//
|
|
1586
|
+
// Wrapping around at `mask + 1` is important, but not for the obvious reason.
|
|
1587
|
+
// As described above, the first few entries of the control byte array
|
|
1588
|
+
// are mirrored at the end of the array, which `Group` will find and use
|
|
1589
|
+
// for selecting candidates. However, when those candidates' slots are
|
|
1590
|
+
// actually inspected, there are no corresponding slots for the cloned bytes,
|
|
1591
|
+
// so we need to make sure we've treated those offsets as "wrapping around".
|
|
1592
|
+
//
|
|
1593
|
+
// It turns out that this probe sequence visits every group exactly once if the
|
|
1594
|
+
// number of groups is a power of two, since (i^2+i)/2 is a bijection in
|
|
1595
|
+
// Z/(2^m). See https://en.wikipedia.org/wiki/Quadratic_probing
|
|
1596
|
+
template <size_t Width>
|
|
1597
|
+
class probe_seq {
|
|
1598
|
+
public:
|
|
1599
|
+
// Creates a new probe sequence using `hash` as the initial value of the
|
|
1600
|
+
// sequence and `capacity` as the mask to apply to each value in the
|
|
1601
|
+
// progression.
|
|
1602
|
+
probe_seq(HashtableCapacity capacity, size_t hash)
|
|
1603
|
+
: capacity_(capacity), offset_(capacity.mask(hash)) {}
|
|
1604
|
+
|
|
1605
|
+
// The offset within the table, i.e., the value `p(i)` above.
|
|
1606
|
+
size_t offset() const { return offset_; }
|
|
1607
|
+
size_t offset(size_t i) const { return capacity_.mask(offset_ + i); }
|
|
1608
|
+
|
|
1609
|
+
void next() {
|
|
1610
|
+
index_ += Width;
|
|
1611
|
+
offset_ += index_;
|
|
1612
|
+
offset_ = capacity_.mask(offset_);
|
|
1613
|
+
}
|
|
1614
|
+
// 0-based probe index, a multiple of `Width`.
|
|
1615
|
+
size_t index() const { return index_; }
|
|
1616
|
+
|
|
1617
|
+
private:
|
|
1618
|
+
HashtableCapacity capacity_;
|
|
1619
|
+
size_t offset_;
|
|
1620
|
+
size_t index_ = 0;
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1397
1623
|
// Begins a probing operation on `common.control`, using `hash`.
|
|
1398
|
-
inline probe_seq<Group::kWidth> probe_h1(
|
|
1399
|
-
|
|
1624
|
+
inline probe_seq<Group::kWidth> probe_h1(HashtableCapacity capacity,
|
|
1625
|
+
size_t h1) {
|
|
1626
|
+
return probe_seq<Group::kWidth>(capacity, h1);
|
|
1400
1627
|
}
|
|
1401
|
-
inline probe_seq<Group::kWidth> probe(
|
|
1628
|
+
inline probe_seq<Group::kWidth> probe(HashtableCapacity capacity, size_t hash) {
|
|
1402
1629
|
return probe_h1(capacity, H1(hash));
|
|
1403
1630
|
}
|
|
1404
1631
|
inline probe_seq<Group::kWidth> probe(const CommonFields& common, size_t hash) {
|
|
1405
|
-
return probe(common.
|
|
1632
|
+
return probe(common.capacity_impl(), hash);
|
|
1406
1633
|
}
|
|
1407
1634
|
|
|
1408
1635
|
constexpr size_t kProbedElementIndexSentinel = ~size_t{};
|
|
@@ -1563,51 +1790,54 @@ struct PolicyFunctions {
|
|
|
1563
1790
|
}
|
|
1564
1791
|
};
|
|
1565
1792
|
|
|
1566
|
-
//
|
|
1567
|
-
// This
|
|
1568
|
-
//
|
|
1793
|
+
// The following functions are used for calculating the max valid size of the
|
|
1794
|
+
// table. This is important for security to avoid overflowing size_t when
|
|
1795
|
+
// calculating the allocation size of the backing array
|
|
1796
|
+
// (https://nvd.nist.gov/vuln/detail/CVE-2025-0838). We also limit the max valid
|
|
1797
|
+
// size based on the size of the key_type, and this is an optimization because
|
|
1798
|
+
// we ABSL_ASSUME that the size is less than MaxValidSize, which can enable
|
|
1799
|
+
// other optimizations for tables with small keys.
|
|
1800
|
+
|
|
1569
1801
|
template <size_t kSizeOfSizeT = sizeof(size_t)>
|
|
1570
|
-
constexpr size_t
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
static_assert(kSizeOfSizeT == 4);
|
|
1576
|
-
return CapacityToGrowth((size_t{1} << (kSizeOfSizeT * 8 - 2)) - 1);
|
|
1577
|
-
}
|
|
1802
|
+
constexpr size_t MaxSizeAtMaxValidCapacity(size_t slot_size) {
|
|
1803
|
+
using SizeT = std::conditional_t<kSizeOfSizeT == 4, uint32_t, uint64_t>;
|
|
1804
|
+
// We shift right by 2 for a safe margin against overflow.
|
|
1805
|
+
constexpr SizeT kMaxValidCapacity = ~SizeT{} >> 2;
|
|
1806
|
+
return CapacityToGrowth(kMaxValidCapacity) / slot_size;
|
|
1578
1807
|
}
|
|
1579
1808
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1809
|
+
constexpr size_t MaxStorableSize() {
|
|
1810
|
+
return static_cast<size_t>(uint64_t{1}
|
|
1811
|
+
<< HashtableInlineData::kSizeBitCount) -
|
|
1812
|
+
1;
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// There are no more than 2^sizeof(key_type) unique key_types (and hashtable
|
|
1816
|
+
// keys must be unique) so we can't have a hashtable with more than
|
|
1817
|
+
// 2^sizeof(key_type) elements.
|
|
1582
1818
|
template <size_t kSizeOfSizeT = sizeof(size_t)>
|
|
1583
|
-
constexpr size_t
|
|
1819
|
+
constexpr size_t MaxValidSizeForKeySize(size_t key_size) {
|
|
1820
|
+
if (key_size < kSizeOfSizeT) return size_t{1} << 8 * key_size;
|
|
1821
|
+
return (std::numeric_limits<size_t>::max)();
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
template <size_t kSizeOfSizeT = sizeof(size_t)>
|
|
1825
|
+
constexpr size_t MaxValidSizeForSlotSize(size_t slot_size) {
|
|
1584
1826
|
if constexpr (kSizeOfSizeT == 8) {
|
|
1585
|
-
// For small slot sizes we are limited by
|
|
1586
|
-
if (slot_size < size_t{1} << (64 -
|
|
1587
|
-
return
|
|
1827
|
+
// For small slot sizes we are limited by HashtableStackData::kSizeBitCount.
|
|
1828
|
+
if (slot_size < size_t{1} << (64 - HashtableInlineData::kSizeBitCount)) {
|
|
1829
|
+
return MaxStorableSize();
|
|
1588
1830
|
}
|
|
1589
|
-
return (size_t{1} << (kSizeOfSizeT * 8 - 2)) / slot_size;
|
|
1590
|
-
} else {
|
|
1591
|
-
return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>() / slot_size;
|
|
1592
1831
|
}
|
|
1832
|
+
return MaxSizeAtMaxValidCapacity<kSizeOfSizeT>(slot_size);
|
|
1593
1833
|
}
|
|
1594
1834
|
|
|
1595
|
-
// Returns
|
|
1596
|
-
// It is an optimization to avoid the division operation in the common case.
|
|
1835
|
+
// Returns the maximum valid size for a table, given the key size and slot size.
|
|
1597
1836
|
// Template parameter is only used to enable testing.
|
|
1598
1837
|
template <size_t kSizeOfSizeT = sizeof(size_t)>
|
|
1599
|
-
constexpr
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
if (ABSL_PREDICT_TRUE(slot_size <
|
|
1603
|
-
(size_t{1} << (64 - HashtableSize::kSizeBitCount)))) {
|
|
1604
|
-
return size > MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
|
|
1605
|
-
}
|
|
1606
|
-
return size > MaxValidSize<kSizeOfSizeT>(slot_size);
|
|
1607
|
-
} else {
|
|
1608
|
-
return uint64_t{size} * slot_size >
|
|
1609
|
-
MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
|
|
1610
|
-
}
|
|
1838
|
+
constexpr size_t MaxValidSize(size_t key_size, size_t slot_size) {
|
|
1839
|
+
return (std::min)(MaxValidSizeForKeySize<kSizeOfSizeT>(key_size),
|
|
1840
|
+
MaxValidSizeForSlotSize<kSizeOfSizeT>(slot_size));
|
|
1611
1841
|
}
|
|
1612
1842
|
|
|
1613
1843
|
// Returns the index of the SOO slot when growing from SOO to non-SOO in a
|
|
@@ -1622,8 +1852,9 @@ constexpr size_t SooSlotIndex() { return 1; }
|
|
|
1622
1852
|
// Allowing till 16 would require additional store that can be avoided.
|
|
1623
1853
|
constexpr size_t MaxSmallAfterSooCapacity() { return 7; }
|
|
1624
1854
|
|
|
1625
|
-
// Type erased version of raw_hash_set::reserve.
|
|
1626
|
-
//
|
|
1855
|
+
// Type erased version of raw_hash_set::reserve. Requires:
|
|
1856
|
+
// 1. `new_size > policy.soo_capacity`.
|
|
1857
|
+
// 2. `new_size <= kMaxValidSize`.
|
|
1627
1858
|
void ReserveTableToFitNewSize(CommonFields& common,
|
|
1628
1859
|
const PolicyFunctions& policy, size_t new_size);
|
|
1629
1860
|
|
|
@@ -1632,11 +1863,13 @@ void ReserveTableToFitNewSize(CommonFields& common,
|
|
|
1632
1863
|
// 1. `c.capacity() == policy.soo_capacity`.
|
|
1633
1864
|
// 2. `c.empty()`.
|
|
1634
1865
|
// 3. `new_size > policy.soo_capacity`.
|
|
1866
|
+
// 4. `bucket_count <= MaxValidCapacity()`.
|
|
1635
1867
|
// The table will be attempted to be sampled.
|
|
1636
1868
|
void ReserveEmptyNonAllocatedTableToFitBucketCount(
|
|
1637
1869
|
CommonFields& common, const PolicyFunctions& policy, size_t bucket_count);
|
|
1638
1870
|
|
|
1639
1871
|
// Type erased version of raw_hash_set::rehash.
|
|
1872
|
+
// Requires: `n <= MaxValidCapacity()`.
|
|
1640
1873
|
void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n);
|
|
1641
1874
|
|
|
1642
1875
|
// Type erased version of copy constructor.
|
|
@@ -1705,9 +1938,9 @@ void ResizeAllocatedTableWithSeedChange(CommonFields& common,
|
|
|
1705
1938
|
|
|
1706
1939
|
// ClearBackingArray clears the backing array, either modifying it in place,
|
|
1707
1940
|
// or creating a new one based on the value of "reuse".
|
|
1708
|
-
// REQUIRES: c.capacity >
|
|
1941
|
+
// REQUIRES: c.capacity > MaxSmallCapacity().
|
|
1709
1942
|
void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
|
|
1710
|
-
void* alloc, bool reuse
|
|
1943
|
+
void* alloc, bool reuse);
|
|
1711
1944
|
|
|
1712
1945
|
// Type-erased versions of raw_hash_set::erase_meta_only_{small,large}.
|
|
1713
1946
|
void EraseMetaOnlySmall(CommonFields& c, bool soo_enabled, size_t slot_size);
|
|
@@ -1828,9 +2061,9 @@ class raw_hash_set {
|
|
|
1828
2061
|
using value_type = typename PolicyTraits::value_type;
|
|
1829
2062
|
using reference = value_type&;
|
|
1830
2063
|
using const_reference = const value_type&;
|
|
1831
|
-
using pointer = typename
|
|
2064
|
+
using pointer = typename std::allocator_traits<
|
|
1832
2065
|
allocator_type>::template rebind_traits<value_type>::pointer;
|
|
1833
|
-
using const_pointer = typename
|
|
2066
|
+
using const_pointer = typename std::allocator_traits<
|
|
1834
2067
|
allocator_type>::template rebind_traits<value_type>::const_pointer;
|
|
1835
2068
|
|
|
1836
2069
|
private:
|
|
@@ -1862,13 +2095,23 @@ class raw_hash_set {
|
|
|
1862
2095
|
constexpr static size_t DefaultCapacity() {
|
|
1863
2096
|
return SooEnabled() ? SooCapacity() : 0;
|
|
1864
2097
|
}
|
|
2098
|
+
constexpr static size_t MaxValidSize() {
|
|
2099
|
+
return container_internal::MaxValidSize(sizeof(key_type),
|
|
2100
|
+
sizeof(slot_type));
|
|
2101
|
+
}
|
|
2102
|
+
constexpr static size_t MaxValidCapacity() {
|
|
2103
|
+
return SizeToCapacity(MaxValidSize());
|
|
2104
|
+
}
|
|
1865
2105
|
|
|
1866
2106
|
// Whether `size` fits in the SOO capacity of this table.
|
|
1867
2107
|
bool fits_in_soo(size_t size) const {
|
|
1868
2108
|
return SooEnabled() && size <= SooCapacity();
|
|
1869
2109
|
}
|
|
1870
2110
|
// Whether this table is in SOO mode or non-SOO mode.
|
|
1871
|
-
bool is_soo() const {
|
|
2111
|
+
bool is_soo() const {
|
|
2112
|
+
HashtableCapacity cap = maybe_invalid_capacity();
|
|
2113
|
+
return cap.IsValid() && fits_in_soo(cap.capacity());
|
|
2114
|
+
}
|
|
1872
2115
|
bool is_full_soo() const { return is_soo() && !empty(); }
|
|
1873
2116
|
|
|
1874
2117
|
bool is_small() const { return common().is_small(); }
|
|
@@ -1884,15 +2127,15 @@ class raw_hash_set {
|
|
|
1884
2127
|
static_assert(sizeof(key_hash_result) >= sizeof(size_t),
|
|
1885
2128
|
"`Hash::operator()` should return a `size_t`");
|
|
1886
2129
|
|
|
1887
|
-
using AllocTraits =
|
|
1888
|
-
using SlotAlloc = typename
|
|
2130
|
+
using AllocTraits = std::allocator_traits<allocator_type>;
|
|
2131
|
+
using SlotAlloc = typename std::allocator_traits<
|
|
1889
2132
|
allocator_type>::template rebind_alloc<slot_type>;
|
|
1890
2133
|
// People are often sloppy with the exact type of their allocator (sometimes
|
|
1891
2134
|
// it has an extra const or is missing the pair, but rebinds made it work
|
|
1892
2135
|
// anyway).
|
|
1893
2136
|
using CharAlloc =
|
|
1894
|
-
typename
|
|
1895
|
-
using SlotAllocTraits = typename
|
|
2137
|
+
typename std::allocator_traits<Alloc>::template rebind_alloc<char>;
|
|
2138
|
+
using SlotAllocTraits = typename std::allocator_traits<
|
|
1896
2139
|
allocator_type>::template rebind_traits<slot_type>;
|
|
1897
2140
|
|
|
1898
2141
|
static_assert(std::is_lvalue_reference<reference>::value,
|
|
@@ -1901,7 +2144,7 @@ class raw_hash_set {
|
|
|
1901
2144
|
// An enabler for insert(T&&): T must be convertible to init_type or be the
|
|
1902
2145
|
// same as [cv] value_type [ref].
|
|
1903
2146
|
template <class T>
|
|
1904
|
-
using Insertable =
|
|
2147
|
+
using Insertable = std::disjunction<
|
|
1905
2148
|
std::is_same<absl::remove_cvref_t<reference>, absl::remove_cvref_t<T>>,
|
|
1906
2149
|
std::is_convertible<T, init_type>>;
|
|
1907
2150
|
template <class T>
|
|
@@ -1941,9 +2184,9 @@ class raw_hash_set {
|
|
|
1941
2184
|
using iterator_category = std::forward_iterator_tag;
|
|
1942
2185
|
using value_type = typename raw_hash_set::value_type;
|
|
1943
2186
|
using reference =
|
|
1944
|
-
|
|
2187
|
+
std::conditional_t<PolicyTraits::constant_iterators::value,
|
|
1945
2188
|
const value_type&, value_type&>;
|
|
1946
|
-
using pointer =
|
|
2189
|
+
using pointer = std::remove_reference_t<reference>*;
|
|
1947
2190
|
using difference_type = typename raw_hash_set::difference_type;
|
|
1948
2191
|
|
|
1949
2192
|
iterator() {}
|
|
@@ -2116,7 +2359,8 @@ class raw_hash_set {
|
|
|
2116
2359
|
alloc) {
|
|
2117
2360
|
if (bucket_count > DefaultCapacity()) {
|
|
2118
2361
|
ReserveEmptyNonAllocatedTableToFitBucketCount(
|
|
2119
|
-
common(), GetPolicyFunctions(),
|
|
2362
|
+
common(), GetPolicyFunctions(),
|
|
2363
|
+
(std::min)(bucket_count, MaxValidCapacity()));
|
|
2120
2364
|
}
|
|
2121
2365
|
}
|
|
2122
2366
|
|
|
@@ -2149,6 +2393,28 @@ class raw_hash_set {
|
|
|
2149
2393
|
const allocator_type& alloc)
|
|
2150
2394
|
: raw_hash_set(first, last, bucket_count, hasher(), key_equal(), alloc) {}
|
|
2151
2395
|
|
|
2396
|
+
#if defined(__cpp_lib_containers_ranges) && \
|
|
2397
|
+
__cpp_lib_containers_ranges >= 202202L
|
|
2398
|
+
template <typename R>
|
|
2399
|
+
raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count = 0,
|
|
2400
|
+
const hasher& hash = hasher(), const key_equal& eq = key_equal(),
|
|
2401
|
+
const allocator_type& alloc = allocator_type())
|
|
2402
|
+
: raw_hash_set(std::begin(rg), std::end(rg), bucket_count, hash, eq,
|
|
2403
|
+
alloc) {}
|
|
2404
|
+
|
|
2405
|
+
template <typename R>
|
|
2406
|
+
raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count,
|
|
2407
|
+
const allocator_type& alloc)
|
|
2408
|
+
: raw_hash_set(std::from_range, std::forward<R>(rg), bucket_count,
|
|
2409
|
+
hasher(), key_equal(), alloc) {}
|
|
2410
|
+
|
|
2411
|
+
template <typename R>
|
|
2412
|
+
raw_hash_set(std::from_range_t, R&& rg, size_type bucket_count,
|
|
2413
|
+
const hasher& hash, const allocator_type& alloc)
|
|
2414
|
+
: raw_hash_set(std::from_range, std::forward<R>(rg), bucket_count, hash,
|
|
2415
|
+
key_equal(), alloc) {}
|
|
2416
|
+
#endif
|
|
2417
|
+
|
|
2152
2418
|
template <class InputIter>
|
|
2153
2419
|
raw_hash_set(InputIter first, InputIter last, const allocator_type& alloc)
|
|
2154
2420
|
: raw_hash_set(first, last, 0, hasher(), key_equal(), alloc) {}
|
|
@@ -2243,7 +2509,8 @@ class raw_hash_set {
|
|
|
2243
2509
|
// Note: we avoid using exchange for better generated code.
|
|
2244
2510
|
settings_(PolicyTraits::transfer_uses_memcpy() || !that.is_full_soo()
|
|
2245
2511
|
? std::move(that.common())
|
|
2246
|
-
: CommonFields{full_soo_tag_t{}
|
|
2512
|
+
: CommonFields{full_soo_tag_t{},
|
|
2513
|
+
that.common().soo_has_tried_sampling()},
|
|
2247
2514
|
that.hash_ref(), that.eq_ref(), that.char_alloc_ref()) {
|
|
2248
2515
|
if (!PolicyTraits::transfer_uses_memcpy() && that.is_full_soo()) {
|
|
2249
2516
|
transfer(soo_slot(), that.soo_slot());
|
|
@@ -2294,7 +2561,7 @@ class raw_hash_set {
|
|
|
2294
2561
|
~raw_hash_set() {
|
|
2295
2562
|
destructor_impl();
|
|
2296
2563
|
if constexpr (SwisstableAssertAccessToDestroyedTable()) {
|
|
2297
|
-
common().set_capacity(
|
|
2564
|
+
common().set_capacity(HashtableCapacity::CreateDestroyed());
|
|
2298
2565
|
}
|
|
2299
2566
|
}
|
|
2300
2567
|
|
|
@@ -2326,21 +2593,27 @@ class raw_hash_set {
|
|
|
2326
2593
|
bool empty() const { return !size(); }
|
|
2327
2594
|
size_t size() const {
|
|
2328
2595
|
AssertNotDebugCapacity();
|
|
2329
|
-
|
|
2596
|
+
const size_t size = common().size();
|
|
2597
|
+
[[maybe_unused]] const size_t kMaxValidSize = MaxValidSize();
|
|
2598
|
+
ABSL_ASSUME(size <= kMaxValidSize);
|
|
2599
|
+
return size;
|
|
2330
2600
|
}
|
|
2331
2601
|
size_t capacity() const {
|
|
2332
2602
|
const size_t cap = common().capacity();
|
|
2333
|
-
// Compiler complains when using functions in ASSUME so use local
|
|
2334
|
-
[[maybe_unused]]
|
|
2335
|
-
|
|
2603
|
+
// Compiler complains when using functions in ASSUME so use local variables.
|
|
2604
|
+
[[maybe_unused]] const bool kIsValid = IsValidCapacity(cap);
|
|
2605
|
+
[[maybe_unused]] const size_t kDefaultCapacity = DefaultCapacity();
|
|
2606
|
+
[[maybe_unused]] const size_t kMaxValidCapacity = MaxValidCapacity();
|
|
2607
|
+
ABSL_ASSUME(kIsValid || cap == 0);
|
|
2336
2608
|
ABSL_ASSUME(cap >= kDefaultCapacity);
|
|
2609
|
+
ABSL_ASSUME(cap <= kMaxValidCapacity);
|
|
2337
2610
|
return cap;
|
|
2338
2611
|
}
|
|
2339
|
-
size_t max_size() const { return MaxValidSize(
|
|
2612
|
+
size_t max_size() const { return MaxValidSize(); }
|
|
2340
2613
|
|
|
2341
2614
|
ABSL_ATTRIBUTE_REINITIALIZES void clear() {
|
|
2342
2615
|
if (SwisstableGenerationsEnabled() &&
|
|
2343
|
-
|
|
2616
|
+
maybe_invalid_capacity().IsMovedFrom()) {
|
|
2344
2617
|
common().set_capacity(DefaultCapacity());
|
|
2345
2618
|
}
|
|
2346
2619
|
AssertNotDebugCapacity();
|
|
@@ -2644,8 +2917,8 @@ class raw_hash_set {
|
|
|
2644
2917
|
iterator erase(const_iterator first,
|
|
2645
2918
|
const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
|
2646
2919
|
AssertNotDebugCapacity();
|
|
2647
|
-
// We check for empty
|
|
2648
|
-
// capacity() >
|
|
2920
|
+
// We check for empty and for is_small because clear_backing_array requires
|
|
2921
|
+
// that capacity() > MaxSmallCapacity() as a precondition.
|
|
2649
2922
|
if (empty()) return end();
|
|
2650
2923
|
if (first == last) return last.inner_;
|
|
2651
2924
|
if (is_small()) {
|
|
@@ -2736,11 +3009,14 @@ class raw_hash_set {
|
|
|
2736
3009
|
typename AllocTraits::propagate_on_container_swap{});
|
|
2737
3010
|
}
|
|
2738
3011
|
|
|
2739
|
-
void rehash(size_t n) {
|
|
3012
|
+
void rehash(size_t n) {
|
|
3013
|
+
Rehash(common(), GetPolicyFunctions(), (std::min)(n, MaxValidCapacity()));
|
|
3014
|
+
}
|
|
2740
3015
|
|
|
2741
3016
|
void reserve(size_t n) {
|
|
2742
3017
|
if (ABSL_PREDICT_TRUE(n > DefaultCapacity())) {
|
|
2743
|
-
ReserveTableToFitNewSize(common(), GetPolicyFunctions(),
|
|
3018
|
+
ReserveTableToFitNewSize(common(), GetPolicyFunctions(),
|
|
3019
|
+
(std::min)(n, MaxValidSize()));
|
|
2744
3020
|
}
|
|
2745
3021
|
}
|
|
2746
3022
|
|
|
@@ -2974,19 +3250,31 @@ class raw_hash_set {
|
|
|
2974
3250
|
}
|
|
2975
3251
|
}
|
|
2976
3252
|
|
|
2977
|
-
// Returns true if the table needs to be sampled.
|
|
3253
|
+
// Returns true if the table needs to be sampled. This keeps track of whether
|
|
3254
|
+
// sampling has already been evaluated and ensures that it can only return
|
|
3255
|
+
// true on its first evaluation. All subsequent calls will return false.
|
|
3256
|
+
//
|
|
2978
3257
|
// This should be called on insertion into an empty SOO table and in copy
|
|
2979
3258
|
// construction when the size can fit in SOO capacity.
|
|
2980
|
-
bool should_sample_soo()
|
|
3259
|
+
bool should_sample_soo() {
|
|
2981
3260
|
ABSL_SWISSTABLE_ASSERT(is_soo());
|
|
2982
|
-
if (!ShouldSampleHashtablezInfoForAlloc<CharAlloc>())
|
|
3261
|
+
if constexpr (!ShouldSampleHashtablezInfoForAlloc<CharAlloc>()) {
|
|
3262
|
+
return false;
|
|
3263
|
+
}
|
|
3264
|
+
if (common().soo_has_tried_sampling()) {
|
|
3265
|
+
// Already evaluated sampling on this SOO table; do not re-evaluate
|
|
3266
|
+
// sampling each time it transitions from empty to full SOO state.
|
|
3267
|
+
return false;
|
|
3268
|
+
}
|
|
3269
|
+
// TODO: b/396049910 -- consider managing this flag on the 1->0 size
|
|
3270
|
+
// transition of SOO tables rather than the 0->1 transition.
|
|
3271
|
+
common().set_soo_has_tried_sampling();
|
|
2983
3272
|
return ABSL_PREDICT_FALSE(ShouldSampleNextTable());
|
|
2984
3273
|
}
|
|
2985
3274
|
|
|
2986
3275
|
void clear_backing_array(bool reuse) {
|
|
2987
|
-
ABSL_SWISSTABLE_ASSERT(capacity() >
|
|
2988
|
-
ClearBackingArray(common(), GetPolicyFunctions(), &char_alloc_ref(), reuse
|
|
2989
|
-
SooEnabled());
|
|
3276
|
+
ABSL_SWISSTABLE_ASSERT(capacity() > MaxSmallCapacity());
|
|
3277
|
+
ClearBackingArray(common(), GetPolicyFunctions(), &char_alloc_ref(), reuse);
|
|
2990
3278
|
}
|
|
2991
3279
|
|
|
2992
3280
|
void destroy_slots() {
|
|
@@ -2997,7 +3285,7 @@ class raw_hash_set {
|
|
|
2997
3285
|
};
|
|
2998
3286
|
if constexpr (SwisstableAssertAccessToDestroyedTable()) {
|
|
2999
3287
|
CommonFields common_copy(non_soo_tag_t{}, this->common());
|
|
3000
|
-
common().set_capacity(
|
|
3288
|
+
common().set_capacity(HashtableCapacity::CreateDestroyed());
|
|
3001
3289
|
IterateOverFullSlots(common_copy, sizeof(slot_type), destroy_slot);
|
|
3002
3290
|
common().set_capacity(common_copy.capacity());
|
|
3003
3291
|
} else {
|
|
@@ -3018,7 +3306,7 @@ class raw_hash_set {
|
|
|
3018
3306
|
|
|
3019
3307
|
void destructor_impl() {
|
|
3020
3308
|
if (SwisstableGenerationsEnabled() &&
|
|
3021
|
-
|
|
3309
|
+
maybe_invalid_capacity().IsMovedFrom()) {
|
|
3022
3310
|
return;
|
|
3023
3311
|
}
|
|
3024
3312
|
if (capacity() == 0) return;
|
|
@@ -3113,11 +3401,13 @@ class raw_hash_set {
|
|
|
3113
3401
|
// than using NDEBUG) to avoid issues in which NDEBUG is enabled in some
|
|
3114
3402
|
// translation units but not in others.
|
|
3115
3403
|
if (SwisstableGenerationsEnabled()) {
|
|
3116
|
-
that.common().set_capacity(this == &that
|
|
3117
|
-
|
|
3404
|
+
that.common().set_capacity(this == &that
|
|
3405
|
+
? HashtableCapacity::CreateSelfMovedFrom()
|
|
3406
|
+
: HashtableCapacity::CreateMovedFrom());
|
|
3118
3407
|
}
|
|
3119
|
-
if (!SwisstableGenerationsEnabled() ||
|
|
3120
|
-
|
|
3408
|
+
if (!SwisstableGenerationsEnabled() ||
|
|
3409
|
+
!maybe_invalid_capacity().IsValid() ||
|
|
3410
|
+
capacity() == DefaultCapacity()) {
|
|
3121
3411
|
return;
|
|
3122
3412
|
}
|
|
3123
3413
|
common().increment_generation();
|
|
@@ -3211,7 +3501,6 @@ class raw_hash_set {
|
|
|
3211
3501
|
}
|
|
3212
3502
|
if (!empty()) {
|
|
3213
3503
|
if (equal_to(key, single_slot())) {
|
|
3214
|
-
common().infoz().RecordInsertHit();
|
|
3215
3504
|
return {single_iterator(), false};
|
|
3216
3505
|
}
|
|
3217
3506
|
}
|
|
@@ -3243,7 +3532,6 @@ class raw_hash_set {
|
|
|
3243
3532
|
if (ABSL_PREDICT_TRUE(equal_to(key, slot_array() + seq.offset(i)))) {
|
|
3244
3533
|
index = seq.offset(i);
|
|
3245
3534
|
inserted = false;
|
|
3246
|
-
common().infoz().RecordInsertHit();
|
|
3247
3535
|
return;
|
|
3248
3536
|
}
|
|
3249
3537
|
}
|
|
@@ -3288,21 +3576,21 @@ class raw_hash_set {
|
|
|
3288
3576
|
return;
|
|
3289
3577
|
}
|
|
3290
3578
|
#endif
|
|
3291
|
-
|
|
3292
|
-
|
|
3579
|
+
const HashtableCapacity cap = maybe_invalid_capacity();
|
|
3580
|
+
if (ABSL_PREDICT_TRUE(cap.IsValid())) {
|
|
3293
3581
|
return;
|
|
3294
3582
|
}
|
|
3295
|
-
assert(
|
|
3583
|
+
assert(!cap.IsReentrance() &&
|
|
3296
3584
|
"Reentrant container access during element construction/destruction "
|
|
3297
3585
|
"is not allowed.");
|
|
3298
3586
|
if constexpr (SwisstableAssertAccessToDestroyedTable()) {
|
|
3299
|
-
if (
|
|
3587
|
+
if (cap.IsDestroyed()) {
|
|
3300
3588
|
ABSL_RAW_LOG(FATAL, "Use of destroyed hash table.");
|
|
3301
3589
|
}
|
|
3302
3590
|
}
|
|
3303
3591
|
if (SwisstableGenerationsEnabled() &&
|
|
3304
|
-
ABSL_PREDICT_FALSE(
|
|
3305
|
-
if (
|
|
3592
|
+
ABSL_PREDICT_FALSE(cap.IsMovedFrom())) {
|
|
3593
|
+
if (cap.IsSelfMovedFrom()) {
|
|
3306
3594
|
// If this log triggers, then a hash table was move-assigned to itself
|
|
3307
3595
|
// and then used again later without being reinitialized.
|
|
3308
3596
|
ABSL_RAW_LOG(FATAL, "Use of self-move-assigned hash table.");
|
|
@@ -3430,6 +3718,11 @@ class raw_hash_set {
|
|
|
3430
3718
|
CommonFields& common() { return settings_.template get<0>(); }
|
|
3431
3719
|
const CommonFields& common() const { return settings_.template get<0>(); }
|
|
3432
3720
|
|
|
3721
|
+
// For use when the capacity is potentially invalid we return
|
|
3722
|
+
// HashtableCapacity directly.
|
|
3723
|
+
HashtableCapacity maybe_invalid_capacity() const {
|
|
3724
|
+
return common().maybe_invalid_capacity();
|
|
3725
|
+
}
|
|
3433
3726
|
ctrl_t* control() const {
|
|
3434
3727
|
ABSL_SWISSTABLE_ASSERT(!is_soo());
|
|
3435
3728
|
return common().control();
|
|
@@ -3676,7 +3969,7 @@ void ForEach(Callback& cb, const raw_hash_set<P, Params...>* c) {
|
|
|
3676
3969
|
|
|
3677
3970
|
namespace hashtable_debug_internal {
|
|
3678
3971
|
template <typename Set>
|
|
3679
|
-
struct HashtableDebugAccess<Set,
|
|
3972
|
+
struct HashtableDebugAccess<Set, std::void_t<typename Set::raw_hash_set>> {
|
|
3680
3973
|
using Traits = typename Set::PolicyTraits;
|
|
3681
3974
|
using Slot = typename Traits::slot_type;
|
|
3682
3975
|
|