Snap for 13871854 from 287980c4245f8f3acdb1f0975d0a5c574f23d090 to androidx-sqlite-release
Change-Id: Ia50938ed23a475a4d6b11505da0ca39d044cbc6d
diff --git a/Android.bp b/Android.bp
index db8d742..2a6bf5c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,9 @@
+// This Android.bp file was autogenerated by external/absel-cpp/generate_bp.py
+// DO NOT EDIT
+
package {
default_applicable_licenses: ["libabsl_license"],
+ default_visibility: ["//visibility:private"],
}
license {
@@ -9,60 +13,13121 @@
license_text: ["LICENSE"],
}
-// Monolithic module for use on device. Currently restricted to 3P libraries
-// which require it as a dependency. See go/absl-android for more information.
-cc_library_static {
- name: "libabsl",
+cc_defaults {
+ name: "absl_defaults",
host_supported: true,
- vendor_available: true,
product_available: true,
+ ramdisk_available: true,
recovery_available: true,
- srcs: [
- "absl/**/*.cc",
- ],
- exclude_srcs: [
- "absl/**/*benchmark.cc",
- "absl/**/*benchmarks.cc",
- "absl/**/*_test.cc",
- "absl/**/*_testing.cc",
- "absl/base/spinlock_test_common.cc",
- "absl/hash/internal/print_hash_of.cc",
- "absl/log/internal/test_helpers.cc",
- "absl/log/internal/test_matchers.cc",
- "absl/log/scoped_mock_log.cc",
- "absl/random/internal/gaussian_distribution_gentables.cc",
- "absl/status/internal/status_matchers.cc",
- ],
- export_include_dirs: ["."],
- shared_libs: [
- "liblog",
- ],
- stl: "libc++",
- sdk_version: "current",
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ sdk_version: "29",
min_sdk_version: "apex_inherit",
+ stl: "libc++",
apex_available: [
"//apex_available:platform",
- "com.android.adservices",
- "com.android.extservices",
- "com.android.ondevicepersonalization",
+ "//apex_available:anyapex",
],
- visibility: [
- "//external/federated-compute:__subpackages__",
- "//external/grpc-grpc:__subpackages__",
- "//external/iamf_tools:__subpackages__",
- "//external/libtextclassifier:__subpackages__",
- "//external/kythe:__subpackages__",
- "//external/tensorflow:__subpackages__",
- "//external/tflite-support:__subpackages__",
- "//external/webrtc:__subpackages__",
- "//frameworks/av/media/libeffects/preprocessing",
- ],
+ target: {
+ windows: {
+ enabled: true,
+ cflags: ["-Wno-unknown-pragmas"],
+ },
+ },
}
-// Globally visible host-only library.
-cc_library_host_static {
- name: "libabsl_host",
- whole_static_libs: ["libabsl"],
- export_include_dirs: ["."],
+cc_defaults {
+ name: "absl_notls_defaults",
+ defaults_visibility: ["//external/protobuf:__subpackages__"],
+ host_supported: true,
+ ramdisk_available: true,
+ recovery_available: true,
+ vendor_ramdisk_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.runtime",
+ ],
+ cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
+}
+
+cc_defaults {
+ name: "absl_test_defaults",
+ host_supported: true,
+ product_available: true,
+ vendor_available: true,
stl: "libc++",
}
+
+cc_defaults {
+ name: "absl_notls_test_defaults",
+ host_supported: true,
+ stl: "libc++",
+ cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
+}
+
+genrule {
+ name: "absl_synchronization_hdrs",
+ srcs: [
+ "absl/synchronization/barrier.h",
+ "absl/synchronization/blocking_counter.h",
+ "absl/synchronization/internal/create_thread_identity.h",
+ "absl/synchronization/internal/futex.h",
+ "absl/synchronization/internal/futex_waiter.h",
+ "absl/synchronization/internal/per_thread_sem.h",
+ "absl/synchronization/internal/pthread_waiter.h",
+ "absl/synchronization/internal/sem_waiter.h",
+ "absl/synchronization/internal/stdcpp_waiter.h",
+ "absl/synchronization/internal/waiter.h",
+ "absl/synchronization/internal/waiter_base.h",
+ "absl/synchronization/internal/win32_waiter.h",
+ "absl/synchronization/mutex.h",
+ "absl/synchronization/notification.h",
+ ],
+ out: [
+ "my_include_dir/absl/synchronization/barrier.h",
+ "my_include_dir/absl/synchronization/blocking_counter.h",
+ "my_include_dir/absl/synchronization/internal/create_thread_identity.h",
+ "my_include_dir/absl/synchronization/internal/futex.h",
+ "my_include_dir/absl/synchronization/internal/futex_waiter.h",
+ "my_include_dir/absl/synchronization/internal/per_thread_sem.h",
+ "my_include_dir/absl/synchronization/internal/pthread_waiter.h",
+ "my_include_dir/absl/synchronization/internal/sem_waiter.h",
+ "my_include_dir/absl/synchronization/internal/stdcpp_waiter.h",
+ "my_include_dir/absl/synchronization/internal/waiter.h",
+ "my_include_dir/absl/synchronization/internal/waiter_base.h",
+ "my_include_dir/absl/synchronization/internal/win32_waiter.h",
+ "my_include_dir/absl/synchronization/mutex.h",
+ "my_include_dir/absl/synchronization/notification.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_synchronization",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/synchronization/barrier.cc",
+ "absl/synchronization/blocking_counter.cc",
+ "absl/synchronization/internal/create_thread_identity.cc",
+ "absl/synchronization/internal/futex_waiter.cc",
+ "absl/synchronization/internal/per_thread_sem.cc",
+ "absl/synchronization/internal/pthread_waiter.cc",
+ "absl/synchronization/internal/sem_waiter.cc",
+ "absl/synchronization/internal/stdcpp_waiter.cc",
+ "absl/synchronization/internal/waiter_base.cc",
+ "absl/synchronization/internal/win32_waiter.cc",
+ "absl/synchronization/mutex.cc",
+ "absl/synchronization/notification.cc",
+ ],
+ generated_headers: ["absl_synchronization_hdrs"],
+ export_generated_headers: ["absl_synchronization_hdrs"],
+
+ whole_static_libs: [
+ "absl_synchronization_graphcycles_internal",
+ "absl_synchronization_kernel_timeout_internal",
+ "absl_base",
+ "absl_base_atomic_hook",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_malloc_internal",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_tracing_internal",
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_time",
+ ],
+ export_static_lib_headers: [
+ "absl_synchronization_graphcycles_internal",
+ "absl_synchronization_kernel_timeout_internal",
+ "absl_base",
+ "absl_base_atomic_hook",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_malloc_internal",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_tracing_internal",
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_time",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_synchronization_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/synchronization/barrier.cc",
+ "absl/synchronization/blocking_counter.cc",
+ "absl/synchronization/internal/create_thread_identity.cc",
+ "absl/synchronization/internal/futex_waiter.cc",
+ "absl/synchronization/internal/per_thread_sem.cc",
+ "absl/synchronization/internal/pthread_waiter.cc",
+ "absl/synchronization/internal/sem_waiter.cc",
+ "absl/synchronization/internal/stdcpp_waiter.cc",
+ "absl/synchronization/internal/waiter_base.cc",
+ "absl/synchronization/internal/win32_waiter.cc",
+ "absl/synchronization/mutex.cc",
+ "absl/synchronization/notification.cc",
+ ],
+ generated_headers: ["absl_synchronization_hdrs"],
+ export_generated_headers: ["absl_synchronization_hdrs"],
+
+ whole_static_libs: [
+ "absl_synchronization_graphcycles_internal_notls",
+ "absl_synchronization_kernel_timeout_internal_notls",
+ "absl_base_notls",
+ "absl_base_atomic_hook_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_tracing_internal_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_time_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_synchronization_graphcycles_internal_notls",
+ "absl_synchronization_kernel_timeout_internal_notls",
+ "absl_base_notls",
+ "absl_base_atomic_hook_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_tracing_internal_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_time_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_time_hdrs",
+ srcs: [
+ "absl/time/civil_time.h",
+ "absl/time/clock.h",
+ "absl/time/time.h",
+ "absl/time/internal/get_current_time_chrono.inc",
+ "absl/time/internal/get_current_time_posix.inc",
+ ],
+ out: [
+ "my_include_dir/absl/time/civil_time.h",
+ "my_include_dir/absl/time/clock.h",
+ "my_include_dir/absl/time/time.h",
+ "my_include_dir/absl/time/internal/get_current_time_chrono.inc",
+ "my_include_dir/absl/time/internal/get_current_time_posix.inc",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_time",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/time/civil_time.cc",
+ "absl/time/clock.cc",
+ "absl/time/duration.cc",
+ "absl/time/format.cc",
+ "absl/time/time.cc",
+ ],
+ generated_headers: ["absl_time_hdrs"],
+ export_generated_headers: ["absl_time_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_strings_string_view",
+ "absl_time_internal_cctz_civil_time",
+ "absl_time_internal_cctz_time_zone",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_strings_string_view",
+ "absl_time_internal_cctz_civil_time",
+ "absl_time_internal_cctz_time_zone",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_time_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/time/civil_time.cc",
+ "absl/time/clock.cc",
+ "absl/time/duration.cc",
+ "absl/time/format.cc",
+ "absl/time/time.cc",
+ ],
+ generated_headers: ["absl_time_hdrs"],
+ export_generated_headers: ["absl_time_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_strings_string_view_notls",
+ "absl_time_internal_cctz_civil_time_notls",
+ "absl_time_internal_cctz_time_zone_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_strings_string_view_notls",
+ "absl_time_internal_cctz_civil_time_notls",
+ "absl_time_internal_cctz_time_zone_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_types_optional_hdrs",
+ srcs: [
+ "absl/types/optional.h",
+ ],
+ out: [
+ "my_include_dir/absl/types/optional.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_types_optional",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_optional_hdrs"],
+ export_generated_headers: ["absl_types_optional_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_types_optional_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_optional_hdrs"],
+ export_generated_headers: ["absl_types_optional_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_utility_hdrs",
+ srcs: [
+ "absl/utility/utility.h",
+ ],
+ out: [
+ "my_include_dir/absl/utility/utility.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_utility",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_utility_hdrs"],
+ export_generated_headers: ["absl_utility_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_utility_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_utility_hdrs"],
+ export_generated_headers: ["absl_utility_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_meta_type_traits_hdrs",
+ srcs: [
+ "absl/meta/type_traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/meta/type_traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_meta_type_traits",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_meta_type_traits_hdrs"],
+ export_generated_headers: ["absl_meta_type_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_meta_type_traits_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_meta_type_traits_hdrs"],
+ export_generated_headers: ["absl_meta_type_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_core_headers_hdrs",
+ srcs: [
+ "absl/base/attributes.h",
+ "absl/base/const_init.h",
+ "absl/base/macros.h",
+ "absl/base/optimization.h",
+ "absl/base/port.h",
+ "absl/base/thread_annotations.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/attributes.h",
+ "my_include_dir/absl/base/const_init.h",
+ "my_include_dir/absl/base/macros.h",
+ "my_include_dir/absl/base/optimization.h",
+ "my_include_dir/absl/base/port.h",
+ "my_include_dir/absl/base/thread_annotations.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_core_headers",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_core_headers_hdrs"],
+ export_generated_headers: ["absl_base_core_headers_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_core_headers_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_core_headers_hdrs"],
+ export_generated_headers: ["absl_base_core_headers_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_config_hdrs",
+ srcs: [
+ "absl/base/config.h",
+ "absl/base/options.h",
+ "absl/base/policy_checks.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/config.h",
+ "my_include_dir/absl/base/options.h",
+ "my_include_dir/absl/base/policy_checks.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_config",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_config_hdrs"],
+ export_generated_headers: ["absl_base_config_hdrs"],
+
+ whole_static_libs: [
+
+ ],
+ export_static_lib_headers: [
+
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_config_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_config_hdrs"],
+ export_generated_headers: ["absl_base_config_hdrs"],
+
+ whole_static_libs: [
+
+ ],
+ export_static_lib_headers: [
+
+ ],
+
+}
+
+genrule {
+ name: "absl_time_internal_cctz_time_zone_hdrs",
+ srcs: [
+ "absl/time/internal/cctz/include/cctz/time_zone.h",
+ "absl/time/internal/cctz/include/cctz/zone_info_source.h",
+ "absl/time/internal/cctz/src/time_zone_fixed.h",
+ "absl/time/internal/cctz/src/time_zone_if.h",
+ "absl/time/internal/cctz/src/time_zone_impl.h",
+ "absl/time/internal/cctz/src/time_zone_info.h",
+ "absl/time/internal/cctz/src/time_zone_libc.h",
+ "absl/time/internal/cctz/src/time_zone_posix.h",
+ "absl/time/internal/cctz/src/tzfile.h",
+ ],
+ out: [
+ "my_include_dir/absl/time/internal/cctz/include/cctz/time_zone.h",
+ "my_include_dir/absl/time/internal/cctz/include/cctz/zone_info_source.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_fixed.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_if.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_impl.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_info.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_libc.h",
+ "my_include_dir/absl/time/internal/cctz/src/time_zone_posix.h",
+ "my_include_dir/absl/time/internal/cctz/src/tzfile.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_time_internal_cctz_time_zone",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/time/internal/cctz/src/time_zone_fixed.cc",
+ "absl/time/internal/cctz/src/time_zone_format.cc",
+ "absl/time/internal/cctz/src/time_zone_if.cc",
+ "absl/time/internal/cctz/src/time_zone_impl.cc",
+ "absl/time/internal/cctz/src/time_zone_info.cc",
+ "absl/time/internal/cctz/src/time_zone_libc.cc",
+ "absl/time/internal/cctz/src/time_zone_lookup.cc",
+ "absl/time/internal/cctz/src/time_zone_posix.cc",
+ "absl/time/internal/cctz/src/zone_info_source.cc",
+ ],
+ generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
+ export_generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
+
+ whole_static_libs: [
+ "absl_time_internal_cctz_civil_time",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_time_internal_cctz_civil_time",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_time_internal_cctz_time_zone_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/time/internal/cctz/src/time_zone_fixed.cc",
+ "absl/time/internal/cctz/src/time_zone_format.cc",
+ "absl/time/internal/cctz/src/time_zone_if.cc",
+ "absl/time/internal/cctz/src/time_zone_impl.cc",
+ "absl/time/internal/cctz/src/time_zone_info.cc",
+ "absl/time/internal/cctz/src/time_zone_libc.cc",
+ "absl/time/internal/cctz/src/time_zone_lookup.cc",
+ "absl/time/internal/cctz/src/time_zone_posix.cc",
+ "absl/time/internal/cctz/src/zone_info_source.cc",
+ ],
+ generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
+ export_generated_headers: ["absl_time_internal_cctz_time_zone_hdrs"],
+
+ whole_static_libs: [
+ "absl_time_internal_cctz_civil_time_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_time_internal_cctz_civil_time_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_time_internal_cctz_civil_time_hdrs",
+ srcs: [
+ "absl/time/internal/cctz/include/cctz/civil_time.h",
+ "absl/time/internal/cctz/include/cctz/civil_time_detail.h",
+ ],
+ out: [
+ "my_include_dir/absl/time/internal/cctz/include/cctz/civil_time.h",
+ "my_include_dir/absl/time/internal/cctz/include/cctz/civil_time_detail.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_time_internal_cctz_civil_time",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/time/internal/cctz/src/civil_time_detail.cc",
+ ],
+ generated_headers: ["absl_time_internal_cctz_civil_time_hdrs"],
+ export_generated_headers: ["absl_time_internal_cctz_civil_time_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_time_internal_cctz_civil_time_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/time/internal/cctz/src/civil_time_detail.cc",
+ ],
+ generated_headers: ["absl_time_internal_cctz_civil_time_hdrs"],
+ export_generated_headers: ["absl_time_internal_cctz_civil_time_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_string_view_hdrs",
+ srcs: [
+ "absl/strings/string_view.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/string_view.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_string_view",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/strings/string_view.cc",
+ ],
+ generated_headers: ["absl_strings_string_view_hdrs"],
+ export_generated_headers: ["absl_strings_string_view_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_throw_delegate",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_throw_delegate",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_string_view_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/strings/string_view.cc",
+ ],
+ generated_headers: ["absl_strings_string_view_hdrs"],
+ export_generated_headers: ["absl_strings_string_view_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_throw_delegate_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_throw_delegate_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_throw_delegate_hdrs",
+ srcs: [
+ "absl/base/internal/throw_delegate.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/throw_delegate.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_throw_delegate",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/base/internal/throw_delegate.cc",
+ ],
+ generated_headers: ["absl_base_throw_delegate_hdrs"],
+ export_generated_headers: ["absl_base_throw_delegate_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_throw_delegate_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/base/internal/throw_delegate.cc",
+ ],
+ generated_headers: ["absl_base_throw_delegate_hdrs"],
+ export_generated_headers: ["absl_base_throw_delegate_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_raw_logging_internal_hdrs",
+ srcs: [
+ "absl/base/internal/raw_logging.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/raw_logging.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_raw_logging_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/base/internal/raw_logging.cc",
+ ],
+ generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+ export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ "absl_base_log_severity",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ "absl_base_log_severity",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_raw_logging_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/base/internal/raw_logging.cc",
+ ],
+ generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+ export_generated_headers: ["absl_base_raw_logging_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_log_severity_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_log_severity_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_log_severity_hdrs",
+ srcs: [
+ "absl/base/log_severity.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/log_severity.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_log_severity",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/base/log_severity.cc",
+ ],
+ generated_headers: ["absl_base_log_severity_hdrs"],
+ export_generated_headers: ["absl_base_log_severity_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_log_severity_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/base/log_severity.cc",
+ ],
+ generated_headers: ["absl_base_log_severity_hdrs"],
+ export_generated_headers: ["absl_base_log_severity_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_errno_saver_hdrs",
+ srcs: [
+ "absl/base/internal/errno_saver.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/errno_saver.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_errno_saver",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_errno_saver_hdrs"],
+ export_generated_headers: ["absl_base_errno_saver_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_errno_saver_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_errno_saver_hdrs"],
+ export_generated_headers: ["absl_base_errno_saver_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_atomic_hook_hdrs",
+ srcs: [
+ "absl/base/internal/atomic_hook.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/atomic_hook.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_atomic_hook",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_atomic_hook_hdrs"],
+ export_generated_headers: ["absl_base_atomic_hook_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_atomic_hook_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_atomic_hook_hdrs"],
+ export_generated_headers: ["absl_base_atomic_hook_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_nullability_hdrs",
+ srcs: [
+ "absl/base/nullability.h",
+ "absl/base/internal/nullability_deprecated.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/nullability.h",
+ "my_include_dir/absl/base/internal/nullability_deprecated.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_nullability",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_nullability_hdrs"],
+ export_generated_headers: ["absl_base_nullability_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_nullability_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_nullability_hdrs"],
+ export_generated_headers: ["absl_base_nullability_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_hdrs",
+ srcs: [
+ "absl/base/call_once.h",
+ "absl/base/casts.h",
+ "absl/base/internal/cycleclock.h",
+ "absl/base/internal/low_level_scheduling.h",
+ "absl/base/internal/per_thread_tls.h",
+ "absl/base/internal/spinlock.h",
+ "absl/base/internal/sysinfo.h",
+ "absl/base/internal/thread_identity.h",
+ "absl/base/internal/tsan_mutex_interface.h",
+ "absl/base/internal/unscaledcycleclock.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/call_once.h",
+ "my_include_dir/absl/base/casts.h",
+ "my_include_dir/absl/base/internal/cycleclock.h",
+ "my_include_dir/absl/base/internal/low_level_scheduling.h",
+ "my_include_dir/absl/base/internal/per_thread_tls.h",
+ "my_include_dir/absl/base/internal/spinlock.h",
+ "my_include_dir/absl/base/internal/sysinfo.h",
+ "my_include_dir/absl/base/internal/thread_identity.h",
+ "my_include_dir/absl/base/internal/tsan_mutex_interface.h",
+ "my_include_dir/absl/base/internal/unscaledcycleclock.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/base/internal/cycleclock.cc",
+ "absl/base/internal/spinlock.cc",
+ "absl/base/internal/sysinfo.cc",
+ "absl/base/internal/thread_identity.cc",
+ "absl/base/internal/unscaledcycleclock.cc",
+ ],
+ generated_headers: ["absl_base_hdrs"],
+ export_generated_headers: ["absl_base_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_cycleclock_internal",
+ "absl_base_dynamic_annotations",
+ "absl_base_log_severity",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_spinlock_wait",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_cycleclock_internal",
+ "absl_base_dynamic_annotations",
+ "absl_base_log_severity",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_spinlock_wait",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/base/internal/cycleclock.cc",
+ "absl/base/internal/spinlock.cc",
+ "absl/base/internal/sysinfo.cc",
+ "absl/base/internal/thread_identity.cc",
+ "absl/base/internal/unscaledcycleclock.cc",
+ ],
+ generated_headers: ["absl_base_hdrs"],
+ export_generated_headers: ["absl_base_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_cycleclock_internal_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_spinlock_wait_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_cycleclock_internal_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_spinlock_wait_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_spinlock_wait_hdrs",
+ srcs: [
+ "absl/base/internal/spinlock_wait.h",
+ "absl/base/internal/spinlock_akaros.inc",
+ "absl/base/internal/spinlock_linux.inc",
+ "absl/base/internal/spinlock_posix.inc",
+ "absl/base/internal/spinlock_win32.inc",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/spinlock_wait.h",
+ "my_include_dir/absl/base/internal/spinlock_akaros.inc",
+ "my_include_dir/absl/base/internal/spinlock_linux.inc",
+ "my_include_dir/absl/base/internal/spinlock_posix.inc",
+ "my_include_dir/absl/base/internal/spinlock_win32.inc",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_spinlock_wait",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/base/internal/spinlock_wait.cc",
+ ],
+ generated_headers: ["absl_base_spinlock_wait_hdrs"],
+ export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_spinlock_wait_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/base/internal/spinlock_wait.cc",
+ ],
+ generated_headers: ["absl_base_spinlock_wait_hdrs"],
+ export_generated_headers: ["absl_base_spinlock_wait_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_base_internal_hdrs",
+ srcs: [
+ "absl/base/internal/hide_ptr.h",
+ "absl/base/internal/identity.h",
+ "absl/base/internal/scheduling_mode.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/hide_ptr.h",
+ "my_include_dir/absl/base/internal/identity.h",
+ "my_include_dir/absl/base/internal/scheduling_mode.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_base_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_base_internal_hdrs"],
+ export_generated_headers: ["absl_base_base_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_base_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_base_internal_hdrs"],
+ export_generated_headers: ["absl_base_base_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_dynamic_annotations_hdrs",
+ srcs: [
+ "absl/base/dynamic_annotations.h",
+ "absl/base/internal/dynamic_annotations.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/dynamic_annotations.h",
+ "my_include_dir/absl/base/internal/dynamic_annotations.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_dynamic_annotations",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+ export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_dynamic_annotations_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+ export_generated_headers: ["absl_base_dynamic_annotations_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_cycleclock_internal_hdrs",
+ srcs: [
+ "absl/base/internal/cycleclock_config.h",
+ "absl/base/internal/unscaledcycleclock_config.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/cycleclock_config.h",
+ "my_include_dir/absl/base/internal/unscaledcycleclock_config.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_cycleclock_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+ export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_cycleclock_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+ export_generated_headers: ["absl_base_cycleclock_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_hdrs",
+ srcs: [
+ "absl/strings/ascii.h",
+ "absl/strings/charconv.h",
+ "absl/strings/escaping.h",
+ "absl/strings/has_absl_stringify.h",
+ "absl/strings/internal/damerau_levenshtein_distance.h",
+ "absl/strings/internal/string_constant.h",
+ "absl/strings/match.h",
+ "absl/strings/numbers.h",
+ "absl/strings/str_cat.h",
+ "absl/strings/str_join.h",
+ "absl/strings/str_replace.h",
+ "absl/strings/str_split.h",
+ "absl/strings/string_view.h",
+ "absl/strings/strip.h",
+ "absl/strings/substitute.h",
+ "absl/strings/internal/charconv_bigint.h",
+ "absl/strings/internal/charconv_parse.h",
+ "absl/strings/internal/memutil.h",
+ "absl/strings/internal/stl_type_traits.h",
+ "absl/strings/internal/str_join_internal.h",
+ "absl/strings/internal/str_split_internal.h",
+ "absl/strings/internal/stringify_sink.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/ascii.h",
+ "my_include_dir/absl/strings/charconv.h",
+ "my_include_dir/absl/strings/escaping.h",
+ "my_include_dir/absl/strings/has_absl_stringify.h",
+ "my_include_dir/absl/strings/internal/damerau_levenshtein_distance.h",
+ "my_include_dir/absl/strings/internal/string_constant.h",
+ "my_include_dir/absl/strings/match.h",
+ "my_include_dir/absl/strings/numbers.h",
+ "my_include_dir/absl/strings/str_cat.h",
+ "my_include_dir/absl/strings/str_join.h",
+ "my_include_dir/absl/strings/str_replace.h",
+ "my_include_dir/absl/strings/str_split.h",
+ "my_include_dir/absl/strings/string_view.h",
+ "my_include_dir/absl/strings/strip.h",
+ "my_include_dir/absl/strings/substitute.h",
+ "my_include_dir/absl/strings/internal/charconv_bigint.h",
+ "my_include_dir/absl/strings/internal/charconv_parse.h",
+ "my_include_dir/absl/strings/internal/memutil.h",
+ "my_include_dir/absl/strings/internal/stl_type_traits.h",
+ "my_include_dir/absl/strings/internal/str_join_internal.h",
+ "my_include_dir/absl/strings/internal/str_split_internal.h",
+ "my_include_dir/absl/strings/internal/stringify_sink.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/strings/ascii.cc",
+ "absl/strings/charconv.cc",
+ "absl/strings/escaping.cc",
+ "absl/strings/internal/charconv_bigint.cc",
+ "absl/strings/internal/charconv_parse.cc",
+ "absl/strings/internal/damerau_levenshtein_distance.cc",
+ "absl/strings/internal/memutil.cc",
+ "absl/strings/internal/stringify_sink.cc",
+ "absl/strings/match.cc",
+ "absl/strings/numbers.cc",
+ "absl/strings/str_cat.cc",
+ "absl/strings/str_replace.cc",
+ "absl/strings/str_split.cc",
+ "absl/strings/substitute.cc",
+ ],
+ generated_headers: ["absl_strings_hdrs"],
+ export_generated_headers: ["absl_strings_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_charset",
+ "absl_strings_internal",
+ "absl_strings_string_view",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_iterator_traits_internal",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_throw_delegate",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_charset",
+ "absl_strings_internal",
+ "absl_strings_string_view",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_iterator_traits_internal",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_throw_delegate",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/strings/ascii.cc",
+ "absl/strings/charconv.cc",
+ "absl/strings/escaping.cc",
+ "absl/strings/internal/charconv_bigint.cc",
+ "absl/strings/internal/charconv_parse.cc",
+ "absl/strings/internal/damerau_levenshtein_distance.cc",
+ "absl/strings/internal/memutil.cc",
+ "absl/strings/internal/stringify_sink.cc",
+ "absl/strings/match.cc",
+ "absl/strings/numbers.cc",
+ "absl/strings/str_cat.cc",
+ "absl/strings/str_replace.cc",
+ "absl/strings/str_split.cc",
+ "absl/strings/substitute.cc",
+ ],
+ generated_headers: ["absl_strings_hdrs"],
+ export_generated_headers: ["absl_strings_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_charset_notls",
+ "absl_strings_internal_notls",
+ "absl_strings_string_view_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_charset_notls",
+ "absl_strings_internal_notls",
+ "absl_strings_string_view_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_numeric_int128_hdrs",
+ srcs: [
+ "absl/numeric/int128.h",
+ "absl/numeric/int128_have_intrinsic.inc",
+ "absl/numeric/int128_no_intrinsic.inc",
+ ],
+ out: [
+ "my_include_dir/absl/numeric/int128.h",
+ "my_include_dir/absl/numeric/int128_have_intrinsic.inc",
+ "my_include_dir/absl/numeric/int128_no_intrinsic.inc",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_numeric_int128",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/numeric/int128.cc",
+ ],
+ generated_headers: ["absl_numeric_int128_hdrs"],
+ export_generated_headers: ["absl_numeric_int128_hdrs"],
+
+ whole_static_libs: [
+ "absl_numeric_bits",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_types_compare",
+ ],
+ export_static_lib_headers: [
+ "absl_numeric_bits",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_types_compare",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_numeric_int128_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/numeric/int128.cc",
+ ],
+ generated_headers: ["absl_numeric_int128_hdrs"],
+ export_generated_headers: ["absl_numeric_int128_hdrs"],
+
+ whole_static_libs: [
+ "absl_numeric_bits_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_types_compare_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_numeric_bits_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_types_compare_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_types_compare_hdrs",
+ srcs: [
+ "absl/types/compare.h",
+ ],
+ out: [
+ "my_include_dir/absl/types/compare.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_types_compare",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_compare_hdrs"],
+ export_generated_headers: ["absl_types_compare_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_types_compare_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_compare_hdrs"],
+ export_generated_headers: ["absl_types_compare_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_numeric_bits_hdrs",
+ srcs: [
+ "absl/numeric/bits.h",
+ "absl/numeric/internal/bits.h",
+ ],
+ out: [
+ "my_include_dir/absl/numeric/bits.h",
+ "my_include_dir/absl/numeric/internal/bits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_numeric_bits",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_numeric_bits_hdrs"],
+ export_generated_headers: ["absl_numeric_bits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_numeric_bits_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_numeric_bits_hdrs"],
+ export_generated_headers: ["absl_numeric_bits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_endian_hdrs",
+ srcs: [
+ "absl/base/internal/endian.h",
+ "absl/base/internal/unaligned_access.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/endian.h",
+ "my_include_dir/absl/base/internal/unaligned_access.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_endian",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_endian_hdrs"],
+ export_generated_headers: ["absl_base_endian_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_endian_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_endian_hdrs"],
+ export_generated_headers: ["absl_base_endian_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_memory_hdrs",
+ srcs: [
+ "absl/memory/memory.h",
+ ],
+ out: [
+ "my_include_dir/absl/memory/memory.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_memory",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_memory_hdrs"],
+ export_generated_headers: ["absl_memory_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_memory_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_memory_hdrs"],
+ export_generated_headers: ["absl_memory_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_iterator_traits_internal_hdrs",
+ srcs: [
+ "absl/base/internal/iterator_traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/iterator_traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_iterator_traits_internal",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_iterator_traits_internal_hdrs"],
+ export_generated_headers: ["absl_base_iterator_traits_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_iterator_traits_internal_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_iterator_traits_internal_hdrs"],
+ export_generated_headers: ["absl_base_iterator_traits_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_internal_hdrs",
+ srcs: [
+ "absl/strings/internal/escaping.h",
+ "absl/strings/internal/ostringstream.h",
+ "absl/strings/internal/resize_uninitialized.h",
+ "absl/strings/internal/utf8.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/escaping.h",
+ "my_include_dir/absl/strings/internal/ostringstream.h",
+ "my_include_dir/absl/strings/internal/resize_uninitialized.h",
+ "my_include_dir/absl/strings/internal/utf8.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_internal",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/strings/internal/escaping.cc",
+ "absl/strings/internal/ostringstream.cc",
+ "absl/strings/internal/utf8.cc",
+ ],
+ generated_headers: ["absl_strings_internal_hdrs"],
+ export_generated_headers: ["absl_strings_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_raw_logging_internal",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_raw_logging_internal",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_internal_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/strings/internal/escaping.cc",
+ "absl/strings/internal/ostringstream.cc",
+ "absl/strings/internal/utf8.cc",
+ ],
+ generated_headers: ["absl_strings_internal_hdrs"],
+ export_generated_headers: ["absl_strings_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_charset_hdrs",
+ srcs: [
+ "absl/strings/charset.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/charset.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_charset",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_charset_hdrs"],
+ export_generated_headers: ["absl_strings_charset_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_string_view",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_string_view",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_charset_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_charset_hdrs"],
+ export_generated_headers: ["absl_strings_charset_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_string_view_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_string_view_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_symbolize_hdrs",
+ srcs: [
+ "absl/debugging/internal/symbolize.h",
+ "absl/debugging/symbolize.h",
+ "absl/debugging/symbolize_darwin.inc",
+ "absl/debugging/symbolize_elf.inc",
+ "absl/debugging/symbolize_emscripten.inc",
+ "absl/debugging/symbolize_unimplemented.inc",
+ "absl/debugging/symbolize_win32.inc",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/symbolize.h",
+ "my_include_dir/absl/debugging/symbolize.h",
+ "my_include_dir/absl/debugging/symbolize_darwin.inc",
+ "my_include_dir/absl/debugging/symbolize_elf.inc",
+ "my_include_dir/absl/debugging/symbolize_emscripten.inc",
+ "my_include_dir/absl/debugging/symbolize_unimplemented.inc",
+ "my_include_dir/absl/debugging/symbolize_win32.inc",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_symbolize",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/symbolize.cc",
+ ],
+ generated_headers: ["absl_debugging_symbolize_hdrs"],
+ export_generated_headers: ["absl_debugging_symbolize_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_debugging_internal",
+ "absl_debugging_demangle_internal",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_malloc_internal",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_debugging_internal",
+ "absl_debugging_demangle_internal",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_malloc_internal",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_symbolize_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/symbolize.cc",
+ ],
+ generated_headers: ["absl_debugging_symbolize_hdrs"],
+ export_generated_headers: ["absl_debugging_symbolize_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_debugging_internal_notls",
+ "absl_debugging_demangle_internal_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_debugging_internal_notls",
+ "absl_debugging_demangle_internal_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_malloc_internal_hdrs",
+ srcs: [
+ "absl/base/internal/direct_mmap.h",
+ "absl/base/internal/low_level_alloc.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/direct_mmap.h",
+ "my_include_dir/absl/base/internal/low_level_alloc.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_malloc_internal",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/base/internal/low_level_alloc.cc",
+ ],
+ generated_headers: ["absl_base_malloc_internal_hdrs"],
+ export_generated_headers: ["absl_base_malloc_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_malloc_internal_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/base/internal/low_level_alloc.cc",
+ ],
+ generated_headers: ["absl_base_malloc_internal_hdrs"],
+ export_generated_headers: ["absl_base_malloc_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_demangle_internal_hdrs",
+ srcs: [
+ "absl/debugging/internal/demangle.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/demangle.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_demangle_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/demangle.cc",
+ ],
+ generated_headers: ["absl_debugging_demangle_internal_hdrs"],
+ export_generated_headers: ["absl_debugging_demangle_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_demangle_rust",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_demangle_rust",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_demangle_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/demangle.cc",
+ ],
+ generated_headers: ["absl_debugging_demangle_internal_hdrs"],
+ export_generated_headers: ["absl_debugging_demangle_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_demangle_rust_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_demangle_rust_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_demangle_rust_hdrs",
+ srcs: [
+ "absl/debugging/internal/demangle_rust.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/demangle_rust.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_demangle_rust",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/internal/demangle_rust.cc",
+ ],
+ generated_headers: ["absl_debugging_demangle_rust_hdrs"],
+ export_generated_headers: ["absl_debugging_demangle_rust_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_decode_rust_punycode",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_decode_rust_punycode",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_demangle_rust_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/internal/demangle_rust.cc",
+ ],
+ generated_headers: ["absl_debugging_demangle_rust_hdrs"],
+ export_generated_headers: ["absl_debugging_demangle_rust_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_decode_rust_punycode_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_decode_rust_punycode_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_decode_rust_punycode_hdrs",
+ srcs: [
+ "absl/debugging/internal/decode_rust_punycode.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/decode_rust_punycode.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_decode_rust_punycode",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/internal/decode_rust_punycode.cc",
+ ],
+ generated_headers: ["absl_debugging_decode_rust_punycode_hdrs"],
+ export_generated_headers: ["absl_debugging_decode_rust_punycode_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_bounded_utf8_length_sequence",
+ "absl_debugging_utf8_for_code_point",
+ "absl_base_config",
+ "absl_base_nullability",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_bounded_utf8_length_sequence",
+ "absl_debugging_utf8_for_code_point",
+ "absl_base_config",
+ "absl_base_nullability",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_decode_rust_punycode_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/internal/decode_rust_punycode.cc",
+ ],
+ generated_headers: ["absl_debugging_decode_rust_punycode_hdrs"],
+ export_generated_headers: ["absl_debugging_decode_rust_punycode_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_bounded_utf8_length_sequence_notls",
+ "absl_debugging_utf8_for_code_point_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_bounded_utf8_length_sequence_notls",
+ "absl_debugging_utf8_for_code_point_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_utf8_for_code_point_hdrs",
+ srcs: [
+ "absl/debugging/internal/utf8_for_code_point.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/utf8_for_code_point.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_utf8_for_code_point",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/internal/utf8_for_code_point.cc",
+ ],
+ generated_headers: ["absl_debugging_utf8_for_code_point_hdrs"],
+ export_generated_headers: ["absl_debugging_utf8_for_code_point_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_utf8_for_code_point_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/internal/utf8_for_code_point.cc",
+ ],
+ generated_headers: ["absl_debugging_utf8_for_code_point_hdrs"],
+ export_generated_headers: ["absl_debugging_utf8_for_code_point_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_bounded_utf8_length_sequence_hdrs",
+ srcs: [
+ "absl/debugging/internal/bounded_utf8_length_sequence.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/bounded_utf8_length_sequence.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_bounded_utf8_length_sequence",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_debugging_bounded_utf8_length_sequence_hdrs"],
+ export_generated_headers: ["absl_debugging_bounded_utf8_length_sequence_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_bounded_utf8_length_sequence_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_debugging_bounded_utf8_length_sequence_hdrs"],
+ export_generated_headers: ["absl_debugging_bounded_utf8_length_sequence_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_debugging_internal_hdrs",
+ srcs: [
+ "absl/debugging/internal/address_is_readable.h",
+ "absl/debugging/internal/addresses.h",
+ "absl/debugging/internal/elf_mem_image.h",
+ "absl/debugging/internal/vdso_support.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/address_is_readable.h",
+ "my_include_dir/absl/debugging/internal/addresses.h",
+ "my_include_dir/absl/debugging/internal/elf_mem_image.h",
+ "my_include_dir/absl/debugging/internal/vdso_support.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_debugging_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/address_is_readable.cc",
+ "absl/debugging/internal/elf_mem_image.cc",
+ "absl/debugging/internal/vdso_support.cc",
+ ],
+ generated_headers: ["absl_debugging_debugging_internal_hdrs"],
+ export_generated_headers: ["absl_debugging_debugging_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_errno_saver",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_errno_saver",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_debugging_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/address_is_readable.cc",
+ "absl/debugging/internal/elf_mem_image.cc",
+ "absl/debugging/internal/vdso_support.cc",
+ ],
+ generated_headers: ["absl_debugging_debugging_internal_hdrs"],
+ export_generated_headers: ["absl_debugging_debugging_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_stacktrace_hdrs",
+ srcs: [
+ "absl/debugging/stacktrace.h",
+ "absl/debugging/internal/stacktrace_aarch64-inl.inc",
+ "absl/debugging/internal/stacktrace_arm-inl.inc",
+ "absl/debugging/internal/stacktrace_config.h",
+ "absl/debugging/internal/stacktrace_emscripten-inl.inc",
+ "absl/debugging/internal/stacktrace_generic-inl.inc",
+ "absl/debugging/internal/stacktrace_powerpc-inl.inc",
+ "absl/debugging/internal/stacktrace_riscv-inl.inc",
+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc",
+ "absl/debugging/internal/stacktrace_win32-inl.inc",
+ "absl/debugging/internal/stacktrace_x86-inl.inc",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/stacktrace.h",
+ "my_include_dir/absl/debugging/internal/stacktrace_aarch64-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_arm-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_config.h",
+ "my_include_dir/absl/debugging/internal/stacktrace_emscripten-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_generic-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_powerpc-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_riscv-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_unimplemented-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_win32-inl.inc",
+ "my_include_dir/absl/debugging/internal/stacktrace_x86-inl.inc",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_stacktrace",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/stacktrace.cc",
+ ],
+ generated_headers: ["absl_debugging_stacktrace_hdrs"],
+ export_generated_headers: ["absl_debugging_stacktrace_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_debugging_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_debugging_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_stacktrace_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/stacktrace.cc",
+ ],
+ generated_headers: ["absl_debugging_stacktrace_hdrs"],
+ export_generated_headers: ["absl_debugging_stacktrace_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_debugging_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_debugging_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_tracing_internal_hdrs",
+ srcs: [
+ "absl/base/internal/tracing.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/tracing.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_tracing_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/base/internal/tracing.cc",
+ ],
+ generated_headers: ["absl_base_tracing_internal_hdrs"],
+ export_generated_headers: ["absl_base_tracing_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_tracing_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/base/internal/tracing.cc",
+ ],
+ generated_headers: ["absl_base_tracing_internal_hdrs"],
+ export_generated_headers: ["absl_base_tracing_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_synchronization_kernel_timeout_internal_hdrs",
+ srcs: [
+ "absl/synchronization/internal/kernel_timeout.h",
+ ],
+ out: [
+ "my_include_dir/absl/synchronization/internal/kernel_timeout.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_synchronization_kernel_timeout_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/synchronization/internal/kernel_timeout.cc",
+ ],
+ generated_headers: ["absl_synchronization_kernel_timeout_internal_hdrs"],
+ export_generated_headers: ["absl_synchronization_kernel_timeout_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_time",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_time",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_synchronization_kernel_timeout_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/synchronization/internal/kernel_timeout.cc",
+ ],
+ generated_headers: ["absl_synchronization_kernel_timeout_internal_hdrs"],
+ export_generated_headers: ["absl_synchronization_kernel_timeout_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_time_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_time_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_synchronization_graphcycles_internal_hdrs",
+ srcs: [
+ "absl/synchronization/internal/graphcycles.h",
+ ],
+ out: [
+ "my_include_dir/absl/synchronization/internal/graphcycles.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_synchronization_graphcycles_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/synchronization/internal/graphcycles.cc",
+ ],
+ generated_headers: ["absl_synchronization_graphcycles_internal_hdrs"],
+ export_generated_headers: ["absl_synchronization_graphcycles_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_malloc_internal",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_malloc_internal",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_synchronization_graphcycles_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/synchronization/internal/graphcycles.cc",
+ ],
+ generated_headers: ["absl_synchronization_graphcycles_internal_hdrs"],
+ export_generated_headers: ["absl_synchronization_graphcycles_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_malloc_internal_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_status_statusor_hdrs",
+ srcs: [
+ "absl/status/statusor.h",
+ "absl/status/internal/statusor_internal.h",
+ ],
+ out: [
+ "my_include_dir/absl/status/statusor.h",
+ "my_include_dir/absl/status/internal/statusor_internal.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_status_statusor",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/status/statusor.cc",
+ ],
+ generated_headers: ["absl_status_statusor_hdrs"],
+ export_generated_headers: ["absl_status_statusor_hdrs"],
+
+ whole_static_libs: [
+ "absl_status",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_has_ostream_operator",
+ "absl_strings_str_format",
+ "absl_types_variant",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_status",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_has_ostream_operator",
+ "absl_strings_str_format",
+ "absl_types_variant",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_status_statusor_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/status/statusor.cc",
+ ],
+ generated_headers: ["absl_status_statusor_hdrs"],
+ export_generated_headers: ["absl_status_statusor_hdrs"],
+
+ whole_static_libs: [
+ "absl_status_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_has_ostream_operator_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_variant_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_status_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_has_ostream_operator_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_variant_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_types_variant_hdrs",
+ srcs: [
+ "absl/types/variant.h",
+ ],
+ out: [
+ "my_include_dir/absl/types/variant.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_types_variant",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_variant_hdrs"],
+ export_generated_headers: ["absl_types_variant_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_types_variant_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_variant_hdrs"],
+ export_generated_headers: ["absl_types_variant_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_str_format_hdrs",
+ srcs: [
+ "absl/strings/str_format.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/str_format.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_str_format",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_str_format_hdrs"],
+ export_generated_headers: ["absl_strings_str_format_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_str_format_internal",
+ "absl_strings_string_view",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_str_format_internal",
+ "absl_strings_string_view",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_str_format_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_str_format_hdrs"],
+ export_generated_headers: ["absl_strings_str_format_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_str_format_internal_notls",
+ "absl_strings_string_view_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_str_format_internal_notls",
+ "absl_strings_string_view_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_types_span_hdrs",
+ srcs: [
+ "absl/types/span.h",
+ "absl/types/internal/span.h",
+ ],
+ out: [
+ "my_include_dir/absl/types/span.h",
+ "my_include_dir/absl/types/internal/span.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_types_span",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_span_hdrs"],
+ export_generated_headers: ["absl_types_span_hdrs"],
+
+ whole_static_libs: [
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_types_span_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_types_span_hdrs"],
+ export_generated_headers: ["absl_types_span_hdrs"],
+
+ whole_static_libs: [
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_hash_weakly_mixed_integer_hdrs",
+ srcs: [
+ "absl/hash/internal/weakly_mixed_integer.h",
+ ],
+ out: [
+ "my_include_dir/absl/hash/internal/weakly_mixed_integer.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_hash_weakly_mixed_integer",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+ export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_hash_weakly_mixed_integer_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+ export_generated_headers: ["absl_hash_weakly_mixed_integer_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_algorithm_hdrs",
+ srcs: [
+ "absl/algorithm/algorithm.h",
+ ],
+ out: [
+ "my_include_dir/absl/algorithm/algorithm.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_algorithm",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_algorithm_hdrs"],
+ export_generated_headers: ["absl_algorithm_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_algorithm_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_algorithm_hdrs"],
+ export_generated_headers: ["absl_algorithm_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_str_format_internal_hdrs",
+ srcs: [
+ "absl/strings/internal/str_format/arg.h",
+ "absl/strings/internal/str_format/bind.h",
+ "absl/strings/internal/str_format/checker.h",
+ "absl/strings/internal/str_format/constexpr_parser.h",
+ "absl/strings/internal/str_format/extension.h",
+ "absl/strings/internal/str_format/float_conversion.h",
+ "absl/strings/internal/str_format/output.h",
+ "absl/strings/internal/str_format/parser.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/str_format/arg.h",
+ "my_include_dir/absl/strings/internal/str_format/bind.h",
+ "my_include_dir/absl/strings/internal/str_format/checker.h",
+ "my_include_dir/absl/strings/internal/str_format/constexpr_parser.h",
+ "my_include_dir/absl/strings/internal/str_format/extension.h",
+ "my_include_dir/absl/strings/internal/str_format/float_conversion.h",
+ "my_include_dir/absl/strings/internal/str_format/output.h",
+ "my_include_dir/absl/strings/internal/str_format/parser.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_str_format_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/strings/internal/str_format/arg.cc",
+ "absl/strings/internal/str_format/bind.cc",
+ "absl/strings/internal/str_format/extension.cc",
+ "absl/strings/internal/str_format/float_conversion.cc",
+ "absl/strings/internal/str_format/output.cc",
+ "absl/strings/internal/str_format/parser.cc",
+ ],
+ generated_headers: ["absl_strings_str_format_internal_hdrs"],
+ export_generated_headers: ["absl_strings_str_format_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_internal",
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_container_fixed_array",
+ "absl_container_inlined_vector",
+ "absl_functional_function_ref",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ "absl_numeric_representation",
+ "absl_types_optional",
+ "absl_types_span",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_internal",
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_container_fixed_array",
+ "absl_container_inlined_vector",
+ "absl_functional_function_ref",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ "absl_numeric_representation",
+ "absl_types_optional",
+ "absl_types_span",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_str_format_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/strings/internal/str_format/arg.cc",
+ "absl/strings/internal/str_format/bind.cc",
+ "absl/strings/internal/str_format/extension.cc",
+ "absl/strings/internal/str_format/float_conversion.cc",
+ "absl/strings/internal/str_format/output.cc",
+ "absl/strings/internal/str_format/parser.cc",
+ ],
+ generated_headers: ["absl_strings_str_format_internal_hdrs"],
+ export_generated_headers: ["absl_strings_str_format_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_internal_notls",
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_container_fixed_array_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_functional_function_ref_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ "absl_numeric_representation_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_internal_notls",
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_container_fixed_array_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_functional_function_ref_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ "absl_numeric_representation_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_numeric_representation_hdrs",
+ srcs: [
+ "absl/numeric/internal/representation.h",
+ ],
+ out: [
+ "my_include_dir/absl/numeric/internal/representation.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_numeric_representation",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_numeric_representation_hdrs"],
+ export_generated_headers: ["absl_numeric_representation_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_numeric_representation_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_numeric_representation_hdrs"],
+ export_generated_headers: ["absl_numeric_representation_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_functional_function_ref_hdrs",
+ srcs: [
+ "absl/functional/function_ref.h",
+ "absl/functional/internal/function_ref.h",
+ ],
+ out: [
+ "my_include_dir/absl/functional/function_ref.h",
+ "my_include_dir/absl/functional/internal/function_ref.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_functional_function_ref",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_function_ref_hdrs"],
+ export_generated_headers: ["absl_functional_function_ref_hdrs"],
+
+ whole_static_libs: [
+ "absl_functional_any_invocable",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_functional_any_invocable",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_functional_function_ref_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_function_ref_hdrs"],
+ export_generated_headers: ["absl_functional_function_ref_hdrs"],
+
+ whole_static_libs: [
+ "absl_functional_any_invocable_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_functional_any_invocable_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_functional_any_invocable_hdrs",
+ srcs: [
+ "absl/functional/any_invocable.h",
+ "absl/functional/internal/any_invocable.h",
+ ],
+ out: [
+ "my_include_dir/absl/functional/any_invocable.h",
+ "my_include_dir/absl/functional/internal/any_invocable.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_functional_any_invocable",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_any_invocable_hdrs"],
+ export_generated_headers: ["absl_functional_any_invocable_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_functional_any_invocable_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_any_invocable_hdrs"],
+ export_generated_headers: ["absl_functional_any_invocable_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_inlined_vector_hdrs",
+ srcs: [
+ "absl/container/inlined_vector.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/inlined_vector.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_inlined_vector",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_inlined_vector_hdrs"],
+ export_generated_headers: ["absl_container_inlined_vector_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_inlined_vector_internal",
+ "absl_algorithm",
+ "absl_base_core_headers",
+ "absl_base_iterator_traits_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_inlined_vector_internal",
+ "absl_algorithm",
+ "absl_base_core_headers",
+ "absl_base_iterator_traits_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_inlined_vector_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_inlined_vector_hdrs"],
+ export_generated_headers: ["absl_container_inlined_vector_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_inlined_vector_internal_notls",
+ "absl_algorithm_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_inlined_vector_internal_notls",
+ "absl_algorithm_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_inlined_vector_internal_hdrs",
+ srcs: [
+ "absl/container/internal/inlined_vector.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/inlined_vector.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_inlined_vector_internal",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_inlined_vector_internal_hdrs"],
+ export_generated_headers: ["absl_container_inlined_vector_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple",
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_inlined_vector_internal_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_inlined_vector_internal_hdrs"],
+ export_generated_headers: ["absl_container_inlined_vector_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple_notls",
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_compressed_tuple_hdrs",
+ srcs: [
+ "absl/container/internal/compressed_tuple.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/compressed_tuple.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_compressed_tuple",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_compressed_tuple_hdrs"],
+ export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
+
+ whole_static_libs: [
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_compressed_tuple_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_compressed_tuple_hdrs"],
+ export_generated_headers: ["absl_container_compressed_tuple_hdrs"],
+
+ whole_static_libs: [
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_fixed_array_hdrs",
+ srcs: [
+ "absl/container/fixed_array.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/fixed_array.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_fixed_array",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_fixed_array_hdrs"],
+ export_generated_headers: ["absl_container_fixed_array_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple",
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_iterator_traits_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple",
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_iterator_traits_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_fixed_array_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_fixed_array_hdrs"],
+ export_generated_headers: ["absl_container_fixed_array_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple_notls",
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple_notls",
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_has_ostream_operator_hdrs",
+ srcs: [
+ "absl/strings/has_ostream_operator.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/has_ostream_operator.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_has_ostream_operator",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_has_ostream_operator_hdrs"],
+ export_generated_headers: ["absl_strings_has_ostream_operator_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_has_ostream_operator_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_has_ostream_operator_hdrs"],
+ export_generated_headers: ["absl_strings_has_ostream_operator_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_status_hdrs",
+ srcs: [
+ "absl/status/status.h",
+ "absl/status/status_payload_printer.h",
+ "absl/status/internal/status_internal.h",
+ ],
+ out: [
+ "my_include_dir/absl/status/status.h",
+ "my_include_dir/absl/status/status_payload_printer.h",
+ "my_include_dir/absl/status/internal/status_internal.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_status",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/status/internal/status_internal.cc",
+ "absl/status/status.cc",
+ "absl/status/status_payload_printer.cc",
+ ],
+ generated_headers: ["absl_status_hdrs"],
+ export_generated_headers: ["absl_status_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_strerror",
+ "absl_container_inlined_vector",
+ "absl_debugging_leak_check",
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_functional_function_ref",
+ "absl_memory",
+ "absl_strings",
+ "absl_strings_cord",
+ "absl_strings_str_format",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_strerror",
+ "absl_container_inlined_vector",
+ "absl_debugging_leak_check",
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_functional_function_ref",
+ "absl_memory",
+ "absl_strings",
+ "absl_strings_cord",
+ "absl_strings_str_format",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_status_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/status/internal/status_internal.cc",
+ "absl/status/status.cc",
+ "absl/status/status_payload_printer.cc",
+ ],
+ generated_headers: ["absl_status_hdrs"],
+ export_generated_headers: ["absl_status_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_strerror_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_leak_check_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_functional_function_ref_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_strerror_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_leak_check_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_functional_function_ref_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cord_hdrs",
+ srcs: [
+ "absl/strings/cord.h",
+ "absl/strings/cord_buffer.h",
+ "absl/strings/cord_analysis.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/cord.h",
+ "my_include_dir/absl/strings/cord_buffer.h",
+ "my_include_dir/absl/strings/cord_analysis.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cord",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/strings/cord.cc",
+ "absl/strings/cord_analysis.cc",
+ ],
+ generated_headers: ["absl_strings_cord_hdrs"],
+ export_generated_headers: ["absl_strings_cord_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_info",
+ "absl_strings_cordz_update_scope",
+ "absl_strings_cordz_update_tracker",
+ "absl_strings_internal",
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_container_inlined_vector",
+ "absl_crc_crc32c",
+ "absl_crc_crc_cord_state",
+ "absl_functional_function_ref",
+ "absl_hash_weakly_mixed_integer",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_types_compare",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_info",
+ "absl_strings_cordz_update_scope",
+ "absl_strings_cordz_update_tracker",
+ "absl_strings_internal",
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_container_inlined_vector",
+ "absl_crc_crc32c",
+ "absl_crc_crc_cord_state",
+ "absl_functional_function_ref",
+ "absl_hash_weakly_mixed_integer",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_types_compare",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cord_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/strings/cord.cc",
+ "absl/strings/cord_analysis.cc",
+ ],
+ generated_headers: ["absl_strings_cord_hdrs"],
+ export_generated_headers: ["absl_strings_cord_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_info_notls",
+ "absl_strings_cordz_update_scope_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_strings_internal_notls",
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_crc_crc32c_notls",
+ "absl_crc_crc_cord_state_notls",
+ "absl_functional_function_ref_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_types_compare_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_info_notls",
+ "absl_strings_cordz_update_scope_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_strings_internal_notls",
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_crc_crc32c_notls",
+ "absl_crc_crc_cord_state_notls",
+ "absl_functional_function_ref_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_types_compare_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_crc_cord_state_hdrs",
+ srcs: [
+ "absl/crc/internal/crc_cord_state.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/internal/crc_cord_state.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_crc_cord_state",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/crc/internal/crc_cord_state.cc",
+ ],
+ generated_headers: ["absl_crc_crc_cord_state_hdrs"],
+ export_generated_headers: ["absl_crc_crc_cord_state_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_crc32c",
+ "absl_base_config",
+ "absl_base_no_destructor",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_crc32c",
+ "absl_base_config",
+ "absl_base_no_destructor",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_crc_cord_state_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/crc/internal/crc_cord_state.cc",
+ ],
+ generated_headers: ["absl_crc_crc_cord_state_hdrs"],
+ export_generated_headers: ["absl_crc_crc_cord_state_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_crc32c_notls",
+ "absl_base_config_notls",
+ "absl_base_no_destructor_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_crc32c_notls",
+ "absl_base_config_notls",
+ "absl_base_no_destructor_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_no_destructor_hdrs",
+ srcs: [
+ "absl/base/no_destructor.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/no_destructor.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_no_destructor",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_no_destructor_hdrs"],
+ export_generated_headers: ["absl_base_no_destructor_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_nullability",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_nullability",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_no_destructor_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_no_destructor_hdrs"],
+ export_generated_headers: ["absl_base_no_destructor_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_crc32c_hdrs",
+ srcs: [
+ "absl/crc/crc32c.h",
+ "absl/crc/internal/crc32c.h",
+ "absl/crc/internal/crc_memcpy.h",
+ "absl/crc/internal/crc32c_inline.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/crc32c.h",
+ "my_include_dir/absl/crc/internal/crc32c.h",
+ "my_include_dir/absl/crc/internal/crc_memcpy.h",
+ "my_include_dir/absl/crc/internal/crc32c_inline.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_crc32c",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/crc/crc32c.cc",
+ "absl/crc/internal/crc_memcpy_fallback.cc",
+ "absl/crc/internal/crc_memcpy_x86_arm_combined.cc",
+ "absl/crc/internal/crc_non_temporal_memcpy.cc",
+ ],
+ generated_headers: ["absl_crc_crc32c_hdrs"],
+ export_generated_headers: ["absl_crc_crc32c_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_cpu_detect",
+ "absl_crc_crc_internal",
+ "absl_crc_non_temporal_memcpy",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_strings",
+ "absl_strings_str_format",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_cpu_detect",
+ "absl_crc_crc_internal",
+ "absl_crc_non_temporal_memcpy",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_strings",
+ "absl_strings_str_format",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_crc32c_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/crc/crc32c.cc",
+ "absl/crc/internal/crc_memcpy_fallback.cc",
+ "absl/crc/internal/crc_memcpy_x86_arm_combined.cc",
+ "absl/crc/internal/crc_non_temporal_memcpy.cc",
+ ],
+ generated_headers: ["absl_crc_crc32c_hdrs"],
+ export_generated_headers: ["absl_crc_crc32c_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_cpu_detect_notls",
+ "absl_crc_crc_internal_notls",
+ "absl_crc_non_temporal_memcpy_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_cpu_detect_notls",
+ "absl_crc_crc_internal_notls",
+ "absl_crc_non_temporal_memcpy_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_prefetch_hdrs",
+ srcs: [
+ "absl/base/prefetch.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/prefetch.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_prefetch",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_prefetch_hdrs"],
+ export_generated_headers: ["absl_base_prefetch_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_prefetch_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_prefetch_hdrs"],
+ export_generated_headers: ["absl_base_prefetch_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_non_temporal_memcpy_hdrs",
+ srcs: [
+ "absl/crc/internal/non_temporal_memcpy.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/internal/non_temporal_memcpy.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_non_temporal_memcpy",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_crc_non_temporal_memcpy_hdrs"],
+ export_generated_headers: ["absl_crc_non_temporal_memcpy_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_non_temporal_arm_intrinsics",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_non_temporal_arm_intrinsics",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_non_temporal_memcpy_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_crc_non_temporal_memcpy_hdrs"],
+ export_generated_headers: ["absl_crc_non_temporal_memcpy_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_non_temporal_arm_intrinsics_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_non_temporal_arm_intrinsics_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_non_temporal_arm_intrinsics_hdrs",
+ srcs: [
+ "absl/crc/internal/non_temporal_arm_intrinsics.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/internal/non_temporal_arm_intrinsics.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_non_temporal_arm_intrinsics",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_crc_non_temporal_arm_intrinsics_hdrs"],
+ export_generated_headers: ["absl_crc_non_temporal_arm_intrinsics_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_non_temporal_arm_intrinsics_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_crc_non_temporal_arm_intrinsics_hdrs"],
+ export_generated_headers: ["absl_crc_non_temporal_arm_intrinsics_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_crc_internal_hdrs",
+ srcs: [
+ "absl/crc/internal/crc.h",
+ "absl/crc/internal/crc32_x86_arm_combined_simd.h",
+ "absl/crc/internal/crc_internal.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/internal/crc.h",
+ "my_include_dir/absl/crc/internal/crc32_x86_arm_combined_simd.h",
+ "my_include_dir/absl/crc/internal/crc_internal.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_crc_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/crc/internal/crc.cc",
+ "absl/crc/internal/crc_x86_arm_combined.cc",
+ ],
+ generated_headers: ["absl_crc_crc_internal_hdrs"],
+ export_generated_headers: ["absl_crc_crc_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_cpu_detect",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_base_raw_logging_internal",
+ "absl_memory",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_cpu_detect",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_base_raw_logging_internal",
+ "absl_memory",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_crc_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/crc/internal/crc.cc",
+ "absl/crc/internal/crc_x86_arm_combined.cc",
+ ],
+ generated_headers: ["absl_crc_crc_internal_hdrs"],
+ export_generated_headers: ["absl_crc_crc_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_crc_cpu_detect_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_memory_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_crc_cpu_detect_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_memory_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_crc_cpu_detect_hdrs",
+ srcs: [
+ "absl/crc/internal/cpu_detect.h",
+ ],
+ out: [
+ "my_include_dir/absl/crc/internal/cpu_detect.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_crc_cpu_detect",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/crc/internal/cpu_detect.cc",
+ ],
+ generated_headers: ["absl_crc_cpu_detect_hdrs"],
+ export_generated_headers: ["absl_crc_cpu_detect_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_crc_cpu_detect_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/crc/internal/cpu_detect.cc",
+ ],
+ generated_headers: ["absl_crc_cpu_detect_hdrs"],
+ export_generated_headers: ["absl_crc_cpu_detect_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_update_tracker_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_update_tracker.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_update_tracker.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_update_tracker",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_update_tracker_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_update_tracker_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_update_tracker_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_update_tracker_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_update_tracker_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_update_scope_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_update_scope.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_update_scope.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_update_scope",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_update_scope_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_update_scope_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_info",
+ "absl_strings_cordz_update_tracker",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_info",
+ "absl_strings_cordz_update_tracker",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_update_scope_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_update_scope_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_update_scope_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_info_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_info_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_info_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_info.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_info.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_info",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_info.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_info_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_info_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_functions",
+ "absl_strings_cordz_handle",
+ "absl_strings_cordz_statistics",
+ "absl_strings_cordz_update_tracker",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_container_inlined_vector",
+ "absl_debugging_stacktrace",
+ "absl_synchronization",
+ "absl_time",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal",
+ "absl_strings_cordz_functions",
+ "absl_strings_cordz_handle",
+ "absl_strings_cordz_statistics",
+ "absl_strings_cordz_update_tracker",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_container_inlined_vector",
+ "absl_debugging_stacktrace",
+ "absl_synchronization",
+ "absl_time",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_info_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_info.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_info_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_info_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_functions_notls",
+ "absl_strings_cordz_handle_notls",
+ "absl_strings_cordz_statistics_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cord_internal_notls",
+ "absl_strings_cordz_functions_notls",
+ "absl_strings_cordz_handle_notls",
+ "absl_strings_cordz_statistics_notls",
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_statistics_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_statistics.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_statistics.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_statistics",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_statistics_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_statistics_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cordz_update_tracker",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cordz_update_tracker",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_statistics_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_strings_cordz_statistics_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_statistics_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_cordz_update_tracker_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_handle_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_handle.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_handle.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_handle",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_handle.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_handle_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_handle_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_handle_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_handle.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_handle_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_handle_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cordz_functions_hdrs",
+ srcs: [
+ "absl/strings/internal/cordz_functions.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cordz_functions.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_functions",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_functions.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_functions_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_functions_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_profiling_exponential_biased",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_profiling_exponential_biased",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cordz_functions_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cordz_functions.cc",
+ ],
+ generated_headers: ["absl_strings_cordz_functions_hdrs"],
+ export_generated_headers: ["absl_strings_cordz_functions_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_profiling_exponential_biased_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_profiling_exponential_biased_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_profiling_exponential_biased_hdrs",
+ srcs: [
+ "absl/profiling/internal/exponential_biased.h",
+ ],
+ out: [
+ "my_include_dir/absl/profiling/internal/exponential_biased.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_profiling_exponential_biased",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/profiling/internal/exponential_biased.cc",
+ ],
+ generated_headers: ["absl_profiling_exponential_biased_hdrs"],
+ export_generated_headers: ["absl_profiling_exponential_biased_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_profiling_exponential_biased_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/profiling/internal/exponential_biased.cc",
+ ],
+ generated_headers: ["absl_profiling_exponential_biased_hdrs"],
+ export_generated_headers: ["absl_profiling_exponential_biased_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_strings_cord_internal_hdrs",
+ srcs: [
+ "absl/strings/internal/cord_data_edge.h",
+ "absl/strings/internal/cord_internal.h",
+ "absl/strings/internal/cord_rep_btree.h",
+ "absl/strings/internal/cord_rep_btree_navigator.h",
+ "absl/strings/internal/cord_rep_btree_reader.h",
+ "absl/strings/internal/cord_rep_consume.h",
+ "absl/strings/internal/cord_rep_crc.h",
+ "absl/strings/internal/cord_rep_flat.h",
+ ],
+ out: [
+ "my_include_dir/absl/strings/internal/cord_data_edge.h",
+ "my_include_dir/absl/strings/internal/cord_internal.h",
+ "my_include_dir/absl/strings/internal/cord_rep_btree.h",
+ "my_include_dir/absl/strings/internal/cord_rep_btree_navigator.h",
+ "my_include_dir/absl/strings/internal/cord_rep_btree_reader.h",
+ "my_include_dir/absl/strings/internal/cord_rep_consume.h",
+ "my_include_dir/absl/strings/internal/cord_rep_crc.h",
+ "my_include_dir/absl/strings/internal/cord_rep_flat.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_strings_cord_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cord_internal.cc",
+ "absl/strings/internal/cord_rep_btree.cc",
+ "absl/strings/internal/cord_rep_btree_navigator.cc",
+ "absl/strings/internal/cord_rep_btree_reader.cc",
+ "absl/strings/internal/cord_rep_consume.cc",
+ "absl/strings/internal/cord_rep_crc.cc",
+ ],
+ generated_headers: ["absl_strings_cord_internal_hdrs"],
+ export_generated_headers: ["absl_strings_cord_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_inlined_vector",
+ "absl_crc_crc_cord_state",
+ "absl_functional_function_ref",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_strings",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_inlined_vector",
+ "absl_crc_crc_cord_state",
+ "absl_functional_function_ref",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_strings_cord_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/strings/internal/cord_internal.cc",
+ "absl/strings/internal/cord_rep_btree.cc",
+ "absl/strings/internal/cord_rep_btree_navigator.cc",
+ "absl/strings/internal/cord_rep_btree_reader.cc",
+ "absl/strings/internal/cord_rep_consume.cc",
+ "absl/strings/internal/cord_rep_crc.cc",
+ ],
+ generated_headers: ["absl_strings_cord_internal_hdrs"],
+ export_generated_headers: ["absl_strings_cord_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_crc_crc_cord_state_notls",
+ "absl_functional_function_ref_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_strings_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_crc_crc_cord_state_notls",
+ "absl_functional_function_ref_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_container_memory_hdrs",
+ srcs: [
+ "absl/container/internal/container_memory.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/container_memory.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_container_memory",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_container_memory_hdrs"],
+ export_generated_headers: ["absl_container_container_memory_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_container_memory_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_container_memory_hdrs"],
+ export_generated_headers: ["absl_container_container_memory_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_leak_check_hdrs",
+ srcs: [
+ "absl/debugging/leak_check.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/leak_check.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_leak_check",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/leak_check.cc",
+ ],
+ generated_headers: ["absl_debugging_leak_check_hdrs"],
+ export_generated_headers: ["absl_debugging_leak_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_leak_check_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/leak_check.cc",
+ ],
+ generated_headers: ["absl_debugging_leak_check_hdrs"],
+ export_generated_headers: ["absl_debugging_leak_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_strerror_hdrs",
+ srcs: [
+ "absl/base/internal/strerror.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/internal/strerror.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_strerror",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/base/internal/strerror.cc",
+ ],
+ generated_headers: ["absl_base_strerror_hdrs"],
+ export_generated_headers: ["absl_base_strerror_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_strerror_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/base/internal/strerror.cc",
+ ],
+ generated_headers: ["absl_base_strerror_hdrs"],
+ export_generated_headers: ["absl_base_strerror_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_hdrs",
+ srcs: [
+ "absl/random/random.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/random.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_hdrs"],
+ export_generated_headers: ["absl_random_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_distributions",
+ "absl_random_seed_sequences",
+ "absl_base_config",
+ "absl_random_internal_nonsecure_base",
+ "absl_random_internal_pcg_engine",
+ "absl_random_internal_randen_engine",
+ ],
+ export_static_lib_headers: [
+ "absl_random_distributions",
+ "absl_random_seed_sequences",
+ "absl_base_config",
+ "absl_random_internal_nonsecure_base",
+ "absl_random_internal_pcg_engine",
+ "absl_random_internal_randen_engine",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_hdrs"],
+ export_generated_headers: ["absl_random_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_distributions_notls",
+ "absl_random_seed_sequences_notls",
+ "absl_base_config_notls",
+ "absl_random_internal_nonsecure_base_notls",
+ "absl_random_internal_pcg_engine_notls",
+ "absl_random_internal_randen_engine_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_distributions_notls",
+ "absl_random_seed_sequences_notls",
+ "absl_base_config_notls",
+ "absl_random_internal_nonsecure_base_notls",
+ "absl_random_internal_pcg_engine_notls",
+ "absl_random_internal_randen_engine_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_randen_engine_hdrs",
+ srcs: [
+ "absl/random/internal/randen_engine.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/randen_engine.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_engine",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_randen_engine_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_engine_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_iostream_state_saver",
+ "absl_random_internal_randen",
+ "absl_base_endian",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_iostream_state_saver",
+ "absl_random_internal_randen",
+ "absl_base_endian",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_engine_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_randen_engine_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_engine_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_random_internal_randen_notls",
+ "absl_base_endian_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_random_internal_randen_notls",
+ "absl_base_endian_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_randen_hdrs",
+ srcs: [
+ "absl/random/internal/randen.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/randen.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen_hwaes",
+ "absl_random_internal_randen_slow",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen_hwaes",
+ "absl_random_internal_randen_slow",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_hwaes_notls",
+ "absl_random_internal_randen_slow_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_hwaes_notls",
+ "absl_random_internal_randen_slow_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_randen_slow_hdrs",
+ srcs: [
+ "absl/random/internal/randen_slow.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/randen_slow.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_slow",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_slow.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_slow_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_slow_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_slow_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_slow.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_slow_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_slow_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_platform_hdrs",
+ srcs: [
+ "absl/random/internal/platform.h",
+ "absl/random/internal/randen_traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/platform.h",
+ "my_include_dir/absl/random/internal/randen_traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_platform",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_round_keys.cc",
+ ],
+ generated_headers: ["absl_random_internal_platform_hdrs"],
+ export_generated_headers: ["absl_random_internal_platform_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_platform_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_round_keys.cc",
+ ],
+ generated_headers: ["absl_random_internal_platform_hdrs"],
+ export_generated_headers: ["absl_random_internal_platform_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_randen_hwaes_hdrs",
+ srcs: [
+ "absl/random/internal/randen_detect.h",
+ "absl/random/internal/randen_hwaes.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/randen_detect.h",
+ "my_include_dir/absl/random/internal/randen_hwaes.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_hwaes",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_detect.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hwaes_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hwaes_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen_hwaes_impl",
+ "absl_base_config",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen_hwaes_impl",
+ "absl_base_config",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_hwaes_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_detect.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hwaes_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hwaes_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_hwaes_impl_notls",
+ "absl_base_config_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_hwaes_impl_notls",
+ "absl_base_config_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_randen_hwaes_impl_hdrs",
+ srcs: [
+ "absl/random/internal/randen_hwaes.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/randen_hwaes.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_hwaes_impl",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_hwaes.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hwaes_impl_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hwaes_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_randen_hwaes_impl_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/randen_hwaes.cc",
+ ],
+ generated_headers: ["absl_random_internal_randen_hwaes_impl_hdrs"],
+ export_generated_headers: ["absl_random_internal_randen_hwaes_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_iostream_state_saver_hdrs",
+ srcs: [
+ "absl/random/internal/iostream_state_saver.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/iostream_state_saver.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_iostream_state_saver",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_iostream_state_saver_hdrs"],
+ export_generated_headers: ["absl_random_internal_iostream_state_saver_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_meta_type_traits",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_iostream_state_saver_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_iostream_state_saver_hdrs"],
+ export_generated_headers: ["absl_random_internal_iostream_state_saver_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_pcg_engine_hdrs",
+ srcs: [
+ "absl/random/internal/pcg_engine.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/pcg_engine.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_pcg_engine",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_pcg_engine_hdrs"],
+ export_generated_headers: ["absl_random_internal_pcg_engine_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fastmath",
+ "absl_random_internal_iostream_state_saver",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fastmath",
+ "absl_random_internal_iostream_state_saver",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_pcg_engine_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_pcg_engine_hdrs"],
+ export_generated_headers: ["absl_random_internal_pcg_engine_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_fastmath_hdrs",
+ srcs: [
+ "absl/random/internal/fastmath.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/fastmath.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_fastmath",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_fastmath_hdrs"],
+ export_generated_headers: ["absl_random_internal_fastmath_hdrs"],
+
+ whole_static_libs: [
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_fastmath_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_fastmath_hdrs"],
+ export_generated_headers: ["absl_random_internal_fastmath_hdrs"],
+
+ whole_static_libs: [
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_nonsecure_base_hdrs",
+ srcs: [
+ "absl/random/internal/nonsecure_base.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/nonsecure_base.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_nonsecure_base",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_nonsecure_base_hdrs"],
+ export_generated_headers: ["absl_random_internal_nonsecure_base_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_entropy_pool",
+ "absl_random_internal_salted_seed_seq",
+ "absl_random_internal_seed_material",
+ "absl_base_config",
+ "absl_container_inlined_vector",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_entropy_pool",
+ "absl_random_internal_salted_seed_seq",
+ "absl_random_internal_seed_material",
+ "absl_base_config",
+ "absl_container_inlined_vector",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_nonsecure_base_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_nonsecure_base_hdrs"],
+ export_generated_headers: ["absl_random_internal_nonsecure_base_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_entropy_pool_notls",
+ "absl_random_internal_salted_seed_seq_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_base_config_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_entropy_pool_notls",
+ "absl_random_internal_salted_seed_seq_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_base_config_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_seed_material_hdrs",
+ srcs: [
+ "absl/random/internal/seed_material.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/seed_material.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_seed_material",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/seed_material.cc",
+ ],
+ generated_headers: ["absl_random_internal_seed_material_hdrs"],
+ export_generated_headers: ["absl_random_internal_seed_material_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fast_uniform_bits",
+ "absl_base_config",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fast_uniform_bits",
+ "absl_base_config",
+ "absl_base_dynamic_annotations",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_seed_material_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/seed_material.cc",
+ ],
+ generated_headers: ["absl_random_internal_seed_material_hdrs"],
+ export_generated_headers: ["absl_random_internal_seed_material_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fast_uniform_bits_notls",
+ "absl_base_config_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fast_uniform_bits_notls",
+ "absl_base_config_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_fast_uniform_bits_hdrs",
+ srcs: [
+ "absl/random/internal/fast_uniform_bits.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/fast_uniform_bits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_fast_uniform_bits",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_fast_uniform_bits_hdrs"],
+ export_generated_headers: ["absl_random_internal_fast_uniform_bits_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_fast_uniform_bits_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_fast_uniform_bits_hdrs"],
+ export_generated_headers: ["absl_random_internal_fast_uniform_bits_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_traits_hdrs",
+ srcs: [
+ "absl/random/internal/traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_traits",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_traits_hdrs"],
+ export_generated_headers: ["absl_random_internal_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_traits_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_traits_hdrs"],
+ export_generated_headers: ["absl_random_internal_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_salted_seed_seq_hdrs",
+ srcs: [
+ "absl/random/internal/salted_seed_seq.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/salted_seed_seq.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_salted_seed_seq",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_salted_seed_seq_hdrs"],
+ export_generated_headers: ["absl_random_internal_salted_seed_seq_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_seed_material",
+ "absl_container_inlined_vector",
+ "absl_meta_type_traits",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_seed_material",
+ "absl_container_inlined_vector",
+ "absl_meta_type_traits",
+ "absl_types_optional",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_salted_seed_seq_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_salted_seed_seq_hdrs"],
+ export_generated_headers: ["absl_random_internal_salted_seed_seq_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_seed_material_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_meta_type_traits_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_seed_material_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_meta_type_traits_notls",
+ "absl_types_optional_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_entropy_pool_hdrs",
+ srcs: [
+ "absl/random/internal/entropy_pool.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/entropy_pool.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_entropy_pool",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/random/internal/entropy_pool.cc",
+ ],
+ generated_headers: ["absl_random_internal_entropy_pool_hdrs"],
+ export_generated_headers: ["absl_random_internal_entropy_pool_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen",
+ "absl_random_internal_seed_material",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_random_seed_gen_exception",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform",
+ "absl_random_internal_randen",
+ "absl_random_internal_seed_material",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_random_seed_gen_exception",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_entropy_pool_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/random/internal/entropy_pool.cc",
+ ],
+ generated_headers: ["absl_random_internal_entropy_pool_hdrs"],
+ export_generated_headers: ["absl_random_internal_entropy_pool_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_random_seed_gen_exception_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_platform_notls",
+ "absl_random_internal_randen_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_random_seed_gen_exception_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_seed_gen_exception_hdrs",
+ srcs: [
+ "absl/random/seed_gen_exception.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/seed_gen_exception.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_seed_gen_exception",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/random/seed_gen_exception.cc",
+ ],
+ generated_headers: ["absl_random_seed_gen_exception_hdrs"],
+ export_generated_headers: ["absl_random_seed_gen_exception_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_seed_gen_exception_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/random/seed_gen_exception.cc",
+ ],
+ generated_headers: ["absl_random_seed_gen_exception_hdrs"],
+ export_generated_headers: ["absl_random_seed_gen_exception_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_seed_sequences_hdrs",
+ srcs: [
+ "absl/random/seed_sequences.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/seed_sequences.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_seed_sequences",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/random/seed_sequences.cc",
+ ],
+ generated_headers: ["absl_random_seed_sequences_hdrs"],
+ export_generated_headers: ["absl_random_seed_sequences_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_seed_gen_exception",
+ "absl_base_config",
+ "absl_base_nullability",
+ "absl_random_internal_entropy_pool",
+ "absl_random_internal_salted_seed_seq",
+ "absl_random_internal_seed_material",
+ "absl_strings_string_view",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_random_seed_gen_exception",
+ "absl_base_config",
+ "absl_base_nullability",
+ "absl_random_internal_entropy_pool",
+ "absl_random_internal_salted_seed_seq",
+ "absl_random_internal_seed_material",
+ "absl_strings_string_view",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_seed_sequences_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/random/seed_sequences.cc",
+ ],
+ generated_headers: ["absl_random_seed_sequences_hdrs"],
+ export_generated_headers: ["absl_random_seed_sequences_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_seed_gen_exception_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ "absl_random_internal_entropy_pool_notls",
+ "absl_random_internal_salted_seed_seq_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_strings_string_view_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_seed_gen_exception_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ "absl_random_internal_entropy_pool_notls",
+ "absl_random_internal_salted_seed_seq_notls",
+ "absl_random_internal_seed_material_notls",
+ "absl_strings_string_view_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_distributions_hdrs",
+ srcs: [
+ "absl/random/bernoulli_distribution.h",
+ "absl/random/beta_distribution.h",
+ "absl/random/discrete_distribution.h",
+ "absl/random/distributions.h",
+ "absl/random/exponential_distribution.h",
+ "absl/random/gaussian_distribution.h",
+ "absl/random/log_uniform_int_distribution.h",
+ "absl/random/poisson_distribution.h",
+ "absl/random/uniform_int_distribution.h",
+ "absl/random/uniform_real_distribution.h",
+ "absl/random/zipf_distribution.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/bernoulli_distribution.h",
+ "my_include_dir/absl/random/beta_distribution.h",
+ "my_include_dir/absl/random/discrete_distribution.h",
+ "my_include_dir/absl/random/distributions.h",
+ "my_include_dir/absl/random/exponential_distribution.h",
+ "my_include_dir/absl/random/gaussian_distribution.h",
+ "my_include_dir/absl/random/log_uniform_int_distribution.h",
+ "my_include_dir/absl/random/poisson_distribution.h",
+ "my_include_dir/absl/random/uniform_int_distribution.h",
+ "my_include_dir/absl/random/uniform_real_distribution.h",
+ "my_include_dir/absl/random/zipf_distribution.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_distributions",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/random/discrete_distribution.cc",
+ "absl/random/gaussian_distribution.cc",
+ ],
+ generated_headers: ["absl_random_distributions_hdrs"],
+ export_generated_headers: ["absl_random_distributions_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ "absl_random_internal_distribution_caller",
+ "absl_random_internal_fast_uniform_bits",
+ "absl_random_internal_fastmath",
+ "absl_random_internal_generate_real",
+ "absl_random_internal_iostream_state_saver",
+ "absl_random_internal_traits",
+ "absl_random_internal_uniform_helper",
+ "absl_random_internal_wide_multiply",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ "absl_random_internal_distribution_caller",
+ "absl_random_internal_fast_uniform_bits",
+ "absl_random_internal_fastmath",
+ "absl_random_internal_generate_real",
+ "absl_random_internal_iostream_state_saver",
+ "absl_random_internal_traits",
+ "absl_random_internal_uniform_helper",
+ "absl_random_internal_wide_multiply",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_distributions_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/random/discrete_distribution.cc",
+ "absl/random/gaussian_distribution.cc",
+ ],
+ generated_headers: ["absl_random_distributions_hdrs"],
+ export_generated_headers: ["absl_random_distributions_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ "absl_random_internal_distribution_caller_notls",
+ "absl_random_internal_fast_uniform_bits_notls",
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_generate_real_notls",
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_random_internal_traits_notls",
+ "absl_random_internal_uniform_helper_notls",
+ "absl_random_internal_wide_multiply_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_base_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ "absl_random_internal_distribution_caller_notls",
+ "absl_random_internal_fast_uniform_bits_notls",
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_generate_real_notls",
+ "absl_random_internal_iostream_state_saver_notls",
+ "absl_random_internal_traits_notls",
+ "absl_random_internal_uniform_helper_notls",
+ "absl_random_internal_wide_multiply_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_wide_multiply_hdrs",
+ srcs: [
+ "absl/random/internal/wide_multiply.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/wide_multiply.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_wide_multiply",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_wide_multiply_hdrs"],
+ export_generated_headers: ["absl_random_internal_wide_multiply_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_wide_multiply_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_wide_multiply_hdrs"],
+ export_generated_headers: ["absl_random_internal_wide_multiply_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_uniform_helper_hdrs",
+ srcs: [
+ "absl/random/internal/uniform_helper.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/uniform_helper.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_uniform_helper",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_uniform_helper_hdrs"],
+ export_generated_headers: ["absl_random_internal_uniform_helper_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits",
+ "absl_base_config",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_uniform_helper_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_uniform_helper_hdrs"],
+ export_generated_headers: ["absl_random_internal_uniform_helper_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_traits_notls",
+ "absl_base_config_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_generate_real_hdrs",
+ srcs: [
+ "absl/random/internal/generate_real.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/generate_real.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_generate_real",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_generate_real_hdrs"],
+ export_generated_headers: ["absl_random_internal_generate_real_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fastmath",
+ "absl_random_internal_traits",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fastmath",
+ "absl_random_internal_traits",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_generate_real_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_generate_real_hdrs"],
+ export_generated_headers: ["absl_random_internal_generate_real_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_traits_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_internal_fastmath_notls",
+ "absl_random_internal_traits_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_internal_distribution_caller_hdrs",
+ srcs: [
+ "absl/random/internal/distribution_caller.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/internal/distribution_caller.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_internal_distribution_caller",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_distribution_caller_hdrs"],
+ export_generated_headers: ["absl_random_internal_distribution_caller_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_internal_distribution_caller_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_internal_distribution_caller_hdrs"],
+ export_generated_headers: ["absl_random_internal_distribution_caller_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_base_fast_type_id_hdrs",
+ srcs: [
+ "absl/base/fast_type_id.h",
+ ],
+ out: [
+ "my_include_dir/absl/base/fast_type_id.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_base_fast_type_id",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_fast_type_id_hdrs"],
+ export_generated_headers: ["absl_base_fast_type_id_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_base_fast_type_id_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_base_fast_type_id_hdrs"],
+ export_generated_headers: ["absl_base_fast_type_id_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_random_bit_gen_ref_hdrs",
+ srcs: [
+ "absl/random/bit_gen_ref.h",
+ ],
+ out: [
+ "my_include_dir/absl/random/bit_gen_ref.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_random_bit_gen_ref",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_bit_gen_ref_hdrs"],
+ export_generated_headers: ["absl_random_bit_gen_ref_hdrs"],
+
+ whole_static_libs: [
+ "absl_random",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_fast_type_id",
+ "absl_meta_type_traits",
+ "absl_random_internal_distribution_caller",
+ "absl_random_internal_fast_uniform_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_random",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_fast_type_id",
+ "absl_meta_type_traits",
+ "absl_random_internal_distribution_caller",
+ "absl_random_internal_fast_uniform_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_random_bit_gen_ref_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_random_bit_gen_ref_hdrs"],
+ export_generated_headers: ["absl_random_bit_gen_ref_hdrs"],
+
+ whole_static_libs: [
+ "absl_random_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_meta_type_traits_notls",
+ "absl_random_internal_distribution_caller_notls",
+ "absl_random_internal_fast_uniform_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_random_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_meta_type_traits_notls",
+ "absl_random_internal_distribution_caller_notls",
+ "absl_random_internal_fast_uniform_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_scoped_mock_log_hdrs",
+ srcs: [
+ "absl/log/scoped_mock_log.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/scoped_mock_log.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_test_library {
+ name: "absl_log_scoped_mock_log",
+ defaults: ["absl_test_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/log/scoped_mock_log.cc",
+ ],
+ generated_headers: ["absl_log_scoped_mock_log_hdrs"],
+ export_generated_headers: ["absl_log_scoped_mock_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_log_log_sink_registry",
+ "absl_base_config",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_log_log_sink_registry",
+ "absl_base_config",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ ],
+
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ ],
+ shared: {
+ enabled: false,
+ },
+
+}
+
+cc_test_library {
+ name: "absl_log_scoped_mock_log_notls",
+ defaults: ["absl_notls_test_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/log/scoped_mock_log.cc",
+ ],
+ generated_headers: ["absl_log_scoped_mock_log_hdrs"],
+ export_generated_headers: ["absl_log_scoped_mock_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_log_log_sink_registry_notls",
+ "absl_base_config_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_log_log_sink_registry_notls",
+ "absl_base_config_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ ],
+
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ ],
+ shared: {
+ enabled: false,
+ },
+
+}
+
+genrule {
+ name: "absl_log_log_sink_registry_hdrs",
+ srcs: [
+ "absl/log/log_sink_registry.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/log_sink_registry.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_log_sink_registry",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_log_sink_registry_hdrs"],
+ export_generated_headers: ["absl_log_log_sink_registry_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_sink",
+ "absl_base_config",
+ "absl_base_nullability",
+ "absl_log_internal_log_sink_set",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_sink",
+ "absl_base_config",
+ "absl_base_nullability",
+ "absl_log_internal_log_sink_set",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_log_sink_registry_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_log_sink_registry_hdrs"],
+ export_generated_headers: ["absl_log_log_sink_registry_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_sink_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ "absl_log_internal_log_sink_set_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_sink_notls",
+ "absl_base_config_notls",
+ "absl_base_nullability_notls",
+ "absl_log_internal_log_sink_set_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_log_sink_set_hdrs",
+ srcs: [
+ "absl/log/internal/log_sink_set.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/log_sink_set.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_sink_set",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_sink_set.cc",
+ ],
+ generated_headers: ["absl_log_internal_log_sink_set_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_sink_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_config",
+ "absl_log_internal_globals",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_cleanup",
+ "absl_log_globals",
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_config",
+ "absl_log_internal_globals",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_cleanup",
+ "absl_log_globals",
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_types_span",
+ ],
+
+ target: {
+ android: {
+ shared_libs: ["liblog"],
+ },
+ },
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_sink_set_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_sink_set.cc",
+ ],
+ generated_headers: ["absl_log_internal_log_sink_set_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_sink_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_cleanup_notls",
+ "absl_log_globals_notls",
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_cleanup_notls",
+ "absl_log_globals_notls",
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_types_span_notls",
+ ],
+
+ target: {
+ android: {
+ shared_libs: ["liblog"],
+ },
+ },
+
+}
+
+genrule {
+ name: "absl_log_log_sink_hdrs",
+ srcs: [
+ "absl/log/log_sink.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/log_sink.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_log_sink",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/log/log_sink.cc",
+ ],
+ generated_headers: ["absl_log_log_sink_hdrs"],
+ export_generated_headers: ["absl_log_log_sink_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_entry",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_entry",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_log_sink_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/log/log_sink.cc",
+ ],
+ generated_headers: ["absl_log_log_sink_hdrs"],
+ export_generated_headers: ["absl_log_log_sink_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_log_entry_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_log_entry_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_log_entry_hdrs",
+ srcs: [
+ "absl/log/log_entry.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/log_entry.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_log_entry",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_log_entry_hdrs"],
+ export_generated_headers: ["absl_log_log_entry_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_log_internal_config",
+ "absl_strings",
+ "absl_time",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_log_internal_config",
+ "absl_strings",
+ "absl_time",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_log_entry_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_log_entry_hdrs"],
+ export_generated_headers: ["absl_log_log_entry_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_log_internal_config_notls",
+ "absl_strings_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_log_internal_config_notls",
+ "absl_strings_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_config_hdrs",
+ srcs: [
+ "absl/log/internal/config.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/config.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_config",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_config_hdrs"],
+ export_generated_headers: ["absl_log_internal_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_config_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_config_hdrs"],
+ export_generated_headers: ["absl_log_internal_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_globals_hdrs",
+ srcs: [
+ "absl/log/globals.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/globals.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_globals",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/log/globals.cc",
+ ],
+ generated_headers: ["absl_log_globals_hdrs"],
+ export_generated_headers: ["absl_log_globals_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_hash",
+ "absl_log_internal_vlog_config",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_hash",
+ "absl_log_internal_vlog_config",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_globals_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/log/globals.cc",
+ ],
+ generated_headers: ["absl_log_globals_hdrs"],
+ export_generated_headers: ["absl_log_globals_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_hash_notls",
+ "absl_log_internal_vlog_config_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_atomic_hook_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_hash_notls",
+ "absl_log_internal_vlog_config_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_vlog_config_hdrs",
+ srcs: [
+ "absl/log/internal/vlog_config.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/vlog_config.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_vlog_config",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/vlog_config.cc",
+ ],
+ generated_headers: ["absl_log_internal_vlog_config_hdrs"],
+ export_generated_headers: ["absl_log_internal_vlog_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_fnmatch",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_nullability",
+ "absl_memory",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_fnmatch",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_nullability",
+ "absl_memory",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_vlog_config_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/vlog_config.cc",
+ ],
+ generated_headers: ["absl_log_internal_vlog_config_hdrs"],
+ export_generated_headers: ["absl_log_internal_vlog_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_fnmatch_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_nullability_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_fnmatch_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_nullability_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_fnmatch_hdrs",
+ srcs: [
+ "absl/log/internal/fnmatch.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/fnmatch.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_fnmatch",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/fnmatch.cc",
+ ],
+ generated_headers: ["absl_log_internal_fnmatch_hdrs"],
+ export_generated_headers: ["absl_log_internal_fnmatch_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_fnmatch_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/fnmatch.cc",
+ ],
+ generated_headers: ["absl_log_internal_fnmatch_hdrs"],
+ export_generated_headers: ["absl_log_internal_fnmatch_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_hash_hdrs",
+ srcs: [
+ "absl/hash/hash.h",
+ "absl/hash/internal/hash.h",
+ ],
+ out: [
+ "my_include_dir/absl/hash/hash.h",
+ "my_include_dir/absl/hash/internal/hash.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_hash",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/hash/internal/hash.cc",
+ ],
+ generated_headers: ["absl_hash_hdrs"],
+ export_generated_headers: ["absl_hash_hdrs"],
+
+ whole_static_libs: [
+ "absl_hash_city",
+ "absl_hash_low_level_hash",
+ "absl_hash_weakly_mixed_integer",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_container_fixed_array",
+ "absl_functional_function_ref",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_types_optional",
+ "absl_types_variant",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_hash_city",
+ "absl_hash_low_level_hash",
+ "absl_hash_weakly_mixed_integer",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_container_fixed_array",
+ "absl_functional_function_ref",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_types_optional",
+ "absl_types_variant",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_hash_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/hash/internal/hash.cc",
+ ],
+ generated_headers: ["absl_hash_hdrs"],
+ export_generated_headers: ["absl_hash_hdrs"],
+
+ whole_static_libs: [
+ "absl_hash_city_notls",
+ "absl_hash_low_level_hash_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_container_fixed_array_notls",
+ "absl_functional_function_ref_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ "absl_types_variant_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_hash_city_notls",
+ "absl_hash_low_level_hash_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_container_fixed_array_notls",
+ "absl_functional_function_ref_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ "absl_types_variant_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_hash_low_level_hash_hdrs",
+ srcs: [
+ "absl/hash/internal/low_level_hash.h",
+ ],
+ out: [
+ "my_include_dir/absl/hash/internal/low_level_hash.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_hash_low_level_hash",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/hash/internal/low_level_hash.cc",
+ ],
+ generated_headers: ["absl_hash_low_level_hash_hdrs"],
+ export_generated_headers: ["absl_hash_low_level_hash_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_numeric_int128",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_base_prefetch",
+ "absl_numeric_int128",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_hash_low_level_hash_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/hash/internal/low_level_hash.cc",
+ ],
+ generated_headers: ["absl_hash_low_level_hash_hdrs"],
+ export_generated_headers: ["absl_hash_low_level_hash_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_numeric_int128_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_base_prefetch_notls",
+ "absl_numeric_int128_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_hash_city_hdrs",
+ srcs: [
+ "absl/hash/internal/city.h",
+ ],
+ out: [
+ "my_include_dir/absl/hash/internal/city.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_hash_city",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/hash/internal/city.cc",
+ ],
+ generated_headers: ["absl_hash_city_hdrs"],
+ export_generated_headers: ["absl_hash_city_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_hash_city_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/hash/internal/city.cc",
+ ],
+ generated_headers: ["absl_hash_city_hdrs"],
+ export_generated_headers: ["absl_hash_city_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_cleanup_hdrs",
+ srcs: [
+ "absl/cleanup/cleanup.h",
+ ],
+ out: [
+ "my_include_dir/absl/cleanup/cleanup.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_cleanup",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_cleanup_hdrs"],
+ export_generated_headers: ["absl_cleanup_hdrs"],
+
+ whole_static_libs: [
+ "absl_cleanup_cleanup_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_cleanup_cleanup_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_cleanup_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_cleanup_hdrs"],
+ export_generated_headers: ["absl_cleanup_hdrs"],
+
+ whole_static_libs: [
+ "absl_cleanup_cleanup_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_cleanup_cleanup_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_cleanup_cleanup_internal_hdrs",
+ srcs: [
+ "absl/cleanup/internal/cleanup.h",
+ ],
+ out: [
+ "my_include_dir/absl/cleanup/internal/cleanup.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_cleanup_cleanup_internal",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_cleanup_cleanup_internal_hdrs"],
+ export_generated_headers: ["absl_cleanup_cleanup_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_core_headers",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_core_headers",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_cleanup_cleanup_internal_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_cleanup_cleanup_internal_hdrs"],
+ export_generated_headers: ["absl_cleanup_cleanup_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_core_headers_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_core_headers_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_globals_hdrs",
+ srcs: [
+ "absl/log/internal/globals.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/globals.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_globals",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/globals.cc",
+ ],
+ generated_headers: ["absl_log_internal_globals_hdrs"],
+ export_generated_headers: ["absl_log_internal_globals_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_time",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_time",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_globals_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/globals.cc",
+ ],
+ generated_headers: ["absl_log_internal_globals_hdrs"],
+ export_generated_headers: ["absl_log_internal_globals_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_time_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_time_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_hdrs",
+ srcs: [
+ "absl/log/log.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/log.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_hdrs"],
+ export_generated_headers: ["absl_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_vlog_is_on",
+ "absl_log_internal_log_impl",
+ ],
+ export_static_lib_headers: [
+ "absl_log_vlog_is_on",
+ "absl_log_internal_log_impl",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_hdrs"],
+ export_generated_headers: ["absl_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_vlog_is_on_notls",
+ "absl_log_internal_log_impl_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_vlog_is_on_notls",
+ "absl_log_internal_log_impl_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_log_impl_hdrs",
+ srcs: [
+ "absl/log/internal/log_impl.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/log_impl.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_impl",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_log_impl_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ "absl_log_absl_vlog_is_on",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ "absl_log_absl_vlog_is_on",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_impl_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_log_impl_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ "absl_log_absl_vlog_is_on_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ "absl_log_absl_vlog_is_on_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_absl_vlog_is_on_hdrs",
+ srcs: [
+ "absl/log/absl_vlog_is_on.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/absl_vlog_is_on.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_absl_vlog_is_on",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_vlog_is_on_hdrs"],
+ export_generated_headers: ["absl_log_absl_vlog_is_on_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_log_internal_vlog_config",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_log_internal_vlog_config",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_absl_vlog_is_on_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_vlog_is_on_hdrs"],
+ export_generated_headers: ["absl_log_absl_vlog_is_on_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_log_internal_vlog_config_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_log_internal_vlog_config_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_strip_hdrs",
+ srcs: [
+ "absl/log/internal/strip.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/strip.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_strip",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_strip_hdrs"],
+ export_generated_headers: ["absl_log_internal_strip_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_log_message",
+ "absl_log_internal_nullstream",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_log_message",
+ "absl_log_internal_nullstream",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_strip_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_strip_hdrs"],
+ export_generated_headers: ["absl_log_internal_strip_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_nullstream_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_nullstream_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_nullstream_hdrs",
+ srcs: [
+ "absl/log/internal/nullstream.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/nullstream.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_nullstream",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_nullstream_hdrs"],
+ export_generated_headers: ["absl_log_internal_nullstream_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_nullstream_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_nullstream_hdrs"],
+ export_generated_headers: ["absl_log_internal_nullstream_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_log_message_hdrs",
+ srcs: [
+ "absl/log/internal/log_message.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/log_message.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_message",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_message.cc",
+ ],
+ generated_headers: ["absl_log_internal_log_message_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_message_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_append_truncated",
+ "absl_log_internal_format",
+ "absl_log_internal_globals",
+ "absl_log_internal_log_sink_set",
+ "absl_log_internal_nullguard",
+ "absl_log_internal_proto",
+ "absl_log_internal_structured_proto",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ "absl_base_log_severity",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_strerror",
+ "absl_container_inlined_vector",
+ "absl_debugging_examine_stack",
+ "absl_log_globals",
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_log_log_sink_registry",
+ "absl_memory",
+ "absl_strings",
+ "absl_strings_internal",
+ "absl_time",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_append_truncated",
+ "absl_log_internal_format",
+ "absl_log_internal_globals",
+ "absl_log_internal_log_sink_set",
+ "absl_log_internal_nullguard",
+ "absl_log_internal_proto",
+ "absl_log_internal_structured_proto",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_errno_saver",
+ "absl_base_log_severity",
+ "absl_base_nullability",
+ "absl_base_raw_logging_internal",
+ "absl_base_strerror",
+ "absl_container_inlined_vector",
+ "absl_debugging_examine_stack",
+ "absl_log_globals",
+ "absl_log_log_entry",
+ "absl_log_log_sink",
+ "absl_log_log_sink_registry",
+ "absl_memory",
+ "absl_strings",
+ "absl_strings_internal",
+ "absl_time",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_log_message_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_message.cc",
+ ],
+ generated_headers: ["absl_log_internal_log_message_hdrs"],
+ export_generated_headers: ["absl_log_internal_log_message_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_append_truncated_notls",
+ "absl_log_internal_format_notls",
+ "absl_log_internal_globals_notls",
+ "absl_log_internal_log_sink_set_notls",
+ "absl_log_internal_nullguard_notls",
+ "absl_log_internal_proto_notls",
+ "absl_log_internal_structured_proto_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_strerror_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_examine_stack_notls",
+ "absl_log_globals_notls",
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_log_log_sink_registry_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_strings_internal_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_append_truncated_notls",
+ "absl_log_internal_format_notls",
+ "absl_log_internal_globals_notls",
+ "absl_log_internal_log_sink_set_notls",
+ "absl_log_internal_nullguard_notls",
+ "absl_log_internal_proto_notls",
+ "absl_log_internal_structured_proto_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_errno_saver_notls",
+ "absl_base_log_severity_notls",
+ "absl_base_nullability_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_strerror_notls",
+ "absl_container_inlined_vector_notls",
+ "absl_debugging_examine_stack_notls",
+ "absl_log_globals_notls",
+ "absl_log_log_entry_notls",
+ "absl_log_log_sink_notls",
+ "absl_log_log_sink_registry_notls",
+ "absl_memory_notls",
+ "absl_strings_notls",
+ "absl_strings_internal_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_examine_stack_hdrs",
+ srcs: [
+ "absl/debugging/internal/examine_stack.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/internal/examine_stack.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_examine_stack",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/examine_stack.cc",
+ ],
+ generated_headers: ["absl_debugging_examine_stack_hdrs"],
+ export_generated_headers: ["absl_debugging_examine_stack_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_stacktrace",
+ "absl_debugging_symbolize",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_examine_stack_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/debugging/internal/examine_stack.cc",
+ ],
+ generated_headers: ["absl_debugging_examine_stack_hdrs"],
+ export_generated_headers: ["absl_debugging_examine_stack_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_stacktrace_notls",
+ "absl_debugging_symbolize_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_structured_proto_hdrs",
+ srcs: [
+ "absl/log/internal/structured_proto.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/structured_proto.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_structured_proto",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/structured_proto.cc",
+ ],
+ generated_headers: ["absl_log_internal_structured_proto_hdrs"],
+ export_generated_headers: ["absl_log_internal_structured_proto_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_proto",
+ "absl_base_config",
+ "absl_strings",
+ "absl_types_span",
+ "absl_types_variant",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_proto",
+ "absl_base_config",
+ "absl_strings",
+ "absl_types_span",
+ "absl_types_variant",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_structured_proto_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/structured_proto.cc",
+ ],
+ generated_headers: ["absl_log_internal_structured_proto_hdrs"],
+ export_generated_headers: ["absl_log_internal_structured_proto_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_proto_notls",
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ "absl_types_variant_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_proto_notls",
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ "absl_types_variant_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_proto_hdrs",
+ srcs: [
+ "absl/log/internal/proto.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/proto.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_proto",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/proto.cc",
+ ],
+ generated_headers: ["absl_log_internal_proto_hdrs"],
+ export_generated_headers: ["absl_log_internal_proto_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_strings",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_strings",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_proto_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/proto.cc",
+ ],
+ generated_headers: ["absl_log_internal_proto_hdrs"],
+ export_generated_headers: ["absl_log_internal_proto_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_nullguard_hdrs",
+ srcs: [
+ "absl/log/internal/nullguard.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/nullguard.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_nullguard",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/nullguard.cc",
+ ],
+ generated_headers: ["absl_log_internal_nullguard_hdrs"],
+ export_generated_headers: ["absl_log_internal_nullguard_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_nullguard_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/nullguard.cc",
+ ],
+ generated_headers: ["absl_log_internal_nullguard_hdrs"],
+ export_generated_headers: ["absl_log_internal_nullguard_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_format_hdrs",
+ srcs: [
+ "absl/log/internal/log_format.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/log_format.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_format",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_format.cc",
+ ],
+ generated_headers: ["absl_log_internal_format_hdrs"],
+ export_generated_headers: ["absl_log_internal_format_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_append_truncated",
+ "absl_log_internal_config",
+ "absl_log_internal_globals",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_strings",
+ "absl_strings_str_format",
+ "absl_time",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_append_truncated",
+ "absl_log_internal_config",
+ "absl_log_internal_globals",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_strings",
+ "absl_strings_str_format",
+ "absl_time",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_format_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/log_format.cc",
+ ],
+ generated_headers: ["absl_log_internal_format_hdrs"],
+ export_generated_headers: ["absl_log_internal_format_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_append_truncated_notls",
+ "absl_log_internal_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_append_truncated_notls",
+ "absl_log_internal_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ "absl_time_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_append_truncated_hdrs",
+ srcs: [
+ "absl/log/internal/append_truncated.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/append_truncated.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_append_truncated",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_append_truncated_hdrs"],
+ export_generated_headers: ["absl_log_internal_append_truncated_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_strings",
+ "absl_strings_internal",
+ "absl_types_span",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_strings",
+ "absl_strings_internal",
+ "absl_types_span",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_append_truncated_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_append_truncated_hdrs"],
+ export_generated_headers: ["absl_log_internal_append_truncated_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ "absl_strings_internal_notls",
+ "absl_types_span_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ "absl_strings_internal_notls",
+ "absl_types_span_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_conditions_hdrs",
+ srcs: [
+ "absl/log/internal/conditions.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/conditions.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_conditions",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/conditions.cc",
+ ],
+ generated_headers: ["absl_log_internal_conditions_hdrs"],
+ export_generated_headers: ["absl_log_internal_conditions_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_voidify",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_voidify",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_conditions_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/conditions.cc",
+ ],
+ generated_headers: ["absl_log_internal_conditions_hdrs"],
+ export_generated_headers: ["absl_log_internal_conditions_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_voidify_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_voidify_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_voidify_hdrs",
+ srcs: [
+ "absl/log/internal/voidify.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/voidify.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_voidify",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_voidify_hdrs"],
+ export_generated_headers: ["absl_log_internal_voidify_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_voidify_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_voidify_hdrs"],
+ export_generated_headers: ["absl_log_internal_voidify_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_vlog_is_on_hdrs",
+ srcs: [
+ "absl/log/vlog_is_on.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/vlog_is_on.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_vlog_is_on",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_vlog_is_on_hdrs"],
+ export_generated_headers: ["absl_log_vlog_is_on_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_absl_vlog_is_on",
+ ],
+ export_static_lib_headers: [
+ "absl_log_absl_vlog_is_on",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_vlog_is_on_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_vlog_is_on_hdrs"],
+ export_generated_headers: ["absl_log_vlog_is_on_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_absl_vlog_is_on_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_absl_vlog_is_on_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_initialize_hdrs",
+ srcs: [
+ "absl/log/initialize.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/initialize.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_initialize",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/log/initialize.cc",
+ ],
+ generated_headers: ["absl_log_initialize_hdrs"],
+ export_generated_headers: ["absl_log_initialize_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_globals",
+ "absl_base_config",
+ "absl_log_internal_globals",
+ "absl_time",
+ ],
+ export_static_lib_headers: [
+ "absl_log_globals",
+ "absl_base_config",
+ "absl_log_internal_globals",
+ "absl_time",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_initialize_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/log/initialize.cc",
+ ],
+ generated_headers: ["absl_log_initialize_hdrs"],
+ export_generated_headers: ["absl_log_initialize_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_globals_notls",
+ "absl_base_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_time_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_globals_notls",
+ "absl_base_config_notls",
+ "absl_log_internal_globals_notls",
+ "absl_time_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_die_if_null_hdrs",
+ srcs: [
+ "absl/log/die_if_null.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/die_if_null.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_die_if_null",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/log/die_if_null.cc",
+ ],
+ generated_headers: ["absl_log_die_if_null_hdrs"],
+ export_generated_headers: ["absl_log_die_if_null_hdrs"],
+
+ whole_static_libs: [
+ "absl_log",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_log",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_die_if_null_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/log/die_if_null.cc",
+ ],
+ generated_headers: ["absl_log_die_if_null_hdrs"],
+ export_generated_headers: ["absl_log_die_if_null_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_check_hdrs",
+ srcs: [
+ "absl/log/check.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/check.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_check",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_check_hdrs"],
+ export_generated_headers: ["absl_log_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_impl",
+ "absl_log_internal_check_op",
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_impl",
+ "absl_log_internal_check_op",
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_check_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_check_hdrs"],
+ export_generated_headers: ["absl_log_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_impl_notls",
+ "absl_log_internal_check_op_notls",
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_impl_notls",
+ "absl_log_internal_check_op_notls",
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_check_op_hdrs",
+ srcs: [
+ "absl/log/internal/check_op.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/check_op.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_check_op",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/log/internal/check_op.cc",
+ ],
+ generated_headers: ["absl_log_internal_check_op_hdrs"],
+ export_generated_headers: ["absl_log_internal_check_op_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_nullguard",
+ "absl_log_internal_nullstream",
+ "absl_log_internal_strip",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_debugging_leak_check",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_nullguard",
+ "absl_log_internal_nullstream",
+ "absl_log_internal_strip",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_debugging_leak_check",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_check_op_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/log/internal/check_op.cc",
+ ],
+ generated_headers: ["absl_log_internal_check_op_hdrs"],
+ export_generated_headers: ["absl_log_internal_check_op_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_nullguard_notls",
+ "absl_log_internal_nullstream_notls",
+ "absl_log_internal_strip_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_debugging_leak_check_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_nullguard_notls",
+ "absl_log_internal_nullstream_notls",
+ "absl_log_internal_strip_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_debugging_leak_check_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_internal_check_impl_hdrs",
+ srcs: [
+ "absl/log/internal/check_impl.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/internal/check_impl.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_internal_check_impl",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_check_impl_hdrs"],
+ export_generated_headers: ["absl_log_internal_check_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_op",
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ "absl_base_core_headers",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_op",
+ "absl_log_internal_conditions",
+ "absl_log_internal_log_message",
+ "absl_log_internal_strip",
+ "absl_base_core_headers",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_internal_check_impl_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_internal_check_impl_hdrs"],
+ export_generated_headers: ["absl_log_internal_check_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_op_notls",
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ "absl_base_core_headers_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_op_notls",
+ "absl_log_internal_conditions_notls",
+ "absl_log_internal_log_message_notls",
+ "absl_log_internal_strip_notls",
+ "absl_base_core_headers_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_absl_log_hdrs",
+ srcs: [
+ "absl/log/absl_log.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/absl_log.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_absl_log",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_log_hdrs"],
+ export_generated_headers: ["absl_log_absl_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_log_impl",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_log_impl",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_absl_log_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_log_hdrs"],
+ export_generated_headers: ["absl_log_absl_log_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_log_impl_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_log_impl_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_log_absl_check_hdrs",
+ srcs: [
+ "absl/log/absl_check.h",
+ ],
+ out: [
+ "my_include_dir/absl/log/absl_check.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_log_absl_check",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_check_hdrs"],
+ export_generated_headers: ["absl_log_absl_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_impl",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_impl",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_log_absl_check_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_log_absl_check_hdrs"],
+ export_generated_headers: ["absl_log_absl_check_hdrs"],
+
+ whole_static_libs: [
+ "absl_log_internal_check_impl_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_log_internal_check_impl_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_functional_bind_front_hdrs",
+ srcs: [
+ "absl/functional/bind_front.h",
+ "absl/functional/internal/front_binder.h",
+ ],
+ out: [
+ "my_include_dir/absl/functional/bind_front.h",
+ "my_include_dir/absl/functional/internal/front_binder.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_functional_bind_front",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_bind_front_hdrs"],
+ export_generated_headers: ["absl_functional_bind_front_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple",
+ "absl_meta_type_traits",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_functional_bind_front_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_functional_bind_front_hdrs"],
+ export_generated_headers: ["absl_functional_bind_front_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_compressed_tuple_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_compressed_tuple_notls",
+ "absl_meta_type_traits_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_parse_hdrs",
+ srcs: [
+ "absl/flags/internal/parse.h",
+ "absl/flags/parse.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/parse.h",
+ "my_include_dir/absl/flags/parse.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_parse",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/parse.cc",
+ ],
+ generated_headers: ["absl_flags_parse_hdrs"],
+ export_generated_headers: ["absl_flags_parse_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_flag",
+ "absl_flags_flag_internal",
+ "absl_flags_private_handle_accessor",
+ "absl_flags_program_name",
+ "absl_flags_reflection",
+ "absl_flags_usage",
+ "absl_flags_usage_internal",
+ "absl_algorithm_container",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_flag",
+ "absl_flags_flag_internal",
+ "absl_flags_private_handle_accessor",
+ "absl_flags_program_name",
+ "absl_flags_reflection",
+ "absl_flags_usage",
+ "absl_flags_usage_internal",
+ "absl_algorithm_container",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_parse_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/parse.cc",
+ ],
+ generated_headers: ["absl_flags_parse_hdrs"],
+ export_generated_headers: ["absl_flags_parse_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_flags_program_name_notls",
+ "absl_flags_reflection_notls",
+ "absl_flags_usage_notls",
+ "absl_flags_usage_internal_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_flags_program_name_notls",
+ "absl_flags_reflection_notls",
+ "absl_flags_usage_notls",
+ "absl_flags_usage_internal_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_algorithm_container_hdrs",
+ srcs: [
+ "absl/algorithm/container.h",
+ ],
+ out: [
+ "my_include_dir/absl/algorithm/container.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_algorithm_container",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_algorithm_container_hdrs"],
+ export_generated_headers: ["absl_algorithm_container_hdrs"],
+
+ whole_static_libs: [
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_algorithm",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_algorithm_container_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_algorithm_container_hdrs"],
+ export_generated_headers: ["absl_algorithm_container_hdrs"],
+
+ whole_static_libs: [
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_algorithm_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_usage_internal_hdrs",
+ srcs: [
+ "absl/flags/internal/usage.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/usage.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_usage_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/flags/internal/usage.cc",
+ ],
+ generated_headers: ["absl_flags_usage_internal_hdrs"],
+ export_generated_headers: ["absl_flags_usage_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_config",
+ "absl_flags_flag",
+ "absl_flags_flag_internal",
+ "absl_flags_path_util",
+ "absl_flags_private_handle_accessor",
+ "absl_flags_program_name",
+ "absl_flags_reflection",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_config",
+ "absl_flags_flag",
+ "absl_flags_flag_internal",
+ "absl_flags_path_util",
+ "absl_flags_private_handle_accessor",
+ "absl_flags_program_name",
+ "absl_flags_reflection",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_usage_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/flags/internal/usage.cc",
+ ],
+ generated_headers: ["absl_flags_usage_internal_hdrs"],
+ export_generated_headers: ["absl_flags_usage_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_path_util_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_flags_program_name_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_path_util_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_flags_program_name_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_reflection_hdrs",
+ srcs: [
+ "absl/flags/internal/registry.h",
+ "absl/flags/reflection.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/registry.h",
+ "my_include_dir/absl/flags/reflection.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_reflection",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/reflection.cc",
+ ],
+ generated_headers: ["absl_flags_reflection_hdrs"],
+ export_generated_headers: ["absl_flags_reflection_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_private_handle_accessor",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_fast_type_id",
+ "absl_base_no_destructor",
+ "absl_container_flat_hash_map",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_private_handle_accessor",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_fast_type_id",
+ "absl_base_no_destructor",
+ "absl_container_flat_hash_map",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_reflection_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/reflection.cc",
+ ],
+ generated_headers: ["absl_flags_reflection_hdrs"],
+ export_generated_headers: ["absl_flags_reflection_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_base_no_destructor_notls",
+ "absl_container_flat_hash_map_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_private_handle_accessor_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_base_no_destructor_notls",
+ "absl_container_flat_hash_map_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_flat_hash_map_hdrs",
+ srcs: [
+ "absl/container/flat_hash_map.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/flat_hash_map.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_flat_hash_map",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_flat_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_flat_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_raw_hash_map",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_raw_hash_map",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_flat_hash_map_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_flat_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_flat_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_raw_hash_map_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_raw_hash_map_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_raw_hash_map_hdrs",
+ srcs: [
+ "absl/container/internal/raw_hash_map.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/raw_hash_map.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_map",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_raw_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_policy_traits",
+ "absl_container_container_memory",
+ "absl_container_raw_hash_set",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_throw_delegate",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_policy_traits",
+ "absl_container_container_memory",
+ "absl_container_raw_hash_set",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_throw_delegate",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_map_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_raw_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_policy_traits_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_policy_traits_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_raw_hash_set_hdrs",
+ srcs: [
+ "absl/container/internal/raw_hash_set.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/raw_hash_set.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_set",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/container/internal/raw_hash_set.cc",
+ ],
+ generated_headers: ["absl_container_raw_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common",
+ "absl_container_common_policy_traits",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_hash_function_defaults",
+ "absl_container_hash_policy_traits",
+ "absl_container_hashtable_control_bytes",
+ "absl_container_hashtable_debug_hooks",
+ "absl_container_hashtablez_sampler",
+ "absl_container_raw_hash_set_resize_impl",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_endian",
+ "absl_base_iterator_traits_internal",
+ "absl_base_prefetch",
+ "absl_base_raw_logging_internal",
+ "absl_functional_function_ref",
+ "absl_hash",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common",
+ "absl_container_common_policy_traits",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_hash_function_defaults",
+ "absl_container_hash_policy_traits",
+ "absl_container_hashtable_control_bytes",
+ "absl_container_hashtable_debug_hooks",
+ "absl_container_hashtablez_sampler",
+ "absl_container_raw_hash_set_resize_impl",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_endian",
+ "absl_base_iterator_traits_internal",
+ "absl_base_prefetch",
+ "absl_base_raw_logging_internal",
+ "absl_functional_function_ref",
+ "absl_hash",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_numeric_bits",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_set_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/container/internal/raw_hash_set.cc",
+ ],
+ generated_headers: ["absl_container_raw_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_notls",
+ "absl_container_common_policy_traits_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_hash_function_defaults_notls",
+ "absl_container_hash_policy_traits_notls",
+ "absl_container_hashtable_control_bytes_notls",
+ "absl_container_hashtable_debug_hooks_notls",
+ "absl_container_hashtablez_sampler_notls",
+ "absl_container_raw_hash_set_resize_impl_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_endian_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_prefetch_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_functional_function_ref_notls",
+ "absl_hash_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_notls",
+ "absl_container_common_policy_traits_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_hash_function_defaults_notls",
+ "absl_container_hash_policy_traits_notls",
+ "absl_container_hashtable_control_bytes_notls",
+ "absl_container_hashtable_debug_hooks_notls",
+ "absl_container_hashtablez_sampler_notls",
+ "absl_container_raw_hash_set_resize_impl_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_endian_notls",
+ "absl_base_iterator_traits_internal_notls",
+ "absl_base_prefetch_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_functional_function_ref_notls",
+ "absl_hash_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_numeric_bits_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_raw_hash_set_resize_impl_hdrs",
+ srcs: [
+ "absl/container/internal/raw_hash_set_resize_impl.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/raw_hash_set_resize_impl.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_set_resize_impl",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_raw_hash_set_resize_impl_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_set_resize_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_raw_hash_set_resize_impl_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_raw_hash_set_resize_impl_hdrs"],
+ export_generated_headers: ["absl_container_raw_hash_set_resize_impl_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hashtablez_sampler_hdrs",
+ srcs: [
+ "absl/container/internal/hashtablez_sampler.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/hashtablez_sampler.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hashtablez_sampler",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/container/internal/hashtablez_sampler.cc",
+ "absl/container/internal/hashtablez_sampler_force_weak_definition.cc",
+ ],
+ generated_headers: ["absl_container_hashtablez_sampler_hdrs"],
+ export_generated_headers: ["absl_container_hashtablez_sampler_hdrs"],
+
+ whole_static_libs: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_debugging_stacktrace",
+ "absl_memory",
+ "absl_profiling_exponential_biased",
+ "absl_profiling_sample_recorder",
+ "absl_synchronization",
+ "absl_time",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_base_raw_logging_internal",
+ "absl_debugging_stacktrace",
+ "absl_memory",
+ "absl_profiling_exponential_biased",
+ "absl_profiling_sample_recorder",
+ "absl_synchronization",
+ "absl_time",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hashtablez_sampler_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/container/internal/hashtablez_sampler.cc",
+ "absl/container/internal/hashtablez_sampler_force_weak_definition.cc",
+ ],
+ generated_headers: ["absl_container_hashtablez_sampler_hdrs"],
+ export_generated_headers: ["absl_container_hashtablez_sampler_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_memory_notls",
+ "absl_profiling_exponential_biased_notls",
+ "absl_profiling_sample_recorder_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_memory_notls",
+ "absl_profiling_exponential_biased_notls",
+ "absl_profiling_sample_recorder_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_profiling_sample_recorder_hdrs",
+ srcs: [
+ "absl/profiling/internal/sample_recorder.h",
+ ],
+ out: [
+ "my_include_dir/absl/profiling/internal/sample_recorder.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_profiling_sample_recorder",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_profiling_sample_recorder_hdrs"],
+ export_generated_headers: ["absl_profiling_sample_recorder_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_synchronization",
+ "absl_time",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_synchronization",
+ "absl_time",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_profiling_sample_recorder_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_profiling_sample_recorder_hdrs"],
+ export_generated_headers: ["absl_profiling_sample_recorder_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_synchronization_notls",
+ "absl_time_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hashtable_debug_hooks_hdrs",
+ srcs: [
+ "absl/container/internal/hashtable_debug_hooks.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/hashtable_debug_hooks.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hashtable_debug_hooks",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hashtable_debug_hooks_hdrs"],
+ export_generated_headers: ["absl_container_hashtable_debug_hooks_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hashtable_debug_hooks_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hashtable_debug_hooks_hdrs"],
+ export_generated_headers: ["absl_container_hashtable_debug_hooks_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hashtable_control_bytes_hdrs",
+ srcs: [
+ "absl/container/internal/hashtable_control_bytes.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/hashtable_control_bytes.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hashtable_control_bytes",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hashtable_control_bytes_hdrs"],
+ export_generated_headers: ["absl_container_hashtable_control_bytes_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_numeric_bits",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_endian",
+ "absl_numeric_bits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hashtable_control_bytes_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hashtable_control_bytes_hdrs"],
+ export_generated_headers: ["absl_container_hashtable_control_bytes_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_numeric_bits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_endian_notls",
+ "absl_numeric_bits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hash_policy_traits_hdrs",
+ srcs: [
+ "absl/container/internal/hash_policy_traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/hash_policy_traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hash_policy_traits",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_policy_traits_hdrs"],
+ export_generated_headers: ["absl_container_hash_policy_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_policy_traits",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_policy_traits",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hash_policy_traits_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_policy_traits_hdrs"],
+ export_generated_headers: ["absl_container_hash_policy_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_policy_traits_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_policy_traits_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_common_policy_traits_hdrs",
+ srcs: [
+ "absl/container/internal/common_policy_traits.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/common_policy_traits.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_common_policy_traits",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_common_policy_traits_hdrs"],
+ export_generated_headers: ["absl_container_common_policy_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_common_policy_traits_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_common_policy_traits_hdrs"],
+ export_generated_headers: ["absl_container_common_policy_traits_hdrs"],
+
+ whole_static_libs: [
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hash_function_defaults_hdrs",
+ srcs: [
+ "absl/container/internal/hash_function_defaults.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/hash_function_defaults.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hash_function_defaults",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_function_defaults_hdrs"],
+ export_generated_headers: ["absl_container_hash_function_defaults_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common",
+ "absl_base_config",
+ "absl_hash",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_cord",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common",
+ "absl_base_config",
+ "absl_hash",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_cord",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hash_function_defaults_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_function_defaults_hdrs"],
+ export_generated_headers: ["absl_container_hash_function_defaults_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_notls",
+ "absl_base_config_notls",
+ "absl_hash_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_notls",
+ "absl_base_config_notls",
+ "absl_hash_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_common_hdrs",
+ srcs: [
+ "absl/container/internal/common.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/common.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_common",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_common_hdrs"],
+ export_generated_headers: ["absl_container_common_hdrs"],
+
+ whole_static_libs: [
+ "absl_meta_type_traits",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_meta_type_traits",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_common_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_common_hdrs"],
+ export_generated_headers: ["absl_container_common_hdrs"],
+
+ whole_static_libs: [
+ "absl_meta_type_traits_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_meta_type_traits_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_hash_container_defaults_hdrs",
+ srcs: [
+ "absl/container/hash_container_defaults.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/hash_container_defaults.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_hash_container_defaults",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_container_defaults_hdrs"],
+ export_generated_headers: ["absl_container_hash_container_defaults_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_hash_function_defaults",
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_container_hash_function_defaults",
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_hash_container_defaults_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_hash_container_defaults_hdrs"],
+ export_generated_headers: ["absl_container_hash_container_defaults_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_hash_function_defaults_notls",
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_hash_function_defaults_notls",
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_private_handle_accessor_hdrs",
+ srcs: [
+ "absl/flags/internal/private_handle_accessor.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/private_handle_accessor.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_private_handle_accessor",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/flags/internal/private_handle_accessor.cc",
+ ],
+ generated_headers: ["absl_flags_private_handle_accessor_hdrs"],
+ export_generated_headers: ["absl_flags_private_handle_accessor_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_base_config",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_base_config",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_private_handle_accessor_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/flags/internal/private_handle_accessor.cc",
+ ],
+ generated_headers: ["absl_flags_private_handle_accessor_hdrs"],
+ export_generated_headers: ["absl_flags_private_handle_accessor_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_commandlineflag_internal_hdrs",
+ srcs: [
+ "absl/flags/internal/commandlineflag.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/commandlineflag.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_commandlineflag_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/flags/internal/commandlineflag.cc",
+ ],
+ generated_headers: ["absl_flags_commandlineflag_internal_hdrs"],
+ export_generated_headers: ["absl_flags_commandlineflag_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_commandlineflag_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/flags/internal/commandlineflag.cc",
+ ],
+ generated_headers: ["absl_flags_commandlineflag_internal_hdrs"],
+ export_generated_headers: ["absl_flags_commandlineflag_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_commandlineflag_hdrs",
+ srcs: [
+ "absl/flags/commandlineflag.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/commandlineflag.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_commandlineflag",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/commandlineflag.cc",
+ ],
+ generated_headers: ["absl_flags_commandlineflag_hdrs"],
+ export_generated_headers: ["absl_flags_commandlineflag_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_internal",
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ "absl_strings",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_internal",
+ "absl_base_config",
+ "absl_base_fast_type_id",
+ "absl_strings",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_commandlineflag_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/commandlineflag.cc",
+ ],
+ generated_headers: ["absl_flags_commandlineflag_hdrs"],
+ export_generated_headers: ["absl_flags_commandlineflag_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_strings_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_config_hdrs",
+ srcs: [
+ "absl/flags/config.h",
+ "absl/flags/usage_config.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/config.h",
+ "my_include_dir/absl/flags/usage_config.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_config",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/usage_config.cc",
+ ],
+ generated_headers: ["absl_flags_config_hdrs"],
+ export_generated_headers: ["absl_flags_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_path_util",
+ "absl_flags_program_name",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_path_util",
+ "absl_flags_program_name",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_config_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/usage_config.cc",
+ ],
+ generated_headers: ["absl_flags_config_hdrs"],
+ export_generated_headers: ["absl_flags_config_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_path_util_notls",
+ "absl_flags_program_name_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_path_util_notls",
+ "absl_flags_program_name_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_program_name_hdrs",
+ srcs: [
+ "absl/flags/internal/program_name.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/program_name.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_program_name",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/flags/internal/program_name.cc",
+ ],
+ generated_headers: ["absl_flags_program_name_hdrs"],
+ export_generated_headers: ["absl_flags_program_name_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_path_util",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_path_util",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_no_destructor",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_program_name_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/flags/internal/program_name.cc",
+ ],
+ generated_headers: ["absl_flags_program_name_hdrs"],
+ export_generated_headers: ["absl_flags_program_name_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_path_util_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_path_util_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_no_destructor_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_path_util_hdrs",
+ srcs: [
+ "absl/flags/internal/path_util.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/path_util.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_path_util",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_flags_path_util_hdrs"],
+ export_generated_headers: ["absl_flags_path_util_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_path_util_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+
+ ],
+ generated_headers: ["absl_flags_path_util_hdrs"],
+ export_generated_headers: ["absl_flags_path_util_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_flag_internal_hdrs",
+ srcs: [
+ "absl/flags/internal/flag.h",
+ "absl/flags/internal/sequence_lock.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/internal/flag.h",
+ "my_include_dir/absl/flags/internal/sequence_lock.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_flag_internal",
+ defaults: ["absl_defaults"],
+
+ srcs: [
+ "absl/flags/internal/flag.cc",
+ ],
+ generated_headers: ["absl_flags_flag_internal_hdrs"],
+ export_generated_headers: ["absl_flags_flag_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_marshalling",
+ "absl_flags_reflection",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_fast_type_id",
+ "absl_base_no_destructor",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_commandlineflag_internal",
+ "absl_flags_config",
+ "absl_flags_marshalling",
+ "absl_flags_reflection",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_dynamic_annotations",
+ "absl_base_fast_type_id",
+ "absl_base_no_destructor",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_synchronization",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_flag_internal_notls",
+ defaults: ["absl_notls_defaults"],
+
+ srcs: [
+ "absl/flags/internal/flag.cc",
+ ],
+ generated_headers: ["absl_flags_flag_internal_hdrs"],
+ export_generated_headers: ["absl_flags_flag_internal_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_marshalling_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_base_no_destructor_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_commandlineflag_internal_notls",
+ "absl_flags_config_notls",
+ "absl_flags_marshalling_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_dynamic_annotations_notls",
+ "absl_base_fast_type_id_notls",
+ "absl_base_no_destructor_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ "absl_utility_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_marshalling_hdrs",
+ srcs: [
+ "absl/flags/marshalling.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/marshalling.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_marshalling",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/marshalling.cc",
+ ],
+ generated_headers: ["absl_flags_marshalling_hdrs"],
+ export_generated_headers: ["absl_flags_marshalling_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_strings_str_format",
+ "absl_types_optional",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_log_severity",
+ "absl_numeric_int128",
+ "absl_strings",
+ "absl_strings_str_format",
+ "absl_types_optional",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_marshalling_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/marshalling.cc",
+ ],
+ generated_headers: ["absl_flags_marshalling_hdrs"],
+ export_generated_headers: ["absl_flags_marshalling_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_optional_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_log_severity_notls",
+ "absl_numeric_int128_notls",
+ "absl_strings_notls",
+ "absl_strings_str_format_notls",
+ "absl_types_optional_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_flag_hdrs",
+ srcs: [
+ "absl/flags/declare.h",
+ "absl/flags/flag.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/declare.h",
+ "my_include_dir/absl/flags/flag.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_flag",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_flags_flag_hdrs"],
+ export_generated_headers: ["absl_flags_flag_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag",
+ "absl_flags_config",
+ "absl_flags_flag_internal",
+ "absl_flags_reflection",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_strings",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag",
+ "absl_flags_config",
+ "absl_flags_flag_internal",
+ "absl_flags_reflection",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_nullability",
+ "absl_strings",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_flag_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_flags_flag_hdrs"],
+ export_generated_headers: ["absl_flags_flag_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_strings_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_commandlineflag_notls",
+ "absl_flags_config_notls",
+ "absl_flags_flag_internal_notls",
+ "absl_flags_reflection_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_nullability_notls",
+ "absl_strings_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_flags_usage_hdrs",
+ srcs: [
+ "absl/flags/usage.h",
+ ],
+ out: [
+ "my_include_dir/absl/flags/usage.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_flags_usage",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/flags/usage.cc",
+ ],
+ generated_headers: ["absl_flags_usage_hdrs"],
+ export_generated_headers: ["absl_flags_usage_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_usage_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_usage_internal",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_strings",
+ "absl_synchronization",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_flags_usage_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/flags/usage.cc",
+ ],
+ generated_headers: ["absl_flags_usage_hdrs"],
+ export_generated_headers: ["absl_flags_usage_hdrs"],
+
+ whole_static_libs: [
+ "absl_flags_usage_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_flags_usage_internal_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_strings_notls",
+ "absl_synchronization_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_debugging_failure_signal_handler_hdrs",
+ srcs: [
+ "absl/debugging/failure_signal_handler.h",
+ ],
+ out: [
+ "my_include_dir/absl/debugging/failure_signal_handler.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_debugging_failure_signal_handler",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+ "absl/debugging/failure_signal_handler.cc",
+ ],
+ generated_headers: ["absl_debugging_failure_signal_handler_hdrs"],
+ export_generated_headers: ["absl_debugging_failure_signal_handler_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_examine_stack",
+ "absl_debugging_stacktrace",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_examine_stack",
+ "absl_debugging_stacktrace",
+ "absl_base",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_debugging_failure_signal_handler_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+ "absl/debugging/failure_signal_handler.cc",
+ ],
+ generated_headers: ["absl_debugging_failure_signal_handler_hdrs"],
+ export_generated_headers: ["absl_debugging_failure_signal_handler_hdrs"],
+
+ whole_static_libs: [
+ "absl_debugging_examine_stack_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_debugging_examine_stack_notls",
+ "absl_debugging_stacktrace_notls",
+ "absl_base_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_node_hash_set_hdrs",
+ srcs: [
+ "absl/container/node_hash_set.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/node_hash_set.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_node_hash_set",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_node_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_node_slot_policy",
+ "absl_container_raw_hash_set",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_node_slot_policy",
+ "absl_container_raw_hash_set",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_node_hash_set_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_node_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_node_slot_policy_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_node_slot_policy_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_node_slot_policy_hdrs",
+ srcs: [
+ "absl/container/internal/node_slot_policy.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/node_slot_policy.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_node_slot_policy",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_slot_policy_hdrs"],
+ export_generated_headers: ["absl_container_node_slot_policy_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_node_slot_policy_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_slot_policy_hdrs"],
+ export_generated_headers: ["absl_container_node_slot_policy_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_node_hash_map_hdrs",
+ srcs: [
+ "absl/container/node_hash_map.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/node_hash_map.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_node_hash_map",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_node_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_node_slot_policy",
+ "absl_container_raw_hash_map",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_node_slot_policy",
+ "absl_container_raw_hash_map",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_node_hash_map_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_node_hash_map_hdrs"],
+ export_generated_headers: ["absl_container_node_hash_map_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_node_slot_policy_notls",
+ "absl_container_raw_hash_map_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_node_slot_policy_notls",
+ "absl_container_raw_hash_map_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_flat_hash_set_hdrs",
+ srcs: [
+ "absl/container/flat_hash_set.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/flat_hash_set.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_flat_hash_set",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_flat_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_flat_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_raw_hash_set",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory",
+ "absl_container_hash_container_defaults",
+ "absl_container_raw_hash_set",
+ "absl_algorithm_container",
+ "absl_base_core_headers",
+ "absl_memory",
+ "absl_meta_type_traits",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_flat_hash_set_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_flat_hash_set_hdrs"],
+ export_generated_headers: ["absl_container_flat_hash_set_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_container_memory_notls",
+ "absl_container_hash_container_defaults_notls",
+ "absl_container_raw_hash_set_notls",
+ "absl_algorithm_container_notls",
+ "absl_base_core_headers_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_btree_hdrs",
+ srcs: [
+ "absl/container/btree_map.h",
+ "absl/container/btree_set.h",
+ "absl/container/internal/btree.h",
+ "absl/container/internal/btree_container.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/btree_map.h",
+ "my_include_dir/absl/container/btree_set.h",
+ "my_include_dir/absl/container/internal/btree.h",
+ "my_include_dir/absl/container/internal/btree_container.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_btree",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_btree_hdrs"],
+ export_generated_headers: ["absl_container_btree_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common",
+ "absl_container_common_policy_traits",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_layout",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_cord",
+ "absl_types_compare",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common",
+ "absl_container_common_policy_traits",
+ "absl_container_compressed_tuple",
+ "absl_container_container_memory",
+ "absl_container_layout",
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_base_raw_logging_internal",
+ "absl_base_throw_delegate",
+ "absl_hash_weakly_mixed_integer",
+ "absl_memory",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_strings_cord",
+ "absl_types_compare",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_btree_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_btree_hdrs"],
+ export_generated_headers: ["absl_container_btree_hdrs"],
+
+ whole_static_libs: [
+ "absl_container_common_notls",
+ "absl_container_common_policy_traits_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_layout_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ "absl_types_compare_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_container_common_notls",
+ "absl_container_common_policy_traits_notls",
+ "absl_container_compressed_tuple_notls",
+ "absl_container_container_memory_notls",
+ "absl_container_layout_notls",
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_base_raw_logging_internal_notls",
+ "absl_base_throw_delegate_notls",
+ "absl_hash_weakly_mixed_integer_notls",
+ "absl_memory_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_strings_cord_notls",
+ "absl_types_compare_notls",
+ ],
+
+}
+
+genrule {
+ name: "absl_container_layout_hdrs",
+ srcs: [
+ "absl/container/internal/layout.h",
+ ],
+ out: [
+ "my_include_dir/absl/container/internal/layout.h",
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp",
+}
+
+cc_library_static {
+ name: "absl_container_layout",
+ defaults: ["absl_defaults"],
+ visibility: ["//visibility:public"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_layout_hdrs"],
+ export_generated_headers: ["absl_container_layout_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_debugging_demangle_internal",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_types_span",
+ "absl_utility",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config",
+ "absl_base_core_headers",
+ "absl_debugging_demangle_internal",
+ "absl_meta_type_traits",
+ "absl_strings",
+ "absl_types_span",
+ "absl_utility",
+ ],
+
+}
+
+cc_library_static {
+ name: "absl_container_layout_notls",
+ defaults: ["absl_notls_defaults"],
+ visibility: ["//external/protobuf"],
+ srcs: [
+
+ ],
+ generated_headers: ["absl_container_layout_hdrs"],
+ export_generated_headers: ["absl_container_layout_hdrs"],
+
+ whole_static_libs: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_debugging_demangle_internal_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ "absl_utility_notls",
+ ],
+ export_static_lib_headers: [
+ "absl_base_config_notls",
+ "absl_base_core_headers_notls",
+ "absl_debugging_demangle_internal_notls",
+ "absl_meta_type_traits_notls",
+ "absl_strings_notls",
+ "absl_types_span_notls",
+ "absl_utility_notls",
+ ],
+
+}
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 32cc28f..f01021b 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -10,6 +10,7 @@
"base/config.h"
"base/const_init.h"
"base/dynamic_annotations.h"
+ "base/fast_type_id.h"
"base/internal/atomic_hook.h"
"base/internal/cycleclock.cc"
"base/internal/cycleclock.h"
@@ -18,15 +19,13 @@
"base/internal/dynamic_annotations.h"
"base/internal/endian.h"
"base/internal/errno_saver.h"
- "base/internal/fast_type_id.h"
"base/internal/hide_ptr.h"
"base/internal/identity.h"
- "base/internal/invoke.h"
- "base/internal/inline_variable.h"
+ "base/internal/iterator_traits.h"
"base/internal/low_level_alloc.cc"
"base/internal/low_level_alloc.h"
"base/internal/low_level_scheduling.h"
- "base/internal/nullability_impl.h"
+ "base/internal/nullability_deprecated.h"
"base/internal/per_thread_tls.h"
"base/internal/poison.cc"
"base/internal/poison.h"
@@ -49,6 +48,8 @@
"base/internal/thread_identity.h"
"base/internal/throw_delegate.cc"
"base/internal/throw_delegate.h"
+ "base/internal/tracing.cc"
+ "base/internal/tracing.h"
"base/internal/tsan_mutex_interface.h"
"base/internal/unaligned_access.h"
"base/internal/unscaledcycleclock.cc"
@@ -81,6 +82,7 @@
"container/internal/container_memory.h"
"container/internal/hash_function_defaults.h"
"container/internal/hash_policy_traits.h"
+ "container/internal/hashtable_control_bytes.h"
"container/internal/hashtable_debug.h"
"container/internal/hashtable_debug_hooks.h"
"container/internal/hashtablez_sampler.cc"
@@ -92,6 +94,7 @@
"container/internal/raw_hash_map.h"
"container/internal/raw_hash_set.cc"
"container/internal/raw_hash_set.h"
+ "container/internal/raw_hash_set_resize_impl.h"
"container/internal/tracked.h"
"container/node_hash_map.h"
"container/node_hash_set.h"
@@ -124,6 +127,7 @@
"debugging/symbolize.h"
"debugging/internal/address_is_readable.cc"
"debugging/internal/address_is_readable.h"
+ "debugging/internal/addresses.h"
"debugging/internal/bounded_utf8_length_sequence.h"
"debugging/internal/decode_rust_punycode.cc"
"debugging/internal/decode_rust_punycode.h"
@@ -158,6 +162,7 @@
"hash/internal/spy_hash_state.h"
"hash/internal/low_level_hash.h"
"hash/internal/low_level_hash.cc"
+ "hash/internal/weakly_mixed_integer.h"
"log/absl_check.h"
"log/absl_log.h"
"log/absl_vlog_is_on.h"
@@ -191,13 +196,14 @@
"log/internal/proto.cc"
"log/internal/strip.h"
"log/internal/structured.h"
+ "log/internal/structured_proto.cc"
+ "log/internal/structured_proto.h"
"log/internal/vlog_config.cc"
"log/internal/vlog_config.h"
"log/internal/voidify.h"
"log/initialize.cc"
"log/initialize.h"
"log/log.h"
- "log/log_entry.cc"
"log/log_entry.h"
"log/log_sink.cc"
"log/log_sink.h"
@@ -234,8 +240,8 @@
"random/internal/nonsecure_base.h"
"random/internal/pcg_engine.h"
"random/internal/platform.h"
- "random/internal/pool_urbg.cc"
- "random/internal/pool_urbg.h"
+ "random/internal/entropy_pool.cc"
+ "random/internal/entropy_pool.h"
"random/internal/randen.cc"
"random/internal/randen.h"
"random/internal/randen_detect.cc"
@@ -282,7 +288,6 @@
"strings/cord.h"
"strings/cord_analysis.cc"
"strings/cord_analysis.h"
- "strings/cord_buffer.cc"
"strings/cord_buffer.h"
"strings/escaping.cc"
"strings/escaping.h"
@@ -428,20 +433,11 @@
"time/internal/cctz/src/tzfile.h"
"time/internal/cctz/src/zone_info_source.cc"
"types/any.h"
- "types/bad_any_cast.cc"
- "types/bad_any_cast.h"
- "types/bad_optional_access.cc"
- "types/bad_optional_access.h"
- "types/bad_variant_access.cc"
- "types/bad_variant_access.h"
"types/compare.h"
- "types/internal/variant.h"
"types/optional.h"
- "types/internal/optional.h"
"types/span.h"
"types/internal/span.h"
"types/variant.h"
- "utility/internal/if_constexpr.h"
"utility/utility.h"
"debugging/leak_check.cc"
)
@@ -492,10 +488,6 @@
"any"
"any_invocable"
"atomic_hook"
- "bad_any_cast"
- "bad_any_cast_impl"
- "bad_optional_access"
- "bad_variant_access"
"base"
"base_internal"
"bind_front"
@@ -727,10 +719,8 @@
if(ABSL_INTERNAL_AT_LEAST_CXX20)
set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_20)
-elseif(ABSL_INTERNAL_AT_LEAST_CXX17)
- set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_17)
else()
- set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_14)
+ set(ABSL_INTERNAL_CXX_STD_FEATURE cxx_std_17)
endif()
function(absl_internal_dll_contains)
@@ -834,6 +824,7 @@
PRIVATE
${_dll_libs}
${ABSL_DEFAULT_LINKOPTS}
+ $<$<BOOL:${ANDROID}>:-llog>
)
set_target_properties(${_dll} PROPERTIES
LINKER_LANGUAGE "CXX"
@@ -894,7 +885,7 @@
)
if(ABSL_PROPAGATE_CXX_STD)
- # Abseil libraries require C++14 as the current minimum standard. When
+ # Abseil libraries require C++17 as the current minimum standard. When
# compiled with a higher minimum (either because it is the compiler's
# default or explicitly requested), then Abseil requires that standard.
target_compile_features(${_dll} PUBLIC ${ABSL_INTERNAL_CXX_STD_FEATURE})
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake
index b177e59..624a3c7 100644
--- a/CMake/AbseilHelpers.cmake
+++ b/CMake/AbseilHelpers.cmake
@@ -186,16 +186,16 @@
endif()
endif()
endforeach()
- set(skip_next_cflag OFF)
foreach(cflag ${ABSL_CC_LIB_COPTS})
- if(skip_next_cflag)
- set(skip_next_cflag OFF)
- elseif(${cflag} MATCHES "^-Xarch_")
+ # Strip out the CMake-specific `SHELL:` prefix, which is used to construct
+ # a group of space-separated options.
+ # https://cmake.org/cmake/help/v3.30/command/target_compile_options.html#option-de-duplication
+ string(REGEX REPLACE "^SHELL:" "" cflag "${cflag}")
+ if(${cflag} MATCHES "^-Xarch_")
# An -Xarch_ flag implies that its successor only applies to the
- # specified platform. Filter both of them out before the successor
- # reaches the "^-m" filter.
- set(skip_next_cflag ON)
- elseif(${cflag} MATCHES "^(-Wno|/wd)")
+ # specified platform. Such option groups are each specified in a single
+ # `SHELL:`-prefixed string in the COPTS list, which we simply ignore.
+ elseif(${cflag} MATCHES "^(-Wno-|/wd)")
# These flags are needed to suppress warnings that might fire in our headers.
set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
@@ -301,7 +301,7 @@
endif()
if(ABSL_PROPAGATE_CXX_STD)
- # Abseil libraries require C++14 as the current minimum standard. When
+ # Abseil libraries require C++17 as the current minimum standard. When
# compiled with a higher standard (either because it is the compiler's
# default or explicitly requested), then Abseil requires that standard.
target_compile_features(${_NAME} PUBLIC ${ABSL_INTERNAL_CXX_STD_FEATURE})
@@ -338,7 +338,7 @@
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
if(ABSL_PROPAGATE_CXX_STD)
- # Abseil libraries require C++14 as the current minimum standard.
+ # Abseil libraries require C++17 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} INTERFACE ${ABSL_INTERNAL_CXX_STD_FEATURE})
@@ -450,7 +450,7 @@
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
if(ABSL_PROPAGATE_CXX_STD)
- # Abseil libraries require C++14 as the current minimum standard.
+ # Abseil libraries require C++17 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} PUBLIC ${ABSL_INTERNAL_CXX_STD_FEATURE})
diff --git a/CMake/README.md b/CMake/README.md
index 808edfe..ecaeaf0 100644
--- a/CMake/README.md
+++ b/CMake/README.md
@@ -43,8 +43,8 @@
project(my_app_project)
# Pick the C++ standard to compile with.
-# Abseil currently supports C++14, C++17, and C++20.
-set(CMAKE_CXX_STANDARD 14)
+# Abseil currently supports C++17 and C++20.
+set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(abseil-cpp)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c82b3a..8d3059d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,8 +23,8 @@
cmake_policy(SET CMP0141 NEW)
endif (POLICY CMP0141)
-project(absl LANGUAGES CXX VERSION 20240722)
-set(ABSL_SOVERSION "2407.0.0")
+project(absl LANGUAGES CXX VERSION 20250512)
+set(ABSL_SOVERSION "2505.0.0")
include(CTest)
# Output directory is correct by default for most build setups. However, when
@@ -46,11 +46,8 @@
set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
option(ABSL_PROPAGATE_CXX_STD
- "Use CMake C++ standard meta features (e.g. cxx_std_14) that propagate to targets that link to Abseil"
- OFF) # TODO: Default to ON for CMake 3.8 and greater.
-if(NOT ABSL_PROPAGATE_CXX_STD)
- message(WARNING "A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake 3.8 and up. We recommend enabling this option to ensure your project still builds correctly.")
-endif()
+ "Use CMake C++ standard meta features (e.g. cxx_std_17) that propagate to targets that link to Abseil"
+ ON)
option(ABSL_USE_SYSTEM_INCLUDES
"Silence warnings in Abseil headers by marking them as SYSTEM includes"
@@ -204,11 +201,13 @@
)
endif() # absl_VERSION
+ # Install the headers except for "options.h" which is installed separately.
install(DIRECTORY absl
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING
PATTERN "*.inc"
PATTERN "*.h"
+ PATTERN "options.h" EXCLUDE
PATTERN "copts" EXCLUDE
PATTERN "testdata" EXCLUDE
)
@@ -248,7 +247,21 @@
ABSL_INTERNAL_OPTIONS_H_PINNED
"${ABSL_INTERNAL_OPTIONS_H_CONTENTS}")
- file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/options-pinned.h" CONTENT "${ABSL_INTERNAL_OPTIONS_H_PINNED}")
+ # If the file already exists, check if it matches the new contents.
+ # This avoids writing the file if it is already up-to-date when the CMake
+ # generation is triggered and triggering unnecessary rebuilds.
+ set(ABSL_INTERNAL_OPTIONS_H_PINNED_NEEDS_UPDATE TRUE)
+ if (EXISTS "${CMAKE_BINARY_DIR}/options-pinned.h")
+ file(READ "${CMAKE_BINARY_DIR}/options-pinned.h" ABSL_INTERNAL_OPTIONS_PINNED_H_CONTENTS)
+ if ("${ABSL_INTERNAL_OPTIONS_H_PINNED}" STREQUAL "${ABSL_INTERNAL_OPTIONS_PINNED_H_CONTENTS}")
+ set(ABSL_INTERNAL_OPTIONS_H_PINNED_NEEDS_UPDATE FALSE)
+ endif()
+ endif()
+
+ # If the file needs an update, generate it.
+ if (ABSL_INTERNAL_OPTIONS_H_PINNED_NEEDS_UPDATE)
+ file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/options-pinned.h" CONTENT "${ABSL_INTERNAL_OPTIONS_H_PINNED}")
+ endif()
install(FILES "${CMAKE_BINARY_DIR}/options-pinned.h"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/absl/base
diff --git a/METADATA b/METADATA
index 4f42d94..8475b65 100644
--- a/METADATA
+++ b/METADATA
@@ -1,18 +1,20 @@
-name: "extern/abseil-cpp"
-description:
- "An open-source collection of C++ code designed to augment the C++ standard "
- "library"
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/abseil-cpp
+# For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
+name: "extern/abseil-cpp"
+description: "An open-source collection of C++ code designed to augment the C++ standard library"
third_party {
- url {
- type: HOMEPAGE
- value: "https://abseil.io"
- }
- url {
- type: GIT
- value: "https://github.com/abseil/abseil-cpp"
- }
- version: "20240722.0"
- last_upgrade_date { year: 2024 month: 11 day: 4 }
license_type: NOTICE
+ last_upgrade_date {
+ year: 2025
+ month: 7
+ day: 2
+ }
+ homepage: "https://abseil.io"
+ identifier {
+ type: "Git"
+ value: "https://github.com/abseil/abseil-cpp"
+ version: "20250512.1"
+ }
}
diff --git a/MODULE.bazel b/MODULE.bazel
index 75285b6..48a65c7 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -16,27 +16,28 @@
module(
name = "abseil-cpp",
- version = "20240722.0",
+ version = "20250512.1",
compatibility_level = 1,
)
-cc_configure = use_extension("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_configure_extension")
+cc_configure = use_extension("@rules_cc//cc:extensions.bzl",
+ "cc_configure_extension",
+ dev_dependency = True)
use_repo(cc_configure, "local_config_cc")
-# Only direct dependencies need to be listed below.
-# Please keep the versions in sync with the versions in the WORKSPACE file.
+bazel_dep(name = "rules_cc", version = "0.1.1")
+bazel_dep(name = "bazel_skylib", version = "1.7.1")
+bazel_dep(name = "platforms", version = "0.0.11")
-bazel_dep(name = "bazel_skylib",
- version = "1.5.0")
+bazel_dep(
+ name = "google_benchmark",
+ version = "1.9.2",
+ dev_dependency = True,
+)
-bazel_dep(name = "google_benchmark",
- version = "1.8.3",
- repo_name = "com_github_google_benchmark",
- dev_dependency = True)
-
-bazel_dep(name = "googletest",
- version = "1.15.2",
- repo_name = "com_google_googletest")
-
-bazel_dep(name = "platforms",
- version = "0.0.10")
+# Note: Googletest is NOT a dev_dependency. Some Abseil test utilities
+# intended to be used by Abseil users depend on GoogleTest.
+bazel_dep(
+ name = "googletest",
+ version = "1.17.0",
+)
diff --git a/README.md b/README.md
index f834fcd..c2c851e 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# Abseil - C++ Common Libraries
The repository contains the Abseil C++ library code. Abseil is an open-source
-collection of C++ code (compliant to C++14) designed to augment the C++
+collection of C++ code (compliant to C++17) designed to augment the C++
standard library.
## Table of Contents
@@ -99,8 +99,8 @@
<br /> The `memory` library contains memory management facilities that augment
C++'s `<memory>` library.
* [`meta`](absl/meta/)
- <br /> The `meta` library contains compatible versions of type checks
- available within C++14 and C++17 versions of the C++ `<type_traits>` library.
+ <br /> The `meta` library contains type checks
+ similar to those available in the C++ `<type_traits>` library.
* [`numeric`](absl/numeric/)
<br /> The `numeric` library contains 128-bit integer types as well as
implementations of C++20's bitwise math functions.
@@ -108,15 +108,14 @@
<br /> The `profiling` library contains utility code for profiling C++
entities. It is currently a private dependency of other Abseil libraries.
* [`random`](absl/random/)
- <br /> The `random` library contains functions for generating psuedorandom
+ <br /> The `random` library contains functions for generating pseudorandom
values.
* [`status`](absl/status/)
<br /> The `status` library contains abstractions for error handling,
specifically `absl::Status` and `absl::StatusOr<T>`.
* [`strings`](absl/strings/)
<br /> The `strings` library contains a variety of strings routines and
- utilities, including a C++14-compatible version of the C++17
- `std::string_view` type.
+ utilities.
* [`synchronization`](absl/synchronization/)
<br /> The `synchronization` library contains concurrency primitives (Abseil's
`absl::Mutex` class, an alternative to `std::mutex`) and a variety of
@@ -126,8 +125,7 @@
points in time, durations of time, and formatting and parsing time within
time zones.
* [`types`](absl/types/)
- <br /> The `types` library contains non-container utility types, like a
- C++14-compatible version of the C++17 `std::optional` type.
+ <br /> The `types` library contains non-container utility types.
* [`utility`](absl/utility/)
<br /> The `utility` library contains utility and helper code.
diff --git a/WORKSPACE b/WORKSPACE
deleted file mode 100644
index dee6d05..0000000
--- a/WORKSPACE
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright 2019 The Abseil Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-workspace(name = "com_google_absl")
-
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
-
-# GoogleTest/GoogleMock framework. Used by most unit-tests.
-http_archive(
- name = "com_google_googletest",
- sha256 = "7b42b4d6ed48810c5362c265a17faebe90dc2373c885e5216439d37927f02926",
- strip_prefix = "googletest-1.15.2",
- # Keep this URL in sync with the version in ci/cmake_common.sh and
- # ci/windows_msvc_cmake.bat.
- urls = ["https://github.com/google/googletest/releases/download/v1.15.2/googletest-1.15.2.tar.gz"],
-)
-
-# RE2 (the regular expression library used by GoogleTest)
-http_archive(
- name = "com_googlesource_code_re2",
- sha256 = "eb2df807c781601c14a260a507a5bb4509be1ee626024cb45acbd57cb9d4032b",
- strip_prefix = "re2-2024-07-02",
- urls = ["https://github.com/google/re2/releases/download/2024-07-02/re2-2024-07-02.tar.gz"],
- repo_mapping = {"@abseil-cpp": "@com_google_absl"},
-)
-
-# Google benchmark.
-http_archive(
- name = "com_github_google_benchmark",
- sha256 = "6bc180a57d23d4d9515519f92b0c83d61b05b5bab188961f36ac7b06b0d9e9ce",
- strip_prefix = "benchmark-1.8.3",
- urls = ["https://github.com/google/benchmark/archive/refs/tags/v1.8.3.tar.gz"],
-)
-
-# Bazel Skylib.
-http_archive(
- name = "bazel_skylib",
- sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
- urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz"],
-)
-
-# Bazel platform rules.
-http_archive(
- name = "platforms",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz",
- "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz",
- ],
- sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee",
-)
diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod
deleted file mode 100644
index 83e67ba..0000000
--- a/WORKSPACE.bzlmod
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2024 The Abseil Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# https://bazel.build/external/migration#workspace.bzlmod
-#
-# This file is intentionally empty. When bzlmod is enabled and this
-# file exists, the contents of WORKSPACE is ignored. This prevents
-# bzlmod builds from unintentionally depending on the WORKSPACE file.
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index 253c0ae..2a25ac6 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -29,14 +29,6 @@
)
config_setting(
- name = "gcc_compiler",
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "gcc",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
name = "mingw_unspecified_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "mingw",
@@ -53,91 +45,10 @@
)
config_setting(
- name = "msvc_compiler",
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "msvc-cl",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "clang-cl_compiler",
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "clang-cl",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "osx",
- constraint_values = [
- "@platforms//os:osx",
- ],
-)
-
-config_setting(
- name = "ios",
- constraint_values = [
- "@platforms//os:ios",
- ],
-)
-
-config_setting(
- name = "ppc",
- values = {
- "cpu": "ppc",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "cpu_wasm",
- values = {
- "cpu": "wasm",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "cpu_wasm32",
- values = {
- "cpu": "wasm32",
- },
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "platforms_wasm32",
- constraint_values = [
- "@platforms//cpu:wasm32",
- ],
- visibility = [":__subpackages__"],
-)
-
-config_setting(
- name = "platforms_wasm64",
- constraint_values = [
- "@platforms//cpu:wasm64",
- ],
- visibility = [":__subpackages__"],
-)
-
-selects.config_setting_group(
- name = "wasm",
- match_any = [
- ":cpu_wasm",
- ":cpu_wasm32",
- ":platforms_wasm32",
- ":platforms_wasm64",
- ],
- visibility = [":__subpackages__"],
-)
-
-config_setting(
name = "fuchsia",
- values = {
- "cpu": "fuchsia",
- },
+ constraint_values = [
+ "@platforms//os:fuchsia",
+ ],
visibility = [":__subpackages__"],
)
diff --git a/absl/abseil.podspec.gen.py b/absl/abseil.podspec.gen.py
index cbf7cb4..e1afa21 100755
--- a/absl/abseil.podspec.gen.py
+++ b/absl/abseil.podspec.gen.py
@@ -43,10 +43,11 @@
'USE_HEADERMAP' => 'NO',
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
}
- s.ios.deployment_target = '9.0'
- s.osx.deployment_target = '10.11'
- s.tvos.deployment_target = '9.0'
- s.watchos.deployment_target = '2.0'
+ s.ios.deployment_target = '12.0'
+ s.osx.deployment_target = '10.13'
+ s.tvos.deployment_target = '12.0'
+ s.watchos.deployment_target = '4.0'
+ s.visionos.deployment_target = '1.0'
s.subspec 'xcprivacy' do |ss|
ss.resource_bundles = {
ss.module_name => 'PrivacyInfo.xcprivacy',
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index f20e729..0ec8b92 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -51,8 +51,8 @@
deps = [
":algorithm",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -83,8 +83,9 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/memory",
+ "//absl/random",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt
index 252b6b2..f3dd138 100644
--- a/absl/algorithm/CMakeLists.txt
+++ b/absl/algorithm/CMakeLists.txt
@@ -68,6 +68,7 @@
absl::config
absl::core_headers
absl::memory
+ absl::random_random
absl::span
GTest::gmock_main
)
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
index 59aeed7..48f5950 100644
--- a/absl/algorithm/algorithm.h
+++ b/absl/algorithm/algorithm.h
@@ -53,8 +53,8 @@
// n = (`last` - `first`) comparisons. A linear search over short containers
// may be faster than a binary search, even when the container is sorted.
template <typename InputIterator, typename EqualityComparable>
-bool linear_search(InputIterator first, InputIterator last,
- const EqualityComparable& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool linear_search(
+ InputIterator first, InputIterator last, const EqualityComparable& value) {
return std::find(first, last, value) != last;
}
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc
index e6ee469..1c1a307 100644
--- a/absl/algorithm/algorithm_test.cc
+++ b/absl/algorithm/algorithm_test.cc
@@ -14,11 +14,9 @@
#include "absl/algorithm/algorithm.h"
-#include <algorithm>
-#include <list>
+#include <array>
#include <vector>
-#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
@@ -47,4 +45,16 @@
absl::linear_search(const_container->begin(), const_container->end(), 4));
}
+#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
+ ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
+TEST_F(LinearSearchTest, Constexpr) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::linear_search(kArray.begin(), kArray.end(), 3));
+ static_assert(!absl::linear_search(kArray.begin(), kArray.end(), 4));
+}
+
+#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
+ // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
} // namespace
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index 6bbe3b5..6f9c193 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -44,7 +44,6 @@
#include <cassert>
#include <iterator>
#include <numeric>
-#include <random>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
@@ -76,8 +75,8 @@
// An MSVC bug involving template parameter substitution requires us to use
// decltype() here instead of just std::pair.
template <typename C1, typename C2>
-using ContainerIterPairType =
- decltype(std::make_pair(ContainerIter<C1>(), ContainerIter<C2>()));
+using ContainerIterPairType = decltype(std::make_pair(
+ std::declval<ContainerIter<C1>>(), std::declval<ContainerIter<C2>>()));
template <typename C>
using ContainerDifferenceType = decltype(std::distance(
@@ -131,11 +130,14 @@
//
// Container-based version of absl::linear_search() for performing a linear
// search within a container.
+//
+// For a generalization that uses a predicate, see absl::c_any_of().
template <typename C, typename EqualityComparable>
-bool c_linear_search(const C& c, EqualityComparable&& value) {
- return linear_search(container_algorithm_internal::c_begin(c),
- container_algorithm_internal::c_end(c),
- std::forward<EqualityComparable>(value));
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_linear_search(
+ const C& c, EqualityComparable&& value) {
+ return absl::linear_search(container_algorithm_internal::c_begin(c),
+ container_algorithm_internal::c_end(c),
+ std::forward<EqualityComparable>(value));
}
//------------------------------------------------------------------------------
@@ -163,7 +165,7 @@
// Container-based version of the <algorithm> `std::all_of()` function to
// test if all elements within a container satisfy a condition.
template <typename C, typename Pred>
-bool c_all_of(const C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_all_of(const C& c, Pred&& pred) {
return std::all_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -174,7 +176,7 @@
// Container-based version of the <algorithm> `std::any_of()` function to
// test if any element in a container fulfills a condition.
template <typename C, typename Pred>
-bool c_any_of(const C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_any_of(const C& c, Pred&& pred) {
return std::any_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -185,7 +187,7 @@
// Container-based version of the <algorithm> `std::none_of()` function to
// test if no elements in a container fulfill a condition.
template <typename C, typename Pred>
-bool c_none_of(const C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_none_of(const C& c, Pred&& pred) {
return std::none_of(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -196,7 +198,8 @@
// Container-based version of the <algorithm> `std::for_each()` function to
// apply a function to a container's elements.
template <typename C, typename Function>
-decay_t<Function> c_for_each(C&& c, Function&& f) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 decay_t<Function> c_for_each(C&& c,
+ Function&& f) {
return std::for_each(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Function>(f));
@@ -207,7 +210,9 @@
// Container-based version of the <algorithm> `std::find()` function to find
// the first element containing the passed value within a container value.
template <typename C, typename T>
-container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<C>
+ c_find(C& c, T&& value) {
return std::find(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<T>(value));
@@ -218,7 +223,8 @@
// Container-based version of the <algorithm> `std::ranges::contains()` C++23
// function to search a container for a value.
template <typename Sequence, typename T>
-bool c_contains(const Sequence& sequence, T&& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains(const Sequence& sequence,
+ T&& value) {
return absl::c_find(sequence, std::forward<T>(value)) !=
container_algorithm_internal::c_end(sequence);
}
@@ -228,7 +234,9 @@
// Container-based version of the <algorithm> `std::find_if()` function to find
// the first element in a container matching the given condition.
template <typename C, typename Pred>
-container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<C>
+ c_find_if(C& c, Pred&& pred) {
return std::find_if(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -239,8 +247,9 @@
// Container-based version of the <algorithm> `std::find_if_not()` function to
// find the first element in a container not matching the given condition.
template <typename C, typename Pred>
-container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c,
- Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<C>
+ c_find_if_not(C& c, Pred&& pred) {
return std::find_if_not(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -251,8 +260,9 @@
// Container-based version of the <algorithm> `std::find_end()` function to
// find the last subsequence within a container.
template <typename Sequence1, typename Sequence2>
-container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
- Sequence1& sequence, Sequence2& subsequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence1>
+ c_find_end(Sequence1& sequence, Sequence2& subsequence) {
return std::find_end(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence),
@@ -262,8 +272,10 @@
// Overload of c_find_end() for using a predicate evaluation other than `==` as
// the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
-container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
- Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence1>
+ c_find_end(Sequence1& sequence, Sequence2& subsequence,
+ BinaryPredicate&& pred) {
return std::find_end(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence),
@@ -277,8 +289,9 @@
// find the first element within the container that is also within the options
// container.
template <typename C1, typename C2>
-container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
- C2& options) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<C1>
+ c_find_first_of(C1& container, const C2& options) {
return std::find_first_of(container_algorithm_internal::c_begin(container),
container_algorithm_internal::c_end(container),
container_algorithm_internal::c_begin(options),
@@ -288,8 +301,9 @@
// Overload of c_find_first_of() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
-container_algorithm_internal::ContainerIter<C1> c_find_first_of(
- C1& container, C2& options, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<C1>
+ c_find_first_of(C1& container, const C2& options, BinaryPredicate&& pred) {
return std::find_first_of(container_algorithm_internal::c_begin(container),
container_algorithm_internal::c_end(container),
container_algorithm_internal::c_begin(options),
@@ -302,8 +316,9 @@
// Container-based version of the <algorithm> `std::adjacent_find()` function to
// find equal adjacent elements within a container.
template <typename Sequence>
-container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
- Sequence& sequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence>
+ c_adjacent_find(Sequence& sequence) {
return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence));
}
@@ -311,8 +326,9 @@
// Overload of c_adjacent_find() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence, typename BinaryPredicate>
-container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find(
- Sequence& sequence, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence>
+ c_adjacent_find(Sequence& sequence, BinaryPredicate&& pred) {
return std::adjacent_find(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
std::forward<BinaryPredicate>(pred));
@@ -323,8 +339,9 @@
// Container-based version of the <algorithm> `std::count()` function to count
// values that match within a container.
template <typename C, typename T>
-container_algorithm_internal::ContainerDifferenceType<const C> c_count(
- const C& c, T&& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerDifferenceType<const C>
+ c_count(const C& c, T&& value) {
return std::count(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<T>(value));
@@ -335,8 +352,9 @@
// Container-based version of the <algorithm> `std::count_if()` function to
// count values matching a condition within a container.
template <typename C, typename Pred>
-container_algorithm_internal::ContainerDifferenceType<const C> c_count_if(
- const C& c, Pred&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerDifferenceType<const C>
+ c_count_if(const C& c, Pred&& pred) {
return std::count_if(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c),
std::forward<Pred>(pred));
@@ -348,8 +366,9 @@
// return the first element where two ordered containers differ. Applies `==` to
// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2>
-container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(C1& c1,
- C2& c2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIterPairType<C1, C2>
+ c_mismatch(C1& c1, C2& c2) {
return std::mismatch(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -360,8 +379,9 @@
// the function's test condition. Applies `pred`to the first N elements of `c1`
// and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2, typename BinaryPredicate>
-container_algorithm_internal::ContainerIterPairType<C1, C2> c_mismatch(
- C1& c1, C2& c2, BinaryPredicate pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIterPairType<C1, C2>
+ c_mismatch(C1& c1, C2& c2, BinaryPredicate pred) {
return std::mismatch(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -373,7 +393,7 @@
// Container-based version of the <algorithm> `std::equal()` function to
// test whether two containers are equal.
template <typename C1, typename C2>
-bool c_equal(const C1& c1, const C2& c2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_equal(const C1& c1, const C2& c2) {
return std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -383,7 +403,8 @@
// Overload of c_equal() for using a predicate evaluation other than `==` as
// the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
-bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_equal(const C1& c1, const C2& c2,
+ BinaryPredicate&& pred) {
return std::equal(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -396,7 +417,8 @@
// Container-based version of the <algorithm> `std::is_permutation()` function
// to test whether a container is a permutation of another.
template <typename C1, typename C2>
-bool c_is_permutation(const C1& c1, const C2& c2) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_permutation(const C1& c1,
+ const C2& c2) {
return std::is_permutation(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -406,7 +428,8 @@
// Overload of c_is_permutation() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
-bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_is_permutation(
+ const C1& c1, const C2& c2, BinaryPredicate&& pred) {
return std::is_permutation(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2),
@@ -419,8 +442,9 @@
// Container-based version of the <algorithm> `std::search()` function to search
// a container for a subsequence.
template <typename Sequence1, typename Sequence2>
-container_algorithm_internal::ContainerIter<Sequence1> c_search(
- Sequence1& sequence, Sequence2& subsequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence1>
+ c_search(Sequence1& sequence, Sequence2& subsequence) {
return std::search(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence),
@@ -430,8 +454,10 @@
// Overload of c_search() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
-container_algorithm_internal::ContainerIter<Sequence1> c_search(
- Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence1>
+ c_search(Sequence1& sequence, Sequence2& subsequence,
+ BinaryPredicate&& pred) {
return std::search(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(subsequence),
@@ -444,7 +470,8 @@
// Container-based version of the <algorithm> `std::ranges::contains_subrange()`
// C++23 function to search a container for a subsequence.
template <typename Sequence1, typename Sequence2>
-bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains_subrange(
+ Sequence1& sequence, Sequence2& subsequence) {
return absl::c_search(sequence, subsequence) !=
container_algorithm_internal::c_end(sequence);
}
@@ -452,8 +479,8 @@
// Overload of c_contains_subrange() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
-bool c_contains_subrange(Sequence1& sequence, Sequence2& subsequence,
- BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool c_contains_subrange(
+ Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) {
return absl::c_search(sequence, subsequence,
std::forward<BinaryPredicate>(pred)) !=
container_algorithm_internal::c_end(sequence);
@@ -464,8 +491,9 @@
// Container-based version of the <algorithm> `std::search_n()` function to
// search a container for the first sequence of N elements.
template <typename Sequence, typename Size, typename T>
-container_algorithm_internal::ContainerIter<Sequence> c_search_n(
- Sequence& sequence, Size count, T&& value) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence>
+ c_search_n(Sequence& sequence, Size count, T&& value) {
return std::search_n(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), count,
std::forward<T>(value));
@@ -475,8 +503,10 @@
// `==` as the function's test condition.
template <typename Sequence, typename Size, typename T,
typename BinaryPredicate>
-container_algorithm_internal::ContainerIter<Sequence> c_search_n(
- Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
+ container_algorithm_internal::ContainerIter<Sequence>
+ c_search_n(Sequence& sequence, Size count, T&& value,
+ BinaryPredicate&& pred) {
return std::search_n(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), count,
std::forward<T>(value),
@@ -816,25 +846,9 @@
typename UniformRandomBitGenerator>
OutputIterator c_sample(const C& c, OutputIterator result, Distance n,
UniformRandomBitGenerator&& gen) {
-#if defined(__cpp_lib_sample) && __cpp_lib_sample >= 201603L
return std::sample(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), result, n,
std::forward<UniformRandomBitGenerator>(gen));
-#else
- // Fall back to a stable selection-sampling implementation.
- auto first = container_algorithm_internal::c_begin(c);
- Distance unsampled_elements = c_distance(c);
- n = (std::min)(n, unsampled_elements);
- for (; n != 0; ++first) {
- Distance r =
- std::uniform_int_distribution<Distance>(0, --unsampled_elements)(gen);
- if (r < n) {
- *result++ = *first;
- --n;
- }
- }
- return result;
-#endif
}
//------------------------------------------------------------------------------
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 5012224..cb06335 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -16,6 +16,7 @@
#include <algorithm>
#include <array>
+#include <cstddef>
#include <functional>
#include <initializer_list>
#include <iterator>
@@ -35,6 +36,7 @@
#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
+#include "absl/random/random.h"
#include "absl/types/span.h"
namespace {
@@ -139,11 +141,13 @@
TEST_F(NonMutatingTest, FindFirstOf) {
absl::c_find_first_of(container_, sequence_);
absl::c_find_first_of(sequence_, container_);
+ absl::c_find_first_of(sequence_, std::array<int, 2>{1, 2});
}
TEST_F(NonMutatingTest, FindFirstOfWithPredicate) {
absl::c_find_first_of(container_, sequence_, BinPredicate);
absl::c_find_first_of(sequence_, container_, BinPredicate);
+ absl::c_find_first_of(sequence_, std::array<int, 2>{1, 2}, BinPredicate);
}
TEST_F(NonMutatingTest, AdjacentFind) { absl::c_adjacent_find(sequence_); }
@@ -984,25 +988,16 @@
EXPECT_THAT(actual, ElementsAre(3, 4, 1, 2, 5));
}
-template <typename T>
-T RandomlySeededPrng() {
- std::random_device rdev;
- std::seed_seq::result_type data[T::state_size];
- std::generate_n(data, T::state_size, std::ref(rdev));
- std::seed_seq prng_seed(data, data + T::state_size);
- return T(prng_seed);
-}
-
TEST(MutatingTest, Shuffle) {
std::vector<int> actual = {1, 2, 3, 4, 5};
- absl::c_shuffle(actual, RandomlySeededPrng<std::mt19937_64>());
+ absl::c_shuffle(actual, absl::InsecureBitGen());
EXPECT_THAT(actual, UnorderedElementsAre(1, 2, 3, 4, 5));
}
TEST(MutatingTest, Sample) {
std::vector<int> actual;
absl::c_sample(std::vector<int>{1, 2, 3, 4, 5}, std::back_inserter(actual), 3,
- RandomlySeededPrng<std::mt19937_64>());
+ absl::InsecureBitGen());
EXPECT_THAT(actual, IsSubsetOf({1, 2, 3, 4, 5}));
EXPECT_THAT(actual, SizeIs(3));
}
@@ -1164,6 +1159,7 @@
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
+
TEST(ConstexprTest, Distance) {
// Works at compile time with constexpr containers.
static_assert(absl::c_distance(std::array<int, 3>()) == 3);
@@ -1203,8 +1199,216 @@
static_assert(*kMinMaxPair.first == 3);
static_assert(*kMinMaxPair.second == 1);
}
-
#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
// ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
+#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
+ ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
+TEST(ConstexprTest, LinearSearch) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_linear_search(kArray, 3));
+ static_assert(!absl::c_linear_search(kArray, 4));
+}
+
+TEST(ConstexprTest, AllOf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(!absl::c_all_of(kArray, [](int x) { return x > 1; }));
+ static_assert(absl::c_all_of(kArray, [](int x) { return x > 0; }));
+}
+
+TEST(ConstexprTest, AnyOf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_any_of(kArray, [](int x) { return x > 2; }));
+ static_assert(!absl::c_any_of(kArray, [](int x) { return x > 5; }));
+}
+
+TEST(ConstexprTest, NoneOf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(!absl::c_none_of(kArray, [](int x) { return x > 2; }));
+ static_assert(absl::c_none_of(kArray, [](int x) { return x > 5; }));
+}
+
+TEST(ConstexprTest, ForEach) {
+ static constexpr std::array<int, 3> kArray = [] {
+ std::array<int, 3> array = {1, 2, 3};
+ absl::c_for_each(array, [](int& x) { x += 1; });
+ return array;
+ }();
+ static_assert(kArray == std::array{2, 3, 4});
+}
+
+TEST(ConstexprTest, Find) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_find(kArray, 1) == kArray.begin());
+ static_assert(absl::c_find(kArray, 4) == kArray.end());
+}
+
+TEST(ConstexprTest, Contains) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_contains(kArray, 1));
+ static_assert(!absl::c_contains(kArray, 4));
+}
+
+TEST(ConstexprTest, FindIf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_find_if(kArray, [](int x) { return x > 2; }) ==
+ kArray.begin() + 2);
+ static_assert(absl::c_find_if(kArray, [](int x) { return x > 5; }) ==
+ kArray.end());
+}
+
+TEST(ConstexprTest, FindIfNot) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_find_if_not(kArray, [](int x) { return x > 1; }) ==
+ kArray.begin());
+ static_assert(absl::c_find_if_not(kArray, [](int x) { return x > 0; }) ==
+ kArray.end());
+}
+
+TEST(ConstexprTest, FindEnd) {
+ static constexpr std::array<int, 5> kHaystack = {1, 2, 3, 2, 3};
+ static constexpr std::array<int, 2> kNeedle = {2, 3};
+ static_assert(absl::c_find_end(kHaystack, kNeedle) == kHaystack.begin() + 3);
+}
+
+TEST(ConstexprTest, FindFirstOf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_find_first_of(kArray, kArray) == kArray.begin());
+}
+
+TEST(ConstexprTest, AdjacentFind) {
+ static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
+ static_assert(absl::c_adjacent_find(kArray) == kArray.begin() + 1);
+}
+
+TEST(ConstexprTest, AdjacentFindWithPredicate) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_adjacent_find(kArray, std::less<int>()) ==
+ kArray.begin());
+}
+
+TEST(ConstexprTest, Count) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_count(kArray, 1) == 1);
+ static_assert(absl::c_count(kArray, 2) == 1);
+ static_assert(absl::c_count(kArray, 3) == 1);
+ static_assert(absl::c_count(kArray, 4) == 0);
+}
+
+TEST(ConstexprTest, CountIf) {
+ static constexpr std::array<int, 3> kArray = {1, 2, 3};
+ static_assert(absl::c_count_if(kArray, [](int x) { return x > 0; }) == 3);
+ static_assert(absl::c_count_if(kArray, [](int x) { return x > 1; }) == 2);
+}
+
+TEST(ConstexprTest, Mismatch) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_mismatch(kArray1, kArray2) ==
+ std::pair{kArray1.end(), kArray2.end()});
+ static_assert(absl::c_mismatch(kArray1, kArray3) ==
+ std::pair{kArray1.begin(), kArray3.begin()});
+}
+
+TEST(ConstexprTest, MismatchWithPredicate) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_mismatch(kArray1, kArray2, std::not_equal_to<int>()) ==
+ std::pair{kArray1.begin(), kArray2.begin()});
+ static_assert(absl::c_mismatch(kArray1, kArray3, std::not_equal_to<int>()) ==
+ std::pair{kArray1.end(), kArray3.end()});
+}
+
+TEST(ConstexprTest, Equal) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_equal(kArray1, kArray2));
+ static_assert(!absl::c_equal(kArray1, kArray3));
+}
+
+TEST(ConstexprTest, EqualWithPredicate) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(!absl::c_equal(kArray1, kArray2, std::not_equal_to<int>()));
+ static_assert(absl::c_equal(kArray1, kArray3, std::not_equal_to<int>()));
+}
+
+TEST(ConstexprTest, IsPermutation) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {3, 2, 1};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_is_permutation(kArray1, kArray2));
+ static_assert(!absl::c_is_permutation(kArray1, kArray3));
+}
+
+TEST(ConstexprTest, IsPermutationWithPredicate) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {3, 2, 1};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_is_permutation(kArray1, kArray2, std::equal_to<int>()));
+ static_assert(
+ !absl::c_is_permutation(kArray1, kArray3, std::equal_to<int>()));
+}
+
+TEST(ConstexprTest, Search) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_search(kArray1, kArray2) == kArray1.begin());
+ static_assert(absl::c_search(kArray1, kArray3) == kArray1.end());
+}
+
+TEST(ConstexprTest, SearchWithPredicate) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_search(kArray1, kArray2, std::not_equal_to<int>()) ==
+ kArray1.end());
+ static_assert(absl::c_search(kArray1, kArray3, std::not_equal_to<int>()) ==
+ kArray1.begin());
+}
+
+TEST(ConstexprTest, ContainsSubrange) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(absl::c_contains_subrange(kArray1, kArray2));
+ static_assert(!absl::c_contains_subrange(kArray1, kArray3));
+}
+
+TEST(ConstexprTest, ContainsSubrangeWithPredicate) {
+ static constexpr std::array<int, 3> kArray1 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray2 = {1, 2, 3};
+ static constexpr std::array<int, 3> kArray3 = {2, 3, 4};
+ static_assert(
+ !absl::c_contains_subrange(kArray1, kArray2, std::not_equal_to<>()));
+ static_assert(
+ absl::c_contains_subrange(kArray1, kArray3, std::not_equal_to<>()));
+}
+
+TEST(ConstexprTest, SearchN) {
+ static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
+ static_assert(absl::c_search_n(kArray, 1, 1) == kArray.begin());
+ static_assert(absl::c_search_n(kArray, 2, 2) == kArray.begin() + 1);
+ static_assert(absl::c_search_n(kArray, 1, 4) == kArray.end());
+}
+
+TEST(ConstexprTest, SearchNWithPredicate) {
+ static constexpr std::array<int, 4> kArray = {1, 2, 2, 3};
+ static_assert(absl::c_search_n(kArray, 1, 1, std::not_equal_to<int>()) ==
+ kArray.begin() + 1);
+ static_assert(absl::c_search_n(kArray, 2, 2, std::not_equal_to<int>()) ==
+ kArray.end());
+ static_assert(absl::c_search_n(kArray, 1, 4, std::not_equal_to<int>()) ==
+ kArray.begin());
+}
+
+#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
+ // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
} // namespace
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 96503c9..ef97b4e 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -82,14 +82,13 @@
cc_library(
name = "nullability",
- srcs = ["internal/nullability_impl.h"],
+ srcs = ["internal/nullability_deprecated.h"],
hdrs = ["nullability.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":core_headers",
- "//absl/meta:type_traits",
],
)
@@ -207,9 +206,9 @@
"//conditions:default": [],
}),
linkopts = select({
- "//absl:msvc_compiler": [],
- "//absl:clang-cl_compiler": [],
- "//absl:wasm": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
+ "@rules_cc//cc/compiler:clang-cl": [],
+ "@rules_cc//cc/compiler:emscripten": [],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
visibility = [
@@ -230,8 +229,6 @@
hdrs = [
"internal/hide_ptr.h",
"internal/identity.h",
- "internal/inline_variable.h",
- "internal/invoke.h",
"internal/scheduling_mode.h",
],
copts = ABSL_DEFAULT_COPTS,
@@ -268,17 +265,17 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = select({
- "//absl:msvc_compiler": [
+ "@rules_cc//cc/compiler:msvc-cl": [
"-DEFAULTLIB:advapi32.lib",
],
- "//absl:clang-cl_compiler": [
+ "@rules_cc//cc/compiler:clang-cl": [
"-DEFAULTLIB:advapi32.lib",
],
"//absl:mingw_compiler": [
"-DEFAULTLIB:advapi32.lib",
"-ladvapi32",
],
- "//absl:wasm": [],
+ "@rules_cc//cc/compiler:emscripten": [],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
deps = [
@@ -319,8 +316,8 @@
":atomic_hook",
":atomic_hook_test_helper",
":core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -335,8 +332,23 @@
deps = [
":base",
":core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "attributes_test",
+ srcs = [
+ "attributes_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":core_headers",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -375,8 +387,8 @@
deps = [
":config",
":throw_delegate",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -389,8 +401,8 @@
deps = [
":errno_saver",
":strerror",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -405,7 +417,7 @@
],
deps = [
":config",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -432,7 +444,7 @@
"//absl/meta:type_traits",
"//absl/strings",
"//absl/utility",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -444,41 +456,8 @@
deps = [
":exception_safety_testing",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "inline_variable_test",
- size = "small",
- srcs = [
- "inline_variable_test.cc",
- "inline_variable_test_a.cc",
- "inline_variable_test_b.cc",
- "internal/inline_variable_testing.h",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":base_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "invoke_test",
- size = "small",
- srcs = ["invoke_test.cc"],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":base_internal",
- "//absl/memory",
- "//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -496,7 +475,7 @@
":config",
":core_headers",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
alwayslink = 1,
)
@@ -516,8 +495,8 @@
":config",
":core_headers",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -536,7 +515,7 @@
":no_destructor",
":raw_logging_internal",
"//absl/synchronization",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
alwayslink = 1,
)
@@ -561,6 +540,9 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
deps = [
":base",
":config",
@@ -576,8 +558,8 @@
deps = [
":config",
":endian",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -589,8 +571,8 @@
deps = [
":config",
"//absl/synchronization:thread_pool",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -603,8 +585,8 @@
":base",
":core_headers",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -617,8 +599,8 @@
":config",
":no_destructor",
":raw_logging_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -633,7 +615,7 @@
deps = [
":no_destructor",
":raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -643,8 +625,18 @@
deps = [
":core_headers",
":nullability",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "nullability_default_nonnull_test",
+ srcs = ["nullability_default_nonnull_test.cc"],
+ deps = [
+ ":nullability",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -656,8 +648,8 @@
deps = [
":raw_logging_internal",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -670,8 +662,8 @@
deps = [
":base",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -704,13 +696,14 @@
":base",
":core_headers",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "thread_identity_benchmark",
+ testonly = True,
srcs = ["internal/thread_identity_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -719,8 +712,7 @@
deps = [
":base",
"//absl/synchronization",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -747,8 +739,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":scoped_set_env",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -763,8 +755,8 @@
"//absl/flags:flag_internal",
"//absl/flags:marshalling",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -793,8 +785,8 @@
deps = [
":strerror",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -808,18 +800,15 @@
visibility = ["//visibility:private"],
deps = [
":strerror",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
cc_library(
name = "fast_type_id",
- hdrs = ["internal/fast_type_id.h"],
+ hdrs = ["fast_type_id.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl:__subpackages__",
- ],
deps = [
":config",
],
@@ -828,13 +817,14 @@
cc_test(
name = "fast_type_id_test",
size = "small",
- srcs = ["internal/fast_type_id_test.cc"],
+ srcs = ["fast_type_id_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":core_headers",
":fast_type_id",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -861,8 +851,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":prefetch",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -896,8 +886,8 @@
deps = [
":config",
":poison",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -911,8 +901,8 @@
deps = [
":core_headers",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -925,7 +915,81 @@
deps = [
":core_headers",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "iterator_traits_internal",
+ hdrs = ["internal/iterator_traits.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "iterator_traits_test",
+ srcs = ["internal/iterator_traits_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":iterator_traits_internal",
+ ":iterator_traits_test_helper",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_library(
+ name = "tracing_internal",
+ srcs = ["internal/tracing.cc"],
+ hdrs = ["internal/tracing.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
+)
+
+cc_library(
+ name = "iterator_traits_test_helper",
+ hdrs = ["internal/iterator_traits_test_helper.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [":config"],
+)
+
+cc_test(
+ name = "tracing_internal_weak_test",
+ srcs = ["internal/tracing_weak_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":tracing_internal",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "tracing_internal_strong_test",
+ srcs = ["internal/tracing_strong_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":core_headers",
+ ":tracing_internal",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 97994fc..23942c0 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -73,11 +73,10 @@
HDRS
"nullability.h"
SRCS
- "internal/nullability_impl.h"
+ "internal/nullability_deprecated.h"
DEPS
absl::config
absl::core_headers
- absl::type_traits
COPTS
${ABSL_DEFAULT_COPTS}
)
@@ -95,6 +94,18 @@
GTest::gtest_main
)
+absl_cc_test(
+ NAME
+ nullability_default_nonnull_test
+ SRCS
+ "nullability_default_nonnull_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::nullability
+ GTest::gtest_main
+)
+
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
@@ -204,8 +215,6 @@
HDRS
"internal/hide_ptr.h"
"internal/identity.h"
- "internal/inline_variable.h"
- "internal/invoke.h"
"internal/scheduling_mode.h"
COPTS
${ABSL_DEFAULT_COPTS}
@@ -361,6 +370,19 @@
absl_cc_test(
NAME
+ attributes_test
+ SRCS
+ "attributes_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ GTest::gtest_main
+)
+
+absl_cc_test(
+ NAME
bit_cast_test
SRCS
"bit_cast_test.cc"
@@ -400,36 +422,6 @@
GTest::gtest_main
)
-absl_cc_test(
- NAME
- inline_variable_test
- SRCS
- "internal/inline_variable_testing.h"
- "inline_variable_test.cc"
- "inline_variable_test_a.cc"
- "inline_variable_test_b.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::base_internal
- GTest::gtest_main
-)
-
-absl_cc_test(
- NAME
- invoke_test
- SRCS
- "invoke_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::base_internal
- absl::memory
- absl::strings
- GTest::gmock
- GTest::gtest_main
-)
-
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
@@ -534,6 +526,7 @@
absl::no_destructor
absl::config
absl::raw_logging_internal
+ GTest::gmock
GTest::gtest_main
)
@@ -675,12 +668,11 @@
GTest::gtest_main
)
-# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
fast_type_id
HDRS
- "internal/fast_type_id.h"
+ "fast_type_id.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
@@ -693,10 +685,11 @@
NAME
fast_type_id_test
SRCS
- "internal/fast_type_id_test.cc"
+ "fast_type_id_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::core_headers
absl::fast_type_id
GTest::gtest_main
)
@@ -769,3 +762,83 @@
absl::poison
GTest::gtest_main
)
+
+absl_cc_library(
+ NAME
+ tracing_internal
+ HDRS
+ "internal/tracing.h"
+ SRCS
+ "internal/tracing.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+)
+
+absl_cc_test(
+ NAME
+ tracing_internal_weak_test
+ SRCS
+ "internal/tracing_weak_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::tracing_internal
+ GTest::gtest_main
+)
+
+absl_cc_test(
+ NAME
+ tracing_internal_strong_test
+ SRCS
+ "internal/tracing_strong_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::tracing_internal
+ GTest::gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ iterator_traits_internal
+ HDRS
+ "internal/iterator_traits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::type_traits
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ iterator_traits_test
+ SRCS
+ "internal/iterator_traits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::config
+ absl::iterator_traits_internal
+ absl::iterator_traits_test_helper_internal
+ GTest::gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ iterator_traits_test_helper_internal
+ HDRS
+ "internal/iterator_traits_test_helper.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ PUBLIC
+)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 5ea5ee3..d009f6d 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -31,6 +31,8 @@
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
// assume the attribute exists on GCC (which is verified on GCC 4.7).
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_BASE_ATTRIBUTES_H_
#define ABSL_BASE_ATTRIBUTES_H_
@@ -133,12 +135,14 @@
// Tags a function as weak for the purposes of compilation and linking.
// Weak attributes did not work properly in LLVM's Windows backend before
// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
-// for further information.
+// for further information. Weak attributes do not work across DLL boundary.
// The MinGW compiler doesn't complain about the weak attribute until the link
// step, presumably because Windows doesn't use ELF binaries.
-#if (ABSL_HAVE_ATTRIBUTE(weak) || \
- (defined(__GNUC__) && !defined(__clang__))) && \
- (!defined(_WIN32) || (defined(__clang__) && __clang_major__ >= 9)) && \
+#if (ABSL_HAVE_ATTRIBUTE(weak) || \
+ (defined(__GNUC__) && !defined(__clang__))) && \
+ (!defined(_WIN32) || \
+ (defined(__clang__) && __clang_major__ >= 9 && \
+ !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL))) && \
!defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
@@ -335,9 +339,9 @@
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
#ifdef _AIX
// __attribute__((section(#name))) on AIX is achieved by using the `.csect`
-// psudo op which includes an additional integer as part of its syntax indcating
-// alignment. If data fall under different alignments then you might get a
-// compilation error indicating a `Section type conflict`.
+// pseudo op which includes an additional integer as part of its syntax
+// indicating alignment. If data fall under different alignments then you might
+// get a compilation error indicating a `Section type conflict`.
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
#else
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
@@ -549,12 +553,11 @@
//
// Prevents the compiler from complaining about variables that appear unused.
//
-// For code or headers that are assured to only build with C++17 and up, prefer
-// just using the standard '[[maybe_unused]]' directly over this macro.
+// Deprecated: Use the standard C++17 `[[maybe_unused]` instead.
//
// Due to differences in positioning requirements between the old, compiler
-// specific __attribute__ syntax and the now standard [[maybe_unused]], this
-// macro does not attempt to take advantage of '[[maybe_unused]]'.
+// specific __attribute__ syntax and the now standard `[[maybe_unused]]`, this
+// macro does not attempt to take advantage of `[[maybe_unused]]`.
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
@@ -755,6 +758,76 @@
#define ABSL_CONST_INIT
#endif
+// ABSL_REQUIRE_EXPLICIT_INIT
+//
+// ABSL_REQUIRE_EXPLICIT_INIT is placed *after* the data members of an aggregate
+// type to indicate that the annotated member must be explicitly initialized by
+// the user whenever the aggregate is constructed. For example:
+//
+// struct Coord {
+// int x ABSL_REQUIRE_EXPLICIT_INIT;
+// int y ABSL_REQUIRE_EXPLICIT_INIT;
+// };
+// Coord coord = {1}; // warning: field 'y' is not explicitly initialized
+//
+// Note that usage on C arrays is not supported in C++.
+// Use a struct (such as std::array) to wrap the array member instead.
+//
+// Avoid applying this attribute to the members of non-aggregate types.
+// The behavior within non-aggregates is unspecified and subject to change.
+//
+// Do NOT attempt to suppress or demote the error generated by this attribute.
+// Just like with a missing function argument, it is a hard error by design.
+//
+// See the upstream documentation for more details:
+// https://clang.llvm.org/docs/AttributeReference.html#require-explicit-initialization
+#ifdef __cplusplus
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_explicit_initialization)
+// clang-format off
+#define ABSL_REQUIRE_EXPLICIT_INIT \
+ [[clang::require_explicit_initialization]] = \
+ AbslInternal_YouForgotToExplicitlyInitializeAField::v
+#else
+#define ABSL_REQUIRE_EXPLICIT_INIT \
+ = AbslInternal_YouForgotToExplicitlyInitializeAField::v
+#endif
+// clang-format on
+#else
+// clang-format off
+#if ABSL_HAVE_ATTRIBUTE(require_explicit_initialization)
+#define ABSL_REQUIRE_EXPLICIT_INIT \
+ __attribute__((require_explicit_initialization))
+#else
+#define ABSL_REQUIRE_EXPLICIT_INIT \
+ /* No portable fallback for C is available */
+#endif
+// clang-format on
+#endif
+
+#ifdef __cplusplus
+struct AbslInternal_YouForgotToExplicitlyInitializeAField {
+ // A portable version of [[clang::require_explicit_initialization]] that
+ // never builds, as a last resort for all toolchains.
+ // The error messages are poor, so we don't rely on this unless we have to.
+ template <class T>
+#if !defined(SWIG)
+ constexpr
+#endif
+ operator T() const /* NOLINT */ {
+ const void *volatile deliberately_volatile_ptr = nullptr;
+ // Infinite loop to prevent constexpr compilation
+ for (;;) {
+ // This assignment ensures the 'this' pointer is not optimized away, so
+ // that linking always fails.
+ deliberately_volatile_ptr = this; // Deliberately not constexpr
+ (void)deliberately_volatile_ptr;
+ }
+ }
+ // This is deliberately left undefined to prevent linking
+ static AbslInternal_YouForgotToExplicitlyInitializeAField v;
+};
+#endif
+
// ABSL_ATTRIBUTE_PURE_FUNCTION
//
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
@@ -827,30 +900,76 @@
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
#endif
-// ABSL_INTERNAL_ATTRIBUTE_VIEW indicates that a type acts like a view i.e. a
-// raw (non-owning) pointer. This enables diagnoses similar to those enabled by
-// ABSL_ATTRIBUTE_LIFETIME_BOUND.
+// Internal attribute; name and documentation TBD.
//
-// See the following links for details:
-// https://reviews.llvm.org/D64448
-// https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
-#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Pointer)
-#define ABSL_INTERNAL_ATTRIBUTE_VIEW [[gsl::Pointer]]
+// See the upstream documentation:
+// https://clang.llvm.org/docs/AttributeReference.html#lifetime_capture_by
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetime_capture_by)
+#define ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(Owner) \
+ [[clang::lifetime_capture_by(Owner)]]
#else
-#define ABSL_INTERNAL_ATTRIBUTE_VIEW
+#define ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(Owner)
#endif
-// ABSL_INTERNAL_ATTRIBUTE_OWNER indicates that a type acts like a smart
-// (owning) pointer. This enables diagnoses similar to those enabled by
-// ABSL_ATTRIBUTE_LIFETIME_BOUND.
+// ABSL_ATTRIBUTE_VIEW indicates that a type is solely a "view" of data that it
+// points to, similarly to a span, string_view, or other non-owning reference
+// type.
+// This enables diagnosing certain lifetime issues similar to those enabled by
+// ABSL_ATTRIBUTE_LIFETIME_BOUND, such as:
+//
+// struct ABSL_ATTRIBUTE_VIEW StringView {
+// template<class R>
+// StringView(const R&);
+// };
+//
+// StringView f(std::string s) {
+// return s; // warning: address of stack memory returned
+// }
+//
+// We disable this on Clang versions < 13 because of the following
+// false-positive:
+//
+// absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; }
//
// See the following links for details:
// https://reviews.llvm.org/D64448
// https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
-#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Owner)
-#define ABSL_INTERNAL_ATTRIBUTE_OWNER [[gsl::Owner]]
+#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Pointer) && \
+ (!defined(__clang_major__) || __clang_major__ >= 13)
+#define ABSL_ATTRIBUTE_VIEW [[gsl::Pointer]]
#else
-#define ABSL_INTERNAL_ATTRIBUTE_OWNER
+#define ABSL_ATTRIBUTE_VIEW
+#endif
+
+// ABSL_ATTRIBUTE_OWNER indicates that a type is a container, smart pointer, or
+// similar class that owns all the data that it points to.
+// This enables diagnosing certain lifetime issues similar to those enabled by
+// ABSL_ATTRIBUTE_LIFETIME_BOUND, such as:
+//
+// struct ABSL_ATTRIBUTE_VIEW StringView {
+// template<class R>
+// StringView(const R&);
+// };
+//
+// struct ABSL_ATTRIBUTE_OWNER String {};
+//
+// StringView f(String s) {
+// return s; // warning: address of stack memory returned
+// }
+//
+// We disable this on Clang versions < 13 because of the following
+// false-positive:
+//
+// absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; }
+//
+// See the following links for details:
+// https://reviews.llvm.org/D64448
+// https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
+#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Owner) && \
+ (!defined(__clang_major__) || __clang_major__ >= 13)
+#define ABSL_ATTRIBUTE_OWNER [[gsl::Owner]]
+#else
+#define ABSL_ATTRIBUTE_OWNER
#endif
// ABSL_ATTRIBUTE_TRIVIAL_ABI
diff --git a/absl/base/attributes_test.cc b/absl/base/attributes_test.cc
new file mode 100644
index 0000000..5d213a4
--- /dev/null
+++ b/absl/base/attributes_test.cc
@@ -0,0 +1,43 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/attributes.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace {
+
+TEST(Attributes, RequireExplicitInit) {
+ struct Agg {
+ int f1;
+ int f2 ABSL_REQUIRE_EXPLICIT_INIT;
+ };
+ Agg good1 ABSL_ATTRIBUTE_UNUSED = {1, 2};
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+ Agg good2 ABSL_ATTRIBUTE_UNUSED(1, 2);
+#endif
+ Agg good3 ABSL_ATTRIBUTE_UNUSED{1, 2};
+ Agg good4 ABSL_ATTRIBUTE_UNUSED = {1, 2};
+ Agg good5 ABSL_ATTRIBUTE_UNUSED = Agg{1, 2};
+ Agg good6[1] ABSL_ATTRIBUTE_UNUSED = {{1, 2}};
+ Agg good7[1] ABSL_ATTRIBUTE_UNUSED = {Agg{1, 2}};
+ union {
+ Agg agg;
+ } good8 ABSL_ATTRIBUTE_UNUSED = {{1, 2}};
+ constexpr Agg good9 ABSL_ATTRIBUTE_UNUSED = {1, 2};
+ constexpr Agg good10 ABSL_ATTRIBUTE_UNUSED{1, 2};
+}
+
+} // namespace
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index 7b0e69c..7bfd916 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -28,10 +28,12 @@
#include <algorithm>
#include <atomic>
#include <cstdint>
+#include <functional>
#include <type_traits>
#include <utility>
-#include "absl/base/internal/invoke.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h"
@@ -47,8 +49,8 @@
class once_flag;
namespace base_internal {
-absl::Nonnull<std::atomic<uint32_t>*> ControlWord(
- absl::Nonnull<absl::once_flag*> flag);
+std::atomic<uint32_t>* absl_nonnull ControlWord(
+ absl::once_flag* absl_nonnull flag);
} // namespace base_internal
// call_once()
@@ -91,8 +93,8 @@
once_flag& operator=(const once_flag&) = delete;
private:
- friend absl::Nonnull<std::atomic<uint32_t>*> base_internal::ControlWord(
- absl::Nonnull<once_flag*> flag);
+ friend std::atomic<uint32_t>* absl_nonnull base_internal::ControlWord(
+ once_flag* absl_nonnull flag);
std::atomic<uint32_t> control_;
};
@@ -106,7 +108,7 @@
// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to
// initialize entities used by the scheduler implementation.
template <typename Callable, typename... Args>
-void LowLevelCallOnce(absl::Nonnull<absl::once_flag*> flag, Callable&& fn,
+void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn,
Args&&... args);
// Disables scheduling while on stack when scheduling mode is non-cooperative.
@@ -147,10 +149,10 @@
};
template <typename Callable, typename... Args>
-ABSL_ATTRIBUTE_NOINLINE void CallOnceImpl(
- absl::Nonnull<std::atomic<uint32_t>*> control,
- base_internal::SchedulingMode scheduling_mode, Callable&& fn,
- Args&&... args) {
+ void
+ CallOnceImpl(std::atomic<uint32_t>* absl_nonnull control,
+ base_internal::SchedulingMode scheduling_mode, Callable&& fn,
+ Args&&... args) {
#ifndef NDEBUG
{
uint32_t old_control = control->load(std::memory_order_relaxed);
@@ -179,8 +181,7 @@
std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) {
- base_internal::invoke(std::forward<Callable>(fn),
- std::forward<Args>(args)...);
+ std::invoke(std::forward<Callable>(fn), std::forward<Args>(args)...);
old_control =
control->exchange(base_internal::kOnceDone, std::memory_order_release);
if (old_control == base_internal::kOnceWaiter) {
@@ -189,13 +190,13 @@
} // else *control is already kOnceDone
}
-inline absl::Nonnull<std::atomic<uint32_t>*> ControlWord(
- absl::Nonnull<once_flag*> flag) {
+inline std::atomic<uint32_t>* absl_nonnull ControlWord(
+ once_flag* absl_nonnull flag) {
return &flag->control_;
}
template <typename Callable, typename... Args>
-void LowLevelCallOnce(absl::Nonnull<absl::once_flag*> flag, Callable&& fn,
+void LowLevelCallOnce(absl::once_flag* absl_nonnull flag, Callable&& fn,
Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(flag);
uint32_t s = once->load(std::memory_order_acquire);
@@ -209,7 +210,8 @@
} // namespace base_internal
template <typename Callable, typename... Args>
-void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
+ void
+ call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
std::atomic<uint32_t>* once = base_internal::ControlWord(&flag);
uint32_t s = once->load(std::memory_order_acquire);
if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) {
diff --git a/absl/base/config.h b/absl/base/config.h
index 0b22167..8e5feb5 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -117,8 +117,8 @@
//
// LTS releases can be obtained from
// https://github.com/abseil/abseil-cpp/releases.
-#define ABSL_LTS_RELEASE_VERSION 20240722
-#define ABSL_LTS_RELEASE_PATCH_LEVEL 0
+#define ABSL_LTS_RELEASE_VERSION 20250512
+#define ABSL_LTS_RELEASE_PATCH_LEVEL 1
// Helper macro to convert a CPP variable to a string literal.
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
@@ -274,15 +274,12 @@
#define ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE 1
#endif
-
// ABSL_HAVE_THREAD_LOCAL
//
-// DEPRECATED - `thread_local` is available on all supported platforms.
-// Checks whether C++11's `thread_local` storage duration specifier is
-// supported.
+// Checks whether the `thread_local` storage duration specifier is supported.
#ifdef ABSL_HAVE_THREAD_LOCAL
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
-#else
+#elif !defined(__XTENSA__) && !defined(ANDROID_DISABLE_TLS_FOR_LINKER)
#define ABSL_HAVE_THREAD_LOCAL 1
#endif
@@ -380,7 +377,7 @@
defined(__asmjs__) || defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || \
defined(__sun) || defined(__myriad2__) || defined(__HAIKU__) || \
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__QNX__) || \
- defined(__VXWORKS__) || defined(__hexagon__)
+ defined(__VXWORKS__) || defined(__hexagon__) || defined(__XTENSA__)
#define ABSL_HAVE_MMAP 1
#endif
@@ -469,6 +466,9 @@
//
// Checks the endianness of the platform.
//
+// Prefer using `std::endian` in C++20, or `absl::endian` from
+// absl/numeric/bits.h prior to C++20.
+//
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
// Clang (since 3.2); see
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
@@ -520,54 +520,22 @@
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
#endif
-// ABSL_HAVE_STD_ANY
-//
-// Checks whether C++17 std::any is available.
-#ifdef ABSL_HAVE_STD_ANY
-#error "ABSL_HAVE_STD_ANY cannot be directly set."
-#elif defined(__cpp_lib_any) && __cpp_lib_any >= 201606L
+// Deprecated macros for polyfill detection.
#define ABSL_HAVE_STD_ANY 1
-#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
- !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
-#define ABSL_HAVE_STD_ANY 1
-#endif
-
-// ABSL_HAVE_STD_OPTIONAL
-//
-// Checks whether C++17 std::optional is available.
-#ifdef ABSL_HAVE_STD_OPTIONAL
-#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
-#elif defined(__cpp_lib_optional) && __cpp_lib_optional >= 202106L
+#define ABSL_USES_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1
-#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
- !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
-#define ABSL_HAVE_STD_OPTIONAL 1
-#endif
-
-// ABSL_HAVE_STD_VARIANT
-//
-// Checks whether C++17 std::variant is available.
-#ifdef ABSL_HAVE_STD_VARIANT
-#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
-#elif defined(__cpp_lib_variant) && __cpp_lib_variant >= 201606L
+#define ABSL_USES_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1
-#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
- !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
-#define ABSL_HAVE_STD_VARIANT 1
-#endif
+#define ABSL_USES_STD_VARIANT 1
// ABSL_HAVE_STD_STRING_VIEW
//
-// Checks whether C++17 std::string_view is available.
+// Deprecated: always defined to 1.
+// std::string_view was added in C++17, which means all versions of C++
+// supported by Abseil have it.
#ifdef ABSL_HAVE_STD_STRING_VIEW
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
-#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
-#define ABSL_HAVE_STD_STRING_VIEW 1
-#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
+#else
#define ABSL_HAVE_STD_STRING_VIEW 1
#endif
@@ -587,63 +555,15 @@
#define ABSL_HAVE_STD_ORDERING 1
#endif
-// ABSL_USES_STD_ANY
-//
-// Indicates whether absl::any is an alias for std::any.
-#if !defined(ABSL_OPTION_USE_STD_ANY)
-#error options.h is misconfigured.
-#elif ABSL_OPTION_USE_STD_ANY == 0 || \
- (ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
-#undef ABSL_USES_STD_ANY
-#elif ABSL_OPTION_USE_STD_ANY == 1 || \
- (ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
-#define ABSL_USES_STD_ANY 1
-#else
-#error options.h is misconfigured.
-#endif
-
-// ABSL_USES_STD_OPTIONAL
-//
-// Indicates whether absl::optional is an alias for std::optional.
-#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
-#error options.h is misconfigured.
-#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
- (ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
-#undef ABSL_USES_STD_OPTIONAL
-#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
- (ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
-#define ABSL_USES_STD_OPTIONAL 1
-#else
-#error options.h is misconfigured.
-#endif
-
-// ABSL_USES_STD_VARIANT
-//
-// Indicates whether absl::variant is an alias for std::variant.
-#if !defined(ABSL_OPTION_USE_STD_VARIANT)
-#error options.h is misconfigured.
-#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
- (ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
-#undef ABSL_USES_STD_VARIANT
-#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
- (ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
-#define ABSL_USES_STD_VARIANT 1
-#else
-#error options.h is misconfigured.
-#endif
-
// ABSL_USES_STD_STRING_VIEW
//
// Indicates whether absl::string_view is an alias for std::string_view.
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
#error options.h is misconfigured.
-#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
- (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
- !defined(ABSL_HAVE_STD_STRING_VIEW))
+#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0
#undef ABSL_USES_STD_STRING_VIEW
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
- (ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
- defined(ABSL_HAVE_STD_STRING_VIEW))
+ ABSL_OPTION_USE_STD_STRING_VIEW == 2
#define ABSL_USES_STD_STRING_VIEW 1
#else
#error options.h is misconfigured.
@@ -665,14 +585,6 @@
#error options.h is misconfigured.
#endif
-// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
-// SEH exception from emplace for variant<SomeStruct> when constructing the
-// struct can throw. This defeats some of variant_test and
-// variant_exception_safety_test.
-#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
-#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
-#endif
-
// ABSL_INTERNAL_MANGLED_NS
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
//
@@ -813,36 +725,15 @@
// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
//
-// Class template argument deduction is a language feature added in C++17.
+// Deprecated: always defined to 1.
+// Class template argument deduction is a language feature added in C++17,
+// which means all versions of C++ supported by Abseil have it.
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
-#elif defined(__cpp_deduction_guides)
+#else
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
#endif
-// ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-//
-// Prior to C++17, static constexpr variables defined in classes required a
-// separate definition outside of the class body, for example:
-//
-// class Foo {
-// static constexpr int kBar = 0;
-// };
-// constexpr int Foo::kBar;
-//
-// In C++17, these variables defined in classes are considered inline variables,
-// and the extra declaration is redundant. Since some compilers warn on the
-// extra declarations, ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL can be used
-// conditionally ignore them:
-//
-// #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-// constexpr int Foo::kBar;
-// #endif
-#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
-#define ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
-#endif
-
// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
// RTTI support.
#ifdef ABSL_INTERNAL_HAS_RTTI
@@ -926,7 +817,7 @@
// https://llvm.org/docs/CompileCudaWithLLVM.html#detecting-clang-vs-nvcc-from-code
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
-#elif defined(__ARM_NEON) && !defined(__CUDA_ARCH__)
+#elif defined(__ARM_NEON) && !(defined(__NVCC__) && defined(__CUDACC__))
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
#endif
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index bf5aa7c..55a6fe1 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -705,10 +705,6 @@
static constexpr int kExceptionSentinel = 9999;
};
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel;
-#endif
-
TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) {
auto tester_with_val =
tester.WithInitialValue(BasicGuaranteeWithExtraContracts{});
diff --git a/absl/base/internal/fast_type_id.h b/absl/base/fast_type_id.h
similarity index 67%
rename from absl/base/internal/fast_type_id.h
rename to absl/base/fast_type_id.h
index a547b3a..ff25027 100644
--- a/absl/base/internal/fast_type_id.h
+++ b/absl/base/fast_type_id.h
@@ -1,4 +1,3 @@
-//
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,37 +13,33 @@
// limitations under the License.
//
-#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
-#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#ifndef ABSL_BASE_FAST_TYPE_ID_H_
+#define ABSL_BASE_FAST_TYPE_ID_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
-namespace base_internal {
+namespace base_internal {
template <typename Type>
struct FastTypeTag {
- constexpr static char dummy_var = 0;
+ static constexpr char kDummyVar = 0;
};
+} // namespace base_internal
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-template <typename Type>
-constexpr char FastTypeTag<Type>::dummy_var;
-#endif
-
-// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
-// passed-in type. These are meant to be good match for keys into maps or
-// straight up comparisons.
+// The type returned by `absl::FastTypeId<T>()`.
using FastTypeIdType = const void*;
+// `absl::FastTypeId<Type>()` evaluates at compile-time to a unique id for the
+// passed-in type. These are meant to be good match for keys into maps or
+// straight up comparisons.
template <typename Type>
-constexpr inline FastTypeIdType FastTypeId() {
- return &FastTypeTag<Type>::dummy_var;
+constexpr FastTypeIdType FastTypeId() {
+ return &base_internal::FastTypeTag<Type>::kDummyVar;
}
-} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
-#endif // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
+#endif // ABSL_BASE_FAST_TYPE_ID_H_
diff --git a/absl/base/fast_type_id_test.cc b/absl/base/fast_type_id_test.cc
new file mode 100644
index 0000000..3068e4b
--- /dev/null
+++ b/absl/base/fast_type_id_test.cc
@@ -0,0 +1,127 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/fast_type_id.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+
+namespace {
+
+// NOLINTBEGIN(runtime/int)
+#define PRIM_TYPES(A) \
+ A(bool) \
+ A(short) \
+ A(unsigned short) \
+ A(int) \
+ A(unsigned int) \
+ A(long) \
+ A(unsigned long) \
+ A(long long) \
+ A(unsigned long long) \
+ A(float) \
+ A(double) \
+ A(long double)
+// NOLINTEND(runtime/int)
+
+TEST(FastTypeIdTest, PrimitiveTypes) {
+ // clang-format off
+ constexpr absl::FastTypeIdType kTypeIds[] = {
+#define A(T) absl::FastTypeId<T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<const T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<volatile T>(),
+ PRIM_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<const volatile T>(),
+ PRIM_TYPES(A)
+#undef A
+ };
+ // clang-format on
+
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kTypeIds); ++i) {
+ EXPECT_EQ(kTypeIds[i], kTypeIds[i]);
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(kTypeIds[i], kTypeIds[j]);
+ }
+ }
+}
+
+#define FIXED_WIDTH_TYPES(A) \
+ A(int8_t) \
+ A(uint8_t) \
+ A(int16_t) \
+ A(uint16_t) \
+ A(int32_t) \
+ A(uint32_t) \
+ A(int64_t) \
+ A(uint64_t)
+
+TEST(FastTypeIdTest, FixedWidthTypes) {
+ // clang-format off
+ constexpr absl::FastTypeIdType kTypeIds[] = {
+#define A(T) absl::FastTypeId<T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<const T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<volatile T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+#define A(T) absl::FastTypeId<const volatile T>(),
+ FIXED_WIDTH_TYPES(A)
+#undef A
+ };
+ // clang-format on
+
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kTypeIds); ++i) {
+ EXPECT_EQ(kTypeIds[i], kTypeIds[i]);
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(kTypeIds[i], kTypeIds[j]);
+ }
+ }
+}
+
+TEST(FastTypeIdTest, AliasTypes) {
+ using int_alias = int;
+ EXPECT_EQ(absl::FastTypeId<int_alias>(), absl::FastTypeId<int>());
+}
+
+TEST(FastTypeIdTest, TemplateSpecializations) {
+ EXPECT_NE(absl::FastTypeId<std::vector<int>>(),
+ absl::FastTypeId<std::vector<long>>()); // NOLINT(runtime/int)
+
+ EXPECT_NE((absl::FastTypeId<std::map<int, float>>()),
+ (absl::FastTypeId<std::map<int, double>>()));
+}
+
+struct Base {};
+struct Derived : Base {};
+struct PDerived : private Base {};
+
+TEST(FastTypeIdTest, Inheritance) {
+ EXPECT_NE(absl::FastTypeId<Base>(), absl::FastTypeId<Derived>());
+ EXPECT_NE(absl::FastTypeId<Base>(), absl::FastTypeId<PDerived>());
+}
+
+} // namespace
diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc
deleted file mode 100644
index 37a40e1..0000000
--- a/absl/base/inline_variable_test.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <type_traits>
-
-#include "absl/base/internal/inline_variable.h"
-#include "absl/base/internal/inline_variable_testing.h"
-
-#include "gtest/gtest.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace inline_variable_testing_internal {
-namespace {
-
-TEST(InlineVariableTest, Constexpr) {
- static_assert(inline_variable_foo.value == 5, "");
- static_assert(other_inline_variable_foo.value == 5, "");
- static_assert(inline_variable_int == 5, "");
- static_assert(other_inline_variable_int == 5, "");
-}
-
-TEST(InlineVariableTest, DefaultConstructedIdentityEquality) {
- EXPECT_EQ(get_foo_a().value, 5);
- EXPECT_EQ(get_foo_b().value, 5);
- EXPECT_EQ(&get_foo_a(), &get_foo_b());
-}
-
-TEST(InlineVariableTest, DefaultConstructedIdentityInequality) {
- EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo);
-}
-
-TEST(InlineVariableTest, InitializedIdentityEquality) {
- EXPECT_EQ(get_int_a(), 5);
- EXPECT_EQ(get_int_b(), 5);
- EXPECT_EQ(&get_int_a(), &get_int_b());
-}
-
-TEST(InlineVariableTest, InitializedIdentityInequality) {
- EXPECT_NE(&inline_variable_int, &other_inline_variable_int);
-}
-
-TEST(InlineVariableTest, FunPtrType) {
- static_assert(
- std::is_same<void(*)(),
- std::decay<decltype(inline_variable_fun_ptr)>::type>::value,
- "");
-}
-
-} // namespace
-} // namespace inline_variable_testing_internal
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc
deleted file mode 100644
index f96a58d..0000000
--- a/absl/base/inline_variable_test_a.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/base/internal/inline_variable_testing.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace inline_variable_testing_internal {
-
-const Foo& get_foo_a() { return inline_variable_foo; }
-
-const int& get_int_a() { return inline_variable_int; }
-
-} // namespace inline_variable_testing_internal
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc
deleted file mode 100644
index 038adc3..0000000
--- a/absl/base/inline_variable_test_b.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/base/internal/inline_variable_testing.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace inline_variable_testing_internal {
-
-const Foo& get_foo_b() { return inline_variable_foo; }
-
-const int& get_int_b() { return inline_variable_int; }
-
-} // namespace inline_variable_testing_internal
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc
index 902e3f5..9946601 100644
--- a/absl/base/internal/cycleclock.cc
+++ b/absl/base/internal/cycleclock.cc
@@ -35,11 +35,6 @@
#if ABSL_USE_UNSCALED_CYCLECLOCK
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr int32_t CycleClock::kShift;
-constexpr double CycleClock::kFrequencyScale;
-#endif
-
ABSL_CONST_INIT std::atomic<CycleClockSourceFunc>
CycleClock::cycle_clock_source_{nullptr};
diff --git a/absl/base/internal/cycleclock_config.h b/absl/base/internal/cycleclock_config.h
index 191112b..50a4697 100644
--- a/absl/base/internal/cycleclock_config.h
+++ b/absl/base/internal/cycleclock_config.h
@@ -18,7 +18,6 @@
#include <cstdint>
#include "absl/base/config.h"
-#include "absl/base/internal/inline_variable.h"
#include "absl/base/internal/unscaledcycleclock_config.h"
namespace absl {
@@ -31,22 +30,23 @@
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
-ABSL_INTERNAL_INLINE_CONSTEXPR(int32_t, kCycleClockShift, 1);
+inline constexpr int32_t kCycleClockShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
-ABSL_INTERNAL_INLINE_CONSTEXPR(int32_t, kCycleClockShift, 0);
+inline constexpr int32_t kCycleClockShift = 0;
#endif
#else // NDEBUG
// In debug mode use a different shift to discourage depending on a
// particular shift value.
-ABSL_INTERNAL_INLINE_CONSTEXPR(int32_t, kCycleClockShift, 2);
+inline constexpr int32_t kCycleClockShift = 2;
#endif // NDEBUG
-ABSL_INTERNAL_INLINE_CONSTEXPR(double, kCycleClockFrequencyScale,
- 1.0 / (1 << kCycleClockShift));
-#endif // ABSL_USE_UNSCALED_CYCLECLOC
+inline constexpr double kCycleClockFrequencyScale =
+ 1.0 / (1 << kCycleClockShift);
+
+#endif // ABSL_USE_UNSCALED_CYCLECLOCK
} // namespace base_internal
ABSL_NAMESPACE_END
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
index 943f3d9..fb38f60 100644
--- a/absl/base/internal/endian.h
+++ b/absl/base/internal/endian.h
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
+// This file is for Abseil internal use only.
+// See //absl/numeric/bits.h for supported functions related to endian-ness.
#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
#define ABSL_BASE_INTERNAL_ENDIAN_H_
@@ -28,44 +30,38 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-inline uint64_t gbswap_64(uint64_t host_int) {
+constexpr uint64_t gbswap_64(uint64_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
- return __builtin_bswap64(host_int);
-#elif defined(_MSC_VER)
- return _byteswap_uint64(host_int);
+ return __builtin_bswap64(x);
#else
- return (((host_int & uint64_t{0xFF}) << 56) |
- ((host_int & uint64_t{0xFF00}) << 40) |
- ((host_int & uint64_t{0xFF0000}) << 24) |
- ((host_int & uint64_t{0xFF000000}) << 8) |
- ((host_int & uint64_t{0xFF00000000}) >> 8) |
- ((host_int & uint64_t{0xFF0000000000}) >> 24) |
- ((host_int & uint64_t{0xFF000000000000}) >> 40) |
- ((host_int & uint64_t{0xFF00000000000000}) >> 56));
+ return (((x & uint64_t{0xFF}) << 56) |
+ ((x & uint64_t{0xFF00}) << 40) |
+ ((x & uint64_t{0xFF0000}) << 24) |
+ ((x & uint64_t{0xFF000000}) << 8) |
+ ((x & uint64_t{0xFF00000000}) >> 8) |
+ ((x & uint64_t{0xFF0000000000}) >> 24) |
+ ((x & uint64_t{0xFF000000000000}) >> 40) |
+ ((x & uint64_t{0xFF00000000000000}) >> 56));
#endif
}
-inline uint32_t gbswap_32(uint32_t host_int) {
+constexpr uint32_t gbswap_32(uint32_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
- return __builtin_bswap32(host_int);
-#elif defined(_MSC_VER)
- return _byteswap_ulong(host_int);
+ return __builtin_bswap32(x);
#else
- return (((host_int & uint32_t{0xFF}) << 24) |
- ((host_int & uint32_t{0xFF00}) << 8) |
- ((host_int & uint32_t{0xFF0000}) >> 8) |
- ((host_int & uint32_t{0xFF000000}) >> 24));
+ return (((x & uint32_t{0xFF}) << 24) |
+ ((x & uint32_t{0xFF00}) << 8) |
+ ((x & uint32_t{0xFF0000}) >> 8) |
+ ((x & uint32_t{0xFF000000}) >> 24));
#endif
}
-inline uint16_t gbswap_16(uint16_t host_int) {
+constexpr uint16_t gbswap_16(uint16_t x) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
- return __builtin_bswap16(host_int);
-#elif defined(_MSC_VER)
- return _byteswap_ushort(host_int);
+ return __builtin_bswap16(x);
#else
- return (((host_int & uint16_t{0xFF}) << 8) |
- ((host_int & uint16_t{0xFF00}) >> 8));
+ return (((x & uint16_t{0xFF}) << 8) |
+ ((x & uint16_t{0xFF00}) >> 8));
#endif
}
@@ -161,27 +157,27 @@
}
// Functions to do unaligned loads and stores in little-endian order.
-inline uint16_t Load16(absl::Nonnull<const void *> p) {
+inline uint16_t Load16(const void* absl_nonnull p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
-inline void Store16(absl::Nonnull<void *> p, uint16_t v) {
+inline void Store16(void* absl_nonnull p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
-inline uint32_t Load32(absl::Nonnull<const void *> p) {
+inline uint32_t Load32(const void* absl_nonnull p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
-inline void Store32(absl::Nonnull<void *> p, uint32_t v) {
+inline void Store32(void* absl_nonnull p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
-inline uint64_t Load64(absl::Nonnull<const void *> p) {
+inline uint64_t Load64(const void* absl_nonnull p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
-inline void Store64(absl::Nonnull<void *> p, uint64_t v) {
+inline void Store64(void* absl_nonnull p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
@@ -251,27 +247,27 @@
}
// Functions to do unaligned loads and stores in big-endian order.
-inline uint16_t Load16(absl::Nonnull<const void *> p) {
+inline uint16_t Load16(const void* absl_nonnull p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
}
-inline void Store16(absl::Nonnull<void *> p, uint16_t v) {
+inline void Store16(void* absl_nonnull p, uint16_t v) {
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
-inline uint32_t Load32(absl::Nonnull<const void *> p) {
+inline uint32_t Load32(const void* absl_nonnull p) {
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
}
-inline void Store32(absl::Nonnull<void *>p, uint32_t v) {
+inline void Store32(void* absl_nonnull p, uint32_t v) {
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
-inline uint64_t Load64(absl::Nonnull<const void *> p) {
+inline uint64_t Load64(const void* absl_nonnull p) {
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
}
-inline void Store64(absl::Nonnull<void *> p, uint64_t v) {
+inline void Store64(void* absl_nonnull p, uint64_t v) {
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
diff --git a/absl/base/internal/fast_type_id_test.cc b/absl/base/internal/fast_type_id_test.cc
deleted file mode 100644
index 16f3c14..0000000
--- a/absl/base/internal/fast_type_id_test.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/base/internal/fast_type_id.h"
-
-#include <cstdint>
-#include <map>
-#include <vector>
-
-#include "gtest/gtest.h"
-
-namespace {
-namespace bi = absl::base_internal;
-
-// NOLINTNEXTLINE
-#define PRIM_TYPES(A) \
- A(bool) \
- A(short) \
- A(unsigned short) \
- A(int) \
- A(unsigned int) \
- A(long) \
- A(unsigned long) \
- A(long long) \
- A(unsigned long long) \
- A(float) \
- A(double) \
- A(long double)
-
-TEST(FastTypeIdTest, PrimitiveTypes) {
- bi::FastTypeIdType type_ids[] = {
-#define A(T) bi::FastTypeId<T>(),
- PRIM_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<const T>(),
- PRIM_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<volatile T>(),
- PRIM_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<const volatile T>(),
- PRIM_TYPES(A)
-#undef A
- };
- size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
-
- for (int i = 0; i < total_type_ids; ++i) {
- EXPECT_EQ(type_ids[i], type_ids[i]);
- for (int j = 0; j < i; ++j) {
- EXPECT_NE(type_ids[i], type_ids[j]);
- }
- }
-}
-
-#define FIXED_WIDTH_TYPES(A) \
- A(int8_t) \
- A(uint8_t) \
- A(int16_t) \
- A(uint16_t) \
- A(int32_t) \
- A(uint32_t) \
- A(int64_t) \
- A(uint64_t)
-
-TEST(FastTypeIdTest, FixedWidthTypes) {
- bi::FastTypeIdType type_ids[] = {
-#define A(T) bi::FastTypeId<T>(),
- FIXED_WIDTH_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<const T>(),
- FIXED_WIDTH_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<volatile T>(),
- FIXED_WIDTH_TYPES(A)
-#undef A
-#define A(T) bi::FastTypeId<const volatile T>(),
- FIXED_WIDTH_TYPES(A)
-#undef A
- };
- size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
-
- for (int i = 0; i < total_type_ids; ++i) {
- EXPECT_EQ(type_ids[i], type_ids[i]);
- for (int j = 0; j < i; ++j) {
- EXPECT_NE(type_ids[i], type_ids[j]);
- }
- }
-}
-
-TEST(FastTypeIdTest, AliasTypes) {
- using int_alias = int;
- EXPECT_EQ(bi::FastTypeId<int_alias>(), bi::FastTypeId<int>());
-}
-
-TEST(FastTypeIdTest, TemplateSpecializations) {
- EXPECT_NE(bi::FastTypeId<std::vector<int>>(),
- bi::FastTypeId<std::vector<long>>());
-
- EXPECT_NE((bi::FastTypeId<std::map<int, float>>()),
- (bi::FastTypeId<std::map<int, double>>()));
-}
-
-struct Base {};
-struct Derived : Base {};
-struct PDerived : private Base {};
-
-TEST(FastTypeIdTest, Inheritance) {
- EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<Derived>());
- EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<PDerived>());
-}
-
-} // namespace
diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h
deleted file mode 100644
index 09daf0f..0000000
--- a/absl/base/internal/inline_variable.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
-#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
-
-#include <type_traits>
-
-#include "absl/base/internal/identity.h"
-
-// File:
-// This file define a macro that allows the creation of or emulation of C++17
-// inline variables based on whether or not the feature is supported.
-
-////////////////////////////////////////////////////////////////////////////////
-// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
-//
-// Description:
-// Expands to the equivalent of an inline constexpr instance of the specified
-// `type` and `name`, initialized to the value `init`. If the compiler being
-// used is detected as supporting actual inline variables as a language
-// feature, then the macro expands to an actual inline variable definition.
-//
-// Requires:
-// `type` is a type that is usable in an extern variable declaration.
-//
-// Requires: `name` is a valid identifier
-//
-// Requires:
-// `init` is an expression that can be used in the following definition:
-// constexpr type name = init;
-//
-// Usage:
-//
-// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
-// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
-//
-// Differences in implementation:
-// For a direct, language-level inline variable, decltype(name) will be the
-// type that was specified along with const qualification, whereas for
-// emulated inline variables, decltype(name) may be different (in practice
-// it will likely be a reference type).
-////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cpp_inline_variables
-
-// Clang's -Wmissing-variable-declarations option erroneously warned that
-// inline constexpr objects need to be pre-declared. This has now been fixed,
-// but we will need to support this workaround for people building with older
-// versions of clang.
-//
-// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
-//
-// Note:
-// type_identity_t is used here so that the const and name are in the
-// appropriate place for pointer types, reference types, function pointer
-// types, etc..
-#if defined(__clang__)
-#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
- extern const ::absl::internal::type_identity_t<type> name;
-#else // Otherwise, just define the macro to do nothing.
-#define ABSL_INTERNAL_EXTERN_DECL(type, name)
-#endif // defined(__clang__)
-
-// See above comment at top of file for details.
-#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
- ABSL_INTERNAL_EXTERN_DECL(type, name) \
- inline constexpr ::absl::internal::type_identity_t<type> name = init
-
-#else
-
-// See above comment at top of file for details.
-//
-// Note:
-// type_identity_t is used here so that the const and name are in the
-// appropriate place for pointer types, reference types, function pointer
-// types, etc..
-#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
- template <class /*AbslInternalDummy*/ = void> \
- struct AbslInternalInlineVariableHolder##name { \
- static constexpr ::absl::internal::type_identity_t<var_type> kInstance = \
- init; \
- }; \
- \
- template <class AbslInternalDummy> \
- constexpr ::absl::internal::type_identity_t<var_type> \
- AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
- \
- static constexpr const ::absl::internal::type_identity_t<var_type>& \
- name = /* NOLINT */ \
- AbslInternalInlineVariableHolder##name<>::kInstance; \
- static_assert(sizeof(void (*)(decltype(name))) != 0, \
- "Silence unused variable warnings.")
-
-#endif // __cpp_inline_variables
-
-#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h
deleted file mode 100644
index f3c8145..0000000
--- a/absl/base/internal/inline_variable_testing.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_TESTING_H_
-#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_TESTING_H_
-
-#include "absl/base/internal/inline_variable.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace inline_variable_testing_internal {
-
-struct Foo {
- int value = 5;
-};
-
-ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {});
-
-ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5);
-ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5);
-
-ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr);
-
-const Foo& get_foo_a();
-const Foo& get_foo_b();
-
-const int& get_int_a();
-const int& get_int_b();
-
-} // namespace inline_variable_testing_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_TESTING_H_
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
deleted file mode 100644
index 643c2a4..0000000
--- a/absl/base/internal/invoke.h
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// absl::base_internal::invoke(f, args...) is an implementation of
-// INVOKE(f, args...) from section [func.require] of the C++ standard.
-// When compiled as C++17 and later versions, it is implemented as an alias of
-// std::invoke.
-//
-// [func.require]
-// Define INVOKE (f, t1, t2, ..., tN) as follows:
-// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
-// and t1 is an object of type T or a reference to an object of type T or a
-// reference to an object of a type derived from T;
-// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
-// class T and t1 is not one of the types described in the previous item;
-// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
-// an object of type T or a reference to an object of type T or a reference
-// to an object of a type derived from T;
-// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
-// is not one of the types described in the previous item;
-// 5. f(t1, t2, ..., tN) in all other cases.
-//
-// The implementation is SFINAE-friendly: substitution failure within invoke()
-// isn't an error.
-
-#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
-#define ABSL_BASE_INTERNAL_INVOKE_H_
-
-#include "absl/base/config.h"
-
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-
-#include <functional>
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-using std::invoke;
-using std::invoke_result_t;
-using std::is_invocable_r;
-
-} // namespace base_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-
-#include <algorithm>
-#include <type_traits>
-#include <utility>
-
-#include "absl/meta/type_traits.h"
-
-// The following code is internal implementation detail. See the comment at the
-// top of this file for the API documentation.
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-
-// The five classes below each implement one of the clauses from the definition
-// of INVOKE. The inner class template Accept<F, Args...> checks whether the
-// clause is applicable; static function template Invoke(f, args...) does the
-// invocation.
-//
-// By separating the clause selection logic from invocation we make sure that
-// Invoke() does exactly what the standard says.
-
-template <typename Derived>
-struct StrippedAccept {
- template <typename... Args>
- struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
- typename std::remove_reference<Args>::type>::type...> {};
-};
-
-// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
-// and t1 is an object of type T or a reference to an object of type T or a
-// reference to an object of a type derived from T.
-struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
-
- template <typename MemFunType, typename C, typename Obj, typename... Args>
- struct AcceptImpl<MemFunType C::*, Obj, Args...>
- : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
- absl::is_function<MemFunType>::value> {
- };
-
- template <typename MemFun, typename Obj, typename... Args>
- static decltype((std::declval<Obj>().*
- std::declval<MemFun>())(std::declval<Args>()...))
- Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
-// Ignore bogus GCC warnings on this line.
-// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example.
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
- return (std::forward<Obj>(obj).*
- std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
-#pragma GCC diagnostic pop
-#endif
- }
-};
-
-// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
-// class T and t1 is not one of the types described in the previous item.
-struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
-
- template <typename MemFunType, typename C, typename Ptr, typename... Args>
- struct AcceptImpl<MemFunType C::*, Ptr, Args...>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
- absl::is_function<MemFunType>::value> {
- };
-
- template <typename MemFun, typename Ptr, typename... Args>
- static decltype(((*std::declval<Ptr>()).*
- std::declval<MemFun>())(std::declval<Args>()...))
- Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
- return ((*std::forward<Ptr>(ptr)).*
- std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
- }
-};
-
-// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
-// an object of type T or a reference to an object of type T or a reference
-// to an object of a type derived from T.
-struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
-
- template <typename R, typename C, typename Obj>
- struct AcceptImpl<R C::*, Obj>
- : std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
- !absl::is_function<R>::value> {};
-
- template <typename DataMem, typename Ref>
- static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
- DataMem&& data_mem, Ref&& ref) {
- return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
- }
-};
-
-// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
-// is not one of the types described in the previous item.
-struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
-
- template <typename R, typename C, typename Ptr>
- struct AcceptImpl<R C::*, Ptr>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
- !absl::is_function<R>::value> {};
-
- template <typename DataMem, typename Ptr>
- static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
- DataMem&& data_mem, Ptr&& ptr) {
- return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
- }
-};
-
-// f(t1, t2, ..., tN) in all other cases.
-struct Callable {
- // Callable doesn't have Accept because it's the last clause that gets picked
- // when none of the previous clauses are applicable.
- template <typename F, typename... Args>
- static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
- F&& f, Args&&... args) {
- return std::forward<F>(f)(std::forward<Args>(args)...);
- }
-};
-
-// Resolves to the first matching clause.
-template <typename... Args>
-struct Invoker {
- typedef typename std::conditional<
- MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
- typename std::conditional<
- MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
- typename std::conditional<
- DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
- typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
- DataMemAndPtr, Callable>::type>::type>::
- type>::type type;
-};
-
-// The result type of Invoke<F, Args...>.
-template <typename F, typename... Args>
-using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
- std::declval<F>(), std::declval<Args>()...));
-
-// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
-// [func.require] of the C++ standard.
-template <typename F, typename... Args>
-invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
- return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
- std::forward<Args>(args)...);
-}
-
-template <typename AlwaysVoid, typename, typename, typename...>
-struct IsInvocableRImpl : std::false_type {};
-
-template <typename R, typename F, typename... Args>
-struct IsInvocableRImpl<
- absl::void_t<absl::base_internal::invoke_result_t<F, Args...> >, R, F,
- Args...>
- : std::integral_constant<
- bool,
- std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>,
- R>::value ||
- std::is_void<R>::value> {};
-
-// Type trait whose member `value` is true if invoking `F` with `Args` is valid,
-// and either the return type is convertible to `R`, or `R` is void.
-// C++11-compatible version of `std::is_invocable_r`.
-template <typename R, typename F, typename... Args>
-using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>;
-
-} // namespace base_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-
-#endif // ABSL_BASE_INTERNAL_INVOKE_H_
diff --git a/absl/base/internal/iterator_traits.h b/absl/base/internal/iterator_traits.h
new file mode 100644
index 0000000..472c436
--- /dev/null
+++ b/absl/base/internal/iterator_traits.h
@@ -0,0 +1,71 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: internal/iterator_traits.h
+// -----------------------------------------------------------------------------
+//
+// Helpers for querying traits of iterators, for implementing containers, etc.
+
+#ifndef ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
+#define ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
+
+#include <iterator>
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+template <typename Iterator, typename = void>
+struct IteratorCategory {};
+
+template <typename Iterator>
+struct IteratorCategory<
+ Iterator,
+ absl::void_t<typename std::iterator_traits<Iterator>::iterator_category>> {
+ using type = typename std::iterator_traits<Iterator>::iterator_category;
+};
+
+template <typename Iterator, typename = void>
+struct IteratorConceptImpl : IteratorCategory<Iterator> {};
+
+template <typename Iterator>
+struct IteratorConceptImpl<
+ Iterator,
+ absl::void_t<typename std::iterator_traits<Iterator>::iterator_concept>> {
+ using type = typename std::iterator_traits<Iterator>::iterator_concept;
+};
+
+// The newer `std::iterator_traits<Iterator>::iterator_concept` if available,
+// else `std::iterator_traits<Iterator>::iterator_category`.
+template <typename Iterator>
+using IteratorConcept = typename IteratorConceptImpl<Iterator>::type;
+
+template <typename IteratorTag, typename Iterator>
+using IsAtLeastIterator =
+ std::is_convertible<IteratorConcept<Iterator>, IteratorTag>;
+
+template <typename Iterator>
+using IsAtLeastForwardIterator =
+ IsAtLeastIterator<std::forward_iterator_tag, Iterator>;
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_H_
diff --git a/absl/base/internal/iterator_traits_test.cc b/absl/base/internal/iterator_traits_test.cc
new file mode 100644
index 0000000..cb2044f
--- /dev/null
+++ b/absl/base/internal/iterator_traits_test.cc
@@ -0,0 +1,85 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/iterator_traits.h"
+
+#include <forward_list>
+#include <iterator>
+#include <list>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/iterator_traits_test_helper.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+namespace {
+
+TEST(IsAtLeastIteratorTest, IsAtLeastIterator) {
+ EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag, int*>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag, int*>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag, int*>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::random_access_iterator_tag, int*>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
+ std::vector<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
+ std::vector<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag,
+ std::vector<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::random_access_iterator_tag,
+ std::vector<int>::iterator>()));
+
+ EXPECT_TRUE(
+ (IsAtLeastIterator<std::input_iterator_tag, std::list<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
+ std::list<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::bidirectional_iterator_tag,
+ std::list<int>::iterator>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
+ std::list<int>::iterator>()));
+
+ EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
+ std::forward_list<int>::iterator>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
+ std::forward_list<int>::iterator>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::bidirectional_iterator_tag,
+ std::forward_list<int>::iterator>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
+ std::forward_list<int>::iterator>()));
+
+ EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
+ std::istream_iterator<int>>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::forward_iterator_tag,
+ std::istream_iterator<int>>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::bidirectional_iterator_tag,
+ std::istream_iterator<int>>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
+ std::istream_iterator<int>>()));
+
+ EXPECT_TRUE((IsAtLeastIterator<std::input_iterator_tag,
+ Cpp20ForwardZipIterator<int*>>()));
+ EXPECT_TRUE((IsAtLeastIterator<std::forward_iterator_tag,
+ Cpp20ForwardZipIterator<int*>>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::bidirectional_iterator_tag,
+ Cpp20ForwardZipIterator<int*>>()));
+ EXPECT_FALSE((IsAtLeastIterator<std::random_access_iterator_tag,
+ Cpp20ForwardZipIterator<int*>>()));
+}
+
+} // namespace
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/base/internal/iterator_traits_test_helper.h b/absl/base/internal/iterator_traits_test_helper.h
new file mode 100644
index 0000000..707612d
--- /dev/null
+++ b/absl/base/internal/iterator_traits_test_helper.h
@@ -0,0 +1,97 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_ITERATOR_TRAITS_TEST_HELPER_H_
+#define ABSL_BASE_INTERNAL_ITERATOR_TRAITS_TEST_HELPER_H_
+
+#include <iterator>
+#include <utility>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// This would be a forward_iterator in C++20, but it's only an input iterator
+// before that, since it has a non-reference `reference`.
+template <typename Iterator>
+class Cpp20ForwardZipIterator {
+ using IteratorReference = typename std::iterator_traits<Iterator>::reference;
+
+ public:
+ Cpp20ForwardZipIterator() = default;
+ explicit Cpp20ForwardZipIterator(Iterator left, Iterator right)
+ : left_(left), right_(right) {}
+
+ Cpp20ForwardZipIterator& operator++() {
+ ++left_;
+ ++right_;
+ return *this;
+ }
+
+ Cpp20ForwardZipIterator operator++(int) {
+ Cpp20ForwardZipIterator tmp(*this);
+ ++*this;
+ return *this;
+ }
+
+ std::pair<IteratorReference, IteratorReference> operator*() const {
+ return {*left_, *right_};
+ }
+
+ // C++17 input iterators require `operator->`, but this isn't possible to
+ // implement. C++20 dropped the requirement.
+
+ friend bool operator==(const Cpp20ForwardZipIterator& lhs,
+ const Cpp20ForwardZipIterator& rhs) {
+ return lhs.left_ == rhs.left_ && lhs.right_ == rhs.right_;
+ }
+
+ friend bool operator!=(const Cpp20ForwardZipIterator& lhs,
+ const Cpp20ForwardZipIterator& rhs) {
+ return !(lhs == rhs);
+ }
+
+ private:
+ Iterator left_{};
+ Iterator right_{};
+};
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+template <typename Iterator>
+struct std::iterator_traits<
+ absl::base_internal::Cpp20ForwardZipIterator<Iterator>> {
+ private:
+ using IteratorReference = typename std::iterator_traits<Iterator>::reference;
+
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using iterator_concept = std::forward_iterator_tag;
+ using value_type = std::pair<IteratorReference, IteratorReference>;
+ using difference_type =
+ typename std::iterator_traits<Iterator>::difference_type;
+ using reference = value_type;
+ using pointer = void;
+};
+
+#if defined(__cpp_lib_concepts)
+static_assert(
+ std::forward_iterator<absl::base_internal::Cpp20ForwardZipIterator<int*>>);
+#endif // defined(__cpp_lib_concepts)
+
+#endif // ABSL_BASE_INTERNAL_ITERATOR_TRAITS_TEST_HELPER_H_
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index a563f7b..158b609 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -330,7 +330,7 @@
GetSystemInfo(&system_info);
return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity);
#elif defined(__wasm__) || defined(__asmjs__) || defined(__hexagon__)
- return getpagesize();
+ return static_cast<size_t>(getpagesize());
#else
return static_cast<size_t>(sysconf(_SC_PAGESIZE));
#endif
@@ -448,8 +448,8 @@
// that the freelist is in the correct order, that it
// consists of regions marked "unallocated", and that no two regions
// are adjacent in memory (they should have been coalesced).
-// L >= arena->mu
-static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
+static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena)
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(arena->mu) {
ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
AllocList *next = prev->next[i];
if (next != nullptr) {
@@ -473,6 +473,7 @@
if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size ==
reinterpret_cast<char *>(n)) {
LowLevelAlloc::Arena *arena = a->header.arena;
+ arena->mu.AssertHeld();
a->header.size += n->header.size;
n->header.magic = 0;
n->header.arena = nullptr;
@@ -486,8 +487,8 @@
}
// Adds block at location "v" to the free list
-// L >= arena->mu
-static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) {
+static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena)
+ ABSL_EXCLUSIVE_LOCKS_REQUIRED(arena->mu) {
AllocList *f = reinterpret_cast<AllocList *>(reinterpret_cast<char *>(v) -
sizeof(f->header));
ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
diff --git a/absl/base/internal/nullability_deprecated.h b/absl/base/internal/nullability_deprecated.h
new file mode 100644
index 0000000..1174a96
--- /dev/null
+++ b/absl/base/internal/nullability_deprecated.h
@@ -0,0 +1,106 @@
+// Copyright 2023 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
+#define ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace nullability_internal {
+
+template <typename T>
+using NullableImpl
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
+ [[clang::annotate("Nullable")]]
+#endif
+// Don't add the _Nullable attribute in Objective-C compiles. Many Objective-C
+// projects enable the `-Wnullable-to-nonnull-conversion warning`, which is
+// liable to produce false positives.
+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
+ = T _Nullable;
+#else
+ = T;
+#endif
+
+template <typename T>
+using NonnullImpl
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
+ [[clang::annotate("Nonnull")]]
+#endif
+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
+ = T _Nonnull;
+#else
+ = T;
+#endif
+
+template <typename T>
+using NullabilityUnknownImpl
+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
+ [[clang::annotate("Nullability_Unspecified")]]
+#endif
+#if ABSL_HAVE_FEATURE(nullability_on_classes) && !defined(__OBJC__)
+ = T _Null_unspecified;
+#else
+ = T;
+#endif
+
+} // namespace nullability_internal
+
+// The following template aliases are deprecated forms of nullability
+// annotations. They have some limitations, for example, an incompatibility with
+// `auto*` pointers, as `auto` cannot be used in a template argument.
+//
+// It is important to note that these annotations are not distinct strong
+// *types*. They are alias templates defined to be equal to the underlying
+// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
+// pointer of type `T*`.
+//
+// Prefer the macro style annotations in `absl/base/nullability.h` instead.
+
+// absl::Nonnull, analogous to absl_nonnull
+//
+// Example:
+// absl::Nonnull<int*> foo;
+// Is equivalent to:
+// int* absl_nonnull foo;
+template <typename T>
+using Nonnull [[deprecated("Use `absl_nonnull`.")]] =
+ nullability_internal::NonnullImpl<T>;
+
+// absl::Nullable, analogous to absl_nullable
+//
+// Example:
+// absl::Nullable<int*> foo;
+// Is equivalent to:
+// int* absl_nullable foo;
+template <typename T>
+using Nullable [[deprecated("Use `absl_nullable`.")]] =
+ nullability_internal::NullableImpl<T>;
+
+// absl::NullabilityUnknown, analogous to absl_nullability_unknown
+//
+// Example:
+// absl::NullabilityUnknown<int*> foo;
+// Is equivalent to:
+// int* absl_nullability_unknown foo;
+template <typename T>
+using NullabilityUnknown [[deprecated("Use `absl_nullability_unknown`.")]] =
+ nullability_internal::NullabilityUnknownImpl<T>;
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_NULLABILITY_DEPRECATED_H_
diff --git a/absl/base/internal/nullability_impl.h b/absl/base/internal/nullability_impl.h
deleted file mode 100644
index 03fa243..0000000
--- a/absl/base/internal/nullability_impl.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2023 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
-#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
-
-#include <memory>
-#include <type_traits>
-
-#include "absl/base/attributes.h"
-#include "absl/base/config.h"
-#include "absl/meta/type_traits.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace nullability_internal {
-
-// `IsNullabilityCompatible` checks whether its first argument is a class
-// explicitly tagged as supporting nullability annotations. The tag is the type
-// declaration `absl_nullability_compatible`.
-template <typename, typename = void>
-struct IsNullabilityCompatible : std::false_type {};
-
-template <typename T>
-struct IsNullabilityCompatible<
- T, absl::void_t<typename T::absl_nullability_compatible>> : std::true_type {
-};
-
-template <typename T>
-constexpr bool IsSupportedType = IsNullabilityCompatible<T>::value;
-
-template <typename T>
-constexpr bool IsSupportedType<T*> = true;
-
-template <typename T, typename U>
-constexpr bool IsSupportedType<T U::*> = true;
-
-template <typename T, typename... Deleter>
-constexpr bool IsSupportedType<std::unique_ptr<T, Deleter...>> = true;
-
-template <typename T>
-constexpr bool IsSupportedType<std::shared_ptr<T>> = true;
-
-template <typename T>
-struct EnableNullable {
- static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
- "Template argument must be a raw or supported smart pointer "
- "type. See absl/base/nullability.h.");
- using type = T;
-};
-
-template <typename T>
-struct EnableNonnull {
- static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
- "Template argument must be a raw or supported smart pointer "
- "type. See absl/base/nullability.h.");
- using type = T;
-};
-
-template <typename T>
-struct EnableNullabilityUnknown {
- static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
- "Template argument must be a raw or supported smart pointer "
- "type. See absl/base/nullability.h.");
- using type = T;
-};
-
-// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These
-// only support raw pointers, and conditionally enabling them only for raw
-// pointers inhibits template arg deduction. Ideally, they would support all
-// pointer-like types.
-template <typename T, typename = typename EnableNullable<T>::type>
-using NullableImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
- [[clang::annotate("Nullable")]]
-#endif
- = T;
-
-template <typename T, typename = typename EnableNonnull<T>::type>
-using NonnullImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
- [[clang::annotate("Nonnull")]]
-#endif
- = T;
-
-template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
-using NullabilityUnknownImpl
-#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
- [[clang::annotate("Nullability_Unspecified")]]
-#endif
- = T;
-
-} // namespace nullability_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
index d32b40a..35a08f0 100644
--- a/absl/base/internal/raw_logging.cc
+++ b/absl/base/internal/raw_logging.cc
@@ -175,7 +175,7 @@
} else {
DoRawLog(&buf, &size, "%s", kTruncated);
}
- AsyncSignalSafeWriteError(buffer, strlen(buffer));
+ AsyncSignalSafeWriteError(buffer, static_cast<size_t>(buf - buffer));
}
#else
static_cast<void>(format);
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 381b913..430f775 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -67,15 +67,6 @@
submit_profile_data.Store(fn);
}
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-// Static member variable definitions.
-constexpr uint32_t SpinLock::kSpinLockHeld;
-constexpr uint32_t SpinLock::kSpinLockCooperative;
-constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
-constexpr uint32_t SpinLock::kSpinLockSleeper;
-constexpr uint32_t SpinLock::kWaitTimeMask;
-#endif
-
// Uncommon constructors.
SpinLock::SpinLock(base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index 1bb260f..2a10896 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -89,8 +89,7 @@
// acquisition was successful. If the lock was not acquired, false is
// returned. If this SpinLock is free at the time of the call, TryLock
// will return true with high probability.
- ABSL_MUST_USE_RESULT inline bool TryLock()
- ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ [[nodiscard]] inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
bool res = TryLockImpl();
ABSL_TSAN_MUTEX_POST_LOCK(
@@ -121,7 +120,7 @@
// Determine if the lock is held. When the lock is held by the invoking
// thread, true will always be returned. Intended to be used as
// CHECK(lock.IsHeld()).
- ABSL_MUST_USE_RESULT inline bool IsHeld() const {
+ [[nodiscard]] inline bool IsHeld() const {
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
}
@@ -203,16 +202,7 @@
// Corresponding locker object that arranges to acquire a spinlock for
// the duration of a C++ scope.
-//
-// TODO(b/176172494): Use only [[nodiscard]] when baseline is raised.
-// TODO(b/6695610): Remove forward declaration when #ifdef is no longer needed.
-#if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
-class [[nodiscard]] SpinLockHolder;
-#else
-class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI SpinLockHolder;
-#endif
-
-class ABSL_SCOPED_LOCKABLE SpinLockHolder {
+class ABSL_SCOPED_LOCKABLE [[nodiscard]] SpinLockHolder {
public:
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
: lock_(l) {
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index 79eaba3..1937db3 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -46,6 +46,10 @@
#include <rtems.h>
#endif
+#if defined(__Fuchsia__)
+#include <zircon/process.h>
+#endif
+
#include <string.h>
#include <cassert>
@@ -461,6 +465,16 @@
return reinterpret_cast<pid_t>(thread);
}
+#elif defined(__Fuchsia__)
+
+pid_t GetTID() {
+ // Use our thread handle as the TID, which should be unique within this
+ // process (but may not be globally unique). The handle value was chosen over
+ // a kernel object ID (KOID) because zx_handle_t (32-bits) can be cast to a
+ // pid_t type without loss of precision, but a zx_koid_t (64-bits) cannot.
+ return static_cast<pid_t>(zx_thread_self());
+}
+
#else
// Fallback implementation of `GetTID` using `pthread_self`.
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
index f305b6c..c2b59aa 100644
--- a/absl/base/internal/sysinfo_test.cc
+++ b/absl/base/internal/sysinfo_test.cc
@@ -41,7 +41,7 @@
EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test.
#ifdef __native_client__
// Native Client has a race condition bug that leads to memory
- // exaustion when repeatedly creating and joining threads.
+ // exhaustion when repeatedly creating and joining threads.
// https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027
return;
#endif
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
index b6e917c..acfc15a 100644
--- a/absl/base/internal/thread_identity.h
+++ b/absl/base/internal/thread_identity.h
@@ -130,7 +130,11 @@
};
// The instances of this class are allocated in NewThreadIdentity() with an
-// alignment of PerThreadSynch::kAlignment.
+// alignment of PerThreadSynch::kAlignment and never destroyed. Initialization
+// should happen in OneTimeInitThreadIdentity().
+//
+// Instances may be reused by new threads - fields should be reset in
+// ResetThreadIdentityBetweenReuse().
//
// NOTE: The layout of fields in this structure is critical, please do not
// add, remove, or modify the field placements without fully auditing the
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc
index 0ae10f2..419e82d 100644
--- a/absl/base/internal/thread_identity_benchmark.cc
+++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "benchmark/benchmark.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/synchronization/internal/create_thread_identity.h"
#include "absl/synchronization/internal/per_thread_sem.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/base/internal/tracing.cc b/absl/base/internal/tracing.cc
new file mode 100644
index 0000000..d304e6a
--- /dev/null
+++ b/absl/base/internal/tracing.cc
@@ -0,0 +1,39 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/base/internal/tracing.h"
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+extern "C" {
+
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(
+ const void*, ObjectKind) {}
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(
+ const void*, ObjectKind) {}
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(
+ const void*, ObjectKind) {}
+ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(
+ const void*, ObjectKind) {}
+
+} // extern "C"
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/base/internal/tracing.h b/absl/base/internal/tracing.h
new file mode 100644
index 0000000..e7ab775
--- /dev/null
+++ b/absl/base/internal/tracing.h
@@ -0,0 +1,81 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_TRACING_H_
+#define ABSL_BASE_INTERNAL_TRACING_H_
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Well known Abseil object types that have causality.
+enum class ObjectKind { kUnknown, kBlockingCounter, kNotification };
+
+// `TraceWait` and `TraceContinue` record the start and end of a potentially
+// blocking wait operation on `object`. `object` typically represents a higher
+// level synchronization object such as `absl::Notification`.
+void TraceWait(const void* object, ObjectKind kind);
+void TraceContinue(const void* object, ObjectKind kind);
+
+// `TraceSignal` records a signal on `object`.
+void TraceSignal(const void* object, ObjectKind kind);
+
+// `TraceObserved` records the non-blocking observation of a signaled object.
+void TraceObserved(const void* object, ObjectKind kind);
+
+// ---------------------------------------------------------------------------
+// Weak implementation detail:
+//
+// We define the weak API as extern "C": in some build configurations we pass
+// `--detect-odr-violations` to the gold linker. This causes it to flag weak
+// symbol overrides as ODR violations. Because ODR only applies to C++ and not
+// C, `--detect-odr-violations` ignores symbols not mangled with C++ names.
+// By changing our extension points to be extern "C", we dodge this check.
+// ---------------------------------------------------------------------------
+extern "C" {
+
+ void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
+ ObjectKind kind);
+ void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
+ ObjectKind kind);
+ void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
+ ObjectKind kind);
+ void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
+ ObjectKind kind);
+
+} // extern "C"
+
+inline void TraceWait(const void* object, ObjectKind kind) {
+ ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(object, kind);
+}
+
+inline void TraceContinue(const void* object, ObjectKind kind) {
+ ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(object, kind);
+}
+
+inline void TraceSignal(const void* object, ObjectKind kind) {
+ ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(object, kind);
+}
+
+inline void TraceObserved(const void* object, ObjectKind kind) {
+ ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(object, kind);
+}
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_TRACING_H_
diff --git a/absl/base/internal/tracing_strong_test.cc b/absl/base/internal/tracing_strong_test.cc
new file mode 100644
index 0000000..979f1c5
--- /dev/null
+++ b/absl/base/internal/tracing_strong_test.cc
@@ -0,0 +1,117 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <tuple>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/tracing.h"
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+
+namespace {
+
+using ::testing::ElementsAre;
+
+using ::absl::base_internal::ObjectKind;
+
+enum Function { kWait, kContinue, kSignal, kObserved };
+
+using Record = std::tuple<Function, const void*, ObjectKind>;
+
+thread_local std::vector<Record>* tls_records = nullptr;
+
+} // namespace
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace base_internal {
+
+// Strong extern "C" implementation.
+extern "C" {
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
+ ObjectKind kind) {
+ if (tls_records != nullptr) {
+ tls_records->push_back({kWait, object, kind});
+ }
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
+ ObjectKind kind) {
+ if (tls_records != nullptr) {
+ tls_records->push_back({kContinue, object, kind});
+ }
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
+ ObjectKind kind) {
+ if (tls_records != nullptr) {
+ tls_records->push_back({kSignal, object, kind});
+ }
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
+ ObjectKind kind) {
+ if (tls_records != nullptr) {
+ tls_records->push_back({kObserved, object, kind});
+ }
+}
+
+} // extern "C"
+
+} // namespace base_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+namespace {
+
+TEST(TracingInternal, InvokesStrongFunctionWithNullptr) {
+ std::vector<Record> records;
+ tls_records = &records;
+ auto kind = absl::base_internal::ObjectKind::kUnknown;
+ absl::base_internal::TraceWait(nullptr, kind);
+ absl::base_internal::TraceContinue(nullptr, kind);
+ absl::base_internal::TraceSignal(nullptr, kind);
+ absl::base_internal::TraceObserved(nullptr, kind);
+ tls_records = nullptr;
+
+ EXPECT_THAT(records, ElementsAre(Record{kWait, nullptr, kind},
+ Record{kContinue, nullptr, kind},
+ Record{kSignal, nullptr, kind},
+ Record{kObserved, nullptr, kind}));
+}
+
+TEST(TracingInternal, InvokesStrongFunctionWithObjectAddress) {
+ int object = 0;
+ std::vector<Record> records;
+ tls_records = &records;
+ auto kind = absl::base_internal::ObjectKind::kUnknown;
+ absl::base_internal::TraceWait(&object, kind);
+ absl::base_internal::TraceContinue(&object, kind);
+ absl::base_internal::TraceSignal(&object, kind);
+ absl::base_internal::TraceObserved(&object, kind);
+ tls_records = nullptr;
+
+ EXPECT_THAT(records, ElementsAre(Record{kWait, &object, kind},
+ Record{kContinue, &object, kind},
+ Record{kSignal, &object, kind},
+ Record{kObserved, &object, kind}));
+}
+
+} // namespace
+
+#endif // ABSL_HAVE_ATTRIBUTE_WEAK
diff --git a/absl/base/internal/tracing_weak_test.cc b/absl/base/internal/tracing_weak_test.cc
new file mode 100644
index 0000000..6d7553f
--- /dev/null
+++ b/absl/base/internal/tracing_weak_test.cc
@@ -0,0 +1,34 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/tracing.h"
+
+namespace {
+
+TEST(TracingInternal, HasDefaultImplementation) {
+ auto kind = absl::base_internal::ObjectKind::kUnknown;
+ absl::base_internal::TraceWait(nullptr, kind);
+ absl::base_internal::TraceContinue(nullptr, kind);
+ absl::base_internal::TraceSignal(nullptr, kind);
+ absl::base_internal::TraceObserved(nullptr, kind);
+
+ int object = 0;
+ absl::base_internal::TraceWait(&object, kind);
+ absl::base_internal::TraceContinue(&object, kind);
+ absl::base_internal::TraceSignal(&object, kind);
+ absl::base_internal::TraceObserved(&object, kind);
+}
+
+} // namespace
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
index 4fea457..3f5dd6f 100644
--- a/absl/base/internal/unaligned_access.h
+++ b/absl/base/internal/unaligned_access.h
@@ -36,33 +36,33 @@
ABSL_NAMESPACE_BEGIN
namespace base_internal {
-inline uint16_t UnalignedLoad16(absl::Nonnull<const void *> p) {
+inline uint16_t UnalignedLoad16(const void* absl_nonnull p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
-inline uint32_t UnalignedLoad32(absl::Nonnull<const void *> p) {
+inline uint32_t UnalignedLoad32(const void* absl_nonnull p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
-inline uint64_t UnalignedLoad64(absl::Nonnull<const void *> p) {
+inline uint64_t UnalignedLoad64(const void* absl_nonnull p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
-inline void UnalignedStore16(absl::Nonnull<void *> p, uint16_t v) {
+inline void UnalignedStore16(void* absl_nonnull p, uint16_t v) {
memcpy(p, &v, sizeof v);
}
-inline void UnalignedStore32(absl::Nonnull<void *> p, uint32_t v) {
+inline void UnalignedStore32(void* absl_nonnull p, uint32_t v) {
memcpy(p, &v, sizeof v);
}
-inline void UnalignedStore64(absl::Nonnull<void *> p, uint64_t v) {
+inline void UnalignedStore64(void* absl_nonnull p, uint64_t v) {
memcpy(p, &v, sizeof v);
}
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index a0bf3a6..68f9273 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -105,16 +105,6 @@
#elif defined(__aarch64__)
-// System timer of ARMv8 runs at a different frequency than the CPU's.
-// The frequency is fixed, typically in the range 1-50MHz. It can be
-// read at CNTFRQ special register. We assume the OS has set up
-// the virtual timer properly.
-int64_t UnscaledCycleClock::Now() {
- int64_t virtual_timer_value;
- asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
- return virtual_timer_value;
-}
-
double UnscaledCycleClock::Frequency() {
uint64_t aarch64_timer_frequency;
asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency));
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
index cc1276b..bfd9887 100644
--- a/absl/base/internal/unscaledcycleclock.h
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -85,6 +85,23 @@
return static_cast<int64_t>((high << 32) | low);
}
+#elif defined(__aarch64__)
+
+// System timer of ARMv8 runs at a different frequency than the CPU's.
+//
+// Frequency is fixed. From Armv8.6-A and Armv9.1-A on, the frequency is 1GHz.
+// Pre-Armv8.6-A, the frequency was a system design choice, typically in the
+// range of 1MHz to 50MHz. See also:
+// https://developer.arm.com/documentation/102379/0101/What-is-the-Generic-Timer-
+//
+// It can be read at CNTFRQ special register. We assume the OS has set up the
+// virtual timer properly.
+inline int64_t UnscaledCycleClock::Now() {
+ int64_t virtual_timer_value;
+ asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
+ return virtual_timer_value;
+}
+
#endif
} // namespace base_internal
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
deleted file mode 100644
index 7be26f6..0000000
--- a/absl/base/invoke_test.cc
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/base/internal/invoke.h"
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace base_internal {
-namespace {
-
-int Function(int a, int b) { return a - b; }
-
-void VoidFunction(int& a, int& b) {
- a += b;
- b = a - b;
- a -= b;
-}
-
-int ZeroArgFunction() { return -1937; }
-
-int Sink(std::unique_ptr<int> p) {
- return *p;
-}
-
-std::unique_ptr<int> Factory(int n) {
- return make_unique<int>(n);
-}
-
-void NoOp() {}
-
-struct ConstFunctor {
- int operator()(int a, int b) const { return a - b; }
-};
-
-struct MutableFunctor {
- int operator()(int a, int b) { return a - b; }
-};
-
-struct EphemeralFunctor {
- int operator()(int a, int b) && { return a - b; }
-};
-
-struct OverloadedFunctor {
- template <typename... Args>
- std::string operator()(const Args&... args) & {
- return StrCat("&", args...);
- }
- template <typename... Args>
- std::string operator()(const Args&... args) const& {
- return StrCat("const&", args...);
- }
- template <typename... Args>
- std::string operator()(const Args&... args) && {
- return StrCat("&&", args...);
- }
-};
-
-struct Class {
- int Method(int a, int b) { return a - b; }
- int ConstMethod(int a, int b) const { return a - b; }
- int RefMethod(int a, int b) & { return a - b; }
- int RefRefMethod(int a, int b) && { return a - b; }
- int NoExceptMethod(int a, int b) noexcept { return a - b; }
- int VolatileMethod(int a, int b) volatile { return a - b; }
-
- int member;
-};
-
-struct FlipFlop {
- int ConstMethod() const { return member; }
- FlipFlop operator*() const { return {-member}; }
-
- int member;
-};
-
-// CallMaybeWithArg(f) resolves either to invoke(f) or invoke(f, 42), depending
-// on which one is valid.
-template <typename F>
-decltype(base_internal::invoke(std::declval<const F&>())) CallMaybeWithArg(
- const F& f) {
- return base_internal::invoke(f);
-}
-
-template <typename F>
-decltype(base_internal::invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(
- const F& f) {
- return base_internal::invoke(f, 42);
-}
-
-TEST(InvokeTest, Function) {
- EXPECT_EQ(1, base_internal::invoke(Function, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2));
-}
-
-TEST(InvokeTest, NonCopyableArgument) {
- EXPECT_EQ(42, base_internal::invoke(Sink, make_unique<int>(42)));
-}
-
-TEST(InvokeTest, NonCopyableResult) {
- EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42));
-}
-
-TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); }
-
-TEST(InvokeTest, ConstFunctor) {
- EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2));
-}
-
-TEST(InvokeTest, MutableFunctor) {
- MutableFunctor f;
- EXPECT_EQ(1, base_internal::invoke(f, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(MutableFunctor(), 3, 2));
-}
-
-TEST(InvokeTest, EphemeralFunctor) {
- EphemeralFunctor f;
- EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(EphemeralFunctor(), 3, 2));
-}
-
-TEST(InvokeTest, OverloadedFunctor) {
- OverloadedFunctor f;
- const OverloadedFunctor& cf = f;
-
- EXPECT_EQ("&", base_internal::invoke(f));
- EXPECT_EQ("& 42", base_internal::invoke(f, " 42"));
-
- EXPECT_EQ("const&", base_internal::invoke(cf));
- EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42"));
-
- EXPECT_EQ("&&", base_internal::invoke(std::move(f)));
-
- OverloadedFunctor f2;
- EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 42"));
-}
-
-TEST(InvokeTest, ReferenceWrapper) {
- ConstFunctor cf;
- MutableFunctor mf;
- EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2));
-}
-
-TEST(InvokeTest, MemberFunction) {
- std::unique_ptr<Class> p(new Class);
- std::unique_ptr<const Class> cp(new Class);
- std::unique_ptr<volatile Class> vp(new Class);
-
- EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3,
- 2)); // NOLINT
- EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 3, 2));
-
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *p, 3, 2));
-
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2));
-
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 3, 2));
-
- EXPECT_EQ(1,
- base_internal::invoke(&Class::Method, make_unique<Class>(), 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique<Class>(),
- 3, 2));
- EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod,
- make_unique<const Class>(), 3, 2));
-}
-
-TEST(InvokeTest, DataMember) {
- std::unique_ptr<Class> p(new Class{42});
- std::unique_ptr<const Class> cp(new Class{42});
- EXPECT_EQ(42, base_internal::invoke(&Class::member, p));
- EXPECT_EQ(42, base_internal::invoke(&Class::member, *p));
- EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get()));
-
- base_internal::invoke(&Class::member, p) = 42;
- base_internal::invoke(&Class::member, p.get()) = 42;
-
- EXPECT_EQ(42, base_internal::invoke(&Class::member, cp));
- EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp));
- EXPECT_EQ(42, base_internal::invoke(&Class::member, cp.get()));
-}
-
-TEST(InvokeTest, FlipFlop) {
- FlipFlop obj = {42};
- // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
- // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
- EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj));
- EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj));
-}
-
-TEST(InvokeTest, SfinaeFriendly) {
- CallMaybeWithArg(NoOp);
- EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
-}
-
-TEST(IsInvocableRTest, CallableExactMatch) {
- static_assert(
- base_internal::is_invocable_r<int, decltype(Function), int, int>::value,
- "Should be true for exact match of types on a free function");
-}
-
-TEST(IsInvocableRTest, CallableArgumentConversionMatch) {
- static_assert(
- base_internal::is_invocable_r<int, decltype(Function), char, int>::value,
- "Should be true for convertible argument type");
-}
-
-TEST(IsInvocableRTest, CallableReturnConversionMatch) {
- static_assert(base_internal::is_invocable_r<double, decltype(Function), int,
- int>::value,
- "Should be true for convertible return type");
-}
-
-TEST(IsInvocableRTest, CallableReturnVoid) {
- static_assert(base_internal::is_invocable_r<void, decltype(VoidFunction),
- int&, int&>::value,
- "Should be true for void expected and actual return types");
- static_assert(
- base_internal::is_invocable_r<void, decltype(Function), int, int>::value,
- "Should be true for void expected and non-void actual return types");
-}
-
-TEST(IsInvocableRTest, CallableRefQualifierMismatch) {
- static_assert(!base_internal::is_invocable_r<void, decltype(VoidFunction),
- int&, const int&>::value,
- "Should be false for reference constness mismatch");
- static_assert(!base_internal::is_invocable_r<void, decltype(VoidFunction),
- int&&, int&>::value,
- "Should be false for reference value category mismatch");
-}
-
-TEST(IsInvocableRTest, CallableArgumentTypeMismatch) {
- static_assert(!base_internal::is_invocable_r<int, decltype(Function),
- std::string, int>::value,
- "Should be false for argument type mismatch");
-}
-
-TEST(IsInvocableRTest, CallableReturnTypeMismatch) {
- static_assert(!base_internal::is_invocable_r<std::string, decltype(Function),
- int, int>::value,
- "Should be false for return type mismatch");
-}
-
-TEST(IsInvocableRTest, CallableTooFewArgs) {
- static_assert(
- !base_internal::is_invocable_r<int, decltype(Function), int>::value,
- "Should be false for too few arguments");
-}
-
-TEST(IsInvocableRTest, CallableTooManyArgs) {
- static_assert(!base_internal::is_invocable_r<int, decltype(Function), int,
- int, int>::value,
- "Should be false for too many arguments");
-}
-
-TEST(IsInvocableRTest, MemberFunctionAndReference) {
- static_assert(base_internal::is_invocable_r<int, decltype(&Class::Method),
- Class&, int, int>::value,
- "Should be true for exact match of types on a member function "
- "and class reference");
-}
-
-TEST(IsInvocableRTest, MemberFunctionAndPointer) {
- static_assert(base_internal::is_invocable_r<int, decltype(&Class::Method),
- Class*, int, int>::value,
- "Should be true for exact match of types on a member function "
- "and class pointer");
-}
-
-TEST(IsInvocableRTest, DataMemberAndReference) {
- static_assert(base_internal::is_invocable_r<int, decltype(&Class::member),
- Class&>::value,
- "Should be true for exact match of types on a data member and "
- "class reference");
-}
-
-TEST(IsInvocableRTest, DataMemberAndPointer) {
- static_assert(base_internal::is_invocable_r<int, decltype(&Class::member),
- Class*>::value,
- "Should be true for exact match of types on a data member and "
- "class pointer");
-}
-
-TEST(IsInvocableRTest, CallableZeroArgs) {
- static_assert(
- base_internal::is_invocable_r<int, decltype(ZeroArgFunction)>::value,
- "Should be true for exact match for a zero-arg free function");
-}
-
-} // namespace
-} // namespace base_internal
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/base/macros.h b/absl/base/macros.h
index b318f11..ff89944 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -34,6 +34,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h"
+#include "absl/base/options.h"
#include "absl/base/port.h"
// ABSL_ARRAYSIZE()
@@ -81,8 +82,9 @@
// ABSL_ASSERT()
//
// In C++11, `assert` can't be used portably within constexpr functions.
+// `assert` also generates spurious unused-symbol warnings.
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
-// functions. Example:
+// functions, and maintains references to symbols. Example:
//
// constexpr double Divide(double a, double b) {
// return ABSL_ASSERT(b != 0), a / b;
@@ -91,8 +93,18 @@
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
-#define ABSL_ASSERT(expr) \
- (false ? static_cast<void>(expr) : static_cast<void>(0))
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+// We use `decltype` here to avoid generating unnecessary code that the
+// optimizer then has to optimize away.
+// This not only improves compilation performance by reducing codegen bloat
+// and optimization work, but also guarantees fast run-time performance without
+// having to rely on the optimizer.
+#define ABSL_ASSERT(expr) (decltype((expr) ? void() : void())())
+#else
+// Pre-C++20, lambdas can't be inside unevaluated operands, so we're forced to
+// rely on the optimizer.
+#define ABSL_ASSERT(expr) (false ? ((expr) ? void() : void()) : void())
+#endif
#else
#define ABSL_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
@@ -120,7 +132,7 @@
//
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
// hardened mode.
-#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#if (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2) && defined(NDEBUG)
#define ABSL_HARDENING_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
@@ -128,6 +140,25 @@
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
#endif
+// ABSL_HARDENING_ASSERT_SLOW()
+//
+// `ABSL_HARDENING_ASSERT()` is like `ABSL_HARDENING_ASSERT()`,
+// but specifically for assertions whose predicates are too slow
+// to be enabled in many applications.
+//
+// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT_SLOW()` is identical to
+// `ABSL_ASSERT()`.
+//
+// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
+// hardened mode.
+#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
+#define ABSL_HARDENING_ASSERT_SLOW(expr) \
+ (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
+ : [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
+#else
+#define ABSL_HARDENING_ASSERT_SLOW(expr) ABSL_ASSERT(expr)
+#endif
+
#ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...)
diff --git a/absl/base/no_destructor.h b/absl/base/no_destructor.h
index 43b3540..9d960ee 100644
--- a/absl/base/no_destructor.h
+++ b/absl/base/no_destructor.h
@@ -135,11 +135,11 @@
// Pretend to be a smart pointer to T with deep constness.
// Never returns a null pointer.
T& operator*() { return *get(); }
- absl::Nonnull<T*> operator->() { return get(); }
- absl::Nonnull<T*> get() { return impl_.get(); }
+ T* absl_nonnull operator->() { return get(); }
+ T* absl_nonnull get() { return impl_.get(); }
const T& operator*() const { return *get(); }
- absl::Nonnull<const T*> operator->() const { return get(); }
- absl::Nonnull<const T*> get() const { return impl_.get(); }
+ const T* absl_nonnull operator->() const { return get(); }
+ const T* absl_nonnull get() const { return impl_.get(); }
private:
class DirectImpl {
@@ -147,8 +147,8 @@
template <typename... Args>
explicit constexpr DirectImpl(Args&&... args)
: value_(std::forward<Args>(args)...) {}
- absl::Nonnull<const T*> get() const { return &value_; }
- absl::Nonnull<T*> get() { return &value_; }
+ const T* absl_nonnull get() const { return &value_; }
+ T* absl_nonnull get() { return &value_; }
private:
T value_;
@@ -160,33 +160,14 @@
explicit PlacementImpl(Args&&... args) {
new (&space_) T(std::forward<Args>(args)...);
}
- absl::Nonnull<const T*> get() const {
- return Launder(reinterpret_cast<const T*>(&space_));
+ const T* absl_nonnull get() const {
+ return std::launder(reinterpret_cast<const T*>(&space_));
}
- absl::Nonnull<T*> get() { return Launder(reinterpret_cast<T*>(&space_)); }
+ T* absl_nonnull get() {
+ return std::launder(reinterpret_cast<T*>(&space_));
+ }
private:
- template <typename P>
- static absl::Nonnull<P*> Launder(absl::Nonnull<P*> p) {
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
- return std::launder(p);
-#elif ABSL_HAVE_BUILTIN(__builtin_launder)
- return __builtin_launder(p);
-#else
- // When `std::launder` or equivalent are not available, we rely on
- // undefined behavior, which works as intended on Abseil's officially
- // supported platforms as of Q3 2023.
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#endif
- return p;
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-#endif
- }
-
alignas(T) unsigned char space_[sizeof(T)];
};
@@ -199,12 +180,10 @@
impl_;
};
-#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
// Provide 'Class Template Argument Deduction': the type of NoDestructor's T
// will be the same type as the argument passed to NoDestructor's constructor.
template <typename T>
NoDestructor(T) -> NoDestructor<T>;
-#endif // ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/base/no_destructor_test.cc b/absl/base/no_destructor_test.cc
index 71693c7..316b213 100644
--- a/absl/base/no_destructor_test.cc
+++ b/absl/base/no_destructor_test.cc
@@ -196,14 +196,10 @@
EXPECT_EQ(0, Int()); // should get zero-initialized
}
-#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
-// This would fail to compile if Class Template Argument Deduction was not
-// provided for absl::NoDestructor.
TEST(NoDestructorTest, ClassTemplateArgumentDeduction) {
absl::NoDestructor i(1);
static_assert(std::is_same<decltype(i), absl::NoDestructor<int>>::value,
"Expected deduced type to be int.");
}
-#endif
} // namespace
diff --git a/absl/base/nullability.h b/absl/base/nullability.h
index 34dc083..3a5d6e8 100644
--- a/absl/base/nullability.h
+++ b/absl/base/nullability.h
@@ -16,21 +16,21 @@
// File: nullability.h
// -----------------------------------------------------------------------------
//
-// This header file defines a set of "templated annotations" for designating the
-// expected nullability of pointers. These annotations allow you to designate
-// pointers in one of three classification states:
+// This header file defines a set of annotations for designating the expected
+// nullability of pointers. These annotations allow you to designate pointers in
+// one of three classification states:
//
-// * "Non-null" (for pointers annotated `Nonnull<T>`), indicating that it is
+// * "Non-null" (for pointers annotated `absl_nonnull`), indicating that it is
// invalid for the given pointer to ever be null.
-// * "Nullable" (for pointers annotated `Nullable<T>`), indicating that it is
+// * "Nullable" (for pointers annotated `absl_nullable`), indicating that it is
// valid for the given pointer to be null.
-// * "Unknown" (for pointers annotated `NullabilityUnknown<T>`), indicating
-// that the given pointer has not been yet classified as either nullable or
+// * "Unknown" (for pointers annotated `absl_nullability_unknown`), indicating
+// that the given pointer has not yet been classified as either nullable or
// non-null. This is the default state of unannotated pointers.
//
-// NOTE: unannotated pointers implicitly bear the annotation
-// `NullabilityUnknown<T>`; you should rarely, if ever, see this annotation used
-// in the codebase explicitly.
+// NOTE: Unannotated pointers implicitly bear the annotation
+// `absl_nullability_unknown`; you should rarely, if ever, see this annotation
+// used in the codebase explicitly.
//
// -----------------------------------------------------------------------------
// Nullability and Contracts
@@ -64,16 +64,49 @@
// formalize those contracts within the codebase.
//
// -----------------------------------------------------------------------------
+// Annotation Syntax
+// -----------------------------------------------------------------------------
+//
+// The annotations should be positioned as a qualifier for the pointer type. For
+// example, the position of `const` when declaring a const pointer (not a
+// pointer to a const type) is the position you should also use for these
+// annotations.
+//
+// Example:
+//
+// // A const non-null pointer to an `Employee`.
+// Employee* absl_nonnull const e;
+//
+// // A non-null pointer to a const `Employee`.
+// const Employee* absl_nonnull e;
+//
+// // A non-null pointer to a const nullable pointer to an `Employee`.
+// Employee* absl_nullable const* absl_nonnull e = nullptr;
+//
+// // A non-null function pointer.
+// void (*absl_nonnull func)(int, double);
+//
+// // A non-null array of `Employee`s as a parameter.
+// void func(Employee employees[absl_nonnull]);
+//
+// // A non-null std::unique_ptr to an `Employee`.
+// // As with `const`, it is possible to place the annotation on either side of
+// // a named type not ending in `*`, but placing it before the type it
+// // describes is preferred, unless inconsistent with surrounding code.
+// absl_nonnull std::unique_ptr<Employee> employee;
+//
+// // Invalid annotation usage – this attempts to declare a pointer to a
+// // nullable `Employee`, which is meaningless.
+// absl_nullable Employee* e;
+//
+// -----------------------------------------------------------------------------
// Using Nullability Annotations
// -----------------------------------------------------------------------------
//
-// It is important to note that these annotations are not distinct strong
-// *types*. They are alias templates defined to be equal to the underlying
-// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
-// pointer of type `T*`. Each annotation acts as a form of documentation about
-// the contract for the given pointer. Each annotation requires providers or
-// consumers of these pointers across API boundaries to take appropriate steps
-// when setting or using these pointers:
+// Each annotation acts as a form of documentation about the contract for the
+// given pointer. Each annotation requires providers or consumers of these
+// pointers across API boundaries to take appropriate steps when setting or
+// using these pointers:
//
// * "Non-null" pointers should never be null. It is the responsibility of the
// provider of this pointer to ensure that the pointer may never be set to
@@ -91,20 +124,20 @@
// Example:
//
// // PaySalary() requires the passed pointer to an `Employee` to be non-null.
-// void PaySalary(absl::Nonnull<Employee *> e) {
+// void PaySalary(Employee* absl_nonnull e) {
// pay(e->salary); // OK to dereference
// }
//
// // CompleteTransaction() guarantees the returned pointer to an `Account` to
// // be non-null.
-// absl::Nonnull<Account *> balance CompleteTransaction(double fee) {
+// Account* absl_nonnull balance CompleteTransaction(double fee) {
// ...
// }
//
// // Note that specifying a nullability annotation does not prevent someone
// // from violating the contract:
//
-// Nullable<Employee *> find(Map& employees, std::string_view name);
+// Employee* absl_nullable find(Map& employees, std::string_view name);
//
// void g(Map& employees) {
// Employee *e = find(employees, "Pat");
@@ -135,36 +168,64 @@
// ...
// };
//
-// Note: For the time being, nullability-compatible classes should additionally
-// be marked with an `absl_nullability_compatible` nested type (this will soon
-// be deprecated). The actual definition of this inner type is not relevant as
-// it is used merely as a marker. It is common to use a using declaration of
-// `absl_nullability_compatible` set to void.
-//
-// // Example:
-// struct MyPtr {
-// using absl_nullability_compatible = void;
-// ...
-// };
+// Note: Compilers that don't support the `nullability_on_classes` feature will
+// allow nullability annotations to be applied to any type, not just ones
+// marked with `ABSL_NULLABILITY_COMPATIBLE`.
//
// DISCLAIMER:
// ===========================================================================
// These nullability annotations are primarily a human readable signal about the
// intended contract of the pointer. They are not *types* and do not currently
// provide any correctness guarantees. For example, a pointer annotated as
-// `Nonnull<T*>` is *not guaranteed* to be non-null, and the compiler won't
-// alert or prevent assignment of a `Nullable<T*>` to a `Nonnull<T*>`.
+// `absl_nonnull` is *not guaranteed* to be non-null, and the compiler won't
+// alert or prevent assignment of a `T* absl_nullable` to a `T* absl_nonnull`.
// ===========================================================================
#ifndef ABSL_BASE_NULLABILITY_H_
#define ABSL_BASE_NULLABILITY_H_
#include "absl/base/config.h"
-#include "absl/base/internal/nullability_impl.h"
+#include "absl/base/internal/nullability_deprecated.h"
-namespace absl {
-ABSL_NAMESPACE_BEGIN
+// ABSL_POINTERS_DEFAULT_NONNULL
+//
+// This macro specifies that all unannotated pointer types within the given
+// file are designated as nonnull (instead of the default "unknown"). This macro
+// exists as a standalone statement and applies default nonnull behavior to all
+// subsequent pointers; as a result, place this macro as the first non-comment,
+// non-`#include` line in a file.
+//
+// Example:
+//
+// #include "absl/base/nullability.h"
+//
+// ABSL_POINTERS_DEFAULT_NONNULL
+//
+// void FillMessage(Message *m); // implicitly non-null
+// T* absl_nullable GetNullablePtr(); // explicitly nullable
+// T* absl_nullability_unknown GetUnknownPtr(); // explicitly unknown
+//
+// The macro can be safely used in header files – it will not affect any files
+// that include it.
+//
+// In files with the macro, plain `T*` syntax means `T* absl_nonnull`, and the
+// exceptions (`absl_nullable` and `absl_nullability_unknown`) must be marked
+// explicitly. The same holds, correspondingly, for smart pointer types.
+//
+// For comparison, without the macro, all unannotated pointers would default to
+// unknown, and otherwise require explicit annotations to change this behavior:
+//
+// #include "absl/base/nullability.h"
+//
+// void FillMessage(Message* absl_nonnull m); // explicitly non-null
+// T* absl_nullable GetNullablePtr(); // explicitly nullable
+// T* GetUnknownPtr(); // implicitly unknown
+//
+// No-op except for being a human readable signal.
+#define ABSL_POINTERS_DEFAULT_NONNULL
-// absl::Nonnull
+#if defined(__clang__) && !defined(__OBJC__) && \
+ ABSL_HAVE_FEATURE(nullability_on_classes)
+// absl_nonnull (default with `ABSL_POINTERS_DEFAULT_NONNULL`)
//
// The indicated pointer is never null. It is the responsibility of the provider
// of this pointer across an API boundary to ensure that the pointer is never
@@ -174,13 +235,12 @@
// Example:
//
// // `employee` is designated as not null.
-// void PaySalary(absl::Nonnull<Employee *> employee) {
+// void PaySalary(Employee* absl_nonnull employee) {
// pay(*employee); // OK to dereference
// }
-template <typename T>
-using Nonnull = nullability_internal::NonnullImpl<T>;
+#define absl_nonnull _Nonnull
-// absl::Nullable
+// absl_nullable
//
// The indicated pointer may, by design, be either null or non-null. Consumers
// of this pointer across an API boundary should perform a `nullptr` check
@@ -189,15 +249,14 @@
// Example:
//
// // `employee` may be null.
-// void PaySalary(absl::Nullable<Employee *> employee) {
+// void PaySalary(Employee* absl_nullable employee) {
// if (employee != nullptr) {
// Pay(*employee); // OK to dereference
// }
// }
-template <typename T>
-using Nullable = nullability_internal::NullableImpl<T>;
+#define absl_nullable _Nullable
-// absl::NullabilityUnknown (default)
+// absl_nullability_unknown (default without `ABSL_POINTERS_DEFAULT_NONNULL`)
//
// The indicated pointer has not yet been determined to be definitively
// "non-null" or "nullable." Providers of such pointers across API boundaries
@@ -205,17 +264,18 @@
// Consumers of these pointers across an API boundary should treat such pointers
// with the same caution they treat currently unannotated pointers. Most
// existing code will have "unknown" pointers, which should eventually be
-// migrated into one of the above two nullability states: `Nonnull<T>` or
-// `Nullable<T>`.
+// migrated into one of the above two nullability states: `absl_nonnull` or
+// `absl_nullable`.
//
-// NOTE: Because this annotation is the global default state, unannotated
-// pointers are assumed to have "unknown" semantics. This assumption is designed
-// to minimize churn and reduce clutter within the codebase.
+// NOTE: For files that do not specify `ABSL_POINTERS_DEFAULT_NONNULL`,
+// because this annotation is the global default state, unannotated pointers are
+// are assumed to have "unknown" semantics. This assumption is designed to
+// minimize churn and reduce clutter within the codebase.
//
// Example:
//
// // `employee`s nullability state is unknown.
-// void PaySalary(absl::NullabilityUnknown<Employee *> employee) {
+// void PaySalary(Employee* absl_nullability_unknown employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
//
@@ -226,11 +286,15 @@
// void PaySalary(Employee* employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
-template <typename T>
-using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl<T>;
-
-ABSL_NAMESPACE_END
-} // namespace absl
+#define absl_nullability_unknown _Null_unspecified
+#else
+// No-op for non-Clang compilers or Objective-C.
+#define absl_nonnull
+// No-op for non-Clang compilers or Objective-C.
+#define absl_nullable
+// No-op for non-Clang compilers or Objective-C.
+#define absl_nullability_unknown
+#endif
// ABSL_NULLABILITY_COMPATIBLE
//
@@ -241,6 +305,10 @@
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
// ...
// };
+//
+// Note: Compilers that don't support the `nullability_on_classes` feature will
+// allow nullability annotations to be applied to any type, not just ones marked
+// with `ABSL_NULLABILITY_COMPATIBLE`.
#if ABSL_HAVE_FEATURE(nullability_on_classes)
#define ABSL_NULLABILITY_COMPATIBLE _Nullable
#else
diff --git a/absl/base/nullability_default_nonnull_test.cc b/absl/base/nullability_default_nonnull_test.cc
new file mode 100644
index 0000000..bd5b483
--- /dev/null
+++ b/absl/base/nullability_default_nonnull_test.cc
@@ -0,0 +1,44 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cassert>
+
+#include "gtest/gtest.h"
+#include "absl/base/nullability.h"
+
+ABSL_POINTERS_DEFAULT_NONNULL
+
+namespace {
+
+void FuncWithDefaultNonnullArg(int* /*arg*/) {}
+template <typename T>
+void FuncWithDeducedDefaultNonnullArg(T* /*arg*/) {}
+
+TEST(DefaultNonnullTest, NonnullArgument) {
+ int var = 0;
+ FuncWithDefaultNonnullArg(&var);
+ FuncWithDeducedDefaultNonnullArg<int>(&var);
+}
+
+int* FuncWithDefaultNonnullReturn() {
+ static int var = 0;
+ return &var;
+}
+
+TEST(DefaultNonnullTest, NonnullReturn) {
+ auto var = FuncWithDefaultNonnullReturn();
+ (void)var;
+}
+
+} // namespace
diff --git a/absl/base/nullability_test.cc b/absl/base/nullability_test.cc
index 028ea6c..bccc388 100644
--- a/absl/base/nullability_test.cc
+++ b/absl/base/nullability_test.cc
@@ -16,15 +16,89 @@
#include <cassert>
#include <memory>
+#include <type_traits>
#include <utility>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
namespace {
+namespace macro_annotations {
+void funcWithNonnullArg(int* absl_nonnull /*arg*/) {}
+template <typename T>
+void funcWithDeducedNonnullArg(T* absl_nonnull /*arg*/) {}
+
+TEST(NonnullTest, NonnullArgument) {
+ int var = 0;
+ funcWithNonnullArg(&var);
+ funcWithDeducedNonnullArg(&var);
+}
+
+int* absl_nonnull funcWithNonnullReturn() {
+ static int var = 0;
+ return &var;
+}
+
+TEST(NonnullTest, NonnullReturn) {
+ auto var = funcWithNonnullReturn();
+ (void)var;
+}
+
+TEST(PassThroughTest, PassesThroughRawPointerToInt) {
+ EXPECT_TRUE((std::is_same<int* absl_nonnull, int*>::value));
+ EXPECT_TRUE((std::is_same<int* absl_nullable, int*>::value));
+ EXPECT_TRUE((std::is_same<int* absl_nullability_unknown, int*>::value));
+}
+
+TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
+ EXPECT_TRUE((std::is_same<void* absl_nonnull, void*>::value));
+ EXPECT_TRUE((std::is_same<void* absl_nullable, void*>::value));
+ EXPECT_TRUE((std::is_same<void* absl_nullability_unknown, void*>::value));
+}
+
+TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
+ using T = std::unique_ptr<int>;
+ EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
+}
+
+TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
+ using T = std::shared_ptr<int>;
+ EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
+}
+
+TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
+ using T = std::shared_ptr<void>;
+ EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
+}
+
+TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
+ using T = decltype(&std::pair<int, int>::first);
+ EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
+}
+
+TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
+ using T = decltype(&std::unique_ptr<int>::reset);
+ EXPECT_TRUE((std::is_same<absl_nonnull T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullable T, T>::value));
+ EXPECT_TRUE((std::is_same<absl_nullability_unknown T, T>::value));
+}
+} // namespace macro_annotations
+
+// Allow testing of the deprecated type alias annotations.
+ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
+
using ::absl::Nonnull;
using ::absl::NullabilityUnknown;
using ::absl::Nullable;
+namespace type_alias_annotations {
void funcWithNonnullArg(Nonnull<int*> /*arg*/) {}
template <typename T>
@@ -93,6 +167,7 @@
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
+} // namespace type_alias_annotations
} // namespace
// Nullable ADL lookup test
@@ -126,4 +201,6 @@
EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
}
+
+ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
} // namespace
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 3aa66e1..429ea9c 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -25,6 +25,8 @@
// new code that requires C compatibility or assume C compatibility will remain
// indefinitely.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_BASE_OPTIMIZATION_H_
#define ABSL_BASE_OPTIMIZATION_H_
@@ -271,20 +273,14 @@
#elif defined(_MSC_VER)
#define ABSL_ASSUME(cond) __assume(cond)
#elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
-#define ABSL_ASSUME(cond) \
- do { \
- if (!(cond)) std::unreachable(); \
- } while (false)
+#define ABSL_ASSUME(cond) ((cond) ? void() : std::unreachable())
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
-#define ABSL_ASSUME(cond) \
- do { \
- if (!(cond)) __builtin_unreachable(); \
- } while (false)
+#define ABSL_ASSUME(cond) ((cond) ? void() : __builtin_unreachable())
+#elif ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+// Unimplemented. Uses the same definition as ABSL_ASSERT in the NDEBUG case.
+#define ABSL_ASSUME(expr) (decltype((expr) ? void() : void())())
#else
-#define ABSL_ASSUME(cond) \
- do { \
- static_cast<void>(false && (cond)); \
- } while (false)
+#define ABSL_ASSUME(expr) (false ? ((expr) ? void() : void()) : void())
#endif
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
diff --git a/absl/base/optimization_test.cc b/absl/base/optimization_test.cc
index e83369f..b47b11a 100644
--- a/absl/base/optimization_test.cc
+++ b/absl/base/optimization_test.cc
@@ -88,9 +88,9 @@
EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value));
}
-class ImplictlyConvertibleToBool {
+class ImplicitlyConvertibleToBool {
public:
- explicit ImplictlyConvertibleToBool(bool value) : value_(value) {}
+ explicit ImplicitlyConvertibleToBool(bool value) : value_(value) {}
operator bool() const { // NOLINT(google-explicit-constructor)
return value_;
}
@@ -100,17 +100,17 @@
};
TEST(PredictTest, ImplicitBoolConversion) {
- const ImplictlyConvertibleToBool is_true(true);
- const ImplictlyConvertibleToBool is_false(false);
+ const ImplicitlyConvertibleToBool is_true(true);
+ const ImplicitlyConvertibleToBool is_false(false);
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
}
-class ExplictlyConvertibleToBool {
+class ExplicitlyConvertibleToBool {
public:
- explicit ExplictlyConvertibleToBool(bool value) : value_(value) {}
+ explicit ExplicitlyConvertibleToBool(bool value) : value_(value) {}
explicit operator bool() const { return value_; }
private:
@@ -118,12 +118,24 @@
};
TEST(PredictTest, ExplicitBoolConversion) {
- const ExplictlyConvertibleToBool is_true(true);
- const ExplictlyConvertibleToBool is_false(false);
+ const ExplicitlyConvertibleToBool is_true(true);
+ const ExplicitlyConvertibleToBool is_false(false);
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
}
+// This verifies that ABSL_ASSUME compiles in a variety of contexts.
+// It does not test optimization.
+TEST(AbslAssume, Compiles) {
+ int x = 0;
+ ABSL_ASSUME(x >= 0);
+ EXPECT_EQ(x, 0);
+
+ // https://github.com/abseil/abseil-cpp/issues/1814
+ ABSL_ASSUME(x >= 0), (x >= 0) ? ++x : --x;
+ EXPECT_EQ(x, 1);
+}
+
} // namespace
diff --git a/absl/base/options.h b/absl/base/options.h
index 3ea6045..cba75b9 100644
--- a/absl/base/options.h
+++ b/absl/base/options.h
@@ -64,65 +64,14 @@
// proper Abseil implementation at compile-time, which will not be sufficient
// to guarantee ABI stability to package managers.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_BASE_OPTIONS_H_
#define ABSL_BASE_OPTIONS_H_
// -----------------------------------------------------------------------------
// Type Compatibility Options
// -----------------------------------------------------------------------------
-//
-// ABSL_OPTION_USE_STD_ANY
-//
-// This option controls whether absl::any is implemented as an alias to
-// std::any, or as an independent implementation.
-//
-// A value of 0 means to use Abseil's implementation. This requires only C++11
-// support, and is expected to work on every toolchain we support.
-//
-// A value of 1 means to use an alias to std::any. This requires that all code
-// using Abseil is built in C++17 mode or later.
-//
-// A value of 2 means to detect the C++ version being used to compile Abseil,
-// and use an alias only if a working std::any is available. This option is
-// useful when you are building your entire program, including all of its
-// dependencies, from source. It should not be used otherwise -- for example,
-// if you are distributing Abseil in a binary package manager -- since in
-// mode 2, absl::any will name a different type, with a different mangled name
-// and binary layout, depending on the compiler flags passed by the end user.
-// For more info, see https://abseil.io/about/design/dropin-types.
-//
-// User code should not inspect this macro. To check in the preprocessor if
-// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
-
-#define ABSL_OPTION_USE_STD_ANY 1
-
-
-// ABSL_OPTION_USE_STD_OPTIONAL
-//
-// This option controls whether absl::optional is implemented as an alias to
-// std::optional, or as an independent implementation.
-//
-// A value of 0 means to use Abseil's implementation. This requires only C++11
-// support, and is expected to work on every toolchain we support.
-//
-// A value of 1 means to use an alias to std::optional. This requires that all
-// code using Abseil is built in C++17 mode or later.
-//
-// A value of 2 means to detect the C++ version being used to compile Abseil,
-// and use an alias only if a working std::optional is available. This option
-// is useful when you are building your program from source. It should not be
-// used otherwise -- for example, if you are distributing Abseil in a binary
-// package manager -- since in mode 2, absl::optional will name a different
-// type, with a different mangled name and binary layout, depending on the
-// compiler flags passed by the end user. For more info, see
-// https://abseil.io/about/design/dropin-types.
-
-// User code should not inspect this macro. To check in the preprocessor if
-// absl::optional is a typedef of std::optional, use the feature macro
-// ABSL_USES_STD_OPTIONAL.
-
-#define ABSL_OPTION_USE_STD_OPTIONAL 1
-
// ABSL_OPTION_USE_STD_STRING_VIEW
//
@@ -150,32 +99,6 @@
#define ABSL_OPTION_USE_STD_STRING_VIEW 1
-// ABSL_OPTION_USE_STD_VARIANT
-//
-// This option controls whether absl::variant is implemented as an alias to
-// std::variant, or as an independent implementation.
-//
-// A value of 0 means to use Abseil's implementation. This requires only C++11
-// support, and is expected to work on every toolchain we support.
-//
-// A value of 1 means to use an alias to std::variant. This requires that all
-// code using Abseil is built in C++17 mode or later.
-//
-// A value of 2 means to detect the C++ version being used to compile Abseil,
-// and use an alias only if a working std::variant is available. This option
-// is useful when you are building your program from source. It should not be
-// used otherwise -- for example, if you are distributing Abseil in a binary
-// package manager -- since in mode 2, absl::variant will name a different
-// type, with a different mangled name and binary layout, depending on the
-// compiler flags passed by the end user. For more info, see
-// https://abseil.io/about/design/dropin-types.
-//
-// User code should not inspect this macro. To check in the preprocessor if
-// absl::variant is a typedef of std::variant, use the feature macro
-// ABSL_USES_STD_VARIANT.
-
-#define ABSL_OPTION_USE_STD_VARIANT 1
-
// ABSL_OPTION_USE_STD_ORDERING
//
// This option controls whether absl::{partial,weak,strong}_ordering are
@@ -226,7 +149,11 @@
// allowed.
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
-#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20240722
+#ifdef ANDROID_DISABLE_TLS_FOR_LINKER
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512_notls
+#else
+#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20250512
+#endif
// ABSL_OPTION_HARDENED
//
@@ -235,7 +162,10 @@
//
// A value of 0 means that "hardened" mode is not enabled.
//
-// A value of 1 means that "hardened" mode is enabled.
+// A value of 1 means that "hardened" mode is enabled with all checks.
+//
+// A value of 2 means that "hardened" mode is partially enabled, with
+// only a subset of checks chosen to minimize performance impact.
//
// Hardened builds have additional security checks enabled when `NDEBUG` is
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
index 372e848..f84944c 100644
--- a/absl/base/policy_checks.h
+++ b/absl/base/policy_checks.h
@@ -21,6 +21,8 @@
// reported with `#error`. This enforcement is best effort, so successfully
// compiling this header does not guarantee a supported configuration.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_BASE_POLICY_CHECKS_H_
#define ABSL_BASE_POLICY_CHECKS_H_
@@ -69,15 +71,15 @@
// C++ Version Check
// -----------------------------------------------------------------------------
-// Enforce C++14 as the minimum.
+// Enforce C++17 as the minimum.
#if defined(_MSVC_LANG)
-#if _MSVC_LANG < 201402L
-#error "C++ versions less than C++14 are not supported."
-#endif // _MSVC_LANG < 201402L
+#if _MSVC_LANG < 201703L
+#error "C++ versions less than C++17 are not supported."
+#endif // _MSVC_LANG < 201703L
#elif defined(__cplusplus)
-#if __cplusplus < 201402L
-#error "C++ versions less than C++14 are not supported."
-#endif // __cplusplus < 201402L
+#if __cplusplus < 201703L
+#error "C++ versions less than C++17 are not supported."
+#endif // __cplusplus < 201703L
#endif
// -----------------------------------------------------------------------------
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc
index 3d30bd3..f4f3445 100644
--- a/absl/base/raw_logging_test.cc
+++ b/absl/base/raw_logging_test.cc
@@ -35,16 +35,35 @@
ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1);
}
+TEST(RawLoggingCompilationTest, LogWithNulls) {
+ ABSL_RAW_LOG(INFO, "RAW INFO: %s%c%s", "Hello", 0, "World");
+}
+
TEST(RawLoggingCompilationTest, PassingCheck) {
ABSL_RAW_CHECK(true, "RAW CHECK");
}
+TEST(RawLoggingCompilationTest, DebugLog) {
+ ABSL_RAW_DLOG(INFO, "RAW DLOG: %d", 1);
+}
+
+TEST(RawLoggingCompilationTest, PassingDebugCheck) {
+ ABSL_RAW_DCHECK(true, "failure message");
+}
+
// Not all platforms support output from raw log, so we don't verify any
// particular output for RAW check failures (expecting the empty string
// accomplishes this). This test is primarily a compilation test, but we
// are verifying process death when EXPECT_DEATH works for a platform.
const char kExpectedDeathOutput[] = "";
+#if !defined(NDEBUG) // if debug build
+TEST(RawLoggingDeathTest, FailingDebugCheck) {
+ EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_DCHECK(1 == 0, "explanation"),
+ kExpectedDeathOutput);
+}
+#endif // if debug build
+
TEST(RawLoggingDeathTest, FailingCheck) {
EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_CHECK(1 == 0, "explanation"),
kExpectedDeathOutput);
diff --git a/absl/cleanup/BUILD.bazel b/absl/cleanup/BUILD.bazel
index 984d571..d579781 100644
--- a/absl/cleanup/BUILD.bazel
+++ b/absl/cleanup/BUILD.bazel
@@ -36,7 +36,6 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- "//absl/base:base_internal",
"//absl/base:core_headers",
"//absl/utility",
],
@@ -67,7 +66,7 @@
":cleanup",
"//absl/base:config",
"//absl/utility",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/cleanup/CMakeLists.txt b/absl/cleanup/CMakeLists.txt
index f5af40b..eedf449 100644
--- a/absl/cleanup/CMakeLists.txt
+++ b/absl/cleanup/CMakeLists.txt
@@ -21,7 +21,6 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::core_headers
absl::utility
PUBLIC
diff --git a/absl/cleanup/cleanup.h b/absl/cleanup/cleanup.h
index 960ccd0..311e482 100644
--- a/absl/cleanup/cleanup.h
+++ b/absl/cleanup/cleanup.h
@@ -78,7 +78,7 @@
ABSL_NAMESPACE_BEGIN
template <typename Arg, typename Callback = void()>
-class ABSL_MUST_USE_RESULT Cleanup final {
+class [[nodiscard]] Cleanup final {
static_assert(cleanup_internal::WasDeduced<Arg>(),
"Explicit template parameters are not supported.");
@@ -115,10 +115,8 @@
// `absl::Cleanup c = /* callback */;`
//
// C++17 type deduction API for creating an instance of `absl::Cleanup`
-#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
template <typename Callback>
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
-#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
// `auto c = absl::MakeCleanup(/* callback */);`
//
diff --git a/absl/cleanup/cleanup_test.cc b/absl/cleanup/cleanup_test.cc
index 72d7ff2..52774d7 100644
--- a/absl/cleanup/cleanup_test.cc
+++ b/absl/cleanup/cleanup_test.cc
@@ -116,7 +116,6 @@
}
}
-#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
{
auto callback = TypeParam::AsCallback([] {});
@@ -186,7 +185,6 @@
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
}
-#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
TYPED_TEST(CleanupTest, BasicUsage) {
bool called = false;
diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h
index 2783fcb..4dd6f91 100644
--- a/absl/cleanup/internal/cleanup.h
+++ b/absl/cleanup/internal/cleanup.h
@@ -19,7 +19,6 @@
#include <type_traits>
#include <utility>
-#include "absl/base/internal/invoke.h"
#include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
#include "absl/utility/utility.h"
@@ -39,7 +38,7 @@
template <typename Callback>
constexpr bool ReturnsVoid() {
- return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
+ return (std::is_same<std::invoke_result_t<Callback>, void>::value);
}
template <typename Callback>
@@ -70,7 +69,7 @@
Storage& operator=(const Storage& other) = delete;
- void* GetCallbackBuffer() { return static_cast<void*>(+callback_buffer_); }
+ void* GetCallbackBuffer() { return static_cast<void*>(callback_buffer_); }
Callback& GetCallback() {
return *reinterpret_cast<Callback*>(GetCallbackBuffer());
@@ -89,7 +88,7 @@
private:
bool is_callback_engaged_;
- alignas(Callback) char callback_buffer_[sizeof(Callback)];
+ alignas(Callback) unsigned char callback_buffer_[sizeof(Callback)];
};
} // namespace cleanup_internal
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index b00c30f..61e816f 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -54,8 +54,8 @@
"//absl/types:any",
"//absl/types:optional",
"//absl/utility",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -70,7 +70,9 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
+ "//absl/base:iterator_traits_internal",
"//absl/base:throw_delegate",
+ "//absl/hash:weakly_mixed_integer",
"//absl/memory",
],
)
@@ -85,10 +87,11 @@
":test_allocator",
"//absl/base:config",
"//absl/base:exception_testing",
+ "//absl/base:iterator_traits_test_helper",
"//absl/hash:hash_testing",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -101,8 +104,8 @@
":fixed_array",
"//absl/base:config",
"//absl/base:exception_safety_testing",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -115,7 +118,7 @@
tags = ["benchmark"],
deps = [
":fixed_array",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -144,7 +147,9 @@
":inlined_vector_internal",
"//absl/algorithm",
"//absl/base:core_headers",
+ "//absl/base:iterator_traits_internal",
"//absl/base:throw_delegate",
+ "//absl/hash:weakly_mixed_integer",
"//absl/memory",
"//absl/meta:type_traits",
],
@@ -171,12 +176,13 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:exception_testing",
+ "//absl/base:iterator_traits_test_helper",
"//absl/hash:hash_testing",
"//absl/log:check",
"//absl/memory",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -192,7 +198,7 @@
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/strings",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -204,8 +210,8 @@
":inlined_vector",
"//absl/base:config",
"//absl/base:exception_safety_testing",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -229,8 +235,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":test_instance_tracker",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -275,8 +281,8 @@
"//absl/log:check",
"//absl/meta:type_traits",
"//absl/types:any",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -305,6 +311,7 @@
deps = [
":container_memory",
":flat_hash_set",
+ ":hash_container_defaults",
":hash_generator_testing",
":test_allocator",
":unordered_set_constructor_test",
@@ -312,11 +319,12 @@
":unordered_set_members_test",
":unordered_set_modifiers_test",
"//absl/base:config",
+ "//absl/hash",
"//absl/log:check",
"//absl/memory",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -352,8 +360,8 @@
":unordered_map_members_test",
":unordered_map_modifiers_test",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -390,8 +398,8 @@
":unordered_set_modifiers_test",
"//absl/base:config",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -420,8 +428,8 @@
"//absl/base:no_destructor",
"//absl/meta:type_traits",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -469,8 +477,8 @@
"//absl/strings",
"//absl/strings:cord",
"//absl/strings:cord_test_helpers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -486,6 +494,7 @@
"//absl/base:no_destructor",
"//absl/memory",
"//absl/meta:type_traits",
+ "//absl/random",
"//absl/strings",
],
)
@@ -509,8 +518,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_policy_testing",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -533,8 +542,8 @@
deps = [
":container_memory",
":hash_policy_traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -555,8 +564,8 @@
deps = [
":common_policy_traits",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -617,11 +626,12 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/profiling:sample_recorder",
+ "//absl/random",
"//absl/synchronization",
"//absl/synchronization:thread_pool",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -642,8 +652,8 @@
":hash_policy_traits",
":node_slot_policy",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -653,11 +663,13 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":common_policy_traits",
":container_memory",
":raw_hash_set",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:throw_delegate",
+ "//absl/meta:type_traits",
],
)
@@ -673,6 +685,40 @@
)
cc_library(
+ name = "hashtable_control_bytes",
+ hdrs = ["internal/hashtable_control_bytes.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/numeric:bits",
+ ],
+)
+
+cc_library(
+ name = "raw_hash_set_resize_impl",
+ hdrs = ["internal/raw_hash_set_resize_impl.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:config"],
+)
+
+cc_test(
+ name = "raw_hash_set_resize_impl_test",
+ srcs = ["internal/raw_hash_set_resize_impl_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":raw_hash_set_resize_impl",
+ "//absl/base:config",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_library(
name = "raw_hash_set",
srcs = ["internal/raw_hash_set.cc"],
hdrs = ["internal/raw_hash_set.h"],
@@ -680,18 +726,25 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":common",
+ ":common_policy_traits",
":compressed_tuple",
":container_memory",
+ ":hash_function_defaults",
":hash_policy_traits",
+ ":hashtable_control_bytes",
":hashtable_debug_hooks",
":hashtablez_sampler",
+ ":raw_hash_set_resize_impl",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
"//absl/base:endian",
+ "//absl/base:iterator_traits_internal",
"//absl/base:prefetch",
"//absl/base:raw_logging_internal",
+ "//absl/functional:function_ref",
"//absl/hash",
+ "//absl/hash:weakly_mixed_integer",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/numeric:bits",
@@ -715,10 +768,12 @@
":flat_hash_set",
":hash_function_defaults",
":hash_policy_testing",
+ ":hashtable_control_bytes",
":hashtable_debug",
":hashtablez_sampler",
":node_hash_set",
":raw_hash_set",
+ ":raw_hash_set_resize_impl",
":test_allocator",
":test_instance_tracker",
"//absl/base",
@@ -731,9 +786,12 @@
"//absl/log:check",
"//absl/memory",
"//absl/meta:type_traits",
+ "//absl/numeric:int128",
+ "//absl/random",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/types:optional",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -752,7 +810,7 @@
"//absl/base:raw_logging_internal",
"//absl/random",
"//absl/strings:str_format",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -791,8 +849,8 @@
":raw_hash_set",
":tracked",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -826,8 +884,8 @@
"//absl/log:check",
"//absl/types:span",
"//absl/utility",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -843,7 +901,7 @@
":layout",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -867,7 +925,7 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -880,7 +938,7 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -893,7 +951,7 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -907,7 +965,7 @@
":hash_generator_testing",
":hash_policy_testing",
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -919,7 +977,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -931,7 +989,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -944,7 +1002,7 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -957,7 +1015,7 @@
deps = [
":hash_generator_testing",
":hash_policy_testing",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -972,8 +1030,8 @@
":unordered_set_lookup_test",
":unordered_set_members_test",
":unordered_set_modifiers_test",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -988,8 +1046,8 @@
":unordered_map_lookup_test",
":unordered_map_members_test",
":unordered_map_modifiers_test",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1003,10 +1061,11 @@
deps = [
":flat_hash_map",
":flat_hash_set",
+ ":hashtablez_sampler",
":node_hash_map",
":node_hash_set",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1033,6 +1092,7 @@
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate",
+ "//absl/hash:weakly_mixed_integer",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/strings",
@@ -1087,8 +1147,8 @@
"//absl/strings",
"//absl/types:compare",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1117,7 +1177,6 @@
"//absl/strings:cord",
"//absl/strings:str_format",
"//absl/time",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 25831d5..d8cd7d0 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -41,6 +41,7 @@
absl::strings
absl::throw_delegate
absl::type_traits
+ absl::weakly_mixed_integer
)
# Internal-only target, do not depend on directly.
@@ -131,8 +132,10 @@
absl::config
absl::core_headers
absl::dynamic_annotations
+ absl::iterator_traits_internal
absl::throw_delegate
absl::memory
+ absl::weakly_mixed_integer
PUBLIC
)
@@ -148,6 +151,7 @@
absl::config
absl::exception_testing
absl::hash_testing
+ absl::iterator_traits_test_helper_internal
absl::memory
absl::test_allocator
GTest::gmock_main
@@ -200,6 +204,7 @@
absl::throw_delegate
absl::memory
absl::type_traits
+ absl::weakly_mixed_integer
PUBLIC
)
@@ -350,6 +355,8 @@
absl::config
absl::container_memory
absl::flat_hash_set
+ absl::hash
+ absl::hash_container_defaults
absl::hash_generator_testing
absl::memory
absl::strings
@@ -536,6 +543,7 @@
absl::memory
absl::meta
absl::no_destructor
+ absl::random_random
absl::strings
TESTONLY
)
@@ -651,6 +659,7 @@
DEPS
absl::config
absl::hashtablez_sampler
+ absl::random_random
GTest::gmock_main
)
@@ -716,9 +725,11 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
+ absl::common_policy_traits
absl::container_memory
absl::core_headers
absl::raw_hash_set
+ absl::type_traits
absl::throw_delegate
PUBLIC
)
@@ -738,6 +749,21 @@
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
+ hashtable_control_bytes
+ HDRS
+ "internal/hashtable_control_bytes.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bits
+ absl::config
+ absl::core_headers
+ absl::endian
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
raw_hash_set
HDRS
"internal/raw_hash_set.h"
@@ -747,6 +773,7 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::bits
+ absl::common_policy_traits
absl::compressed_tuple
absl::config
absl::container_common
@@ -754,16 +781,21 @@
absl::core_headers
absl::dynamic_annotations
absl::endian
+ absl::function_ref
absl::hash
+ absl::hash_function_defaults
absl::hash_policy_traits
+ absl::hashtable_control_bytes
absl::hashtable_debug_hooks
absl::hashtablez_sampler
+ absl::iterator_traits_internal
absl::memory
absl::meta
absl::optional
absl::prefetch
absl::raw_logging_internal
absl::utility
+ absl::weakly_mixed_integer
PUBLIC
)
@@ -788,10 +820,13 @@
absl::hash_policy_testing
absl::hashtable_debug
absl::hashtablez_sampler
+ absl::int128
absl::log
absl::memory
absl::node_hash_set
+ absl::optional
absl::prefetch
+ absl::random_random
absl::raw_hash_set
absl::strings
absl::test_allocator
@@ -800,6 +835,32 @@
GTest::gmock_main
)
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ raw_hash_set_resize_impl
+ HDRS
+ "internal/raw_hash_set_resize_impl.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ raw_hash_set_resize_impl_test
+ SRCS
+ "internal/raw_hash_set_resize_impl_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::config
+ absl::raw_hash_set_resize_impl
+ GTest::gmock_main
+)
+
absl_cc_test(
NAME
raw_hash_set_allocator_test
@@ -1023,5 +1084,6 @@
absl::flat_hash_set
absl::node_hash_map
absl::node_hash_set
+ absl::hashtablez_sampler
GTest::gmock_main
)
diff --git a/absl/container/btree_benchmark.cc b/absl/container/btree_benchmark.cc
index 0d26fd4..ee4efbd 100644
--- a/absl/container/btree_benchmark.cc
+++ b/absl/container/btree_benchmark.cc
@@ -26,7 +26,6 @@
#include <unordered_set>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/algorithm/container.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/container/btree_map.h"
@@ -42,6 +41,7 @@
#include "absl/strings/cord.h"
#include "absl/strings/str_format.h"
#include "absl/time/time.h"
+#include "benchmark/benchmark.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -406,22 +406,18 @@
template <typename T>
void BM_FwdIter(benchmark::State& state) {
using V = typename remove_pair_const<typename T::value_type>::type;
- using R = typename T::value_type const*;
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
T container(values.begin(), values.end());
auto iter = container.end();
- R r = nullptr;
-
while (state.KeepRunning()) {
if (iter == container.end()) iter = container.begin();
- r = &(*iter);
- ++iter;
+ auto *v = &(*iter);
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(++iter);
}
-
- benchmark::DoNotOptimize(r);
}
// Benchmark random range-construction of a container.
@@ -735,7 +731,7 @@
BIG_TYPE_PTR_BENCHMARKS(32);
-void BM_BtreeSet_IteratorSubtraction(benchmark::State& state) {
+void BM_BtreeSet_IteratorDifference(benchmark::State& state) {
absl::InsecureBitGen bitgen;
std::vector<int> vec;
// Randomize the set's insertion order so the nodes aren't all full.
@@ -756,6 +752,52 @@
}
}
+BENCHMARK(BM_BtreeSet_IteratorDifference)->Range(1 << 10, 1 << 20);
+
+void BM_BtreeSet_IteratorAddition(benchmark::State& state) {
+ absl::InsecureBitGen bitgen;
+ std::vector<int> vec;
+ // Randomize the set's insertion order so the nodes aren't all full.
+ vec.reserve(static_cast<size_t>(state.range(0)));
+ for (int i = 0; i < state.range(0); ++i) vec.push_back(i);
+ absl::c_shuffle(vec, bitgen);
+
+ absl::btree_set<int> set;
+ for (int i : vec) set.insert(i);
+
+ size_t distance = absl::Uniform(bitgen, 0u, set.size());
+ while (state.KeepRunningBatch(distance)) {
+ // Let the increment go all the way to the `end` iterator.
+ const size_t begin =
+ absl::Uniform(absl::IntervalClosed, bitgen, 0u, set.size() - distance);
+ auto it = set.find(static_cast<int>(begin));
+ benchmark::DoNotOptimize(it += static_cast<int>(distance));
+ distance = absl::Uniform(bitgen, 0u, set.size());
+ }
+}
+
+BENCHMARK(BM_BtreeSet_IteratorAddition)->Range(1 << 10, 1 << 20);
+
+void BM_BtreeSet_IteratorSubtraction(benchmark::State& state) {
+ absl::InsecureBitGen bitgen;
+ std::vector<int> vec;
+ // Randomize the set's insertion order so the nodes aren't all full.
+ vec.reserve(static_cast<size_t>(state.range(0)));
+ for (int i = 0; i < state.range(0); ++i) vec.push_back(i);
+ absl::c_shuffle(vec, bitgen);
+
+ absl::btree_set<int> set;
+ for (int i : vec) set.insert(i);
+
+ size_t distance = absl::Uniform(bitgen, 0u, set.size());
+ while (state.KeepRunningBatch(distance)) {
+ size_t end = absl::Uniform(bitgen, distance, set.size());
+ auto it = set.find(static_cast<int>(end));
+ benchmark::DoNotOptimize(it -= static_cast<int>(distance));
+ distance = absl::Uniform(bitgen, 0u, set.size());
+ }
+}
+
BENCHMARK(BM_BtreeSet_IteratorSubtraction)->Range(1 << 10, 1 << 20);
} // namespace
diff --git a/absl/container/btree_map.h b/absl/container/btree_map.h
index b959b67..32a82ef 100644
--- a/absl/container/btree_map.h
+++ b/absl/container/btree_map.h
@@ -47,8 +47,10 @@
// iterator at the current position. Another important difference is that
// key-types must be copy-constructible.
//
-// Another API difference is that btree iterators can be subtracted, and this
-// is faster than using std::distance.
+// There are other API differences: first, btree iterators can be subtracted,
+// and this is faster than using `std::distance`. Additionally, btree
+// iterators can be advanced via `operator+=` and `operator-=`, which is faster
+// than using `std::advance`.
//
// B-tree maps are not exception-safe.
@@ -87,7 +89,7 @@
//
template <typename Key, typename Value, typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value>>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER btree_map
+class ABSL_ATTRIBUTE_OWNER btree_map
: public container_internal::btree_map_container<
container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
@@ -525,7 +527,7 @@
//
template <typename Key, typename Value, typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value>>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER btree_multimap
+class ABSL_ATTRIBUTE_OWNER btree_multimap
: public container_internal::btree_multimap_container<
container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
diff --git a/absl/container/btree_set.h b/absl/container/btree_set.h
index 986d27d..16181de 100644
--- a/absl/container/btree_set.h
+++ b/absl/container/btree_set.h
@@ -46,8 +46,10 @@
// reason, `insert()`, `erase()`, and `extract_and_get_next()` return a valid
// iterator at the current position.
//
-// Another API difference is that btree iterators can be subtracted, and this
-// is faster than using std::distance.
+// There are other API differences: first, btree iterators can be subtracted,
+// and this is faster than using `std::distance`. Additionally, btree
+// iterators can be advanced via `operator+=` and `operator-=`, which is faster
+// than using `std::advance`.
//
// B-tree sets are not exception-safe.
@@ -89,7 +91,7 @@
//
template <typename Key, typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER btree_set
+class ABSL_ATTRIBUTE_OWNER btree_set
: public container_internal::btree_set_container<
container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256,
@@ -445,7 +447,7 @@
//
template <typename Key, typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER btree_multiset
+class ABSL_ATTRIBUTE_OWNER btree_multiset
: public container_internal::btree_multiset_container<
container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256,
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc
index d7102fe..1d2c2a6 100644
--- a/absl/container/btree_test.cc
+++ b/absl/container/btree_test.cc
@@ -2674,8 +2674,6 @@
}
#endif
-// This test requires std::launder for mutable key access in node handles.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
TEST(Btree, NodeHandleMutableKeyAccess) {
{
absl::btree_map<std::string, std::string> map;
@@ -2701,7 +2699,6 @@
EXPECT_THAT(map, ElementsAre(Pair("key", "mapped")));
}
}
-#endif
struct MultiKey {
int i1;
@@ -2949,6 +2946,7 @@
TEST(Btree, ConstructImplicitlyWithUnadaptedComparator) {
absl::btree_set<MultiKey, MultiKeyComp> set = {{}, MultiKeyComp{}};
+ EXPECT_TRUE(set.empty());
}
TEST(Btree, InvalidComparatorsCaught) {
@@ -3353,7 +3351,7 @@
set.insert(0);
}
-TEST(Btree, IteratorSubtraction) {
+TEST(Btree, IteratorDifference) {
absl::BitGen bitgen;
std::vector<int> vec;
// Randomize the set's insertion order so the nodes aren't all full.
@@ -3371,6 +3369,94 @@
}
}
+TEST(Btree, IteratorAddition) {
+ absl::BitGen bitgen;
+ std::vector<int> vec;
+
+ // Randomize the set's insertion order so the nodes aren't all full.
+ constexpr int kSetSize = 1000000;
+ for (int i = 0; i < kSetSize; ++i) vec.push_back(i);
+ absl::c_shuffle(vec, bitgen);
+
+ absl::btree_set<int> set;
+ for (int i : vec) set.insert(i);
+
+ for (int i = 0; i < 1000; ++i) {
+ int begin = absl::Uniform(bitgen, 0, kSetSize);
+ int end = absl::Uniform(bitgen, begin, kSetSize);
+ ASSERT_LE(begin, end);
+
+ auto it = set.find(begin);
+ it += end - begin;
+ ASSERT_EQ(it, set.find(end)) << end;
+
+ it += begin - end;
+ ASSERT_EQ(it, set.find(begin)) << begin;
+ }
+}
+
+TEST(Btree, IteratorAdditionOutOfBounds) {
+ const absl::btree_set<int> set({5});
+
+ auto it = set.find(5);
+
+ auto forward = it;
+ forward += 1;
+ EXPECT_EQ(forward, set.end());
+
+ auto backward = it;
+ EXPECT_EQ(backward, set.begin());
+
+ if (IsAssertEnabled()) {
+ EXPECT_DEATH(forward += 1, "n == 0");
+ EXPECT_DEATH(backward += -1, "position >= node->start");
+ }
+}
+
+TEST(Btree, IteratorSubtraction) {
+ absl::BitGen bitgen;
+ std::vector<int> vec;
+
+ // Randomize the set's insertion order so the nodes aren't all full.
+ constexpr int kSetSize = 1000000;
+ for (int i = 0; i < kSetSize; ++i) vec.push_back(i);
+ absl::c_shuffle(vec, bitgen);
+
+ absl::btree_set<int> set;
+ for (int i : vec) set.insert(i);
+
+ for (int i = 0; i < 1000; ++i) {
+ int begin = absl::Uniform(bitgen, 0, kSetSize);
+ int end = absl::Uniform(bitgen, begin, kSetSize);
+ ASSERT_LE(begin, end);
+
+ auto it = set.find(end);
+ it -= end - begin;
+ ASSERT_EQ(it, set.find(begin)) << begin;
+
+ it -= begin - end;
+ ASSERT_EQ(it, set.find(end)) << end;
+ }
+}
+
+TEST(Btree, IteratorSubtractionOutOfBounds) {
+ const absl::btree_set<int> set({5});
+
+ auto it = set.find(5);
+
+ auto backward = it;
+ EXPECT_EQ(backward, set.begin());
+
+ auto forward = it;
+ forward -= -1;
+ EXPECT_EQ(forward, set.end());
+
+ if (IsAssertEnabled()) {
+ EXPECT_DEATH(backward -= 1, "position >= node->start");
+ EXPECT_DEATH(forward -= -1, "n == 0");
+ }
+}
+
TEST(Btree, DereferencingEndIterator) {
if (!IsAssertEnabled()) GTEST_SKIP() << "Assertions not enabled.";
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index 9f1c813..6c238fc 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -41,13 +41,16 @@
#include <type_traits>
#include "absl/algorithm/algorithm.h"
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/iterator_traits.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/compressed_tuple.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/memory/memory.h"
namespace absl {
@@ -74,7 +77,7 @@
// `std::vector`.
template <typename T, size_t N = kFixedArrayUseDefault,
typename A = std::allocator<T>>
-class FixedArray {
+class ABSL_ATTRIBUTE_WARN_UNUSED FixedArray {
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
"Arrays with unknown bounds cannot be used with FixedArray.");
@@ -84,9 +87,8 @@
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
// but this seems to be mostly pedantic.
template <typename Iterator>
- using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
- typename std::iterator_traits<Iterator>::iterator_category,
- std::forward_iterator_tag>::value>;
+ using EnableIfForwardIterator = std::enable_if_t<
+ base_internal::IsAtLeastForwardIterator<Iterator>::value>;
static constexpr bool NoexceptCopyable() {
return std::is_nothrow_copy_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
@@ -391,7 +393,7 @@
template <typename H>
friend H AbslHashValue(H h, const FixedArray& v) {
return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
- v.size());
+ hash_internal::WeaklyMixedInteger{v.size()});
}
private:
@@ -446,7 +448,8 @@
private:
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
- alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
+ alignas(StorageElement) unsigned char buff_[sizeof(
+ StorageElement[inline_elements])];
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
};
@@ -516,15 +519,6 @@
Storage storage_;
};
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-template <typename T, size_t N, typename A>
-constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
-
-template <typename T, size_t N, typename A>
-constexpr typename FixedArray<T, N, A>::size_type
- FixedArray<T, N, A>::inline_elements;
-#endif
-
template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n) {
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index 2421b5f..6175a7c 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -17,18 +17,21 @@
#include <stdio.h>
#include <cstring>
+#include <forward_list>
#include <list>
#include <memory>
#include <numeric>
#include <scoped_allocator>
#include <stdexcept>
#include <string>
+#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/iterator_traits_test_helper.h"
#include "absl/base/options.h"
#include "absl/container/internal/test_allocator.h"
#include "absl/hash/hash_testing.h"
@@ -409,6 +412,20 @@
EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
}
+TEST(IteratorConstructorTest, FromCpp20ForwardIteratorRange) {
+ std::forward_list<int> const kUnzippedInput = {2, 3, 5, 7, 11, 13, 17};
+ absl::base_internal::Cpp20ForwardZipIterator<
+ std::forward_list<int>::const_iterator> const
+ begin(std::begin(kUnzippedInput), std::begin(kUnzippedInput));
+ absl::base_internal::
+ Cpp20ForwardZipIterator<std::forward_list<int>::const_iterator> const end(
+ std::end(kUnzippedInput), std::end(kUnzippedInput));
+
+ std::forward_list<std::pair<int, int>> const items(begin, end);
+ absl::FixedArray<std::pair<int, int>> const fixed(begin, end);
+ EXPECT_THAT(fixed, testing::ElementsAreArray(items));
+}
+
TEST(InitListConstructorTest, InitListConstruction) {
absl::FixedArray<int> fixed = {1, 2, 3};
EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
@@ -419,7 +436,7 @@
EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
absl::FixedArray<int, 0> heap_array(4, 1);
- EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
+ EXPECT_THAT(heap_array, testing::ElementsAreArray({1, 1, 1, 1}));
}
TEST(FillConstructorTest, EmptyArray) {
@@ -518,7 +535,10 @@
}
};
-TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
+TEST(FixedArrayTest, UsesGlobalAlloc) {
+ absl::FixedArray<PickyDelete, 0> a(5);
+ EXPECT_EQ(a.size(), 5);
+}
TEST(FixedArrayTest, Data) {
static const int kInput[] = {2, 3, 5, 7, 11, 13, 17};
@@ -782,6 +802,7 @@
AllocFxdArr copy = arr;
EXPECT_EQ(allocated, len * sizeof(int) * 2);
+ EXPECT_EQ(copy, arr);
}
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index ebd9ed6..bc86ced 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -104,6 +104,11 @@
// If your types are not moveable or you require pointer stability for keys,
// consider `absl::node_hash_map`.
//
+// PERFORMANCE WARNING: Erasure & sparsity can negatively affect performance:
+// * Iteration takes O(capacity) time, not O(size).
+// * erase() slows down begin() and ++iterator.
+// * Capacity only shrinks on rehash() or clear() -- not on erase().
+//
// Example:
//
// // Create a flat hash map of three strings (that map to strings)
@@ -125,7 +130,7 @@
template <class K, class V, class Hash = DefaultHashContainerHash<K>,
class Eq = DefaultHashContainerEq<K>,
class Allocator = std::allocator<std::pair<const K, V>>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER flat_hash_map
+class ABSL_ATTRIBUTE_OWNER flat_hash_map
: public absl::container_internal::raw_hash_map<
absl::container_internal::FlatHashMapPolicy<K, V>, Hash, Eq,
Allocator> {
@@ -426,8 +431,7 @@
// flat_hash_map::swap(flat_hash_map& other)
//
// Exchanges the contents of this `flat_hash_map` with those of the `other`
- // flat hash map, avoiding invocation of any move, copy, or swap operations on
- // individual elements.
+ // flat hash map.
//
// All iterators and references on the `flat_hash_map` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
@@ -574,6 +578,21 @@
return container_internal::EraseIf(pred, &c);
}
+// swap(flat_hash_map<>, flat_hash_map<>)
+//
+// Swaps the contents of two `flat_hash_map` containers.
+//
+// NOTE: we need to define this function template in order for
+// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
+// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
+// derived-to-base conversion, whereas `std::swap` is a function template so
+// `std::swap` will be preferred by compiler.
+template <typename K, typename V, typename H, typename E, typename A>
+void swap(flat_hash_map<K, V, H, E, A>& x,
+ flat_hash_map<K, V, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
+ x.swap(y);
+}
+
namespace container_internal {
// c_for_each_fast(flat_hash_map<>, Function)
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index 08915e2..5c83c94 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -115,23 +115,29 @@
}
TEST(FlatHashMap, Relocatability) {
- static_assert(absl::is_trivially_relocatable<int>::value, "");
+ static_assert(absl::is_trivially_relocatable<int>::value);
+#if ABSL_INTERNAL_CPLUSPLUS_LANG <= 202002L
+ // std::pair is not trivially copyable in C++23 in some standard
+ // library versions.
+ // See https://github.com/llvm/llvm-project/pull/95444 for instance.
+ // container_memory.h contains a workaround so what really matters
+ // is the transfer test below.
static_assert(
- absl::is_trivially_relocatable<std::pair<const int, int>>::value, "");
+ absl::is_trivially_relocatable<std::pair<const int, int>>::value);
+#endif
static_assert(
std::is_same<decltype(absl::container_internal::FlatHashMapPolicy<
int, int>::transfer<std::allocator<char>>(nullptr,
nullptr,
nullptr)),
- std::true_type>::value,
- "");
+ std::true_type>::value);
- struct NonRelocatable {
- NonRelocatable() = default;
- NonRelocatable(NonRelocatable&&) {}
- NonRelocatable& operator=(NonRelocatable&&) { return *this; }
- void* self = nullptr;
- };
+ struct NonRelocatable {
+ NonRelocatable() = default;
+ NonRelocatable(NonRelocatable&&) {}
+ NonRelocatable& operator=(NonRelocatable&&) { return *this; }
+ void* self = nullptr;
+ };
EXPECT_FALSE(absl::is_trivially_relocatable<NonRelocatable>::value);
EXPECT_TRUE(
@@ -360,8 +366,6 @@
}
}
-// This test requires std::launder for mutable key access in node handles.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
flat_hash_map<std::string, std::string> map;
@@ -373,7 +377,6 @@
EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
}
-#endif
TEST(FlatHashMap, Reserve) {
// Verify that if we reserve(size() + n) then we can perform n insertions
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index a3e36e0..bf63eb5 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -62,7 +62,7 @@
// Its interface is similar to that of `std::unordered_set<T>` with the
// following notable differences:
//
-// * Requires keys that are CopyConstructible
+// * Requires keys that are MoveConstructible
// * Supports heterogeneous lookup, through `find()` and `insert()`, provided
// that the set is provided a compatible heterogeneous hashing function and
// equality operator. See below for details.
@@ -103,6 +103,11 @@
// `absl::flat_hash_set<std::unique_ptr<T>>`. If your type is not moveable and
// you require pointer stability, consider `absl::node_hash_set` instead.
//
+// PERFORMANCE WARNING: Erasure & sparsity can negatively affect performance:
+// * Iteration takes O(capacity) time, not O(size).
+// * erase() slows down begin() and ++iterator.
+// * Capacity only shrinks on rehash() or clear() -- not on erase().
+//
// Example:
//
// // Create a flat hash set of three strings
@@ -122,7 +127,7 @@
template <class T, class Hash = DefaultHashContainerHash<T>,
class Eq = DefaultHashContainerEq<T>,
class Allocator = std::allocator<T>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER flat_hash_set
+class ABSL_ATTRIBUTE_OWNER flat_hash_set
: public absl::container_internal::raw_hash_set<
absl::container_internal::FlatHashSetPolicy<T>, Hash, Eq, Allocator> {
using Base = typename flat_hash_set::raw_hash_set;
@@ -360,8 +365,7 @@
// flat_hash_set::swap(flat_hash_set& other)
//
// Exchanges the contents of this `flat_hash_set` with those of the `other`
- // flat hash set, avoiding invocation of any move, copy, or swap operations on
- // individual elements.
+ // flat hash set.
//
// All iterators and references on the `flat_hash_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
@@ -478,6 +482,21 @@
return container_internal::EraseIf(pred, &c);
}
+// swap(flat_hash_set<>, flat_hash_set<>)
+//
+// Swaps the contents of two `flat_hash_set` containers.
+//
+// NOTE: we need to define this function template in order for
+// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
+// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
+// derived-to-base conversion, whereas `std::swap` is a function template so
+// `std::swap` will be preferred by compiler.
+template <typename T, typename H, typename E, typename A>
+void swap(flat_hash_set<T, H, E, A>& x,
+ flat_hash_set<T, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
+ return x.swap(y);
+}
+
namespace container_internal {
// c_for_each_fast(flat_hash_set<>, Function)
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index 0dd4326..bb90efa 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -14,8 +14,10 @@
#include "absl/container/flat_hash_set.h"
+#include <cstddef>
#include <cstdint>
#include <memory>
+#include <string>
#include <type_traits>
#include <utility>
#include <vector>
@@ -23,6 +25,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
+#include "absl/container/hash_container_defaults.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/test_allocator.h"
@@ -30,6 +33,7 @@
#include "absl/container/internal/unordered_set_lookup_test.h"
#include "absl/container/internal/unordered_set_members_test.h"
#include "absl/container/internal/unordered_set_modifiers_test.h"
+#include "absl/hash/hash.h"
#include "absl/log/check.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
@@ -291,6 +295,94 @@
std::allocator<int>>(nullptr, nullptr))()));
}
+struct HashEqInvalidOnMove {
+ HashEqInvalidOnMove() = default;
+ HashEqInvalidOnMove(const HashEqInvalidOnMove& rhs) = default;
+ HashEqInvalidOnMove(HashEqInvalidOnMove&& rhs) { rhs.moved = true; }
+ HashEqInvalidOnMove& operator=(const HashEqInvalidOnMove& rhs) = default;
+ HashEqInvalidOnMove& operator=(HashEqInvalidOnMove&& rhs) {
+ rhs.moved = true;
+ return *this;
+ }
+
+ size_t operator()(int x) const {
+ CHECK(!moved);
+ return absl::HashOf(x);
+ }
+
+ bool operator()(int x, int y) const {
+ CHECK(!moved);
+ return x == y;
+ }
+
+ bool moved = false;
+};
+
+TEST(FlatHashSet, MovedFromCleared_HashMustBeValid) {
+ flat_hash_set<int, HashEqInvalidOnMove> s1, s2;
+ // Moving the hashtable must not move the hasher because we need to support
+ // this behavior.
+ s2 = std::move(s1);
+ s1.clear();
+ s1.insert(2);
+ EXPECT_THAT(s1, UnorderedElementsAre(2));
+}
+
+TEST(FlatHashSet, MovedFromCleared_EqMustBeValid) {
+ flat_hash_set<int, DefaultHashContainerHash<int>, HashEqInvalidOnMove> s1, s2;
+ // Moving the hashtable must not move the equality functor because we need to
+ // support this behavior.
+ s2 = std::move(s1);
+ s1.clear();
+ s1.insert(2);
+ EXPECT_THAT(s1, UnorderedElementsAre(2));
+}
+
+TEST(FlatHashSet, Equality) {
+ {
+ flat_hash_set<int> s1 = {1, 2, 3};
+ flat_hash_set<int> s2 = {1, 2, 3};
+ EXPECT_EQ(s1, s2);
+ }
+ {
+ flat_hash_set<std::string> s1 = {"a", "b", "c"};
+ flat_hash_set<std::string> s2 = {"a", "b", "c"};
+ EXPECT_EQ(s1, s2);
+ }
+}
+
+class MoveOnlyInt {
+ public:
+ explicit MoveOnlyInt(int value) : value_(value) {}
+
+ MoveOnlyInt(const MoveOnlyInt& other) = delete;
+ MoveOnlyInt& operator=(const MoveOnlyInt& other) = delete;
+
+ MoveOnlyInt(MoveOnlyInt&& other) = default;
+ MoveOnlyInt& operator=(MoveOnlyInt&& other) = default;
+
+ bool operator==(const MoveOnlyInt& other) const {
+ return value_ == other.value_;
+ }
+ bool operator==(int other) const { return value_ == other; }
+
+ private:
+ template <typename H>
+ friend H AbslHashValue(H h, const MoveOnlyInt& m) {
+ return H::combine(std::move(h), m.value_);
+ }
+
+ int value_;
+};
+
+TEST(FlatHashSet, MoveOnlyKey) {
+ flat_hash_set<MoveOnlyInt> s;
+ s.insert(MoveOnlyInt(1));
+ s.insert(MoveOnlyInt(2));
+ s.insert(MoveOnlyInt(3));
+ EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3));
+}
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 974b652..f871b34 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -46,11 +46,14 @@
#include <utility>
#include "absl/algorithm/algorithm.h"
+#include "absl/base/attributes.h"
+#include "absl/base/internal/iterator_traits.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/internal/inlined_vector.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
@@ -67,7 +70,7 @@
// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
// designed to cover the same API footprint as covered by `std::vector`.
template <typename T, size_t N, typename A = std::allocator<T>>
-class InlinedVector {
+class ABSL_ATTRIBUTE_WARN_UNUSED InlinedVector {
static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
using Storage = inlined_vector_internal::Storage<T, N, A>;
@@ -89,11 +92,11 @@
inlined_vector_internal::DefaultValueAdapter<TheA>;
template <typename Iterator>
- using EnableIfAtLeastForwardIterator = absl::enable_if_t<
- inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
+ using EnableIfAtLeastForwardIterator = std::enable_if_t<
+ base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
template <typename Iterator>
- using DisableIfAtLeastForwardIterator = absl::enable_if_t<
- !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
+ using DisableIfAtLeastForwardIterator = std::enable_if_t<
+ !base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
using MemcpyPolicy = typename Storage::MemcpyPolicy;
using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy;
@@ -1006,7 +1009,8 @@
template <typename H, typename T, size_t N, typename A>
H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
auto size = a.size();
- return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
+ return H::combine(H::combine_contiguous(std::move(h), a.data(), size),
+ hash_internal::WeaklyMixedInteger{size});
}
ABSL_NAMESPACE_END
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 6954262..ff0e77b 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -31,6 +31,7 @@
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
#include "absl/base/internal/exception_testing.h"
+#include "absl/base/internal/iterator_traits_test_helper.h"
#include "absl/base/macros.h"
#include "absl/base/options.h"
#include "absl/container/internal/test_allocator.h"
@@ -649,6 +650,33 @@
}
}
+TEST(IntPairVec, Insert) {
+ for (size_t len = 0; len < 20; len++) {
+ for (ptrdiff_t pos = 0; pos <= static_cast<ptrdiff_t>(len); pos++) {
+ // Iterator range (C++20 forward iterator)
+ const std::forward_list<int> unzipped_input = {9999, 8888, 7777};
+ const absl::base_internal::Cpp20ForwardZipIterator<
+ std::forward_list<int>::const_iterator>
+ begin(unzipped_input.cbegin(), unzipped_input.cbegin());
+ const absl::base_internal::Cpp20ForwardZipIterator<
+ std::forward_list<int>::const_iterator>
+ end(unzipped_input.cend(), unzipped_input.cend());
+
+ std::vector<std::pair<int, int>> std_v;
+ absl::InlinedVector<std::pair<int, int>, 8> v;
+ for (size_t i = 0; i < len; ++i) {
+ std_v.emplace_back(i, i);
+ v.emplace_back(i, i);
+ }
+
+ std_v.insert(std_v.begin() + pos, begin, end);
+ auto it = v.insert(v.cbegin() + pos, begin, end);
+ EXPECT_THAT(v, ElementsAreArray(std_v));
+ EXPECT_EQ(it, v.cbegin() + pos);
+ }
+ }
+}
+
TEST(RefCountedVec, InsertConstructorDestructor) {
// Make sure the proper construction/destruction happen during insert
// operations.
@@ -1190,6 +1218,7 @@
tracker.ResetCopiesMovesSwaps();
{ // Copy constructor should create 'len' more instances.
InstanceVec v_copy(v);
+ EXPECT_EQ(v_copy.size(), v.size());
EXPECT_EQ(tracker.instances(), len + len);
EXPECT_EQ(tracker.copies(), len);
EXPECT_EQ(tracker.moves(), 0);
@@ -1217,6 +1246,7 @@
tracker.ResetCopiesMovesSwaps();
{
InstanceVec v_copy(std::move(v));
+ EXPECT_EQ(v_copy.size(), len);
if (static_cast<size_t>(len) > inlined_capacity) {
// Allocation is moved as a whole.
EXPECT_EQ(tracker.instances(), len);
@@ -1747,61 +1777,80 @@
using MyAlloc = CountingAllocator<int>;
using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
- int64_t allocated = 0;
- MyAlloc alloc(&allocated);
+ int64_t bytes_allocated = 0;
+ int64_t instance_count = 0;
+ MyAlloc alloc(&bytes_allocated, &instance_count);
{
AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc);
- EXPECT_THAT(allocated, Eq(0));
+ EXPECT_THAT(bytes_allocated, Eq(0));
+ EXPECT_THAT(instance_count, Eq(4));
}
- EXPECT_THAT(allocated, Eq(0));
+ EXPECT_THAT(bytes_allocated, Eq(0));
+ EXPECT_THAT(instance_count, Eq(0));
{
AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc);
- EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int))));
+ EXPECT_THAT(bytes_allocated,
+ Eq(static_cast<int64_t>(v.size() * sizeof(int))));
+ EXPECT_THAT(instance_count, Eq(static_cast<int64_t>(v.size())));
}
- EXPECT_THAT(allocated, Eq(0));
+ EXPECT_THAT(bytes_allocated, Eq(0));
+ EXPECT_THAT(instance_count, Eq(0));
{
AllocVec v(4, 1, alloc);
- EXPECT_THAT(allocated, Eq(0));
+ EXPECT_THAT(bytes_allocated, Eq(0));
+ EXPECT_THAT(instance_count, Eq(4));
- int64_t allocated2 = 0;
- MyAlloc alloc2(&allocated2);
- AllocVec v2(v, alloc2);
- EXPECT_THAT(allocated2, Eq(0));
+ int64_t bytes_allocated2 = 0;
+ MyAlloc alloc2(&bytes_allocated2);
+ ABSL_ATTRIBUTE_UNUSED AllocVec v2(v, alloc2);
+ EXPECT_THAT(bytes_allocated2, Eq(0));
- int64_t allocated3 = 0;
- MyAlloc alloc3(&allocated3);
- AllocVec v3(std::move(v), alloc3);
- EXPECT_THAT(allocated3, Eq(0));
+ int64_t bytes_allocated3 = 0;
+ MyAlloc alloc3(&bytes_allocated3);
+ ABSL_ATTRIBUTE_UNUSED AllocVec v3(std::move(v), alloc3);
+ EXPECT_THAT(bytes_allocated3, Eq(0));
}
- EXPECT_THAT(allocated, 0);
+ EXPECT_THAT(bytes_allocated, Eq(0));
+ EXPECT_THAT(instance_count, Eq(0));
{
AllocVec v(8, 2, alloc);
- EXPECT_THAT(allocated, Eq(static_cast<int64_t>(v.size() * sizeof(int))));
+ EXPECT_THAT(bytes_allocated,
+ Eq(static_cast<int64_t>(v.size() * sizeof(int))));
+ EXPECT_THAT(instance_count, Eq(static_cast<int64_t>(v.size())));
- int64_t allocated2 = 0;
- MyAlloc alloc2(&allocated2);
+ int64_t bytes_allocated2 = 0;
+ MyAlloc alloc2(&bytes_allocated2);
AllocVec v2(v, alloc2);
- EXPECT_THAT(allocated2, Eq(static_cast<int64_t>(v2.size() * sizeof(int))));
+ EXPECT_THAT(bytes_allocated2,
+ Eq(static_cast<int64_t>(v2.size() * sizeof(int))));
- int64_t allocated3 = 0;
- MyAlloc alloc3(&allocated3);
+ int64_t bytes_allocated3 = 0;
+ MyAlloc alloc3(&bytes_allocated3);
AllocVec v3(std::move(v), alloc3);
- EXPECT_THAT(allocated3, Eq(static_cast<int64_t>(v3.size() * sizeof(int))));
+ EXPECT_THAT(bytes_allocated3,
+ Eq(static_cast<int64_t>(v3.size() * sizeof(int))));
}
- EXPECT_EQ(allocated, 0);
+ EXPECT_EQ(bytes_allocated, 0);
+ EXPECT_EQ(instance_count, 0);
{
// Test shrink_to_fit deallocations.
AllocVec v(8, 2, alloc);
- EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int)));
+ EXPECT_EQ(bytes_allocated, static_cast<int64_t>(8 * sizeof(int)));
+ EXPECT_EQ(instance_count, 8);
v.resize(5);
- EXPECT_EQ(allocated, static_cast<int64_t>(8 * sizeof(int)));
+ EXPECT_EQ(bytes_allocated, static_cast<int64_t>(8 * sizeof(int)));
+ EXPECT_EQ(instance_count, 5);
v.shrink_to_fit();
- EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int)));
+ EXPECT_EQ(bytes_allocated, static_cast<int64_t>(5 * sizeof(int)));
+ EXPECT_EQ(instance_count, 5);
v.resize(4);
- EXPECT_EQ(allocated, static_cast<int64_t>(5 * sizeof(int)));
+ EXPECT_EQ(bytes_allocated, static_cast<int64_t>(5 * sizeof(int)));
+ EXPECT_EQ(instance_count, 4);
v.shrink_to_fit();
- EXPECT_EQ(allocated, 0);
+ EXPECT_EQ(bytes_allocated, 0);
+ EXPECT_EQ(instance_count, 4);
}
+ EXPECT_EQ(instance_count, 0);
}
TEST(AllocatorSupportTest, SwapBothAllocated) {
diff --git a/absl/container/internal/btree.h b/absl/container/internal/btree.h
index 689e71a..ed541e7 100644
--- a/absl/container/internal/btree.h
+++ b/absl/container/internal/btree.h
@@ -60,6 +60,7 @@
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
#include "absl/container/internal/common.h"
#include "absl/container/internal/common_policy_traits.h"
#include "absl/container/internal/compressed_tuple.h"
@@ -224,7 +225,7 @@
public:
using Base::Base;
- checked_compare(Compare comp) : Base(std::move(comp)) {} // NOLINT
+ checked_compare(Compare cmp) : Base(std::move(cmp)) {} // NOLINT
// Allow converting to Compare for use in key_comp()/value_comp().
explicit operator Compare() const { return comp(); }
@@ -708,6 +709,8 @@
}
// Getter for the parent of this node.
+ // TODO(ezb): assert that the child of the returned node at position
+ // `node_->position()` maps to the current node.
btree_node *parent() const { return *GetField<0>(); }
// Getter for whether the node is the root of the tree. The parent of the
// root of the tree is the leftmost node in the tree which is guaranteed to
@@ -1175,6 +1178,26 @@
return distance_slow(other);
}
+ // Advances the iterator by `n`. Values of `n` must not result in going past
+ // the `end` iterator (for a positive `n`) or before the `begin` iterator (for
+ // a negative `n`).
+ btree_iterator &operator+=(difference_type n) {
+ assert_valid_generation(node_);
+ if (n == 0) return *this;
+ if (n < 0) return decrement_n_slow(-n);
+ return increment_n_slow(n);
+ }
+
+ // Moves the iterator by `n` positions backwards. Values of `n` must not
+ // result in going before the `begin` iterator (for a positive `n`) or past
+ // the `end` iterator (for a negative `n`).
+ btree_iterator &operator-=(difference_type n) {
+ assert_valid_generation(node_);
+ if (n == 0) return *this;
+ if (n < 0) return increment_n_slow(-n);
+ return decrement_n_slow(n);
+ }
+
// Accessors for the key/value the iterator is pointing at.
reference operator*() const {
ABSL_HARDENING_ASSERT(node_ != nullptr);
@@ -1277,6 +1300,7 @@
increment_slow();
}
void increment_slow();
+ btree_iterator &increment_n_slow(difference_type n);
void decrement() {
assert_valid_generation(node_);
@@ -1286,6 +1310,7 @@
decrement_slow();
}
void decrement_slow();
+ btree_iterator &decrement_n_slow(difference_type n);
const key_type &key() const {
return node_->key(static_cast<size_type>(position_));
@@ -2126,50 +2151,128 @@
template <typename N, typename R, typename P>
void btree_iterator<N, R, P>::increment_slow() {
- if (node_->is_leaf()) {
- assert(position_ >= node_->finish());
- btree_iterator save(*this);
- while (position_ == node_->finish() && !node_->is_root()) {
- assert(node_->parent()->child(node_->position()) == node_);
- position_ = node_->position();
- node_ = node_->parent();
+ N* node = node_;
+ int position = position_;
+ if (node->is_leaf()) {
+ assert(position >= node->finish());
+ while (position == node->finish() && !node->is_root()) {
+ assert(node->parent()->child(node->position()) == node);
+ position = node->position();
+ node = node->parent();
}
// TODO(ezb): assert we aren't incrementing end() instead of handling.
- if (position_ == node_->finish()) {
- *this = save;
+ if (position == node->finish()) {
+ return;
}
} else {
- assert(position_ < node_->finish());
- node_ = node_->child(static_cast<field_type>(position_ + 1));
- while (node_->is_internal()) {
- node_ = node_->start_child();
+ assert(position < node->finish());
+ node = node->child(static_cast<field_type>(position + 1));
+ while (node->is_internal()) {
+ node = node->start_child();
}
- position_ = node_->start();
+ position = node->start();
}
+ *this = {node, position};
}
template <typename N, typename R, typename P>
void btree_iterator<N, R, P>::decrement_slow() {
- if (node_->is_leaf()) {
- assert(position_ <= -1);
- btree_iterator save(*this);
- while (position_ < node_->start() && !node_->is_root()) {
- assert(node_->parent()->child(node_->position()) == node_);
- position_ = node_->position() - 1;
- node_ = node_->parent();
+ N* node = node_;
+ int position = position_;
+ if (node->is_leaf()) {
+ assert(position <= -1);
+ while (position < node->start() && !node->is_root()) {
+ assert(node->parent()->child(node->position()) == node);
+ position = node->position() - 1;
+ node = node->parent();
}
// TODO(ezb): assert we aren't decrementing begin() instead of handling.
- if (position_ < node_->start()) {
- *this = save;
+ if (position < node->start()) {
+ return;
}
} else {
- assert(position_ >= node_->start());
- node_ = node_->child(static_cast<field_type>(position_));
- while (node_->is_internal()) {
- node_ = node_->child(node_->finish());
+ assert(position >= node->start());
+ node = node->child(static_cast<field_type>(position));
+ while (node->is_internal()) {
+ node = node->child(node->finish());
}
- position_ = node_->finish() - 1;
+ position = node->finish() - 1;
}
+ *this = {node, position};
+}
+
+template <typename N, typename R, typename P>
+btree_iterator<N, R, P> &btree_iterator<N, R, P>::increment_n_slow(
+ difference_type n) {
+ N *node = node_;
+ int position = position_;
+ ABSL_ASSUME(n > 0);
+ while (n > 0) {
+ if (node->is_leaf()) {
+ if (position + n < node->finish()) {
+ position += n;
+ break;
+ } else {
+ n -= node->finish() - position;
+ position = node->finish();
+ btree_iterator save = {node, position};
+ while (position == node->finish() && !node->is_root()) {
+ position = node->position();
+ node = node->parent();
+ }
+ if (position == node->finish()) {
+ ABSL_HARDENING_ASSERT(n == 0);
+ return *this = save;
+ }
+ }
+ } else {
+ --n;
+ assert(position < node->finish());
+ node = node->child(static_cast<field_type>(position + 1));
+ while (node->is_internal()) {
+ node = node->start_child();
+ }
+ position = node->start();
+ }
+ }
+ node_ = node;
+ position_ = position;
+ return *this;
+}
+
+template <typename N, typename R, typename P>
+btree_iterator<N, R, P> &btree_iterator<N, R, P>::decrement_n_slow(
+ difference_type n) {
+ N *node = node_;
+ int position = position_;
+ ABSL_ASSUME(n > 0);
+ while (n > 0) {
+ if (node->is_leaf()) {
+ if (position - n >= node->start()) {
+ position -= n;
+ break;
+ } else {
+ n -= 1 + position - node->start();
+ position = node->start() - 1;
+ while (position < node->start() && !node->is_root()) {
+ position = node->position() - 1;
+ node = node->parent();
+ }
+ ABSL_HARDENING_ASSERT(position >= node->start());
+ }
+ } else {
+ --n;
+ assert(position >= node->start());
+ node = node->child(static_cast<field_type>(position));
+ while (node->is_internal()) {
+ node = node->child(node->finish());
+ }
+ position = node->finish() - 1;
+ }
+ }
+ node_ = node;
+ position_ = position;
+ return *this;
}
////
diff --git a/absl/container/internal/btree_container.h b/absl/container/internal/btree_container.h
index a68ce44..21f00ae 100644
--- a/absl/container/internal/btree_container.h
+++ b/absl/container/internal/btree_container.h
@@ -18,12 +18,14 @@
#include <algorithm>
#include <initializer_list>
#include <iterator>
+#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/container/internal/btree.h" // IWYU pragma: export
#include "absl/container/internal/common.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
@@ -266,7 +268,8 @@
for (const auto &v : b) {
h = State::combine(std::move(h), v);
}
- return State::combine(std::move(h), b.size());
+ return State::combine(std::move(h),
+ hash_internal::WeaklyMixedInteger{b.size()});
}
protected:
@@ -451,6 +454,29 @@
template <class K>
using key_arg = typename super_type::template key_arg<K>;
+ // NOTE: The mess here is to shorten the code for the (very repetitive)
+ // function overloads, and to allow the lifetime-bound overloads to dispatch
+ // to the non-lifetime-bound overloads, to ensure there is a single source of
+ // truth for each overload set.
+ //
+ // Enabled if an assignment from the given type would require the
+ // source object to remain alive for the life of the element.
+ //
+ // TODO(b/402804213): Remove these traits and simplify the overloads whenever
+ // we have a better mechanism available to handle lifetime analysis.
+ template <class K, bool Value, typename = void>
+ using LifetimeBoundK =
+ HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment<
+ typename Tree::key_type, K>>;
+ template <class M, bool Value, typename = void>
+ using LifetimeBoundV =
+ HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment<
+ typename Tree::params_type::mapped_type, M>>;
+ template <class K, bool KValue, class M, bool MValue, typename... Dummy>
+ using LifetimeBoundKV =
+ absl::conjunction<LifetimeBoundK<K, KValue, absl::void_t<Dummy...>>,
+ LifetimeBoundV<M, MValue>>;
+
public:
using key_type = typename Tree::key_type;
using mapped_type = typename params_type::mapped_type;
@@ -464,85 +490,163 @@
using super_type::super_type;
btree_map_container() {}
+ // TODO(b/402804213): Remove these macros whenever we have a better mechanism
+ // available to handle lifetime analysis.
+#define ABSL_INTERNAL_X(Func, Callee, KQual, MQual, KValue, MValue, ...) \
+ template < \
+ typename K = key_type, class M, \
+ ABSL_INTERNAL_IF_##KValue##_NOR_##MValue( \
+ int = (EnableIf<LifetimeBoundKV<K, KValue, M, MValue, \
+ IfRRef<int KQual>::AddPtr<K>, \
+ IfRRef<int MQual>::AddPtr<M>>>()), \
+ ABSL_INTERNAL_SINGLE_ARG( \
+ int &..., \
+ decltype(EnableIf<LifetimeBoundKV<K, KValue, M, MValue>>()) = \
+ 0))> \
+ decltype(auto) Func( \
+ __VA_ARGS__ key_arg<K> KQual k ABSL_INTERNAL_IF_##KValue( \
+ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \
+ M MQual obj ABSL_INTERNAL_IF_##MValue( \
+ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))) \
+ ABSL_ATTRIBUTE_LIFETIME_BOUND { \
+ return ABSL_INTERNAL_IF_##KValue##_OR_##MValue( \
+ (this->template Func<K, M, 0>), Callee)( \
+ __VA_ARGS__ std::forward<decltype(k)>(k), \
+ std::forward<decltype(obj)>(obj)); \
+ } \
+ friend struct std::enable_if<false> /* just to force a semicolon */
// Insertion routines.
// Note: the nullptr template arguments and extra `const M&` overloads allow
// for supporting bitfield arguments.
- template <typename K = key_type, class M>
- std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, const M &obj)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(k, obj);
- }
- template <typename K = key_type, class M, K * = nullptr>
- std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, const M &obj)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(std::forward<K>(k), obj);
- }
- template <typename K = key_type, class M, M * = nullptr>
- std::pair<iterator, bool> insert_or_assign(const key_arg<K> &k, M &&obj)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(k, std::forward<M>(obj));
- }
- template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
- std::pair<iterator, bool> insert_or_assign(key_arg<K> &&k, M &&obj)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(std::forward<K>(k), std::forward<M>(obj));
- }
- template <typename K = key_type, class M>
- iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
- const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_hint_impl(hint, k, obj);
- }
- template <typename K = key_type, class M, K * = nullptr>
- iterator insert_or_assign(const_iterator hint, key_arg<K> &&k,
- const M &obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_hint_impl(hint, std::forward<K>(k), obj);
- }
- template <typename K = key_type, class M, M * = nullptr>
- iterator insert_or_assign(const_iterator hint, const key_arg<K> &k,
- M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_hint_impl(hint, k, std::forward<M>(obj));
- }
- template <typename K = key_type, class M, K * = nullptr, M * = nullptr>
- iterator insert_or_assign(const_iterator hint, key_arg<K> &&k,
- M &&obj) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_hint_impl(hint, std::forward<K>(k),
- std::forward<M>(obj));
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, true);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, true);
- template <typename K = key_type, typename... Args,
- typename absl::enable_if_t<
- !std::is_convertible<K, const_iterator>::value, int> = 0>
- std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&...args)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return try_emplace_impl(k, std::forward<Args>(args)...);
- }
- template <typename K = key_type, typename... Args,
- typename absl::enable_if_t<
- !std::is_convertible<K, const_iterator>::value, int> = 0>
- std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&...args)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
- }
- template <typename K = key_type, typename... Args>
- iterator try_emplace(const_iterator hint, const key_arg<K> &k,
- Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return try_emplace_hint_impl(hint, k, std::forward<Args>(args)...);
- }
- template <typename K = key_type, typename... Args>
- iterator try_emplace(const_iterator hint, key_arg<K> &&k,
- Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return try_emplace_hint_impl(hint, std::forward<K>(k),
- std::forward<Args>(args)...);
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ true);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ true);
- template <typename K = key_type>
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ true);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ true);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false,
+ false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &,
+ const &, false, false,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &,
+ const &, false, true,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &,
+ const &, true, false,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &,
+ const &, true, true,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&,
+ false, false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&,
+ false, true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&,
+ true, false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, const &, &&,
+ true, true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &,
+ false, false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &,
+ false, true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &,
+ true, false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, const &,
+ true, true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, false,
+ false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, false,
+ true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, true,
+ false, const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_hint_impl, &&, &&, true,
+ true, const_iterator(hint) ABSL_INTERNAL_COMMA);
+#undef ABSL_INTERNAL_X
+
+#define ABSL_INTERNAL_X(Func, Callee, KQual, KValue, ...) \
+ template < \
+ class K = key_type, \
+ ABSL_INTERNAL_IF_##KValue( \
+ class... Args, \
+ int = (EnableIf< \
+ LifetimeBoundK<K, KValue, IfRRef<int KQual>::AddPtr<K>>>())), \
+ ABSL_INTERNAL_IF_##KValue( \
+ decltype(EnableIf<LifetimeBoundK< \
+ K, KValue, IfRRef<int KQual>::AddPtr<K>>>()) = 0, \
+ class... Args), \
+ std::enable_if_t<!std::is_convertible<K, const_iterator>::value, int> = \
+ 0> \
+ decltype(auto) Func( \
+ __VA_ARGS__ key_arg<K> KQual k ABSL_INTERNAL_IF_##KValue( \
+ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND { \
+ return ABSL_INTERNAL_IF_##KValue((this->template Func<K, 0>), Callee)( \
+ __VA_ARGS__ std::forward<decltype(k)>(k), \
+ std::forward<decltype(args)>(args)...); \
+ } \
+ friend struct std::enable_if<false> /* just to force a semicolon */
+ ABSL_INTERNAL_X(try_emplace, try_emplace_impl, const &, false);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_impl, const &, true);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_impl, &&, false);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_impl, &&, true);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, const &, false,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, const &, true,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, &&, false,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(try_emplace, try_emplace_hint_impl, &&, true,
+ const_iterator(hint) ABSL_INTERNAL_COMMA);
+#undef ABSL_INTERNAL_X
+
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>()>
mapped_type &operator[](const key_arg<K> &k) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace(k).first->second;
}
- template <typename K = key_type>
+ template <class K = key_type, int &..., EnableIf<LifetimeBoundK<K, true>> = 0>
+ mapped_type &operator[](
+ const key_arg<K> &k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template operator[]<K, 0>(k);
+ }
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>()>
mapped_type &operator[](key_arg<K> &&k) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace(std::forward<K>(k)).first->second;
}
+ template <class K = key_type, int &..., EnableIf<LifetimeBoundK<K, true>> = 0>
+ mapped_type &operator[](key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(
+ this)) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template operator[]<K, 0>(std::forward<K>(k));
+ }
template <typename K = key_type>
mapped_type &at(const key_arg<K> &key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
index 9239bb4..5ef6c56 100644
--- a/absl/container/internal/common.h
+++ b/absl/container/internal/common.h
@@ -21,10 +21,53 @@
#include "absl/meta/type_traits.h"
#include "absl/types/optional.h"
+// TODO(b/402804213): Clean up these macros when no longer needed.
+#define ABSL_INTERNAL_SINGLE_ARG(...) __VA_ARGS__
+
+#define ABSL_INTERNAL_IF_true(if_satisfied, ...) if_satisfied
+#define ABSL_INTERNAL_IF_false(if_satisfied, ...) __VA_ARGS__
+
+#define ABSL_INTERNAL_IF_true_AND_true ABSL_INTERNAL_IF_true
+#define ABSL_INTERNAL_IF_false_AND_false ABSL_INTERNAL_IF_false
+#define ABSL_INTERNAL_IF_true_AND_false ABSL_INTERNAL_IF_false_AND_false
+#define ABSL_INTERNAL_IF_false_AND_true ABSL_INTERNAL_IF_false_AND_false
+
+#define ABSL_INTERNAL_IF_true_OR_true ABSL_INTERNAL_IF_true
+#define ABSL_INTERNAL_IF_false_OR_false ABSL_INTERNAL_IF_false
+#define ABSL_INTERNAL_IF_true_OR_false ABSL_INTERNAL_IF_true_OR_true
+#define ABSL_INTERNAL_IF_false_OR_true ABSL_INTERNAL_IF_true_OR_true
+
+#define ABSL_INTERNAL_IF_true_NOR_true ABSL_INTERNAL_IF_false_AND_false
+#define ABSL_INTERNAL_IF_false_NOR_false ABSL_INTERNAL_IF_true_AND_true
+#define ABSL_INTERNAL_IF_true_NOR_false ABSL_INTERNAL_IF_false_AND_true
+#define ABSL_INTERNAL_IF_false_NOR_true ABSL_INTERNAL_IF_true_AND_false
+
+#define ABSL_INTERNAL_COMMA ,
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
+// TODO(b/402804213): Clean up these traits when no longer needed or
+// deduplicate them with absl::functional_internal::EnableIf.
+template <class Cond>
+using EnableIf = std::enable_if_t<Cond::value, int>;
+
+template <bool Value, class T>
+using HasValue = std::conditional_t<Value, T, absl::negation<T>>;
+
+template <class T>
+struct IfRRef {
+ template <class Other>
+ using AddPtr = Other;
+};
+
+template <class T>
+struct IfRRef<T&&> {
+ template <class Other>
+ using AddPtr = Other*;
+};
+
template <class, class = void>
struct IsTransparent : std::false_type {};
template <class T>
diff --git a/absl/container/internal/common_policy_traits.h b/absl/container/internal/common_policy_traits.h
index c521f61..86e038e 100644
--- a/absl/container/internal/common_policy_traits.h
+++ b/absl/container/internal/common_policy_traits.h
@@ -28,6 +28,15 @@
ABSL_NAMESPACE_BEGIN
namespace container_internal {
+template <class Policy, class = void>
+struct policy_trait_element_is_owner : std::false_type {};
+
+template <class Policy>
+struct policy_trait_element_is_owner<
+ Policy,
+ std::enable_if_t<!std::is_void<typename Policy::element_is_owner>::value>>
+ : Policy::element_is_owner {};
+
// Defines how slots are initialized/destroyed/moved.
template <class Policy, class = void>
struct common_policy_traits {
@@ -110,7 +119,7 @@
old_slot)) {
return P::transfer(alloc, new_slot, old_slot);
}
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
+
// This overload returns true_type for the trait below.
// The conditional_t is to make the enabler type dependent.
template <class Alloc,
@@ -126,7 +135,6 @@
static_cast<const void*>(&element(old_slot)), sizeof(value_type));
return {};
}
-#endif
template <class Alloc>
static void transfer_impl(Alloc* alloc, slot_type* new_slot,
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index c3edf54..01b334e 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -386,20 +386,6 @@
using Tuple = CompressedTuple<int, double, CompressedTuple<int>, Empty<0>>;
- constexpr int r0 =
- AsLValue(Tuple(1, 0.75, CompressedTuple<int>(9), {})).get<0>();
- constexpr double r1 =
- AsLValue(Tuple(1, 0.75, CompressedTuple<int>(9), {})).get<1>();
- constexpr int r2 =
- AsLValue(Tuple(1, 0.75, CompressedTuple<int>(9), {})).get<2>().get<0>();
- constexpr CallType r3 =
- AsLValue(Tuple(1, 0.75, CompressedTuple<int>(9), {})).get<3>().value();
-
- EXPECT_EQ(r0, 1);
- EXPECT_EQ(r1, 0.75);
- EXPECT_EQ(r2, 9);
- EXPECT_EQ(r3, CallType::kMutableRef);
-
constexpr Tuple x(7, 1.25, CompressedTuple<int>(5), {});
constexpr int x0 = x.get<0>();
constexpr double x1 = x.get<1>();
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index ba8e08a..e7ac1db 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -17,6 +17,7 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <memory>
#include <new>
@@ -373,9 +374,6 @@
return slot->value;
}
- // When C++17 is available, we can use std::launder to provide mutable
- // access to the key for use in node handle.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
static K& mutable_key(slot_type* slot) {
// Still check for kMutableKeys so that we can avoid calling std::launder
// unless necessary because it can interfere with optimizations.
@@ -383,9 +381,6 @@
: *std::launder(const_cast<K*>(
std::addressof(slot->value.first)));
}
-#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
- static const K& mutable_key(slot_type* slot) { return key(slot); }
-#endif
static const K& key(const slot_type* slot) {
return kMutableKeys::value ? slot->key : slot->value.first;
@@ -438,11 +433,17 @@
template <class Allocator>
static auto transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) {
- auto is_relocatable =
- typename absl::is_trivially_relocatable<value_type>::type();
+ // This should really just be
+ // typename absl::is_trivially_relocatable<value_type>::type()
+ // but std::pair is not trivially copyable in C++23 in some standard
+ // library versions.
+ // See https://github.com/llvm/llvm-project/pull/95444 for instance.
+ auto is_relocatable = typename std::conjunction<
+ absl::is_trivially_relocatable<typename value_type::first_type>,
+ absl::is_trivially_relocatable<typename value_type::second_type>>::
+ type();
emplace(new_slot);
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
if (is_relocatable) {
// TODO(b/247130232,b/251814870): remove casts after fixing warnings.
std::memcpy(static_cast<void*>(std::launder(&new_slot->value)),
@@ -450,7 +451,6 @@
sizeof(value_type));
return is_relocatable;
}
-#endif
if (kMutableKeys::value) {
absl::allocator_traits<Allocator>::construct(
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h
index 0f07bcf..c2a757b 100644
--- a/absl/container/internal/hash_function_defaults.h
+++ b/absl/container/internal/hash_function_defaults.h
@@ -49,6 +49,7 @@
#include <functional>
#include <memory>
#include <string>
+#include <string_view>
#include <type_traits>
#include "absl/base/config.h"
@@ -58,10 +59,6 @@
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
@@ -113,8 +110,6 @@
template <>
struct HashEq<absl::Cord> : StringHashEq {};
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-
template <typename TChar>
struct BasicStringHash {
using is_transparent = void;
@@ -153,8 +148,6 @@
template <>
struct HashEq<std::u32string_view> : BasicStringHashEq<char32_t> {};
-#endif // ABSL_HAVE_STD_STRING_VIEW
-
// Supports heterogeneous lookup for pointers and smart pointers.
template <class T>
struct HashEq<T*> {
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc
index 912d119..9a39b07 100644
--- a/absl/container/internal/hash_function_defaults_test.cc
+++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -16,6 +16,7 @@
#include <cstddef>
#include <functional>
+#include <string_view>
#include <type_traits>
#include <utility>
@@ -28,10 +29,6 @@
#include "absl/strings/cord_test_helpers.h"
#include "absl/strings/string_view.h"
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
@@ -118,9 +115,6 @@
}
TEST(BasicStringViewTest, WStringEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::wstring> eq;
EXPECT_TRUE(eq(L"a", L"a"));
EXPECT_TRUE(eq(L"a", std::wstring_view(L"a")));
@@ -128,13 +122,9 @@
EXPECT_FALSE(eq(L"a", L"b"));
EXPECT_FALSE(eq(L"a", std::wstring_view(L"b")));
EXPECT_FALSE(eq(L"a", std::wstring(L"b")));
-#endif
}
TEST(BasicStringViewTest, WStringViewEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::wstring_view> eq;
EXPECT_TRUE(eq(L"a", L"a"));
EXPECT_TRUE(eq(L"a", std::wstring_view(L"a")));
@@ -142,13 +132,9 @@
EXPECT_FALSE(eq(L"a", L"b"));
EXPECT_FALSE(eq(L"a", std::wstring_view(L"b")));
EXPECT_FALSE(eq(L"a", std::wstring(L"b")));
-#endif
}
TEST(BasicStringViewTest, U16StringEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::u16string> eq;
EXPECT_TRUE(eq(u"a", u"a"));
EXPECT_TRUE(eq(u"a", std::u16string_view(u"a")));
@@ -156,13 +142,9 @@
EXPECT_FALSE(eq(u"a", u"b"));
EXPECT_FALSE(eq(u"a", std::u16string_view(u"b")));
EXPECT_FALSE(eq(u"a", std::u16string(u"b")));
-#endif
}
TEST(BasicStringViewTest, U16StringViewEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::u16string_view> eq;
EXPECT_TRUE(eq(u"a", u"a"));
EXPECT_TRUE(eq(u"a", std::u16string_view(u"a")));
@@ -170,13 +152,9 @@
EXPECT_FALSE(eq(u"a", u"b"));
EXPECT_FALSE(eq(u"a", std::u16string_view(u"b")));
EXPECT_FALSE(eq(u"a", std::u16string(u"b")));
-#endif
}
TEST(BasicStringViewTest, U32StringEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::u32string> eq;
EXPECT_TRUE(eq(U"a", U"a"));
EXPECT_TRUE(eq(U"a", std::u32string_view(U"a")));
@@ -184,13 +162,9 @@
EXPECT_FALSE(eq(U"a", U"b"));
EXPECT_FALSE(eq(U"a", std::u32string_view(U"b")));
EXPECT_FALSE(eq(U"a", std::u32string(U"b")));
-#endif
}
TEST(BasicStringViewTest, U32StringViewEqWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_eq<std::u32string_view> eq;
EXPECT_TRUE(eq(U"a", U"a"));
EXPECT_TRUE(eq(U"a", std::u32string_view(U"a")));
@@ -198,85 +172,60 @@
EXPECT_FALSE(eq(U"a", U"b"));
EXPECT_FALSE(eq(U"a", std::u32string_view(U"b")));
EXPECT_FALSE(eq(U"a", std::u32string(U"b")));
-#endif
}
TEST(BasicStringViewTest, WStringHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::wstring> hash;
auto h = hash(L"a");
EXPECT_EQ(h, hash(std::wstring_view(L"a")));
EXPECT_EQ(h, hash(std::wstring(L"a")));
EXPECT_NE(h, hash(std::wstring_view(L"b")));
EXPECT_NE(h, hash(std::wstring(L"b")));
-#endif
}
TEST(BasicStringViewTest, WStringViewHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::wstring_view> hash;
auto h = hash(L"a");
EXPECT_EQ(h, hash(std::wstring_view(L"a")));
EXPECT_EQ(h, hash(std::wstring(L"a")));
EXPECT_NE(h, hash(std::wstring_view(L"b")));
EXPECT_NE(h, hash(std::wstring(L"b")));
-#endif
}
TEST(BasicStringViewTest, U16StringHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::u16string> hash;
auto h = hash(u"a");
EXPECT_EQ(h, hash(std::u16string_view(u"a")));
EXPECT_EQ(h, hash(std::u16string(u"a")));
EXPECT_NE(h, hash(std::u16string_view(u"b")));
EXPECT_NE(h, hash(std::u16string(u"b")));
-#endif
}
TEST(BasicStringViewTest, U16StringViewHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::u16string_view> hash;
auto h = hash(u"a");
EXPECT_EQ(h, hash(std::u16string_view(u"a")));
EXPECT_EQ(h, hash(std::u16string(u"a")));
EXPECT_NE(h, hash(std::u16string_view(u"b")));
EXPECT_NE(h, hash(std::u16string(u"b")));
-#endif
}
TEST(BasicStringViewTest, U32StringHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::u32string> hash;
auto h = hash(U"a");
EXPECT_EQ(h, hash(std::u32string_view(U"a")));
EXPECT_EQ(h, hash(std::u32string(U"a")));
EXPECT_NE(h, hash(std::u32string_view(U"b")));
EXPECT_NE(h, hash(std::u32string(U"b")));
-#endif
}
TEST(BasicStringViewTest, U32StringViewHashWorks) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
hash_default_hash<std::u32string_view> hash;
auto h = hash(U"a");
EXPECT_EQ(h, hash(std::u32string_view(U"a")));
EXPECT_EQ(h, hash(std::u32string(U"a")));
EXPECT_NE(h, hash(std::u32string_view(U"b")));
EXPECT_NE(h, hash(std::u32string(U"b")));
-#endif
}
struct NoDeleter {
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index e89dfdb..be20e21 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -14,61 +14,39 @@
#include "absl/container/internal/hash_generator_testing.h"
+#include <algorithm>
#include <deque>
+#include <random>
+#include <string>
#include "absl/base/no_destructor.h"
+#include "absl/random/random.h"
+#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
namespace hash_internal {
-namespace {
-
-class RandomDeviceSeedSeq {
- public:
- using result_type = typename std::random_device::result_type;
-
- template <class Iterator>
- void generate(Iterator start, Iterator end) {
- while (start != end) {
- *start = gen_();
- ++start;
- }
- }
-
- private:
- std::random_device gen_;
-};
-
-} // namespace
-
-std::mt19937_64* GetSharedRng() {
- static absl::NoDestructor<std::mt19937_64> rng([] {
- RandomDeviceSeedSeq seed_seq;
- return std::mt19937_64(seed_seq);
- }());
- return rng.get();
-}
std::string Generator<std::string>::operator()() const {
+ absl::InsecureBitGen gen;
// NOLINTNEXTLINE(runtime/int)
std::uniform_int_distribution<short> chars(0x20, 0x7E);
std::string res;
res.resize(32);
- std::generate(res.begin(), res.end(),
- [&]() { return chars(*GetSharedRng()); });
+ std::generate(res.begin(), res.end(), [&]() { return chars(gen); });
return res;
}
absl::string_view Generator<absl::string_view>::operator()() const {
static absl::NoDestructor<std::deque<std::string>> arena;
+ absl::InsecureBitGen gen;
// NOLINTNEXTLINE(runtime/int)
std::uniform_int_distribution<short> chars(0x20, 0x7E);
arena->emplace_back();
auto& res = arena->back();
res.resize(32);
- std::generate(res.begin(), res.end(),
- [&]() { return chars(*GetSharedRng()); });
+ std::generate(res.begin(), res.end(), [&]() { return chars(gen); });
return res;
}
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h
index f1f555a..14c878e 100644
--- a/absl/container/internal/hash_generator_testing.h
+++ b/absl/container/internal/hash_generator_testing.h
@@ -23,7 +23,9 @@
#include <algorithm>
#include <cassert>
#include <iosfwd>
+#include <memory>
#include <random>
+#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -32,6 +34,7 @@
#include "absl/container/internal/hash_policy_testing.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
+#include "absl/random/random.h"
#include "absl/strings/string_view.h"
namespace absl {
@@ -48,9 +51,7 @@
} // namespace generator_internal
-std::mt19937_64* GetSharedRng();
-
-enum Enum {
+enum Enum : uint64_t {
kEnumEmpty,
kEnumDeleted,
};
@@ -69,37 +70,27 @@
template <class T>
struct Generator<T, typename std::enable_if<std::is_integral<T>::value>::type> {
- T operator()() const {
- std::uniform_int_distribution<T> dist;
- return dist(*GetSharedRng());
- }
+ T operator()() const { return dist(gen); }
+ mutable absl::InsecureBitGen gen;
+ mutable std::uniform_int_distribution<T> dist;
};
template <>
struct Generator<Enum> {
- Enum operator()() const {
- std::uniform_int_distribution<typename std::underlying_type<Enum>::type>
- dist;
- while (true) {
- auto variate = dist(*GetSharedRng());
- if (variate != kEnumEmpty && variate != kEnumDeleted)
- return static_cast<Enum>(variate);
- }
- }
+ Enum operator()() const { return static_cast<Enum>(dist(gen)); }
+ mutable absl::InsecureBitGen gen;
+ mutable std::uniform_int_distribution<
+ typename std::underlying_type<Enum>::type>
+ dist;
};
template <>
struct Generator<EnumClass> {
- EnumClass operator()() const {
- std::uniform_int_distribution<
- typename std::underlying_type<EnumClass>::type>
- dist;
- while (true) {
- EnumClass variate = static_cast<EnumClass>(dist(*GetSharedRng()));
- if (variate != EnumClass::kEmpty && variate != EnumClass::kDeleted)
- return static_cast<EnumClass>(variate);
- }
- }
+ EnumClass operator()() const { return static_cast<EnumClass>(dist(gen)); }
+ mutable absl::InsecureBitGen gen;
+ mutable std::uniform_int_distribution<
+ typename std::underlying_type<EnumClass>::type>
+ dist;
};
template <>
@@ -143,17 +134,17 @@
template <class U>
struct Generator<U, absl::void_t<decltype(std::declval<U&>().key()),
- decltype(std::declval<U&>().value())>>
+ decltype(std::declval<U&>().value())>>
: Generator<std::pair<
typename std::decay<decltype(std::declval<U&>().key())>::type,
typename std::decay<decltype(std::declval<U&>().value())>::type>> {};
template <class Container>
-using GeneratedType = decltype(
- std::declval<const Generator<
- typename std::conditional<generator_internal::IsMap<Container>::value,
- typename Container::value_type,
- typename Container::key_type>::type>&>()());
+using GeneratedType =
+ decltype(std::declval<const Generator<typename std::conditional<
+ generator_internal::IsMap<Container>::value,
+ typename Container::value_type,
+ typename Container::key_type>::type>&>()());
// Naive wrapper that performs a linear search of previous values.
// Beware this is O(SQR), which is reasonable for smaller kMaxValues.
diff --git a/absl/container/internal/hash_policy_testing.h b/absl/container/internal/hash_policy_testing.h
index 66bb12e..e9f5757 100644
--- a/absl/container/internal/hash_policy_testing.h
+++ b/absl/container/internal/hash_policy_testing.h
@@ -119,7 +119,11 @@
using propagate_on_container_swap = std::true_type;
// Using old paradigm for this to ensure compatibility.
- explicit Alloc(size_t id = 0) : id_(id) {}
+ //
+ // NOTE: As of 2025-05, this constructor cannot be explicit in order to work
+ // with the libstdc++ that ships with GCC15.
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ Alloc(size_t id = 0) : id_(id) {}
Alloc(const Alloc&) = default;
Alloc& operator=(const Alloc&) = default;
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h
index ad835d6..cd6b42f 100644
--- a/absl/container/internal/hash_policy_traits.h
+++ b/absl/container/internal/hash_policy_traits.h
@@ -36,16 +36,12 @@
private:
struct ReturnKey {
- // When C++17 is available, we can use std::launder to provide mutable
- // access to the key for use in node handle.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
template <class Key,
absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
static key_type& Impl(Key&& k, int) {
return *std::launder(
const_cast<key_type*>(std::addressof(std::forward<Key>(k))));
}
-#endif
template <class Key>
static Key Impl(Key&& k, char) {
diff --git a/absl/container/internal/hashtable_control_bytes.h b/absl/container/internal/hashtable_control_bytes.h
new file mode 100644
index 0000000..abaadc3
--- /dev/null
+++ b/absl/container/internal/hashtable_control_bytes.h
@@ -0,0 +1,527 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This file contains the implementation of the hashtable control bytes
+// manipulation.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_CONTROL_BYTES_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLE_CONTROL_BYTES_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+#ifdef ABSL_INTERNAL_HAVE_SSE2
+#include <emmintrin.h>
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_SSSE3
+#include <tmmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
+#include <arm_neon.h>
+#endif
+
+#include "absl/base/optimization.h"
+#include "absl/numeric/bits.h"
+#include "absl/base/internal/endian.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+#ifdef ABSL_SWISSTABLE_ASSERT
+#error ABSL_SWISSTABLE_ASSERT cannot be directly set
+#else
+// We use this macro for assertions that users may see when the table is in an
+// invalid state that sanitizers may help diagnose.
+#define ABSL_SWISSTABLE_ASSERT(CONDITION) \
+ assert((CONDITION) && "Try enabling sanitizers.")
+#endif
+
+
+template <typename T>
+uint32_t TrailingZeros(T x) {
+ ABSL_ASSUME(x != 0);
+ return static_cast<uint32_t>(countr_zero(x));
+}
+
+// 8 bytes bitmask with most significant bit set for every byte.
+constexpr uint64_t kMsbs8Bytes = 0x8080808080808080ULL;
+// 8 kEmpty bytes that is useful for small table initialization.
+constexpr uint64_t k8EmptyBytes = kMsbs8Bytes;
+
+// An abstract bitmask, such as that emitted by a SIMD instruction.
+//
+// Specifically, this type implements a simple bitset whose representation is
+// controlled by `SignificantBits` and `Shift`. `SignificantBits` is the number
+// of abstract bits in the bitset, while `Shift` is the log-base-two of the
+// width of an abstract bit in the representation.
+// This mask provides operations for any number of real bits set in an abstract
+// bit. To add iteration on top of that, implementation must guarantee no more
+// than the most significant real bit is set in a set abstract bit.
+template <class T, int SignificantBits, int Shift = 0>
+class NonIterableBitMask {
+ public:
+ explicit NonIterableBitMask(T mask) : mask_(mask) {}
+
+ explicit operator bool() const { return this->mask_ != 0; }
+
+ // Returns the index of the lowest *abstract* bit set in `self`.
+ uint32_t LowestBitSet() const {
+ return container_internal::TrailingZeros(mask_) >> Shift;
+ }
+
+ // Returns the index of the highest *abstract* bit set in `self`.
+ uint32_t HighestBitSet() const {
+ return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
+ }
+
+ // Returns the number of trailing zero *abstract* bits.
+ uint32_t TrailingZeros() const {
+ return container_internal::TrailingZeros(mask_) >> Shift;
+ }
+
+ // Returns the number of leading zero *abstract* bits.
+ uint32_t LeadingZeros() const {
+ constexpr int total_significant_bits = SignificantBits << Shift;
+ constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
+ return static_cast<uint32_t>(
+ countl_zero(static_cast<T>(mask_ << extra_bits))) >>
+ Shift;
+ }
+
+ T mask_;
+};
+
+// Mask that can be iterable
+//
+// For example, when `SignificantBits` is 16 and `Shift` is zero, this is just
+// an ordinary 16-bit bitset occupying the low 16 bits of `mask`. When
+// `SignificantBits` is 8 and `Shift` is 3, abstract bits are represented as
+// the bytes `0x00` and `0x80`, and it occupies all 64 bits of the bitmask.
+// If NullifyBitsOnIteration is true (only allowed for Shift == 3),
+// non zero abstract bit is allowed to have additional bits
+// (e.g., `0xff`, `0x83` and `0x9c` are ok, but `0x6f` is not).
+//
+// For example:
+// for (int i : BitMask<uint32_t, 16>(0b101)) -> yields 0, 2
+// for (int i : BitMask<uint64_t, 8, 3>(0x0000000080800000)) -> yields 2, 3
+template <class T, int SignificantBits, int Shift = 0,
+ bool NullifyBitsOnIteration = false>
+class BitMask : public NonIterableBitMask<T, SignificantBits, Shift> {
+ using Base = NonIterableBitMask<T, SignificantBits, Shift>;
+ static_assert(std::is_unsigned<T>::value, "");
+ static_assert(Shift == 0 || Shift == 3, "");
+ static_assert(!NullifyBitsOnIteration || Shift == 3, "");
+
+ public:
+ explicit BitMask(T mask) : Base(mask) {
+ if (Shift == 3 && !NullifyBitsOnIteration) {
+ ABSL_SWISSTABLE_ASSERT(this->mask_ == (this->mask_ & kMsbs8Bytes));
+ }
+ }
+ // BitMask is an iterator over the indices of its abstract bits.
+ using value_type = int;
+ using iterator = BitMask;
+ using const_iterator = BitMask;
+
+ BitMask& operator++() {
+ if (Shift == 3 && NullifyBitsOnIteration) {
+ this->mask_ &= kMsbs8Bytes;
+ }
+ this->mask_ &= (this->mask_ - 1);
+ return *this;
+ }
+
+ uint32_t operator*() const { return Base::LowestBitSet(); }
+
+ BitMask begin() const { return *this; }
+ BitMask end() const { return BitMask(0); }
+
+ private:
+ friend bool operator==(const BitMask& a, const BitMask& b) {
+ return a.mask_ == b.mask_;
+ }
+ friend bool operator!=(const BitMask& a, const BitMask& b) {
+ return a.mask_ != b.mask_;
+ }
+};
+
+using h2_t = uint8_t;
+
+// The values here are selected for maximum performance. See the static asserts
+// below for details.
+
+// A `ctrl_t` is a single control byte, which can have one of four
+// states: empty, deleted, full (which has an associated seven-bit h2_t value)
+// and the sentinel. They have the following bit patterns:
+//
+// empty: 1 0 0 0 0 0 0 0
+// deleted: 1 1 1 1 1 1 1 0
+// full: 0 h h h h h h h // h represents the hash bits.
+// sentinel: 1 1 1 1 1 1 1 1
+//
+// These values are specifically tuned for SSE-flavored SIMD.
+// The static_asserts below detail the source of these choices.
+//
+// We use an enum class so that when strict aliasing is enabled, the compiler
+// knows ctrl_t doesn't alias other types.
+enum class ctrl_t : int8_t {
+ kEmpty = -128, // 0b10000000
+ kDeleted = -2, // 0b11111110
+ kSentinel = -1, // 0b11111111
+};
+static_assert(
+ (static_cast<int8_t>(ctrl_t::kEmpty) &
+ static_cast<int8_t>(ctrl_t::kDeleted) &
+ static_cast<int8_t>(ctrl_t::kSentinel) & 0x80) != 0,
+ "Special markers need to have the MSB to make checking for them efficient");
+static_assert(
+ ctrl_t::kEmpty < ctrl_t::kSentinel && ctrl_t::kDeleted < ctrl_t::kSentinel,
+ "ctrl_t::kEmpty and ctrl_t::kDeleted must be smaller than "
+ "ctrl_t::kSentinel to make the SIMD test of IsEmptyOrDeleted() efficient");
+static_assert(
+ ctrl_t::kSentinel == static_cast<ctrl_t>(-1),
+ "ctrl_t::kSentinel must be -1 to elide loading it from memory into SIMD "
+ "registers (pcmpeqd xmm, xmm)");
+static_assert(ctrl_t::kEmpty == static_cast<ctrl_t>(-128),
+ "ctrl_t::kEmpty must be -128 to make the SIMD check for its "
+ "existence efficient (psignb xmm, xmm)");
+static_assert(
+ (~static_cast<int8_t>(ctrl_t::kEmpty) &
+ ~static_cast<int8_t>(ctrl_t::kDeleted) &
+ static_cast<int8_t>(ctrl_t::kSentinel) & 0x7F) != 0,
+ "ctrl_t::kEmpty and ctrl_t::kDeleted must share an unset bit that is not "
+ "shared by ctrl_t::kSentinel to make the scalar test for "
+ "MaskEmptyOrDeleted() efficient");
+static_assert(ctrl_t::kDeleted == static_cast<ctrl_t>(-2),
+ "ctrl_t::kDeleted must be -2 to make the implementation of "
+ "ConvertSpecialToEmptyAndFullToDeleted efficient");
+
+// Helpers for checking the state of a control byte.
+inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; }
+inline bool IsFull(ctrl_t c) {
+ // Cast `c` to the underlying type instead of casting `0` to `ctrl_t` as `0`
+ // is not a value in the enum. Both ways are equivalent, but this way makes
+ // linters happier.
+ return static_cast<std::underlying_type_t<ctrl_t>>(c) >= 0;
+}
+inline bool IsDeleted(ctrl_t c) { return c == ctrl_t::kDeleted; }
+inline bool IsEmptyOrDeleted(ctrl_t c) { return c < ctrl_t::kSentinel; }
+
+#ifdef ABSL_INTERNAL_HAVE_SSE2
+// Quick reference guide for intrinsics used below:
+//
+// * __m128i: An XMM (128-bit) word.
+//
+// * _mm_setzero_si128: Returns a zero vector.
+// * _mm_set1_epi8: Returns a vector with the same i8 in each lane.
+//
+// * _mm_subs_epi8: Saturating-subtracts two i8 vectors.
+// * _mm_and_si128: Ands two i128s together.
+// * _mm_or_si128: Ors two i128s together.
+// * _mm_andnot_si128: And-nots two i128s together.
+//
+// * _mm_cmpeq_epi8: Component-wise compares two i8 vectors for equality,
+// filling each lane with 0x00 or 0xff.
+// * _mm_cmpgt_epi8: Same as above, but using > rather than ==.
+//
+// * _mm_loadu_si128: Performs an unaligned load of an i128.
+// * _mm_storeu_si128: Performs an unaligned store of an i128.
+//
+// * _mm_sign_epi8: Retains, negates, or zeroes each i8 lane of the first
+// argument if the corresponding lane of the second
+// argument is positive, negative, or zero, respectively.
+// * _mm_movemask_epi8: Selects the sign bit out of each i8 lane and produces a
+// bitmask consisting of those bits.
+// * _mm_shuffle_epi8: Selects i8s from the first argument, using the low
+// four bits of each i8 lane in the second argument as
+// indices.
+
+// https://github.com/abseil/abseil-cpp/issues/209
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
+// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
+// Work around this by using the portable implementation of Group
+// when using -funsigned-char under GCC.
+inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) {
+#if defined(__GNUC__) && !defined(__clang__)
+ if (std::is_unsigned<char>::value) {
+ const __m128i mask = _mm_set1_epi8(0x80);
+ const __m128i diff = _mm_subs_epi8(b, a);
+ return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask);
+ }
+#endif
+ return _mm_cmpgt_epi8(a, b);
+}
+
+struct GroupSse2Impl {
+ static constexpr size_t kWidth = 16; // the number of slots per group
+ using BitMaskType = BitMask<uint16_t, kWidth>;
+ using NonIterableBitMaskType = NonIterableBitMask<uint16_t, kWidth>;
+
+ explicit GroupSse2Impl(const ctrl_t* pos) {
+ ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
+ }
+
+ // Returns a bitmask representing the positions of slots that match hash.
+ BitMaskType Match(h2_t hash) const {
+ auto match = _mm_set1_epi8(static_cast<char>(hash));
+ return BitMaskType(
+ static_cast<uint16_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))));
+ }
+
+ // Returns a bitmask representing the positions of empty slots.
+ NonIterableBitMaskType MaskEmpty() const {
+#ifdef ABSL_INTERNAL_HAVE_SSSE3
+ // This only works because ctrl_t::kEmpty is -128.
+ return NonIterableBitMaskType(
+ static_cast<uint16_t>(_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))));
+#else
+ auto match = _mm_set1_epi8(static_cast<char>(ctrl_t::kEmpty));
+ return NonIterableBitMaskType(
+ static_cast<uint16_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))));
+#endif
+ }
+
+ // Returns a bitmask representing the positions of full slots.
+ // Note: for `is_small()` tables group may contain the "same" slot twice:
+ // original and mirrored.
+ BitMaskType MaskFull() const {
+ return BitMaskType(static_cast<uint16_t>(_mm_movemask_epi8(ctrl) ^ 0xffff));
+ }
+
+ // Returns a bitmask representing the positions of non full slots.
+ // Note: this includes: kEmpty, kDeleted, kSentinel.
+ // It is useful in contexts when kSentinel is not present.
+ auto MaskNonFull() const {
+ return BitMaskType(static_cast<uint16_t>(_mm_movemask_epi8(ctrl)));
+ }
+
+ // Returns a bitmask representing the positions of empty or deleted slots.
+ NonIterableBitMaskType MaskEmptyOrDeleted() const {
+ auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
+ return NonIterableBitMaskType(static_cast<uint16_t>(
+ _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))));
+ }
+
+ // Returns the number of trailing empty or deleted elements in the group.
+ uint32_t CountLeadingEmptyOrDeleted() const {
+ auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
+ return TrailingZeros(static_cast<uint32_t>(
+ _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
+ }
+
+ void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+ auto msbs = _mm_set1_epi8(static_cast<char>(-128));
+ auto x126 = _mm_set1_epi8(126);
+#ifdef ABSL_INTERNAL_HAVE_SSSE3
+ auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
+#else
+ auto zero = _mm_setzero_si128();
+ auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
+ auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
+#endif
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
+ }
+
+ __m128i ctrl;
+};
+#endif // ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
+
+#if defined(ABSL_INTERNAL_HAVE_ARM_NEON) && defined(ABSL_IS_LITTLE_ENDIAN)
+struct GroupAArch64Impl {
+ static constexpr size_t kWidth = 8;
+ using BitMaskType = BitMask<uint64_t, kWidth, /*Shift=*/3,
+ /*NullifyBitsOnIteration=*/true>;
+ using NonIterableBitMaskType =
+ NonIterableBitMask<uint64_t, kWidth, /*Shift=*/3>;
+
+ explicit GroupAArch64Impl(const ctrl_t* pos) {
+ ctrl = vld1_u8(reinterpret_cast<const uint8_t*>(pos));
+ }
+
+ auto Match(h2_t hash) const {
+ uint8x8_t dup = vdup_n_u8(hash);
+ auto mask = vceq_u8(ctrl, dup);
+ return BitMaskType(vget_lane_u64(vreinterpret_u64_u8(mask), 0));
+ }
+
+ auto MaskEmpty() const {
+ uint64_t mask =
+ vget_lane_u64(vreinterpret_u64_u8(vceq_s8(
+ vdup_n_s8(static_cast<int8_t>(ctrl_t::kEmpty)),
+ vreinterpret_s8_u8(ctrl))),
+ 0);
+ return NonIterableBitMaskType(mask);
+ }
+
+ // Returns a bitmask representing the positions of full slots.
+ // Note: for `is_small()` tables group may contain the "same" slot twice:
+ // original and mirrored.
+ auto MaskFull() const {
+ uint64_t mask = vget_lane_u64(
+ vreinterpret_u64_u8(vcge_s8(vreinterpret_s8_u8(ctrl),
+ vdup_n_s8(static_cast<int8_t>(0)))),
+ 0);
+ return BitMaskType(mask);
+ }
+
+ // Returns a bitmask representing the positions of non full slots.
+ // Note: this includes: kEmpty, kDeleted, kSentinel.
+ // It is useful in contexts when kSentinel is not present.
+ auto MaskNonFull() const {
+ uint64_t mask = vget_lane_u64(
+ vreinterpret_u64_u8(vclt_s8(vreinterpret_s8_u8(ctrl),
+ vdup_n_s8(static_cast<int8_t>(0)))),
+ 0);
+ return BitMaskType(mask);
+ }
+
+ auto MaskEmptyOrDeleted() const {
+ uint64_t mask =
+ vget_lane_u64(vreinterpret_u64_u8(vcgt_s8(
+ vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel)),
+ vreinterpret_s8_u8(ctrl))),
+ 0);
+ return NonIterableBitMaskType(mask);
+ }
+
+ uint32_t CountLeadingEmptyOrDeleted() const {
+ uint64_t mask =
+ vget_lane_u64(vreinterpret_u64_u8(vcle_s8(
+ vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel)),
+ vreinterpret_s8_u8(ctrl))),
+ 0);
+ // Similar to MaskEmptyorDeleted() but we invert the logic to invert the
+ // produced bitfield. We then count number of trailing zeros.
+ // Clang and GCC optimize countr_zero to rbit+clz without any check for 0,
+ // so we should be fine.
+ return static_cast<uint32_t>(countr_zero(mask)) >> 3;
+ }
+
+ void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+ uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(ctrl), 0);
+ constexpr uint64_t slsbs = 0x0202020202020202ULL;
+ constexpr uint64_t midbs = 0x7e7e7e7e7e7e7e7eULL;
+ auto x = slsbs & (mask >> 6);
+ auto res = (x + midbs) | kMsbs8Bytes;
+ little_endian::Store64(dst, res);
+ }
+
+ uint8x8_t ctrl;
+};
+#endif // ABSL_INTERNAL_HAVE_ARM_NEON && ABSL_IS_LITTLE_ENDIAN
+
+struct GroupPortableImpl {
+ static constexpr size_t kWidth = 8;
+ using BitMaskType = BitMask<uint64_t, kWidth, /*Shift=*/3,
+ /*NullifyBitsOnIteration=*/false>;
+ using NonIterableBitMaskType =
+ NonIterableBitMask<uint64_t, kWidth, /*Shift=*/3>;
+
+ explicit GroupPortableImpl(const ctrl_t* pos)
+ : ctrl(little_endian::Load64(pos)) {}
+
+ BitMaskType Match(h2_t hash) const {
+ // For the technique, see:
+ // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
+ // (Determine if a word has a byte equal to n).
+ //
+ // Caveat: there are false positives but:
+ // - they only occur if there is a real match
+ // - they never occur on ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kSentinel
+ // - they will be handled gracefully by subsequent checks in code
+ //
+ // Example:
+ // v = 0x1716151413121110
+ // hash = 0x12
+ // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000
+ constexpr uint64_t lsbs = 0x0101010101010101ULL;
+ auto x = ctrl ^ (lsbs * hash);
+ return BitMaskType((x - lsbs) & ~x & kMsbs8Bytes);
+ }
+
+ auto MaskEmpty() const {
+ return NonIterableBitMaskType((ctrl & ~(ctrl << 6)) & kMsbs8Bytes);
+ }
+
+ // Returns a bitmask representing the positions of full slots.
+ // Note: for `is_small()` tables group may contain the "same" slot twice:
+ // original and mirrored.
+ auto MaskFull() const {
+ return BitMaskType((ctrl ^ kMsbs8Bytes) & kMsbs8Bytes);
+ }
+
+ // Returns a bitmask representing the positions of non full slots.
+ // Note: this includes: kEmpty, kDeleted, kSentinel.
+ // It is useful in contexts when kSentinel is not present.
+ auto MaskNonFull() const { return BitMaskType(ctrl & kMsbs8Bytes); }
+
+ auto MaskEmptyOrDeleted() const {
+ return NonIterableBitMaskType((ctrl & ~(ctrl << 7)) & kMsbs8Bytes);
+ }
+
+ uint32_t CountLeadingEmptyOrDeleted() const {
+ // ctrl | ~(ctrl >> 7) will have the lowest bit set to zero for kEmpty and
+ // kDeleted. We lower all other bits and count number of trailing zeros.
+ constexpr uint64_t bits = 0x0101010101010101ULL;
+ return static_cast<uint32_t>(countr_zero((ctrl | ~(ctrl >> 7)) & bits) >>
+ 3);
+ }
+
+ void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
+ constexpr uint64_t lsbs = 0x0101010101010101ULL;
+ auto x = ctrl & kMsbs8Bytes;
+ auto res = (~x + (x >> 7)) & ~lsbs;
+ little_endian::Store64(dst, res);
+ }
+
+ uint64_t ctrl;
+};
+
+#ifdef ABSL_INTERNAL_HAVE_SSE2
+using Group = GroupSse2Impl;
+using GroupFullEmptyOrDeleted = GroupSse2Impl;
+#elif defined(ABSL_INTERNAL_HAVE_ARM_NEON) && defined(ABSL_IS_LITTLE_ENDIAN)
+using Group = GroupAArch64Impl;
+// For Aarch64, we use the portable implementation for counting and masking
+// full, empty or deleted group elements. This is to avoid the latency of moving
+// between data GPRs and Neon registers when it does not provide a benefit.
+// Using Neon is profitable when we call Match(), but is not when we don't,
+// which is the case when we do *EmptyOrDeleted and MaskFull operations.
+// It is difficult to make a similar approach beneficial on other architectures
+// such as x86 since they have much lower GPR <-> vector register transfer
+// latency and 16-wide Groups.
+using GroupFullEmptyOrDeleted = GroupPortableImpl;
+#else
+using Group = GroupPortableImpl;
+using GroupFullEmptyOrDeleted = GroupPortableImpl;
+#endif
+
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#undef ABSL_SWISSTABLE_ASSERT
+
+#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_CONTROL_BYTES_H_
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index fd21d96..c0fce87 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -42,10 +42,6 @@
ABSL_NAMESPACE_BEGIN
namespace container_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr int HashtablezInfo::kMaxStackDepth;
-#endif
-
namespace {
ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
false
@@ -126,6 +122,26 @@
return state == kForce;
}
+#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
+HashtablezInfoHandle ForcedTrySample(size_t inline_element_size,
+ size_t key_size, size_t value_size,
+ uint16_t soo_capacity) {
+ return HashtablezInfoHandle(SampleSlow(global_next_sample,
+ inline_element_size, key_size,
+ value_size, soo_capacity));
+}
+void TestOnlyRefreshSamplingStateForCurrentThread() {
+ global_next_sample.next_sample =
+ g_hashtablez_sample_parameter.load(std::memory_order_relaxed);
+ global_next_sample.sample_stride = global_next_sample.next_sample;
+}
+#else
+HashtablezInfoHandle ForcedTrySample(size_t, size_t, size_t, uint16_t) {
+ return HashtablezInfoHandle{nullptr};
+}
+void TestOnlyRefreshSamplingStateForCurrentThread() {}
+#endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
+
HashtablezInfo* SampleSlow(SamplingState& next_sample,
size_t inline_element_size, size_t key_size,
size_t value_size, uint16_t soo_capacity) {
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index d74acf8..305dc85 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -219,22 +219,41 @@
extern ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample;
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
-// Returns a sampling handle.
-inline HashtablezInfoHandle Sample(
- ABSL_ATTRIBUTE_UNUSED size_t inline_element_size,
- ABSL_ATTRIBUTE_UNUSED size_t key_size,
- ABSL_ATTRIBUTE_UNUSED size_t value_size,
- ABSL_ATTRIBUTE_UNUSED uint16_t soo_capacity) {
+// Returns true if the next table should be sampled.
+// This function updates the global state.
+// If the function returns true, actual sampling should be done by calling
+// ForcedTrySample().
+inline bool ShouldSampleNextTable() {
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
if (ABSL_PREDICT_TRUE(--global_next_sample.next_sample > 0)) {
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif // ABSL_INTERNAL_HASHTABLEZ_SAMPLE
+}
+
+// Returns a sampling handle.
+// Must be called only if HashSetShouldBeSampled() returned true.
+// Returned handle still can be unsampled if sampling is not possible.
+HashtablezInfoHandle ForcedTrySample(size_t inline_element_size,
+ size_t key_size, size_t value_size,
+ uint16_t soo_capacity);
+
+// In case sampling needs to be disabled and re-enabled in tests, this function
+// can be used to reset the sampling state for the current thread.
+// It is useful to avoid sampling attempts and sampling delays in tests.
+void TestOnlyRefreshSamplingStateForCurrentThread();
+
+// Returns a sampling handle.
+inline HashtablezInfoHandle Sample(size_t inline_element_size, size_t key_size,
+ size_t value_size, uint16_t soo_capacity) {
+ if (ABSL_PREDICT_TRUE(!ShouldSampleNextTable())) {
return HashtablezInfoHandle(nullptr);
}
- return HashtablezInfoHandle(SampleSlow(global_next_sample,
- inline_element_size, key_size,
- value_size, soo_capacity));
-#else
- return HashtablezInfoHandle(nullptr);
-#endif // !ABSL_PER_THREAD_TLS
+ return ForcedTrySample(inline_element_size, key_size, value_size,
+ soo_capacity);
}
using HashtablezSampler =
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index 24d3bc4..0de1e29 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -27,6 +27,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/profiling/internal/sample_recorder.h"
+#include "absl/random/random.h"
#include "absl/synchronization/blocking_counter.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/synchronization/mutex.h"
@@ -439,8 +440,7 @@
const size_t value_size = 13 + i % 5;
pool.Schedule([&sampler, &stop, sampling_stride, elt_size, key_size,
value_size]() {
- std::random_device rd;
- std::mt19937 gen(rd());
+ absl::InsecureBitGen gen;
std::vector<HashtablezInfo*> infoz;
while (!stop.HasBeenNotified()) {
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
index 2f24e46..b0d3f07 100644
--- a/absl/container/internal/inlined_vector.h
+++ b/absl/container/internal/inlined_vector.h
@@ -73,18 +73,15 @@
template <typename A>
using MoveIterator = typename std::move_iterator<Iterator<A>>;
-template <typename Iterator>
-using IsAtLeastForwardIterator = std::is_convertible<
- typename std::iterator_traits<Iterator>::iterator_category,
- std::forward_iterator_tag>;
-
template <typename A>
using IsMoveAssignOk = std::is_move_assignable<ValueType<A>>;
template <typename A>
using IsSwapOk = absl::type_traits_internal::IsSwappable<ValueType<A>>;
-template <typename A, bool IsTriviallyDestructible =
- absl::is_trivially_destructible<ValueType<A>>::value>
+template <typename A,
+ bool IsTriviallyDestructible =
+ absl::is_trivially_destructible<ValueType<A>>::value &&
+ std::is_same<A, std::allocator<ValueType<A>>>::value>
struct DestroyAdapter;
template <typename A>
@@ -232,7 +229,7 @@
return result.data;
}
- ABSL_MUST_USE_RESULT Allocation<A> Release() && {
+ [[nodiscard]] Allocation<A> Release() && {
Allocation<A> result = {GetData(), GetCapacity()};
Reset();
return result;
@@ -546,7 +543,7 @@
(std::max)(N, sizeof(Allocated) / sizeof(ValueType<A>));
struct Inlined {
- alignas(ValueType<A>) char inlined_data[sizeof(
+ alignas(ValueType<A>) unsigned char inlined_data[sizeof(
ValueType<A>[kOptimalInlinedSize])];
};
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h
index 384929a..58c8d4f 100644
--- a/absl/container/internal/layout.h
+++ b/absl/container/internal/layout.h
@@ -192,7 +192,6 @@
#include <typeinfo>
#include <utility>
-#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/debugging/internal/demangle.h"
#include "absl/meta/type_traits.h"
@@ -306,7 +305,7 @@
template <class T>
std::string TypeName() {
std::string out;
-#if ABSL_INTERNAL_HAS_RTTI
+#ifdef ABSL_INTERNAL_HAS_RTTI
absl::StrAppend(&out, "<",
absl::debugging_internal::DemangleString(typeid(T).name()),
">");
@@ -316,9 +315,6 @@
} // namespace adl_barrier
-template <bool C>
-using EnableIf = typename std::enable_if<C, int>::type;
-
// Can `T` be a template argument of `Layout`?
template <class T>
using IsLegalElementType = std::integral_constant<
@@ -418,17 +414,16 @@
// assert(x.Offset<1>() == 16); // The doubles starts from 16.
//
// Requires: `N <= NumSizes && N < sizeof...(Ts)`.
- template <size_t N, EnableIf<N == 0> = 0>
+ template <size_t N>
constexpr size_t Offset() const {
- return 0;
- }
-
- template <size_t N, EnableIf<N != 0> = 0>
- constexpr size_t Offset() const {
- static_assert(N < NumOffsets, "Index out of bounds");
- return adl_barrier::Align(
- Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(),
- ElementAlignment<N>::value);
+ if constexpr (N == 0) {
+ return 0;
+ } else {
+ static_assert(N < NumOffsets, "Index out of bounds");
+ return adl_barrier::Align(
+ Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(),
+ ElementAlignment<N>::value);
+ }
}
// Offset in bytes of the array with the specified element type. There must
@@ -457,15 +452,14 @@
// assert(x.Size<1>() == 4);
//
// Requires: `N < NumSizes`.
- template <size_t N, EnableIf<(N < NumStaticSizes)> = 0>
+ template <size_t N>
constexpr size_t Size() const {
- return kStaticSizes[N];
- }
-
- template <size_t N, EnableIf<(N >= NumStaticSizes)> = 0>
- constexpr size_t Size() const {
- static_assert(N < NumSizes, "Index out of bounds");
- return size_[N - NumStaticSizes];
+ if constexpr (N < NumStaticSizes) {
+ return kStaticSizes[N];
+ } else {
+ static_assert(N < NumSizes, "Index out of bounds");
+ return size_[N - NumStaticSizes];
+ }
}
// The number of elements in the array with the specified element type.
@@ -596,10 +590,10 @@
//
// Requires: `p` is aligned to `Alignment()`.
//
- // Note: We mark the parameter as unused because GCC detects it is not used
- // when `SizeSeq` is empty [-Werror=unused-but-set-parameter].
+ // Note: We mark the parameter as maybe_unused because GCC detects it is not
+ // used when `SizeSeq` is empty [-Werror=unused-but-set-parameter].
template <class Char>
- auto Slices(ABSL_ATTRIBUTE_UNUSED Char* p) const {
+ auto Slices([[maybe_unused]] Char* p) const {
return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
Slice<SizeSeq>(p)...);
}
@@ -624,15 +618,13 @@
// `Char` must be `[const] [signed|unsigned] char`.
//
// Requires: `p` is aligned to `Alignment()`.
- template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
+ template <class Char, size_t N = NumOffsets - 1>
void PoisonPadding(const Char* p) const {
- Pointer<0>(p); // verify the requirements on `Char` and `p`
- }
-
- template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
- void PoisonPadding(const Char* p) const {
- static_assert(N < NumOffsets, "Index out of bounds");
- (void)p;
+ if constexpr (N == 0) {
+ Pointer<0>(p); // verify the requirements on `Char` and `p`
+ } else {
+ static_assert(N < NumOffsets, "Index out of bounds");
+ (void)p;
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
PoisonPadding<Char, N - 1>(p);
// The `if` is an optimization. It doesn't affect the observable behaviour.
@@ -642,6 +634,7 @@
ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
}
#endif
+ }
}
// Human-readable description of the memory layout. Useful for debugging.
@@ -692,15 +685,6 @@
size_t size_[NumRuntimeSizes > 0 ? NumRuntimeSizes : 1];
};
-// Defining a constexpr static class member variable is redundant and deprecated
-// in C++17, but required in C++14.
-template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
- size_t... SizeSeq, size_t... OffsetSeq>
-constexpr std::array<size_t, sizeof...(StaticSizeSeq)> LayoutImpl<
- std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
- absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
- absl::index_sequence<OffsetSeq...>>::kStaticSizes;
-
template <class StaticSizeSeq, size_t NumRuntimeSizes, class... Ts>
using LayoutType = LayoutImpl<
std::tuple<Ts...>, StaticSizeSeq,
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h
index 464bf23..b42a4f2 100644
--- a/absl/container/internal/raw_hash_map.h
+++ b/absl/container/internal/raw_hash_map.h
@@ -22,8 +22,10 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
+#include "absl/container/internal/common_policy_traits.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
+#include "absl/meta/type_traits.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -43,14 +45,39 @@
using MappedConstReference = decltype(P::value(
std::addressof(std::declval<typename raw_hash_map::const_reference>())));
- using KeyArgImpl =
- KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
+ template <class K>
+ using key_arg =
+ typename KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>::
+ template type<K, typename Policy::key_type>;
+
+ // NOTE: The mess here is to shorten the code for the (very repetitive)
+ // function overloads, and to allow the lifetime-bound overloads to dispatch
+ // to the non-lifetime-bound overloads, to ensure there is a single source of
+ // truth for each overload set.
+ //
+ // Enabled if an assignment from the given type would require the
+ // source object to remain alive for the life of the element.
+ //
+ // TODO(b/402804213): Remove these traits and simplify the overloads whenever
+ // we have a better mechanism available to handle lifetime analysis.
+ template <class K, bool Value, typename = void>
+ using LifetimeBoundK = HasValue<
+ Value, std::conditional_t<policy_trait_element_is_owner<Policy>::value,
+ std::false_type,
+ type_traits_internal::IsLifetimeBoundAssignment<
+ typename Policy::key_type, K>>>;
+ template <class V, bool Value, typename = void>
+ using LifetimeBoundV =
+ HasValue<Value, type_traits_internal::IsLifetimeBoundAssignment<
+ typename Policy::mapped_type, V>>;
+ template <class K, bool KValue, class V, bool VValue, typename... Dummy>
+ using LifetimeBoundKV =
+ absl::conjunction<LifetimeBoundK<K, KValue, absl::void_t<Dummy...>>,
+ LifetimeBoundV<V, VValue>>;
public:
using key_type = typename Policy::key_type;
using mapped_type = typename Policy::mapped_type;
- template <class K>
- using key_arg = typename KeyArgImpl::template type<K, key_type>;
static_assert(!std::is_reference<key_type>::value, "");
@@ -71,87 +98,175 @@
// union { int n : 1; };
// flat_hash_map<int, int> m;
// m.insert_or_assign(n, n);
- template <class K = key_type, class V = mapped_type, K* = nullptr,
- V* = nullptr>
- std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
- }
+ //
+ // TODO(b/402804213): Remove these macros whenever we have a better mechanism
+ // available to handle lifetime analysis.
+#define ABSL_INTERNAL_X(Func, Callee, KQual, VQual, KValue, VValue, Tail, ...) \
+ template < \
+ typename K = key_type, class V = mapped_type, \
+ ABSL_INTERNAL_IF_##KValue##_NOR_##VValue( \
+ int = (EnableIf<LifetimeBoundKV<K, KValue, V, VValue, \
+ IfRRef<int KQual>::AddPtr<K>, \
+ IfRRef<int VQual>::AddPtr<V>>>()), \
+ ABSL_INTERNAL_SINGLE_ARG( \
+ int &..., \
+ decltype(EnableIf<LifetimeBoundKV<K, KValue, V, VValue>>()) = \
+ 0))> \
+ decltype(auto) Func( \
+ __VA_ARGS__ key_arg<K> KQual k ABSL_INTERNAL_IF_##KValue( \
+ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this)), \
+ V VQual v ABSL_INTERNAL_IF_##VValue(ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY( \
+ this))) ABSL_ATTRIBUTE_LIFETIME_BOUND { \
+ return ABSL_INTERNAL_IF_##KValue##_OR_##VValue( \
+ (this->template Func<K, V, 0>), Callee)( \
+ std::forward<decltype(k)>(k), std::forward<decltype(v)>(v)) Tail; \
+ } \
+ static_assert(true, "This is to force a semicolon.")
- template <class K = key_type, class V = mapped_type, K* = nullptr>
- std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(std::forward<K>(k), v);
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, true, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, true, ABSL_INTERNAL_SINGLE_ARG());
- template <class K = key_type, class V = mapped_type, V* = nullptr>
- std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(k, std::forward<V>(v));
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ true, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ true, ABSL_INTERNAL_SINGLE_ARG());
- template <class K = key_type, class V = mapped_type>
- std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign_impl(k, v);
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ true, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ false, ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ true, ABSL_INTERNAL_SINGLE_ARG());
- template <class K = key_type, class V = mapped_type, K* = nullptr,
- V* = nullptr>
- iterator insert_or_assign(const_iterator, key_arg<K>&& k,
- V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, false,
+ ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true,
+ ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false,
+ ABSL_INTERNAL_SINGLE_ARG());
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true,
+ ABSL_INTERNAL_SINGLE_ARG());
- template <class K = key_type, class V = mapped_type, K* = nullptr>
- iterator insert_or_assign(const_iterator, key_arg<K>&& k,
- const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign(std::forward<K>(k), v).first;
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ false, true, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, const &,
+ true, true, .first, const_iterator ABSL_INTERNAL_COMMA);
- template <class K = key_type, class V = mapped_type, V* = nullptr>
- iterator insert_or_assign(const_iterator, const key_arg<K>& k,
- V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign(k, std::forward<V>(v)).first;
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, false,
+ true, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, const &, &&, true,
+ true, .first, const_iterator ABSL_INTERNAL_COMMA);
- template <class K = key_type, class V = mapped_type>
- iterator insert_or_assign(const_iterator, const key_arg<K>& k,
- const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return insert_or_assign(k, v).first;
- }
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, false,
+ true, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ false, .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, const &, true,
+ true, .first, const_iterator ABSL_INTERNAL_COMMA);
+
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, false,
+ .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, false, true,
+ .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, false,
+ .first, const_iterator ABSL_INTERNAL_COMMA);
+ ABSL_INTERNAL_X(insert_or_assign, insert_or_assign_impl, &&, &&, true, true,
+ .first, const_iterator ABSL_INTERNAL_COMMA);
+#undef ABSL_INTERNAL_X
// All `try_emplace()` overloads make the same guarantees regarding rvalue
// arguments as `std::unordered_map::try_emplace()`, namely that these
// functions will not move from rvalue arguments if insertions do not happen.
- template <class K = key_type, class... Args,
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false, K *>>(),
+ class... Args,
typename std::enable_if<
- !std::is_convertible<K, const_iterator>::value, int>::type = 0,
- K* = nullptr>
- std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
+ !std::is_convertible<K, const_iterator>::value, int>::type = 0>
+ std::pair<iterator, bool> try_emplace(key_arg<K> &&k, Args &&...args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
}
template <class K = key_type, class... Args,
+ EnableIf<LifetimeBoundK<K, true, K *>> = 0,
typename std::enable_if<
!std::is_convertible<K, const_iterator>::value, int>::type = 0>
- std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
+ std::pair<iterator, bool> try_emplace(
+ key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template try_emplace<K, 0>(std::forward<K>(k),
+ std::forward<Args>(args)...);
+ }
+
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>(),
+ class... Args,
+ typename std::enable_if<
+ !std::is_convertible<K, const_iterator>::value, int>::type = 0>
+ std::pair<iterator, bool> try_emplace(const key_arg<K> &k, Args &&...args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace_impl(k, std::forward<Args>(args)...);
}
-
- template <class K = key_type, class... Args, K* = nullptr>
- iterator try_emplace(const_iterator, key_arg<K>&& k,
- Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
+ template <class K = key_type, class... Args,
+ EnableIf<LifetimeBoundK<K, true>> = 0,
+ typename std::enable_if<
+ !std::is_convertible<K, const_iterator>::value, int>::type = 0>
+ std::pair<iterator, bool> try_emplace(
+ const key_arg<K> &k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template try_emplace<K, 0>(k, std::forward<Args>(args)...);
}
- template <class K = key_type, class... Args>
- iterator try_emplace(const_iterator, const key_arg<K>& k,
- Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false, K *>>(),
+ class... Args>
+ iterator try_emplace(const_iterator, key_arg<K> &&k,
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
+ }
+ template <class K = key_type, class... Args,
+ EnableIf<LifetimeBoundK<K, true, K *>> = 0>
+ iterator try_emplace(const_iterator hint,
+ key_arg<K> &&k ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template try_emplace<K, 0>(hint, std::forward<K>(k),
+ std::forward<Args>(args)...);
+ }
+
+ template <class K = key_type, int = EnableIf<LifetimeBoundK<K, false>>(),
+ class... Args>
+ iterator try_emplace(const_iterator, const key_arg<K> &k,
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return try_emplace(k, std::forward<Args>(args)...).first;
}
+ template <class K = key_type, class... Args,
+ EnableIf<LifetimeBoundK<K, true>> = 0>
+ iterator try_emplace(const_iterator hint,
+ const key_arg<K> &k
+ ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this),
+ Args &&...args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template try_emplace<K, 0>(hint, std::forward<K>(k),
+ std::forward<Args>(args)...);
+ }
template <class K = key_type, class P = Policy>
MappedReference<P> at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
@@ -174,8 +289,9 @@
return Policy::value(&*it);
}
- template <class K = key_type, class P = Policy, K* = nullptr>
- MappedReference<P> operator[](key_arg<K>&& key)
+ template <class K = key_type, class P = Policy,
+ int = EnableIf<LifetimeBoundK<K, false, K *>>()>
+ MappedReference<P> operator[](key_arg<K> &&key)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// It is safe to use unchecked_deref here because try_emplace
// will always return an iterator pointing to a valid item in the table,
@@ -183,15 +299,30 @@
return Policy::value(
&this->unchecked_deref(try_emplace(std::forward<K>(key)).first));
}
+ template <class K = key_type, class P = Policy, int &...,
+ EnableIf<LifetimeBoundK<K, true, K *>> = 0>
+ MappedReference<P> operator[](
+ key_arg<K> &&key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template operator[]<K, P, 0>(std::forward<K>(key));
+ }
- template <class K = key_type, class P = Policy>
- MappedReference<P> operator[](const key_arg<K>& key)
+ template <class K = key_type, class P = Policy,
+ int = EnableIf<LifetimeBoundK<K, false>>()>
+ MappedReference<P> operator[](const key_arg<K> &key)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
// It is safe to use unchecked_deref here because try_emplace
// will always return an iterator pointing to a valid item in the table,
// since it inserts if nothing is found for the given key.
return Policy::value(&this->unchecked_deref(try_emplace(key).first));
}
+ template <class K = key_type, class P = Policy, int &...,
+ EnableIf<LifetimeBoundK<K, true>> = 0>
+ MappedReference<P> operator[](
+ const key_arg<K> &key ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template operator[]<K, P, 0>(key);
+ }
private:
template <class K, class V>
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 1cae038..339e662 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -24,9 +24,13 @@
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
#include "absl/base/optimization.h"
#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hashtable_control_bytes.h"
#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/container/internal/raw_hash_set_resize_impl.h"
+#include "absl/functional/function_ref.h"
#include "absl/hash/hash.h"
namespace absl {
@@ -63,21 +67,31 @@
static_assert(NumControlBytes(SooCapacity()) <= 17,
"kSooControl capacity too small");
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr size_t Group::kWidth;
+namespace {
+
+#ifdef ABSL_SWISSTABLE_ASSERT
+#error ABSL_SWISSTABLE_ASSERT cannot be directly set
+#else
+// We use this macro for assertions that users may see when the table is in an
+// invalid state that sanitizers may help diagnose.
+#define ABSL_SWISSTABLE_ASSERT(CONDITION) \
+ assert((CONDITION) && "Try enabling sanitizers.")
#endif
-namespace {
+[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void HashTableSizeOverflow() {
+ ABSL_RAW_LOG(FATAL, "Hash table size overflow");
+}
+
+void ValidateMaxSize(size_t size, size_t slot_size) {
+ if (IsAboveValidSize(size, slot_size)) {
+ HashTableSizeOverflow();
+ }
+}
// Returns "random" seed.
inline size_t RandomSeed() {
#ifdef ABSL_HAVE_THREAD_LOCAL
static thread_local size_t counter = 0;
- // On Linux kernels >= 5.4 the MSAN runtime has a false-positive when
- // accessing thread local storage data from loaded libraries
- // (https://github.com/google/sanitizers/issues/1265), for this reason counter
- // needs to be annotated as initialized.
- ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(&counter, sizeof(size_t));
size_t value = ++counter;
#else // ABSL_HAVE_THREAD_LOCAL
static std::atomic<size_t> counter(0);
@@ -86,16 +100,37 @@
return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
}
-bool ShouldRehashForBugDetection(const ctrl_t* ctrl, size_t capacity) {
+bool ShouldRehashForBugDetection(PerTableSeed seed, size_t capacity) {
// Note: we can't use the abseil-random library because abseil-random
// depends on swisstable. We want to return true with probability
// `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
// we probe based on a random hash and see if the offset is less than
// RehashProbabilityConstant().
- return probe(ctrl, capacity, absl::HashOf(RandomSeed())).offset() <
+ return probe(seed, capacity, absl::HashOf(RandomSeed())).offset() <
RehashProbabilityConstant();
}
+// Find a non-deterministic hash for single group table.
+// Last two bits are used to find a position for a newly inserted element after
+// resize.
+// This function basically using H2 last bits to save on shift operation.
+size_t SingleGroupTableH1(size_t hash, PerTableSeed seed) {
+ return hash ^ seed.seed();
+}
+
+// Returns the address of the slot `i` iterations after `slot` assuming each
+// slot has the specified size.
+inline void* NextSlot(void* slot, size_t slot_size, size_t i = 1) {
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) +
+ slot_size * i);
+}
+
+// Returns the address of the slot just before `slot` assuming each slot has the
+// specified size.
+inline void* PrevSlot(void* slot, size_t slot_size) {
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
+}
+
} // namespace
GenerationType* EmptyGeneration() {
@@ -109,42 +144,104 @@
}
bool CommonFieldsGenerationInfoEnabled::
- should_rehash_for_bug_detection_on_insert(const ctrl_t* ctrl,
+ should_rehash_for_bug_detection_on_insert(PerTableSeed seed,
size_t capacity) const {
if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
if (reserved_growth_ > 0) return false;
- return ShouldRehashForBugDetection(ctrl, capacity);
+ return ShouldRehashForBugDetection(seed, capacity);
}
bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
- const ctrl_t* ctrl, size_t capacity) const {
- return ShouldRehashForBugDetection(ctrl, capacity);
+ PerTableSeed seed, size_t capacity) const {
+ return ShouldRehashForBugDetection(seed, capacity);
}
-bool ShouldInsertBackwardsForDebug(size_t capacity, size_t hash,
- const ctrl_t* ctrl) {
- // To avoid problems with weak hashes and single bit tests, we use % 13.
- // TODO(kfm,sbenza): revisit after we do unconditional mixing
- return !is_small(capacity) && (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
+namespace {
+
+FindInfo find_first_non_full_from_h1(const ctrl_t* ctrl, size_t h1,
+ size_t capacity) {
+ auto seq = probe(h1, capacity);
+ if (IsEmptyOrDeleted(ctrl[seq.offset()])) {
+ return {seq.offset(), /*probe_length=*/0};
+ }
+ while (true) {
+ GroupFullEmptyOrDeleted g{ctrl + seq.offset()};
+ auto mask = g.MaskEmptyOrDeleted();
+ if (mask) {
+ return {seq.offset(mask.LowestBitSet()), seq.index()};
+ }
+ seq.next();
+ ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity && "full table!");
+ }
}
-size_t PrepareInsertAfterSoo(size_t hash, size_t slot_size,
- CommonFields& common) {
- assert(common.capacity() == NextCapacity(SooCapacity()));
- // After resize from capacity 1 to 3, we always have exactly the slot with
- // index 1 occupied, so we need to insert either at index 0 or index 2.
- assert(HashSetResizeHelper::SooSlotIndex() == 1);
- PrepareInsertCommon(common);
- const size_t offset = H1(hash, common.control()) & 2;
- common.growth_info().OverwriteEmptyAsFull();
- SetCtrlInSingleGroupTable(common, offset, H2(hash), slot_size);
- common.infoz().RecordInsert(hash, /*distance_from_desired=*/0);
- return offset;
+// Whether a table is "small". A small table fits entirely into a probing
+// group, i.e., has a capacity < `Group::kWidth`.
+//
+// In small mode we are able to use the whole capacity. The extra control
+// bytes give us at least one "empty" control byte to stop the iteration.
+// This is important to make 1 a valid capacity.
+//
+// In small mode only the first `capacity` control bytes after the sentinel
+// are valid. The rest contain dummy ctrl_t::kEmpty values that do not
+// represent a real slot.
+constexpr bool is_small(size_t capacity) {
+ return capacity < Group::kWidth - 1;
}
+template <class Fn>
+void IterateOverFullSlotsImpl(const CommonFields& c, size_t slot_size, Fn cb) {
+ const size_t cap = c.capacity();
+ const ctrl_t* ctrl = c.control();
+ void* slot = c.slot_array();
+ if (is_small(cap)) {
+ // Mirrored/cloned control bytes in small table are also located in the
+ // first group (starting from position 0). We are taking group from position
+ // `capacity` in order to avoid duplicates.
+
+ // Small tables capacity fits into portable group, where
+ // GroupPortableImpl::MaskFull is more efficient for the
+ // capacity <= GroupPortableImpl::kWidth.
+ ABSL_SWISSTABLE_ASSERT(cap <= GroupPortableImpl::kWidth &&
+ "unexpectedly large small capacity");
+ static_assert(Group::kWidth >= GroupPortableImpl::kWidth,
+ "unexpected group width");
+ // Group starts from kSentinel slot, so indices in the mask will
+ // be increased by 1.
+ const auto mask = GroupPortableImpl(ctrl + cap).MaskFull();
+ --ctrl;
+ slot = PrevSlot(slot, slot_size);
+ for (uint32_t i : mask) {
+ cb(ctrl + i, SlotAddress(slot, i, slot_size));
+ }
+ return;
+ }
+ size_t remaining = c.size();
+ ABSL_ATTRIBUTE_UNUSED const size_t original_size_for_assert = remaining;
+ while (remaining != 0) {
+ for (uint32_t i : GroupFullEmptyOrDeleted(ctrl).MaskFull()) {
+ ABSL_SWISSTABLE_ASSERT(IsFull(ctrl[i]) &&
+ "hash table was modified unexpectedly");
+ cb(ctrl + i, SlotAddress(slot, i, slot_size));
+ --remaining;
+ }
+ ctrl += Group::kWidth;
+ slot = NextSlot(slot, slot_size, Group::kWidth);
+ ABSL_SWISSTABLE_ASSERT(
+ (remaining == 0 || *(ctrl - 1) != ctrl_t::kSentinel) &&
+ "hash table was modified unexpectedly");
+ }
+ // NOTE: erasure of the current element is allowed in callback for
+ // absl::erase_if specialization. So we use `>=`.
+ ABSL_SWISSTABLE_ASSERT(original_size_for_assert >= c.size() &&
+ "hash table was modified unexpectedly");
+}
+
+} // namespace
+
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
- assert(ctrl[capacity] == ctrl_t::kSentinel);
- assert(IsValidCapacity(capacity));
+ ABSL_SWISSTABLE_ASSERT(ctrl[capacity] == ctrl_t::kSentinel);
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) {
Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
}
@@ -152,26 +249,25 @@
std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes());
ctrl[capacity] = ctrl_t::kSentinel;
}
-// Extern template instantiation for inline function.
-template FindInfo find_first_non_full(const CommonFields&, size_t);
-FindInfo find_first_non_full_outofline(const CommonFields& common,
- size_t hash) {
- return find_first_non_full(common, hash);
+FindInfo find_first_non_full(const CommonFields& common, size_t hash) {
+ return find_first_non_full_from_h1(common.control(), H1(hash, common.seed()),
+ common.capacity());
+}
+
+void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
+ absl::FunctionRef<void(const ctrl_t*, void*)> cb) {
+ IterateOverFullSlotsImpl(c, slot_size, cb);
}
namespace {
-// Returns the address of the slot just after slot assuming each slot has the
-// specified size.
-static inline void* NextSlot(void* slot, size_t slot_size) {
- return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) + slot_size);
+void ResetGrowthLeft(GrowthInfo& growth_info, size_t capacity, size_t size) {
+ growth_info.InitGrowthLeftNoDeleted(CapacityToGrowth(capacity) - size);
}
-// Returns the address of the slot just before slot assuming each slot has the
-// specified size.
-static inline void* PrevSlot(void* slot, size_t slot_size) {
- return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
+void ResetGrowthLeft(CommonFields& common) {
+ ResetGrowthLeft(common.growth_info(), common.capacity(), common.size());
}
// Finds guaranteed to exists empty slot from the given position.
@@ -184,17 +280,34 @@
return i;
}
}
- assert(false && "no empty slot");
- return ~size_t{};
+ ABSL_UNREACHABLE();
}
-void DropDeletesWithoutResize(CommonFields& common,
- const PolicyFunctions& policy) {
+// Finds guaranteed to exist full slot starting from the given position.
+// NOTE: this function is only triggered for rehash(0), when we need to
+// go back to SOO state, so we keep it simple.
+size_t FindFirstFullSlot(size_t start, size_t end, const ctrl_t* ctrl) {
+ for (size_t i = start; i < end; ++i) {
+ if (IsFull(ctrl[i])) {
+ return i;
+ }
+ }
+ ABSL_UNREACHABLE();
+}
+
+void PrepareInsertCommon(CommonFields& common) {
+ common.increment_size();
+ common.maybe_increment_generation_on_insert();
+}
+
+size_t DropDeletesWithoutResizeAndPrepareInsert(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_hash) {
void* set = &common;
void* slot_array = common.slot_array();
const size_t capacity = common.capacity();
- assert(IsValidCapacity(capacity));
- assert(!is_small(capacity));
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
+ ABSL_SWISSTABLE_ASSERT(!is_single_group(capacity));
// Algorithm:
// - mark all DELETED slots as EMPTY
// - mark all FULL slots as DELETED
@@ -215,7 +328,7 @@
ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity);
const void* hash_fn = policy.hash_fn(common);
auto hasher = policy.hash_slot;
- auto transfer = policy.transfer;
+ auto transfer_n = policy.transfer_n;
const size_t slot_size = policy.slot_size;
size_t total_probe_length = 0;
@@ -228,7 +341,7 @@
for (size_t i = 0; i != capacity;
++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
- assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
+ ABSL_SWISSTABLE_ASSERT(slot_ptr == SlotAddress(slot_array, i, slot_size));
if (IsEmpty(ctrl[i])) {
tmp_space_id = i;
continue;
@@ -243,13 +356,14 @@
// If they do, we don't need to move the object as it falls already in the
// best probe we can.
const size_t probe_offset = probe(common, hash).offset();
+ const h2_t h2 = H2(hash);
const auto probe_index = [probe_offset, capacity](size_t pos) {
return ((pos - probe_offset) & capacity) / Group::kWidth;
};
// Element doesn't move.
if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
- SetCtrl(common, i, H2(hash), slot_size);
+ SetCtrlInLargeTable(common, i, h2, slot_size);
continue;
}
@@ -258,14 +372,14 @@
// Transfer element to the empty spot.
// SetCtrl poisons/unpoisons the slots so we have to call it at the
// right time.
- SetCtrl(common, new_i, H2(hash), slot_size);
- (*transfer)(set, new_slot_ptr, slot_ptr);
- SetCtrl(common, i, ctrl_t::kEmpty, slot_size);
+ SetCtrlInLargeTable(common, new_i, h2, slot_size);
+ (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
+ SetCtrlInLargeTable(common, i, ctrl_t::kEmpty, slot_size);
// Initialize or change empty space id.
tmp_space_id = i;
} else {
- assert(IsDeleted(ctrl[new_i]));
- SetCtrl(common, new_i, H2(hash), slot_size);
+ ABSL_SWISSTABLE_ASSERT(IsDeleted(ctrl[new_i]));
+ SetCtrlInLargeTable(common, new_i, h2, slot_size);
// Until we are done rehashing, DELETED marks previously FULL slots.
if (tmp_space_id == kUnknownId) {
@@ -275,9 +389,9 @@
SanitizerUnpoisonMemoryRegion(tmp_space, slot_size);
// Swap i and new_i elements.
- (*transfer)(set, tmp_space, new_slot_ptr);
- (*transfer)(set, new_slot_ptr, slot_ptr);
- (*transfer)(set, slot_ptr, tmp_space);
+ (*transfer_n)(set, tmp_space, new_slot_ptr, 1);
+ (*transfer_n)(set, new_slot_ptr, slot_ptr, 1);
+ (*transfer_n)(set, slot_ptr, tmp_space, 1);
SanitizerPoisonMemoryRegion(tmp_space, slot_size);
@@ -286,8 +400,14 @@
slot_ptr = PrevSlot(slot_ptr, slot_size);
}
}
+ // Prepare insert for the new element.
+ PrepareInsertCommon(common);
ResetGrowthLeft(common);
+ FindInfo find_info = find_first_non_full(common, new_hash);
+ SetCtrlInLargeTable(common, find_info.offset, H2(new_hash), slot_size);
+ common.infoz().RecordInsert(new_hash, find_info.probe_length);
common.infoz().RecordRehash(total_probe_length);
+ return find_info.offset;
}
static bool WasNeverFull(CommonFields& c, size_t index) {
@@ -307,10 +427,126 @@
Group::kWidth;
}
+// Updates the control bytes to indicate a completely empty table such that all
+// control bytes are kEmpty except for the kSentinel byte.
+void ResetCtrl(CommonFields& common, size_t slot_size) {
+ const size_t capacity = common.capacity();
+ ctrl_t* ctrl = common.control();
+ static constexpr size_t kTwoGroupCapacity = 2 * Group::kWidth - 1;
+ if (ABSL_PREDICT_TRUE(capacity <= kTwoGroupCapacity)) {
+ std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
+ std::memset(ctrl + capacity, static_cast<int8_t>(ctrl_t::kEmpty),
+ Group::kWidth);
+ if (capacity == kTwoGroupCapacity) {
+ std::memset(ctrl + Group::kWidth, static_cast<int8_t>(ctrl_t::kEmpty),
+ Group::kWidth);
+ }
+ } else {
+ std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
+ capacity + 1 + NumClonedBytes());
+ }
+ ctrl[capacity] = ctrl_t::kSentinel;
+ SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity);
+}
+
+// Initializes control bytes for single element table.
+// Capacity of the table must be 1.
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline void InitializeSingleElementControlBytes(
+ uint64_t h2, ctrl_t* new_ctrl) {
+ static constexpr uint64_t kEmptyXorSentinel =
+ static_cast<uint8_t>(ctrl_t::kEmpty) ^
+ static_cast<uint8_t>(ctrl_t::kSentinel);
+ static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
+ // The first 8 bytes, where present slot positions are replaced with 0.
+ static constexpr uint64_t kFirstCtrlBytesWithZeroes =
+ k8EmptyBytes ^ kEmpty64 ^ (kEmptyXorSentinel << 8) ^ (kEmpty64 << 16);
+
+ // Fill the original 0th and mirrored 2nd bytes with the hash.
+ // Result will look like:
+ // HSHEEEEE
+ // Where H = h2, E = kEmpty, S = kSentinel.
+ const uint64_t first_ctrl_bytes =
+ (h2 | kFirstCtrlBytesWithZeroes) | (h2 << 16);
+ // Fill last bytes with kEmpty.
+ std::memset(new_ctrl + 1, static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
+ // Overwrite the first 3 bytes with HSH. Other bytes will not be changed.
+ absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
+}
+
+// Initializes control bytes for growing after SOO to the next capacity.
+// `soo_ctrl` is placed in the position `SooSlotIndex()`.
+// `new_hash` is placed in the position `new_offset`.
+// The table must be non-empty SOO.
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline void
+InitializeThreeElementsControlBytesAfterSoo(ctrl_t soo_ctrl, size_t new_hash,
+ size_t new_offset,
+ ctrl_t* new_ctrl) {
+ static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
+ static_assert(kNewCapacity == 3);
+ static_assert(is_single_group(kNewCapacity));
+ static_assert(SooSlotIndex() == 1);
+ ABSL_SWISSTABLE_ASSERT(new_offset == 0 || new_offset == 2);
+
+ static constexpr uint64_t kEmptyXorSentinel =
+ static_cast<uint8_t>(ctrl_t::kEmpty) ^
+ static_cast<uint8_t>(ctrl_t::kSentinel);
+ static constexpr uint64_t kEmpty64 = static_cast<uint8_t>(ctrl_t::kEmpty);
+ static constexpr size_t kMirroredSooSlotIndex =
+ SooSlotIndex() + kNewCapacity + 1;
+ // The first 8 bytes, where SOO slot original and mirrored positions are
+ // replaced with 0.
+ // Result will look like: E0ESE0EE
+ static constexpr uint64_t kFirstCtrlBytesWithZeroes =
+ k8EmptyBytes ^ (kEmpty64 << (8 * SooSlotIndex())) ^
+ (kEmptyXorSentinel << (8 * kNewCapacity)) ^
+ (kEmpty64 << (8 * kMirroredSooSlotIndex));
+
+ const uint64_t soo_h2 = static_cast<uint64_t>(soo_ctrl);
+ const uint64_t new_h2_xor_empty = static_cast<uint64_t>(
+ H2(new_hash) ^ static_cast<uint8_t>(ctrl_t::kEmpty));
+ // Fill the original and mirrored bytes for SOO slot.
+ // Result will look like:
+ // EHESEHEE
+ // Where H = soo_h2, E = kEmpty, S = kSentinel.
+ uint64_t first_ctrl_bytes =
+ ((soo_h2 << (8 * SooSlotIndex())) | kFirstCtrlBytesWithZeroes) |
+ (soo_h2 << (8 * kMirroredSooSlotIndex));
+ // Replace original and mirrored empty bytes for the new position.
+ // Result for new_offset 0 will look like:
+ // NHESNHEE
+ // Where H = soo_h2, N = H2(new_hash), E = kEmpty, S = kSentinel.
+ // Result for new_offset 2 will look like:
+ // EHNSEHNE
+ first_ctrl_bytes ^= (new_h2_xor_empty << (8 * new_offset));
+ size_t new_mirrored_offset = new_offset + kNewCapacity + 1;
+ first_ctrl_bytes ^= (new_h2_xor_empty << (8 * new_mirrored_offset));
+
+ // Fill last bytes with kEmpty.
+ std::memset(new_ctrl + kNewCapacity, static_cast<int8_t>(ctrl_t::kEmpty),
+ Group::kWidth);
+ // Overwrite the first 8 bytes with first_ctrl_bytes.
+ absl::little_endian::Store64(new_ctrl, first_ctrl_bytes);
+
+ // Example for group size 16:
+ // new_ctrl after 1st memset = ???EEEEEEEEEEEEEEEE
+ // new_offset 0:
+ // new_ctrl after 2nd store = NHESNHEEEEEEEEEEEEE
+ // new_offset 2:
+ // new_ctrl after 2nd store = EHNSEHNEEEEEEEEEEEE
+
+ // Example for group size 8:
+ // new_ctrl after 1st memset = ???EEEEEEEE
+ // new_offset 0:
+ // new_ctrl after 2nd store = NHESNHEEEEE
+ // new_offset 2:
+ // new_ctrl after 2nd store = EHNSEHNEEEE
+}
+
} // namespace
void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
- assert(IsFull(c.control()[index]) && "erasing a dangling iterator");
+ ABSL_SWISSTABLE_ASSERT(IsFull(c.control()[index]) &&
+ "erasing a dangling iterator");
c.decrement_size();
c.infoz().RecordErase();
@@ -321,14 +557,15 @@
}
c.growth_info().OverwriteFullAsDeleted();
- SetCtrl(c, index, ctrl_t::kDeleted, slot_size);
+ SetCtrlInLargeTable(c, index, ctrl_t::kDeleted, slot_size);
}
-void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
+void ClearBackingArray(CommonFields& c,
+ const PolicyFunctions& __restrict policy, void* alloc,
bool reuse, bool soo_enabled) {
- c.set_size(0);
if (reuse) {
- assert(!soo_enabled || c.capacity() > SooCapacity());
+ c.set_size_to_zero();
+ ABSL_SWISSTABLE_ASSERT(!soo_enabled || c.capacity() > SooCapacity());
ResetCtrl(c, policy.slot_size);
ResetGrowthLeft(c);
c.infoz().RecordStorageChanged(0, c.capacity());
@@ -337,192 +574,763 @@
// infoz.
c.infoz().RecordClearedReservation();
c.infoz().RecordStorageChanged(0, soo_enabled ? SooCapacity() : 0);
- (*policy.dealloc)(c, policy);
- c = soo_enabled ? CommonFields{soo_tag_t{}} : CommonFields{};
+ c.infoz().Unregister();
+ (*policy.dealloc)(alloc, c.capacity(), c.control(), policy.slot_size,
+ policy.slot_align, c.has_infoz());
+ c = soo_enabled ? CommonFields{soo_tag_t{}} : CommonFields{non_soo_tag_t{}};
}
}
-void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
- ctrl_t* __restrict new_ctrl, size_t new_capacity) const {
- assert(is_single_group(new_capacity));
+namespace {
+
+enum class ResizeNonSooMode {
+ kGuaranteedEmpty,
+ kGuaranteedAllocated,
+};
+
+// Iterates over full slots in old table, finds new positions for them and
+// transfers the slots.
+// This function is used for reserving or rehashing non-empty tables.
+// This use case is rare so the function is type erased.
+// Returns the total probe length.
+size_t FindNewPositionsAndTransferSlots(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots, size_t old_capacity) {
+ void* new_slots = common.slot_array();
+ const void* hash_fn = policy.hash_fn(common);
+ const size_t slot_size = policy.slot_size;
+
+ const auto insert_slot = [&](void* slot) {
+ size_t hash = policy.hash_slot(hash_fn, slot);
+ auto target = find_first_non_full(common, hash);
+ SetCtrl(common, target.offset, H2(hash), slot_size);
+ policy.transfer_n(&common, SlotAddress(new_slots, target.offset, slot_size),
+ slot, 1);
+ return target.probe_length;
+ };
+ size_t total_probe_length = 0;
+ for (size_t i = 0; i < old_capacity; ++i) {
+ if (IsFull(old_ctrl[i])) {
+ total_probe_length += insert_slot(old_slots);
+ }
+ old_slots = NextSlot(old_slots, slot_size);
+ }
+ return total_probe_length;
+}
+
+template <ResizeNonSooMode kMode>
+void ResizeNonSooImpl(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t new_capacity, HashtablezInfoHandle infoz) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
+ ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
+
+ const size_t old_capacity = common.capacity();
+ [[maybe_unused]] ctrl_t* old_ctrl = common.control();
+ [[maybe_unused]] void* old_slots = common.slot_array();
+
+ const size_t slot_size = policy.slot_size;
+ const size_t slot_align = policy.slot_align;
+ const bool has_infoz = infoz.IsSampled();
+
+ common.set_capacity(new_capacity);
+ RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
+ void* alloc = policy.get_char_alloc(common);
+ char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
+ const GenerationType old_generation = common.generation();
+ common.set_generation_ptr(
+ reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
+ common.set_generation(NextGeneration(old_generation));
+
+ ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
+ common.set_control</*kGenerateSeed=*/true>(new_ctrl);
+ common.set_slots(mem + layout.slot_offset());
+
+ size_t total_probe_length = 0;
+ ResetCtrl(common, slot_size);
+ ABSL_SWISSTABLE_ASSERT(kMode != ResizeNonSooMode::kGuaranteedEmpty ||
+ old_capacity == policy.soo_capacity());
+ ABSL_SWISSTABLE_ASSERT(kMode != ResizeNonSooMode::kGuaranteedAllocated ||
+ old_capacity > 0);
+ if constexpr (kMode == ResizeNonSooMode::kGuaranteedAllocated) {
+ total_probe_length = FindNewPositionsAndTransferSlots(
+ common, policy, old_ctrl, old_slots, old_capacity);
+ (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
+ has_infoz);
+ ResetGrowthLeft(GetGrowthInfoFromControl(new_ctrl), new_capacity,
+ common.size());
+ } else {
+ GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(
+ CapacityToGrowth(new_capacity));
+ }
+
+ if (has_infoz) {
+ common.set_has_infoz();
+ infoz.RecordStorageChanged(common.size(), new_capacity);
+ infoz.RecordRehash(total_probe_length);
+ common.set_infoz(infoz);
+ }
+}
+
+void ResizeEmptyNonAllocatedTableImpl(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t new_capacity, bool force_infoz) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
+ ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
+ ABSL_SWISSTABLE_ASSERT(!force_infoz || policy.soo_enabled);
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= policy.soo_capacity());
+ ABSL_SWISSTABLE_ASSERT(common.empty());
+ const size_t slot_size = policy.slot_size;
+ HashtablezInfoHandle infoz;
+ const bool should_sample =
+ policy.is_hashtablez_eligible && (force_infoz || ShouldSampleNextTable());
+ if (ABSL_PREDICT_FALSE(should_sample)) {
+ infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
+ policy.soo_capacity());
+ }
+ ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedEmpty>(common, policy,
+ new_capacity, infoz);
+}
+
+// If the table was SOO, initializes new control bytes and transfers slot.
+// After transferring the slot, sets control and slots in CommonFields.
+// It is rare to resize an SOO table with one element to a large size.
+// Requires: `c` contains SOO data.
+void InsertOldSooSlotAndInitializeControlBytes(
+ CommonFields& c, const PolicyFunctions& __restrict policy, size_t hash,
+ ctrl_t* new_ctrl, void* new_slots) {
+ ABSL_SWISSTABLE_ASSERT(c.size() == policy.soo_capacity());
+ ABSL_SWISSTABLE_ASSERT(policy.soo_enabled);
+ size_t new_capacity = c.capacity();
+
+ c.generate_new_seed();
+ size_t offset = probe(c.seed(), new_capacity, hash).offset();
+ offset = offset == new_capacity ? 0 : offset;
+ SanitizerPoisonMemoryRegion(new_slots, policy.slot_size * new_capacity);
+ void* target_slot = SlotAddress(new_slots, offset, policy.slot_size);
+ SanitizerUnpoisonMemoryRegion(target_slot, policy.slot_size);
+ policy.transfer_n(&c, target_slot, c.soo_data(), 1);
+ c.set_control</*kGenerateSeed=*/false>(new_ctrl);
+ c.set_slots(new_slots);
+ ResetCtrl(c, policy.slot_size);
+ SetCtrl(c, offset, H2(hash), policy.slot_size);
+}
+
+enum class ResizeFullSooTableSamplingMode {
+ kNoSampling,
+ // Force sampling. If the table was still not sampled, do not resize.
+ kForceSampleNoResizeIfUnsampled,
+};
+
+void AssertSoo([[maybe_unused]] CommonFields& common,
+ [[maybe_unused]] const PolicyFunctions& policy) {
+ ABSL_SWISSTABLE_ASSERT(policy.soo_enabled);
+ ABSL_SWISSTABLE_ASSERT(common.capacity() == policy.soo_capacity());
+}
+void AssertFullSoo([[maybe_unused]] CommonFields& common,
+ [[maybe_unused]] const PolicyFunctions& policy) {
+ AssertSoo(common, policy);
+ ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity());
+}
+
+void ResizeFullSooTable(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t new_capacity,
+ ResizeFullSooTableSamplingMode sampling_mode) {
+ AssertFullSoo(common, policy);
+ const size_t slot_size = policy.slot_size;
+ const size_t slot_align = policy.slot_align;
+
+ HashtablezInfoHandle infoz;
+ if (sampling_mode ==
+ ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled) {
+ if (ABSL_PREDICT_FALSE(policy.is_hashtablez_eligible)) {
+ infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
+ policy.soo_capacity());
+ }
+
+ if (!infoz.IsSampled()) {
+ return;
+ }
+ }
+
+ const bool has_infoz = infoz.IsSampled();
+
+ common.set_capacity(new_capacity);
+
+ RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
+ void* alloc = policy.get_char_alloc(common);
+ char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
+ const GenerationType old_generation = common.generation();
+ common.set_generation_ptr(
+ reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
+ common.set_generation(NextGeneration(old_generation));
+
+ // We do not set control and slots in CommonFields yet to avoid overriding
+ // SOO data.
+ ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
+ void* new_slots = mem + layout.slot_offset();
+
+ const size_t soo_slot_hash =
+ policy.hash_slot(policy.hash_fn(common), common.soo_data());
+
+ InsertOldSooSlotAndInitializeControlBytes(common, policy, soo_slot_hash,
+ new_ctrl, new_slots);
+ ResetGrowthLeft(common);
+ if (has_infoz) {
+ common.set_has_infoz();
+ common.set_infoz(infoz);
+ infoz.RecordStorageChanged(common.size(), new_capacity);
+ }
+}
+
+void GrowIntoSingleGroupShuffleControlBytes(ctrl_t* __restrict old_ctrl,
+ size_t old_capacity,
+ ctrl_t* __restrict new_ctrl,
+ size_t new_capacity) {
+ ABSL_SWISSTABLE_ASSERT(is_single_group(new_capacity));
constexpr size_t kHalfWidth = Group::kWidth / 2;
- constexpr size_t kQuarterWidth = Group::kWidth / 4;
- assert(old_capacity_ < kHalfWidth);
- static_assert(sizeof(uint64_t) >= kHalfWidth,
- "Group size is too large. The ctrl bytes for half a group must "
- "fit into a uint64_t for this implementation.");
- static_assert(sizeof(uint64_t) <= Group::kWidth,
- "Group size is too small. The ctrl bytes for a group must "
- "cover a uint64_t for this implementation.");
+ ABSL_ASSUME(old_capacity < kHalfWidth);
+ ABSL_ASSUME(old_capacity > 0);
+ static_assert(Group::kWidth == 8 || Group::kWidth == 16,
+ "Group size is not supported.");
- const size_t half_old_capacity = old_capacity_ / 2;
-
- // NOTE: operations are done with compile time known size = kHalfWidth.
+ // NOTE: operations are done with compile time known size = 8.
// Compiler optimizes that into single ASM operation.
- // Load the bytes from half_old_capacity + 1. This contains the last half of
- // old_ctrl bytes, followed by the sentinel byte, and then the first half of
- // the cloned bytes. This effectively shuffles the control bytes.
- uint64_t copied_bytes = 0;
- copied_bytes =
- absl::little_endian::Load64(old_ctrl() + half_old_capacity + 1);
+ // Load the bytes from old_capacity. This contains
+ // - the sentinel byte
+ // - all the old control bytes
+ // - the rest is filled with kEmpty bytes
+ // Example:
+ // old_ctrl = 012S012EEEEEEEEE...
+ // copied_bytes = S012EEEE
+ uint64_t copied_bytes = absl::little_endian::Load64(old_ctrl + old_capacity);
// We change the sentinel byte to kEmpty before storing to both the start of
// the new_ctrl, and past the end of the new_ctrl later for the new cloned
// bytes. Note that this is faster than setting the sentinel byte to kEmpty
// after the copy directly in new_ctrl because we are limited on store
// bandwidth.
- constexpr uint64_t kEmptyXorSentinel =
+ static constexpr uint64_t kEmptyXorSentinel =
static_cast<uint8_t>(ctrl_t::kEmpty) ^
static_cast<uint8_t>(ctrl_t::kSentinel);
- const uint64_t mask_convert_old_sentinel_to_empty =
- kEmptyXorSentinel << (half_old_capacity * 8);
- copied_bytes ^= mask_convert_old_sentinel_to_empty;
- // Copy second half of bytes to the beginning. This correctly sets the bytes
- // [0, old_capacity]. We potentially copy more bytes in order to have compile
- // time known size. Mirrored bytes from the old_ctrl() will also be copied. In
- // case of old_capacity_ == 3, we will copy 1st element twice.
- // Examples:
- // (old capacity = 1)
- // old_ctrl = 0S0EEEEEEE...
- // new_ctrl = E0EEEEEE??...
- //
- // (old capacity = 3)
- // old_ctrl = 012S012EEEEE...
- // new_ctrl = 12E012EE????...
- //
- // (old capacity = 7)
- // old_ctrl = 0123456S0123456EE...
- // new_ctrl = 456E0123?????????...
- absl::little_endian::Store64(new_ctrl, copied_bytes);
+ // Replace the first byte kSentinel with kEmpty.
+ // Resulting bytes will be shifted by one byte old control blocks.
+ // Example:
+ // old_ctrl = 012S012EEEEEEEEE...
+ // before = S012EEEE
+ // after = E012EEEE
+ copied_bytes ^= kEmptyXorSentinel;
- // Set the space [old_capacity + 1, new_capacity] to empty as these bytes will
- // not be written again. This is safe because
- // NumControlBytes = new_capacity + kWidth and new_capacity >=
- // old_capacity+1.
- // Examples:
- // (old_capacity = 3, new_capacity = 15)
- // new_ctrl = 12E012EE?????????????...??
- // *new_ctrl = 12E0EEEEEEEEEEEEEEEE?...??
- // position / S
- //
- // (old_capacity = 7, new_capacity = 15)
- // new_ctrl = 456E0123?????????????????...??
- // *new_ctrl = 456E0123EEEEEEEEEEEEEEEE?...??
- // position / S
- std::memset(new_ctrl + old_capacity_ + 1, static_cast<int8_t>(ctrl_t::kEmpty),
- Group::kWidth);
+ if (Group::kWidth == 8) {
+ // With group size 8, we can grow with two write operations.
+ ABSL_SWISSTABLE_ASSERT(old_capacity < 8 &&
+ "old_capacity is too large for group size 8");
+ absl::little_endian::Store64(new_ctrl, copied_bytes);
- // Set the last kHalfWidth bytes to empty, to ensure the bytes all the way to
- // the end are initialized.
- // Examples:
- // new_ctrl = 12E0EEEEEEEEEEEEEEEE?...???????
- // *new_ctrl = 12E0EEEEEEEEEEEEEEEE???EEEEEEEE
- // position S /
- //
- // new_ctrl = 456E0123EEEEEEEEEEEEEEEE???????
- // *new_ctrl = 456E0123EEEEEEEEEEEEEEEEEEEEEEE
- // position S /
- std::memset(new_ctrl + NumControlBytes(new_capacity) - kHalfWidth,
+ static constexpr uint64_t kSentinal64 =
+ static_cast<uint8_t>(ctrl_t::kSentinel);
+
+ // Prepend kSentinel byte to the beginning of copied_bytes.
+ // We have maximum 3 non-empty bytes at the beginning of copied_bytes for
+ // group size 8.
+ // Example:
+ // old_ctrl = 012S012EEEE
+ // before = E012EEEE
+ // after = SE012EEE
+ copied_bytes = (copied_bytes << 8) ^ kSentinal64;
+ absl::little_endian::Store64(new_ctrl + new_capacity, copied_bytes);
+ // Example for capacity 3:
+ // old_ctrl = 012S012EEEE
+ // After the first store:
+ // >!
+ // new_ctrl = E012EEEE???????
+ // After the second store:
+ // >!
+ // new_ctrl = E012EEESE012EEE
+ return;
+ }
+
+ ABSL_SWISSTABLE_ASSERT(Group::kWidth == 16);
+
+ // Fill the second half of the main control bytes with kEmpty.
+ // For small capacity that may write into mirrored control bytes.
+ // It is fine as we will overwrite all the bytes later.
+ std::memset(new_ctrl + kHalfWidth, static_cast<int8_t>(ctrl_t::kEmpty),
+ kHalfWidth);
+ // Fill the second half of the mirrored control bytes with kEmpty.
+ std::memset(new_ctrl + new_capacity + kHalfWidth,
static_cast<int8_t>(ctrl_t::kEmpty), kHalfWidth);
-
- // Copy the first bytes to the end (starting at new_capacity +1) to set the
- // cloned bytes. Note that we use the already copied bytes from old_ctrl here
- // rather than copying from new_ctrl to avoid a Read-after-Write hazard, since
- // new_ctrl was just written to. The first old_capacity-1 bytes are set
- // correctly. Then there may be up to old_capacity bytes that need to be
- // overwritten, and any remaining bytes will be correctly set to empty. This
- // sets [new_capacity + 1, new_capacity +1 + old_capacity] correctly.
- // Examples:
- // new_ctrl = 12E0EEEEEEEEEEEEEEEE?...???????
- // *new_ctrl = 12E0EEEEEEEEEEEE12E012EEEEEEEEE
- // position S/
- //
- // new_ctrl = 456E0123EEEEEEEE?...???EEEEEEEE
- // *new_ctrl = 456E0123EEEEEEEE456E0123EEEEEEE
- // position S/
+ // Copy the first half of the non-mirrored control bytes.
+ absl::little_endian::Store64(new_ctrl, copied_bytes);
+ new_ctrl[new_capacity] = ctrl_t::kSentinel;
+ // Copy the first half of the mirrored control bytes.
absl::little_endian::Store64(new_ctrl + new_capacity + 1, copied_bytes);
- // Set The remaining bytes at the end past the cloned bytes to empty. The
- // incorrectly set bytes are [new_capacity + old_capacity + 2,
- // min(new_capacity + 1 + kHalfWidth, new_capacity + old_capacity + 2 +
- // half_old_capacity)]. Taking the difference, we need to set min(kHalfWidth -
- // (old_capacity + 1), half_old_capacity)]. Since old_capacity < kHalfWidth,
- // half_old_capacity < kQuarterWidth, so we set kQuarterWidth beginning at
- // new_capacity + old_capacity + 2 to kEmpty.
- // Examples:
- // new_ctrl = 12E0EEEEEEEEEEEE12E012EEEEEEEEE
- // *new_ctrl = 12E0EEEEEEEEEEEE12E0EEEEEEEEEEE
- // position S /
+ // Example for growth capacity 1->3:
+ // old_ctrl = 0S0EEEEEEEEEEEEEE
+ // new_ctrl at the end = E0ESE0EEEEEEEEEEEEE
+ // >!
+ // new_ctrl after 1st memset = ????????EEEEEEEE???
+ // >!
+ // new_ctrl after 2nd memset = ????????EEEEEEEEEEE
+ // >!
+ // new_ctrl after 1st store = E0EEEEEEEEEEEEEEEEE
+ // new_ctrl after kSentinel = E0ESEEEEEEEEEEEEEEE
+ // >!
+ // new_ctrl after 2nd store = E0ESE0EEEEEEEEEEEEE
+
+ // Example for growth capacity 3->7:
+ // old_ctrl = 012S012EEEEEEEEEEEE
+ // new_ctrl at the end = E012EEESE012EEEEEEEEEEE
+ // >!
+ // new_ctrl after 1st memset = ????????EEEEEEEE???????
+ // >!
+ // new_ctrl after 2nd memset = ????????EEEEEEEEEEEEEEE
+ // >!
+ // new_ctrl after 1st store = E012EEEEEEEEEEEEEEEEEEE
+ // new_ctrl after kSentinel = E012EEESEEEEEEEEEEEEEEE
+ // >!
+ // new_ctrl after 2nd store = E012EEESE012EEEEEEEEEEE
+
+ // Example for growth capacity 7->15:
+ // old_ctrl = 0123456S0123456EEEEEEEE
+ // new_ctrl at the end = E0123456EEEEEEESE0123456EEEEEEE
+ // >!
+ // new_ctrl after 1st memset = ????????EEEEEEEE???????????????
+ // >!
+ // new_ctrl after 2nd memset = ????????EEEEEEEE???????EEEEEEEE
+ // >!
+ // new_ctrl after 1st store = E0123456EEEEEEEE???????EEEEEEEE
+ // new_ctrl after kSentinel = E0123456EEEEEEES???????EEEEEEEE
+ // >!
+ // new_ctrl after 2nd store = E0123456EEEEEEESE0123456EEEEEEE
+}
+
+// Size of the buffer we allocate on stack for storing probed elements in
+// GrowToNextCapacity algorithm.
+constexpr size_t kProbedElementsBufferSize = 512;
+
+// Decodes information about probed elements from contiguous memory.
+// Finds new position for each element and transfers it to the new slots.
+// Returns the total probe length.
+template <typename ProbedItem>
+ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertImpl(
+ CommonFields& c, const PolicyFunctions& __restrict policy,
+ const ProbedItem* start, const ProbedItem* end, void* old_slots) {
+ const size_t new_capacity = c.capacity();
+
+ void* new_slots = c.slot_array();
+ ctrl_t* new_ctrl = c.control();
+ size_t total_probe_length = 0;
+
+ const size_t slot_size = policy.slot_size;
+ auto transfer_n = policy.transfer_n;
+
+ for (; start < end; ++start) {
+ const FindInfo target = find_first_non_full_from_h1(
+ new_ctrl, static_cast<size_t>(start->h1), new_capacity);
+ total_probe_length += target.probe_length;
+ const size_t old_index = static_cast<size_t>(start->source_offset);
+ const size_t new_i = target.offset;
+ ABSL_SWISSTABLE_ASSERT(old_index < new_capacity / 2);
+ ABSL_SWISSTABLE_ASSERT(new_i < new_capacity);
+ ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_i]));
+ void* src_slot = SlotAddress(old_slots, old_index, slot_size);
+ void* dst_slot = SlotAddress(new_slots, new_i, slot_size);
+ SanitizerUnpoisonMemoryRegion(dst_slot, slot_size);
+ transfer_n(&c, dst_slot, src_slot, 1);
+ SetCtrlInLargeTable(c, new_i, static_cast<h2_t>(start->h2), slot_size);
+ }
+ return total_probe_length;
+}
+
+// Sentinel value for the start of marked elements.
+// Signals that there are no marked elements.
+constexpr size_t kNoMarkedElementsSentinel = ~size_t{};
+
+// Process probed elements that did not fit into available buffers.
+// We marked them in control bytes as kSentinel.
+// Hash recomputation and full probing is done here.
+// This use case should be extremely rare.
+ABSL_ATTRIBUTE_NOINLINE size_t ProcessProbedMarkedElements(
+ CommonFields& c, const PolicyFunctions& __restrict policy, ctrl_t* old_ctrl,
+ void* old_slots, size_t start) {
+ size_t old_capacity = PreviousCapacity(c.capacity());
+ const size_t slot_size = policy.slot_size;
+ void* new_slots = c.slot_array();
+ size_t total_probe_length = 0;
+ const void* hash_fn = policy.hash_fn(c);
+ auto hash_slot = policy.hash_slot;
+ auto transfer_n = policy.transfer_n;
+ for (size_t old_index = start; old_index < old_capacity; ++old_index) {
+ if (old_ctrl[old_index] != ctrl_t::kSentinel) {
+ continue;
+ }
+ void* src_slot = SlotAddress(old_slots, old_index, slot_size);
+ const size_t hash = hash_slot(hash_fn, src_slot);
+ const FindInfo target = find_first_non_full(c, hash);
+ total_probe_length += target.probe_length;
+ const size_t new_i = target.offset;
+ void* dst_slot = SlotAddress(new_slots, new_i, slot_size);
+ SetCtrlInLargeTable(c, new_i, H2(hash), slot_size);
+ transfer_n(&c, dst_slot, src_slot, 1);
+ }
+ return total_probe_length;
+}
+
+// The largest old capacity for which it is guaranteed that all probed elements
+// fit in ProbedItemEncoder's local buffer.
+// For such tables, `encode_probed_element` is trivial.
+constexpr size_t kMaxLocalBufferOldCapacity =
+ kProbedElementsBufferSize / sizeof(ProbedItem4Bytes) - 1;
+static_assert(IsValidCapacity(kMaxLocalBufferOldCapacity));
+constexpr size_t kMaxLocalBufferNewCapacity =
+ NextCapacity(kMaxLocalBufferOldCapacity);
+static_assert(kMaxLocalBufferNewCapacity <= ProbedItem4Bytes::kMaxNewCapacity);
+static_assert(NextCapacity(kMaxLocalBufferNewCapacity) <=
+ ProbedItem4Bytes::kMaxNewCapacity);
+
+// Initializes mirrored control bytes after
+// transfer_unprobed_elements_to_next_capacity.
+void InitializeMirroredControlBytes(ctrl_t* new_ctrl, size_t new_capacity) {
+ std::memcpy(new_ctrl + new_capacity,
+ // We own GrowthInfo just before control bytes. So it is ok
+ // to read one byte from it.
+ new_ctrl - 1, Group::kWidth);
+ new_ctrl[new_capacity] = ctrl_t::kSentinel;
+}
+
+// Encodes probed elements into available memory.
+// At first, a local (on stack) buffer is used. The size of the buffer is
+// kProbedElementsBufferSize bytes.
+// When the local buffer is full, we switch to `control_` buffer. We are allowed
+// to overwrite `control_` buffer till the `source_offset` byte. In case we have
+// no space in `control_` buffer, we fallback to a naive algorithm for all the
+// rest of the probed elements. We mark elements as kSentinel in control bytes
+// and later process them fully. See ProcessMarkedElements for details. It
+// should be extremely rare.
+template <typename ProbedItemType,
+ // If true, we only use the local buffer and never switch to the
+ // control buffer.
+ bool kGuaranteedFitToBuffer = false>
+class ProbedItemEncoder {
+ public:
+ using ProbedItem = ProbedItemType;
+ explicit ProbedItemEncoder(ctrl_t* control) : control_(control) {}
+
+ // Encode item into the best available location.
+ void EncodeItem(ProbedItem item) {
+ if (ABSL_PREDICT_FALSE(!kGuaranteedFitToBuffer && pos_ >= end_)) {
+ return ProcessEncodeWithOverflow(item);
+ }
+ ABSL_SWISSTABLE_ASSERT(pos_ < end_);
+ *pos_ = item;
+ ++pos_;
+ }
+
+ // Decodes information about probed elements from all available sources.
+ // Finds new position for each element and transfers it to the new slots.
+ // Returns the total probe length.
+ size_t DecodeAndInsertToTable(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ void* old_slots) const {
+ if (pos_ == buffer_) {
+ return 0;
+ }
+ if constexpr (kGuaranteedFitToBuffer) {
+ return DecodeAndInsertImpl(common, policy, buffer_, pos_, old_slots);
+ }
+ size_t total_probe_length = DecodeAndInsertImpl(
+ common, policy, buffer_,
+ local_buffer_full_ ? buffer_ + kBufferSize : pos_, old_slots);
+ if (!local_buffer_full_) {
+ return total_probe_length;
+ }
+ total_probe_length +=
+ DecodeAndInsertToTableOverflow(common, policy, old_slots);
+ return total_probe_length;
+ }
+
+ private:
+ static ProbedItem* AlignToNextItem(void* ptr) {
+ return reinterpret_cast<ProbedItem*>(AlignUpTo(
+ reinterpret_cast<uintptr_t>(ptr), alignof(ProbedItem)));
+ }
+
+ ProbedItem* OverflowBufferStart() const {
+ // We reuse GrowthInfo memory as well.
+ return AlignToNextItem(control_ - ControlOffset(/*has_infoz=*/false));
+ }
+
+ // Encodes item when previously allocated buffer is full.
+ // At first that happens when local buffer is full.
+ // We switch from the local buffer to the control buffer.
+ // Every time this function is called, the available buffer is extended till
+ // `item.source_offset` byte in the control buffer.
+ // After the buffer is extended, this function wouldn't be called till the
+ // buffer is exhausted.
//
- // new_ctrl = 456E0123EEEEEEEE456E0123EEEEEEE
- // *new_ctrl = 456E0123EEEEEEEE456E0123EEEEEEE (no change)
- // position S /
- std::memset(new_ctrl + new_capacity + old_capacity_ + 2,
- static_cast<int8_t>(ctrl_t::kEmpty), kQuarterWidth);
+ // If there's no space in the control buffer, we fallback to naive algorithm
+ // and mark probed elements as kSentinel in the control buffer. In this case,
+ // we will call this function for every subsequent probed element.
+ ABSL_ATTRIBUTE_NOINLINE void ProcessEncodeWithOverflow(ProbedItem item) {
+ if (!local_buffer_full_) {
+ local_buffer_full_ = true;
+ pos_ = OverflowBufferStart();
+ }
+ const size_t source_offset = static_cast<size_t>(item.source_offset);
+ // We are in fallback mode so we can't reuse control buffer anymore.
+ // Probed elements are marked as kSentinel in the control buffer.
+ if (ABSL_PREDICT_FALSE(marked_elements_starting_position_ !=
+ kNoMarkedElementsSentinel)) {
+ control_[source_offset] = ctrl_t::kSentinel;
+ return;
+ }
+ // Refresh the end pointer to the new available position.
+ // Invariant: if pos < end, then we have at least sizeof(ProbedItem) bytes
+ // to write.
+ end_ = control_ + source_offset + 1 - sizeof(ProbedItem);
+ if (ABSL_PREDICT_TRUE(pos_ < end_)) {
+ *pos_ = item;
+ ++pos_;
+ return;
+ }
+ control_[source_offset] = ctrl_t::kSentinel;
+ marked_elements_starting_position_ = source_offset;
+ // Now we will always fall down to `ProcessEncodeWithOverflow`.
+ ABSL_SWISSTABLE_ASSERT(pos_ >= end_);
+ }
- // Finally, we set the new sentinel byte.
- new_ctrl[new_capacity] = ctrl_t::kSentinel;
+ // Decodes information about probed elements from control buffer and processes
+ // marked elements.
+ // Finds new position for each element and transfers it to the new slots.
+ // Returns the total probe length.
+ ABSL_ATTRIBUTE_NOINLINE size_t DecodeAndInsertToTableOverflow(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ void* old_slots) const {
+ ABSL_SWISSTABLE_ASSERT(local_buffer_full_ &&
+ "must not be called when local buffer is not full");
+ size_t total_probe_length = DecodeAndInsertImpl(
+ common, policy, OverflowBufferStart(), pos_, old_slots);
+ if (ABSL_PREDICT_TRUE(marked_elements_starting_position_ ==
+ kNoMarkedElementsSentinel)) {
+ return total_probe_length;
+ }
+ total_probe_length +=
+ ProcessProbedMarkedElements(common, policy, control_, old_slots,
+ marked_elements_starting_position_);
+ return total_probe_length;
+ }
+
+ static constexpr size_t kBufferSize =
+ kProbedElementsBufferSize / sizeof(ProbedItem);
+ ProbedItem buffer_[kBufferSize];
+ // If local_buffer_full_ is false, then pos_/end_ are in the local buffer,
+ // otherwise, they're in the overflow buffer.
+ ProbedItem* pos_ = buffer_;
+ const void* end_ = buffer_ + kBufferSize;
+ ctrl_t* const control_;
+ size_t marked_elements_starting_position_ = kNoMarkedElementsSentinel;
+ bool local_buffer_full_ = false;
+};
+
+// Grows to next capacity with specified encoder type.
+// Encoder is used to store probed elements that are processed later.
+// Different encoder is used depending on the capacity of the table.
+// Returns total probe length.
+template <typename Encoder>
+size_t GrowToNextCapacity(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ using ProbedItem = typename Encoder::ProbedItem;
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= ProbedItem::kMaxNewCapacity);
+ Encoder encoder(old_ctrl);
+ policy.transfer_unprobed_elements_to_next_capacity(
+ common, old_ctrl, old_slots, &encoder,
+ [](void* probed_storage, h2_t h2, size_t source_offset, size_t h1) {
+ auto encoder_ptr = static_cast<Encoder*>(probed_storage);
+ encoder_ptr->EncodeItem(ProbedItem(h2, source_offset, h1));
+ });
+ InitializeMirroredControlBytes(common.control(), common.capacity());
+ return encoder.DecodeAndInsertToTable(common, policy, old_slots);
}
-void HashSetResizeHelper::InitControlBytesAfterSoo(ctrl_t* new_ctrl, ctrl_t h2,
- size_t new_capacity) {
- assert(is_single_group(new_capacity));
- std::memset(new_ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
- NumControlBytes(new_capacity));
- assert(HashSetResizeHelper::SooSlotIndex() == 1);
- // This allows us to avoid branching on had_soo_slot_.
- assert(had_soo_slot_ || h2 == ctrl_t::kEmpty);
- new_ctrl[1] = new_ctrl[new_capacity + 2] = h2;
- new_ctrl[new_capacity] = ctrl_t::kSentinel;
+// Grows to next capacity for relatively small tables so that even if all
+// elements are probed, we don't need to overflow the local buffer.
+// Returns total probe length.
+size_t GrowToNextCapacityThatFitsInLocalBuffer(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ ABSL_SWISSTABLE_ASSERT(common.capacity() <= kMaxLocalBufferNewCapacity);
+ return GrowToNextCapacity<
+ ProbedItemEncoder<ProbedItem4Bytes, /*kGuaranteedFitToBuffer=*/true>>(
+ common, policy, old_ctrl, old_slots);
}
-void HashSetResizeHelper::GrowIntoSingleGroupShuffleTransferableSlots(
- void* new_slots, size_t slot_size) const {
- assert(old_capacity_ > 0);
- const size_t half_old_capacity = old_capacity_ / 2;
-
- SanitizerUnpoisonMemoryRegion(old_slots(), slot_size * old_capacity_);
- std::memcpy(new_slots,
- SlotAddress(old_slots(), half_old_capacity + 1, slot_size),
- slot_size * half_old_capacity);
- std::memcpy(SlotAddress(new_slots, half_old_capacity + 1, slot_size),
- old_slots(), slot_size * (half_old_capacity + 1));
+// Grows to next capacity with different encodings. Returns total probe length.
+// These functions are useful to simplify profile analysis.
+size_t GrowToNextCapacity4BytesEncoder(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem4Bytes>>(
+ common, policy, old_ctrl, old_slots);
+}
+size_t GrowToNextCapacity8BytesEncoder(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem8Bytes>>(
+ common, policy, old_ctrl, old_slots);
+}
+size_t GrowToNextCapacity16BytesEncoder(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ return GrowToNextCapacity<ProbedItemEncoder<ProbedItem16Bytes>>(
+ common, policy, old_ctrl, old_slots);
}
-void HashSetResizeHelper::GrowSizeIntoSingleGroupTransferable(
- CommonFields& c, size_t slot_size) {
- assert(old_capacity_ < Group::kWidth / 2);
- assert(is_single_group(c.capacity()));
- assert(IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()));
-
- GrowIntoSingleGroupShuffleControlBytes(c.control(), c.capacity());
- GrowIntoSingleGroupShuffleTransferableSlots(c.slot_array(), slot_size);
-
- // We poison since GrowIntoSingleGroupShuffleTransferableSlots
- // may leave empty slots unpoisoned.
- PoisonSingleGroupEmptySlots(c, slot_size);
+// Grows to next capacity for tables with relatively large capacity so that we
+// can't guarantee that all probed elements fit in the local buffer. Returns
+// total probe length.
+size_t GrowToNextCapacityOverflowLocalBuffer(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ const size_t new_capacity = common.capacity();
+ if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem4Bytes::kMaxNewCapacity)) {
+ return GrowToNextCapacity4BytesEncoder(common, policy, old_ctrl, old_slots);
+ }
+ if (ABSL_PREDICT_TRUE(new_capacity <= ProbedItem8Bytes::kMaxNewCapacity)) {
+ return GrowToNextCapacity8BytesEncoder(common, policy, old_ctrl, old_slots);
+ }
+ // 16 bytes encoding supports the maximum swisstable capacity.
+ return GrowToNextCapacity16BytesEncoder(common, policy, old_ctrl, old_slots);
}
-void HashSetResizeHelper::TransferSlotAfterSoo(CommonFields& c,
- size_t slot_size) {
- assert(was_soo_);
- assert(had_soo_slot_);
- assert(is_single_group(c.capacity()));
- std::memcpy(SlotAddress(c.slot_array(), SooSlotIndex(), slot_size),
- old_soo_data(), slot_size);
- PoisonSingleGroupEmptySlots(c, slot_size);
+// Dispatches to the appropriate `GrowToNextCapacity*` function based on the
+// capacity of the table. Returns total probe length.
+ABSL_ATTRIBUTE_NOINLINE
+size_t GrowToNextCapacityDispatch(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ ctrl_t* old_ctrl, void* old_slots) {
+ const size_t new_capacity = common.capacity();
+ if (ABSL_PREDICT_TRUE(new_capacity <= kMaxLocalBufferNewCapacity)) {
+ return GrowToNextCapacityThatFitsInLocalBuffer(common, policy, old_ctrl,
+ old_slots);
+ } else {
+ return GrowToNextCapacityOverflowLocalBuffer(common, policy, old_ctrl,
+ old_slots);
+ }
}
-namespace {
+// Grows to next capacity and prepares insert for the given new_hash.
+// Returns the offset of the new element.
+size_t GrowToNextCapacityAndPrepareInsert(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_hash) {
+ ABSL_SWISSTABLE_ASSERT(common.growth_left() == 0);
+ const size_t old_capacity = common.capacity();
+ ABSL_SWISSTABLE_ASSERT(old_capacity == 0 ||
+ old_capacity > policy.soo_capacity());
+
+ const size_t new_capacity = NextCapacity(old_capacity);
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(new_capacity));
+ ABSL_SWISSTABLE_ASSERT(new_capacity > policy.soo_capacity());
+
+ ctrl_t* old_ctrl = common.control();
+ void* old_slots = common.slot_array();
+
+ common.set_capacity(new_capacity);
+ const size_t slot_size = policy.slot_size;
+ const size_t slot_align = policy.slot_align;
+ HashtablezInfoHandle infoz;
+ if (old_capacity > 0) {
+ infoz = common.infoz();
+ } else {
+ const bool should_sample =
+ policy.is_hashtablez_eligible && ShouldSampleNextTable();
+ if (ABSL_PREDICT_FALSE(should_sample)) {
+ infoz = ForcedTrySample(slot_size, policy.key_size, policy.value_size,
+ policy.soo_capacity());
+ }
+ }
+ const bool has_infoz = infoz.IsSampled();
+
+ RawHashSetLayout layout(new_capacity, slot_size, slot_align, has_infoz);
+ void* alloc = policy.get_char_alloc(common);
+ char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
+ const GenerationType old_generation = common.generation();
+ common.set_generation_ptr(
+ reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
+ common.set_generation(NextGeneration(old_generation));
+
+ ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
+ void* new_slots = mem + layout.slot_offset();
+ common.set_control</*kGenerateSeed=*/false>(new_ctrl);
+ common.set_slots(new_slots);
+ SanitizerPoisonMemoryRegion(new_slots, new_capacity * slot_size);
+
+ h2_t new_h2 = H2(new_hash);
+ size_t total_probe_length = 0;
+ FindInfo find_info;
+ if (old_capacity == 0) {
+ static_assert(NextCapacity(0) == 1);
+ InitializeSingleElementControlBytes(new_h2, new_ctrl);
+ common.generate_new_seed();
+ find_info = FindInfo{0, 0};
+ SanitizerUnpoisonMemoryRegion(new_slots, slot_size);
+ } else {
+ if (ABSL_PREDICT_TRUE(is_single_group(new_capacity))) {
+ GrowIntoSingleGroupShuffleControlBytes(old_ctrl, old_capacity, new_ctrl,
+ new_capacity);
+ // Single group tables have all slots full on resize. So we can transfer
+ // all slots without checking the control bytes.
+ ABSL_SWISSTABLE_ASSERT(common.size() == old_capacity);
+ auto* target = NextSlot(new_slots, slot_size);
+ SanitizerUnpoisonMemoryRegion(target, old_capacity * slot_size);
+ policy.transfer_n(&common, target, old_slots, old_capacity);
+ // We put the new element either at the beginning or at the end of the
+ // table with approximately equal probability.
+ size_t offset = SingleGroupTableH1(new_hash, common.seed()) & 1
+ ? 0
+ : new_capacity - 1;
+
+ ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[offset]));
+ SetCtrlInSingleGroupTable(common, offset, new_h2, policy.slot_size);
+ find_info = FindInfo{offset, 0};
+ } else {
+ total_probe_length =
+ GrowToNextCapacityDispatch(common, policy, old_ctrl, old_slots);
+ find_info = find_first_non_full(common, new_hash);
+ SetCtrlInLargeTable(common, find_info.offset, new_h2, policy.slot_size);
+ }
+ ABSL_SWISSTABLE_ASSERT(old_capacity > policy.soo_capacity());
+ (*policy.dealloc)(alloc, old_capacity, old_ctrl, slot_size, slot_align,
+ has_infoz);
+ }
+ PrepareInsertCommon(common);
+ ResetGrowthLeft(GetGrowthInfoFromControl(new_ctrl), new_capacity,
+ common.size());
+
+ if (ABSL_PREDICT_FALSE(has_infoz)) {
+ common.set_has_infoz();
+ infoz.RecordStorageChanged(common.size() - 1, new_capacity);
+ infoz.RecordRehash(total_probe_length);
+ infoz.RecordInsert(new_hash, find_info.probe_length);
+ common.set_infoz(infoz);
+ }
+ return find_info.offset;
+}
// Called whenever the table needs to vacate empty slots either by removing
-// tombstones via rehash or growth.
+// tombstones via rehash or growth to next capacity.
ABSL_ATTRIBUTE_NOINLINE
-FindInfo FindInsertPositionWithGrowthOrRehash(CommonFields& common, size_t hash,
- const PolicyFunctions& policy) {
+size_t RehashOrGrowToNextCapacityAndPrepareInsert(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_hash) {
const size_t cap = common.capacity();
+ ABSL_ASSUME(cap > 0);
if (cap > Group::kWidth &&
// Do these calculations in 64-bit to avoid overflow.
common.size() * uint64_t{32} <= cap * uint64_t{25}) {
@@ -567,77 +1375,468 @@
// 762 | 149836 0.37 13 | 148559 0.74 190
// 807 | 149736 0.39 14 | 151107 0.39 14
// 852 | 150204 0.42 15 | 151019 0.42 15
- DropDeletesWithoutResize(common, policy);
+ return DropDeletesWithoutResizeAndPrepareInsert(common, policy, new_hash);
} else {
// Otherwise grow the container.
- policy.resize(common, NextCapacity(cap), HashtablezInfoHandle{});
+ return GrowToNextCapacityAndPrepareInsert(common, policy, new_hash);
}
- // This function is typically called with tables containing deleted slots.
- // The table will be big and `FindFirstNonFullAfterResize` will always
- // fallback to `find_first_non_full`. So using `find_first_non_full` directly.
- return find_first_non_full(common, hash);
+}
+
+// Slow path for PrepareInsertNonSoo that is called when the table has deleted
+// slots or need to be resized or rehashed.
+size_t PrepareInsertNonSooSlow(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t hash) {
+ const GrowthInfo growth_info = common.growth_info();
+ ABSL_SWISSTABLE_ASSERT(!growth_info.HasNoDeletedAndGrowthLeft());
+ if (ABSL_PREDICT_TRUE(growth_info.HasNoGrowthLeftAndNoDeleted())) {
+ // Table without deleted slots (>95% cases) that needs to be resized.
+ ABSL_SWISSTABLE_ASSERT(growth_info.HasNoDeleted() &&
+ growth_info.GetGrowthLeft() == 0);
+ return GrowToNextCapacityAndPrepareInsert(common, policy, hash);
+ }
+ if (ABSL_PREDICT_FALSE(growth_info.HasNoGrowthLeftAssumingMayHaveDeleted())) {
+ // Table with deleted slots that needs to be rehashed or resized.
+ return RehashOrGrowToNextCapacityAndPrepareInsert(common, policy, hash);
+ }
+ // Table with deleted slots that has space for the inserting element.
+ FindInfo target = find_first_non_full(common, hash);
+ PrepareInsertCommon(common);
+ common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
+ SetCtrlInLargeTable(common, target.offset, H2(hash), policy.slot_size);
+ common.infoz().RecordInsert(hash, target.probe_length);
+ return target.offset;
+}
+
+// Resizes empty non-allocated SOO table to NextCapacity(SooCapacity()),
+// forces the table to be sampled and prepares the insert.
+// SOO tables need to switch from SOO to heap in order to store the infoz.
+// Requires:
+// 1. `c.capacity() == SooCapacity()`.
+// 2. `c.empty()`.
+ABSL_ATTRIBUTE_NOINLINE size_t
+GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_hash) {
+ ResizeEmptyNonAllocatedTableImpl(common, policy, NextCapacity(SooCapacity()),
+ /*force_infoz=*/true);
+ PrepareInsertCommon(common);
+ common.growth_info().OverwriteEmptyAsFull();
+ SetCtrlInSingleGroupTable(common, SooSlotIndex(), H2(new_hash),
+ policy.slot_size);
+ common.infoz().RecordInsert(new_hash, /*distance_from_desired=*/0);
+ return SooSlotIndex();
+}
+
+// Resizes empty non-allocated table to the capacity to fit new_size elements.
+// Requires:
+// 1. `c.capacity() == policy.soo_capacity()`.
+// 2. `c.empty()`.
+// 3. `new_size > policy.soo_capacity()`.
+// The table will be attempted to be sampled.
+void ReserveEmptyNonAllocatedTableToFitNewSize(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_size) {
+ ValidateMaxSize(new_size, policy.slot_size);
+ ABSL_ASSUME(new_size > 0);
+ ResizeEmptyNonAllocatedTableImpl(common, policy, SizeToCapacity(new_size),
+ /*force_infoz=*/false);
+ // This is after resize, to ensure that we have completed the allocation
+ // and have potentially sampled the hashtable.
+ common.infoz().RecordReservation(new_size);
+}
+
+// Type erased version of raw_hash_set::reserve for tables that have an
+// allocated backing array.
+//
+// Requires:
+// 1. `c.capacity() > policy.soo_capacity()` OR `!c.empty()`.
+// Reserving already allocated tables is considered to be a rare case.
+ABSL_ATTRIBUTE_NOINLINE void ReserveAllocatedTable(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_size) {
+ const size_t cap = common.capacity();
+ ValidateMaxSize(new_size, policy.slot_size);
+ ABSL_ASSUME(new_size > 0);
+ const size_t new_capacity = SizeToCapacity(new_size);
+ if (cap == policy.soo_capacity()) {
+ ABSL_SWISSTABLE_ASSERT(!common.empty());
+ ResizeFullSooTable(common, policy, new_capacity,
+ ResizeFullSooTableSamplingMode::kNoSampling);
+ } else {
+ ABSL_SWISSTABLE_ASSERT(cap > policy.soo_capacity());
+ // TODO(b/382423690): consider using GrowToNextCapacity, when applicable.
+ ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
+ }
+ common.infoz().RecordReservation(new_size);
}
} // namespace
-const void* GetHashRefForEmptyHasher(const CommonFields& common) {
+void* GetRefForEmptyClass(CommonFields& common) {
// Empty base optimization typically make the empty base class address to be
// the same as the first address of the derived class object.
- // But we generally assume that for empty hasher we can return any valid
+ // But we generally assume that for empty classes we can return any valid
// pointer.
return &common;
}
-size_t PrepareInsertNonSoo(CommonFields& common, size_t hash, FindInfo target,
- const PolicyFunctions& policy) {
+void ResizeAllocatedTableWithSeedChange(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_capacity) {
+ ResizeNonSooImpl<ResizeNonSooMode::kGuaranteedAllocated>(
+ common, policy, new_capacity, common.infoz());
+}
+
+void ReserveEmptyNonAllocatedTableToFitBucketCount(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t bucket_count) {
+ size_t new_capacity = NormalizeCapacity(bucket_count);
+ ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size);
+ ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
+ /*force_infoz=*/false);
+}
+
+// Resizes a full SOO table to the NextCapacity(SooCapacity()).
+template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
+size_t GrowSooTableToNextCapacityAndPrepareInsert(
+ CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t new_hash, ctrl_t soo_slot_ctrl) {
+ AssertSoo(common, policy);
+ if (ABSL_PREDICT_FALSE(soo_slot_ctrl == ctrl_t::kEmpty)) {
+ // The table is empty, it is only used for forced sampling of SOO tables.
+ return GrowEmptySooTableToNextCapacityForceSamplingAndPrepareInsert(
+ common, policy, new_hash);
+ }
+ ABSL_SWISSTABLE_ASSERT(common.size() == policy.soo_capacity());
+ static constexpr size_t kNewCapacity = NextCapacity(SooCapacity());
+ const size_t slot_size = policy.slot_size;
+ const size_t slot_align = policy.slot_align;
+ common.set_capacity(kNewCapacity);
+
+ // Since the table is not empty, it will not be sampled.
+ // The decision to sample was already made during the first insertion.
+ RawHashSetLayout layout(kNewCapacity, slot_size, slot_align,
+ /*has_infoz=*/false);
+ void* alloc = policy.get_char_alloc(common);
+ char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
+ const GenerationType old_generation = common.generation();
+ common.set_generation_ptr(
+ reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
+ common.set_generation(NextGeneration(old_generation));
+
+ // We do not set control and slots in CommonFields yet to avoid overriding
+ // SOO data.
+ ctrl_t* new_ctrl = reinterpret_cast<ctrl_t*>(mem + layout.control_offset());
+ void* new_slots = mem + layout.slot_offset();
+
+ PrepareInsertCommon(common);
+ ABSL_SWISSTABLE_ASSERT(common.size() == 2);
+ GetGrowthInfoFromControl(new_ctrl).InitGrowthLeftNoDeleted(kNewCapacity - 2);
+ common.generate_new_seed();
+
+ // After resize from capacity 1 to 3, we always have exactly the slot with
+ // index 1 occupied, so we need to insert either at index 0 or index 2.
+ static_assert(SooSlotIndex() == 1);
+ const size_t offset = SingleGroupTableH1(new_hash, common.seed()) & 2;
+ InitializeThreeElementsControlBytesAfterSoo(soo_slot_ctrl, new_hash, offset,
+ new_ctrl);
+
+ SanitizerPoisonMemoryRegion(new_slots, slot_size * kNewCapacity);
+ void* target_slot = SlotAddress(new_slots, SooSlotIndex(), slot_size);
+ SanitizerUnpoisonMemoryRegion(target_slot, slot_size);
+ if constexpr (TransferUsesMemcpy) {
+ // Target slot is placed at index 1, but capacity is at
+ // minimum 3. So we are allowed to copy at least twice as much
+ // memory.
+ static_assert(SooSlotIndex() == 1);
+ static_assert(SooSlotMemcpySize > 0);
+ static_assert(SooSlotMemcpySize <= MaxSooSlotSize());
+ ABSL_SWISSTABLE_ASSERT(SooSlotMemcpySize <= 2 * slot_size);
+ ABSL_SWISSTABLE_ASSERT(SooSlotMemcpySize >= slot_size);
+ void* next_slot = SlotAddress(target_slot, 1, slot_size);
+ SanitizerUnpoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
+ std::memcpy(target_slot, common.soo_data(), SooSlotMemcpySize);
+ SanitizerPoisonMemoryRegion(next_slot, SooSlotMemcpySize - slot_size);
+ } else {
+ static_assert(SooSlotMemcpySize == 0);
+ policy.transfer_n(&common, target_slot, common.soo_data(), 1);
+ }
+ // Seed was already generated above.
+ common.set_control</*kGenerateSeed=*/false>(new_ctrl);
+ common.set_slots(new_slots);
+
+ common.infoz().RecordInsert(new_hash, /*distance_from_desired=*/0);
+ SanitizerUnpoisonMemoryRegion(SlotAddress(new_slots, offset, slot_size),
+ slot_size);
+ return offset;
+}
+
+void GrowFullSooTableToNextCapacityForceSampling(
+ CommonFields& common, const PolicyFunctions& __restrict policy) {
+ AssertFullSoo(common, policy);
+ ResizeFullSooTable(
+ common, policy, NextCapacity(SooCapacity()),
+ ResizeFullSooTableSamplingMode::kForceSampleNoResizeIfUnsampled);
+}
+
+void Rehash(CommonFields& common, const PolicyFunctions& __restrict policy,
+ size_t n) {
+ const size_t cap = common.capacity();
+
+ auto clear_backing_array = [&]() {
+ ClearBackingArray(common, policy, policy.get_char_alloc(common),
+ /*reuse=*/false, policy.soo_enabled);
+ };
+
+ const size_t slot_size = policy.slot_size;
+
+ if (n == 0) {
+ if (cap <= policy.soo_capacity()) return;
+ if (common.empty()) {
+ clear_backing_array();
+ return;
+ }
+ if (common.size() <= policy.soo_capacity()) {
+ // When the table is already sampled, we keep it sampled.
+ if (common.infoz().IsSampled()) {
+ static constexpr size_t kInitialSampledCapacity =
+ NextCapacity(SooCapacity());
+ if (cap > kInitialSampledCapacity) {
+ ResizeAllocatedTableWithSeedChange(common, policy,
+ kInitialSampledCapacity);
+ }
+ // This asserts that we didn't lose sampling coverage in `resize`.
+ ABSL_SWISSTABLE_ASSERT(common.infoz().IsSampled());
+ return;
+ }
+ ABSL_SWISSTABLE_ASSERT(slot_size <= sizeof(HeapOrSoo));
+ ABSL_SWISSTABLE_ASSERT(policy.slot_align <= alignof(HeapOrSoo));
+ HeapOrSoo tmp_slot(uninitialized_tag_t{});
+ size_t begin_offset = FindFirstFullSlot(0, cap, common.control());
+ policy.transfer_n(
+ &common, &tmp_slot,
+ SlotAddress(common.slot_array(), begin_offset, slot_size), 1);
+ clear_backing_array();
+ policy.transfer_n(&common, common.soo_data(), &tmp_slot, 1);
+ common.set_full_soo();
+ return;
+ }
+ }
+
+ ValidateMaxSize(n, policy.slot_size);
+ // bitor is a faster way of doing `max` here. We will round up to the next
+ // power-of-2-minus-1, so bitor is good enough.
+ const size_t new_capacity =
+ NormalizeCapacity(n | SizeToCapacity(common.size()));
+ // n == 0 unconditionally rehashes as per the standard.
+ if (n == 0 || new_capacity > cap) {
+ if (cap == policy.soo_capacity()) {
+ if (common.empty()) {
+ ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity,
+ /*force_infoz=*/false);
+ } else {
+ ResizeFullSooTable(common, policy, new_capacity,
+ ResizeFullSooTableSamplingMode::kNoSampling);
+ }
+ } else {
+ ResizeAllocatedTableWithSeedChange(common, policy, new_capacity);
+ }
+ // This is after resize, to ensure that we have completed the allocation
+ // and have potentially sampled the hashtable.
+ common.infoz().RecordReservation(n);
+ }
+}
+
+void Copy(CommonFields& common, const PolicyFunctions& __restrict policy,
+ const CommonFields& other,
+ absl::FunctionRef<void(void*, const void*)> copy_fn) {
+ const size_t size = other.size();
+ ABSL_SWISSTABLE_ASSERT(size > 0);
+ const size_t soo_capacity = policy.soo_capacity();
+ const size_t slot_size = policy.slot_size;
+ if (size <= soo_capacity) {
+ ABSL_SWISSTABLE_ASSERT(size == 1);
+ common.set_full_soo();
+ const void* other_slot =
+ other.capacity() <= soo_capacity
+ ? other.soo_data()
+ : SlotAddress(
+ other.slot_array(),
+ FindFirstFullSlot(0, other.capacity(), other.control()),
+ slot_size);
+ copy_fn(common.soo_data(), other_slot);
+
+ if (policy.is_hashtablez_eligible && ShouldSampleNextTable()) {
+ GrowFullSooTableToNextCapacityForceSampling(common, policy);
+ }
+ return;
+ }
+
+ ReserveTableToFitNewSize(common, policy, size);
+ auto infoz = common.infoz();
+ ABSL_SWISSTABLE_ASSERT(other.capacity() > soo_capacity);
+ const size_t cap = common.capacity();
+ ABSL_SWISSTABLE_ASSERT(cap > soo_capacity);
+ // Note about single group tables:
+ // 1. It is correct to have any order of elements.
+ // 2. Order has to be non deterministic.
+ // 3. We are assigning elements with arbitrary `shift` starting from
+ // `capacity + shift` position.
+ // 4. `shift` must be coprime with `capacity + 1` in order to be able to use
+ // modular arithmetic to traverse all positions, instead of cycling
+ // through a subset of positions. Odd numbers are coprime with any
+ // `capacity + 1` (2^N).
+ size_t offset = cap;
+ const size_t shift = is_single_group(cap) ? (common.seed().seed() | 1) : 0;
+ const void* hash_fn = policy.hash_fn(common);
+ auto hasher = policy.hash_slot;
+ IterateOverFullSlotsImpl(
+ other, slot_size, [&](const ctrl_t* that_ctrl, void* that_slot) {
+ if (shift == 0) {
+ // Big tables case. Position must be searched via probing.
+ // The table is guaranteed to be empty, so we can do faster than
+ // a full `insert`.
+ const size_t hash = (*hasher)(hash_fn, that_slot);
+ FindInfo target = find_first_non_full(common, hash);
+ infoz.RecordInsert(hash, target.probe_length);
+ offset = target.offset;
+ } else {
+ // Small tables case. Next position is computed via shift.
+ offset = (offset + shift) & cap;
+ }
+ const h2_t h2 = static_cast<h2_t>(*that_ctrl);
+ // We rely on the hash not changing for small tables.
+ ABSL_SWISSTABLE_ASSERT(
+ H2((*hasher)(hash_fn, that_slot)) == h2 &&
+ "hash function value changed unexpectedly during the copy");
+ SetCtrl(common, offset, h2, slot_size);
+ copy_fn(SlotAddress(common.slot_array(), offset, slot_size), that_slot);
+ common.maybe_increment_generation_on_insert();
+ });
+ if (shift != 0) {
+ // On small table copy we do not record individual inserts.
+ // RecordInsert requires hash, but it is unknown for small tables.
+ infoz.RecordStorageChanged(size, cap);
+ }
+ common.increment_size(size);
+ common.growth_info().OverwriteManyEmptyAsFull(size);
+}
+
+void ReserveTableToFitNewSize(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t new_size) {
+ common.reset_reserved_growth(new_size);
+ common.set_reservation_size(new_size);
+ ABSL_SWISSTABLE_ASSERT(new_size > policy.soo_capacity());
+ const size_t cap = common.capacity();
+ if (ABSL_PREDICT_TRUE(common.empty() && cap <= policy.soo_capacity())) {
+ return ReserveEmptyNonAllocatedTableToFitNewSize(common, policy, new_size);
+ }
+
+ ABSL_SWISSTABLE_ASSERT(!common.empty() || cap > policy.soo_capacity());
+ ABSL_SWISSTABLE_ASSERT(cap > 0);
+ const size_t max_size_before_growth =
+ cap <= policy.soo_capacity() ? policy.soo_capacity()
+ : common.size() + common.growth_left();
+ if (new_size <= max_size_before_growth) {
+ return;
+ }
+ ReserveAllocatedTable(common, policy, new_size);
+}
+
+size_t PrepareInsertNonSoo(CommonFields& common,
+ const PolicyFunctions& __restrict policy,
+ size_t hash, FindInfo target) {
+ const bool rehash_for_bug_detection =
+ common.should_rehash_for_bug_detection_on_insert() &&
+ // Required to allow use of ResizeAllocatedTable.
+ common.capacity() > 0;
+ if (rehash_for_bug_detection) {
+ // Move to a different heap allocation in order to detect bugs.
+ const size_t cap = common.capacity();
+ ResizeAllocatedTableWithSeedChange(
+ common, policy, common.growth_left() > 0 ? cap : NextCapacity(cap));
+ target = find_first_non_full(common, hash);
+ }
+
+ const GrowthInfo growth_info = common.growth_info();
// When there are no deleted slots in the table
// and growth_left is positive, we can insert at the first
// empty slot in the probe sequence (target).
- const bool use_target_hint =
- // Optimization is disabled when generations are enabled.
- // We have to rehash even sparse tables randomly in such mode.
- !SwisstableGenerationsEnabled() &&
- common.growth_info().HasNoDeletedAndGrowthLeft();
- if (ABSL_PREDICT_FALSE(!use_target_hint)) {
- // Notes about optimized mode when generations are disabled:
- // We do not enter this branch if table has no deleted slots
- // and growth_left is positive.
- // We enter this branch in the following cases listed in decreasing
- // frequency:
- // 1. Table without deleted slots (>95% cases) that needs to be resized.
- // 2. Table with deleted slots that has space for the inserting element.
- // 3. Table with deleted slots that needs to be rehashed or resized.
- if (ABSL_PREDICT_TRUE(common.growth_info().HasNoGrowthLeftAndNoDeleted())) {
- const size_t old_capacity = common.capacity();
- policy.resize(common, NextCapacity(old_capacity), HashtablezInfoHandle{});
- target = HashSetResizeHelper::FindFirstNonFullAfterResize(
- common, old_capacity, hash);
- } else {
- // Note: the table may have no deleted slots here when generations
- // are enabled.
- const bool rehash_for_bug_detection =
- common.should_rehash_for_bug_detection_on_insert();
- if (rehash_for_bug_detection) {
- // Move to a different heap allocation in order to detect bugs.
- const size_t cap = common.capacity();
- policy.resize(common,
- common.growth_left() > 0 ? cap : NextCapacity(cap),
- HashtablezInfoHandle{});
- }
- if (ABSL_PREDICT_TRUE(common.growth_left() > 0)) {
- target = find_first_non_full(common, hash);
- } else {
- target = FindInsertPositionWithGrowthOrRehash(common, hash, policy);
- }
- }
+ if (ABSL_PREDICT_FALSE(!growth_info.HasNoDeletedAndGrowthLeft())) {
+ return PrepareInsertNonSooSlow(common, policy, hash);
}
PrepareInsertCommon(common);
- common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
+ common.growth_info().OverwriteEmptyAsFull();
SetCtrl(common, target.offset, H2(hash), policy.slot_size);
common.infoz().RecordInsert(hash, target.probe_length);
return target.offset;
}
+namespace {
+// Returns true if the following is true
+// 1. OptimalMemcpySizeForSooSlotTransfer(left) >
+// OptimalMemcpySizeForSooSlotTransfer(left - 1)
+// 2. OptimalMemcpySizeForSooSlotTransfer(left) are equal for all i in [left,
+// right].
+// This function is used to verify that we have all the possible template
+// instantiations for GrowFullSooTableToNextCapacity.
+// With this verification the problem may be detected at compile time instead of
+// link time.
+constexpr bool VerifyOptimalMemcpySizeForSooSlotTransferRange(size_t left,
+ size_t right) {
+ size_t optimal_size_for_range = OptimalMemcpySizeForSooSlotTransfer(left);
+ if (optimal_size_for_range <= OptimalMemcpySizeForSooSlotTransfer(left - 1)) {
+ return false;
+ }
+ for (size_t i = left + 1; i <= right; ++i) {
+ if (OptimalMemcpySizeForSooSlotTransfer(i) != optimal_size_for_range) {
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace
+
+// Extern template instantiation for inline function.
+template size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index,
+ size_t old_capacity,
+ ctrl_t* new_ctrl,
+ size_t new_capacity);
+
+// We need to instantiate ALL possible template combinations because we define
+// the function in the cc file.
+template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+template size_t GrowSooTableToNextCapacityAndPrepareInsert<
+ OptimalMemcpySizeForSooSlotTransfer(1), true>(CommonFields&,
+ const PolicyFunctions&,
+ size_t, ctrl_t);
+
+static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(2, 3));
+template size_t GrowSooTableToNextCapacityAndPrepareInsert<
+ OptimalMemcpySizeForSooSlotTransfer(3), true>(CommonFields&,
+ const PolicyFunctions&,
+ size_t, ctrl_t);
+
+static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(4, 8));
+template size_t GrowSooTableToNextCapacityAndPrepareInsert<
+ OptimalMemcpySizeForSooSlotTransfer(8), true>(CommonFields&,
+ const PolicyFunctions&,
+ size_t, ctrl_t);
+
+#if UINTPTR_MAX == UINT32_MAX
+static_assert(MaxSooSlotSize() == 8);
+#else
+static_assert(VerifyOptimalMemcpySizeForSooSlotTransferRange(9, 16));
+template size_t GrowSooTableToNextCapacityAndPrepareInsert<
+ OptimalMemcpySizeForSooSlotTransfer(16), true>(CommonFields&,
+ const PolicyFunctions&,
+ size_t, ctrl_t);
+static_assert(MaxSooSlotSize() == 16);
+#endif
+
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index d4fe8f5..f5e3fdf 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -41,12 +41,6 @@
// When heterogeneous lookup is disabled, only the explicit `key_type` overloads
// exist.
//
-// find() also supports passing the hash explicitly:
-//
-// iterator find(const key_type& key, size_t hash);
-// template <class U>
-// iterator find(const U& key, size_t hash);
-//
// In addition the pointer to element and iterator stability guarantees are
// weaker: all iterators and pointers are invalidated after a new element is
// inserted.
@@ -190,6 +184,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <functional>
#include <initializer_list>
#include <iterator>
#include <limits>
@@ -201,6 +196,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/endian.h"
+#include "absl/base/internal/iterator_traits.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
@@ -208,32 +204,22 @@
#include "absl/base/port.h"
#include "absl/base/prefetch.h"
#include "absl/container/internal/common.h" // IWYU pragma: export // for node_handle
+#include "absl/container/internal/common_policy_traits.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/container/internal/container_memory.h"
+#include "absl/container/internal/hash_function_defaults.h"
#include "absl/container/internal/hash_policy_traits.h"
+#include "absl/container/internal/hashtable_control_bytes.h"
#include "absl/container/internal/hashtable_debug_hooks.h"
#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/functional/function_ref.h"
+#include "absl/hash/hash.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/bits.h"
#include "absl/utility/utility.h"
-#ifdef ABSL_INTERNAL_HAVE_SSE2
-#include <emmintrin.h>
-#endif
-
-#ifdef ABSL_INTERNAL_HAVE_SSSE3
-#include <tmmintrin.h>
-#endif
-
-#ifdef _MSC_VER
-#include <intrin.h>
-#endif
-
-#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
-#include <arm_neon.h>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace container_internal {
@@ -252,6 +238,15 @@
#define ABSL_SWISSTABLE_ENABLE_GENERATIONS
#endif
+#ifdef ABSL_SWISSTABLE_ASSERT
+#error ABSL_SWISSTABLE_ASSERT cannot be directly set
+#else
+// We use this macro for assertions that users may see when the table is in an
+// invalid state that sanitizers may help diagnose.
+#define ABSL_SWISSTABLE_ASSERT(CONDITION) \
+ assert((CONDITION) && "Try enabling sanitizers.")
+#endif
+
// We use uint8_t so we don't need to worry about padding.
using GenerationType = uint8_t;
@@ -271,6 +266,15 @@
constexpr size_t NumGenerationBytes() { return 0; }
#endif
+// Returns true if we should assert that the table is not accessed after it has
+// been destroyed or during the destruction of the table.
+constexpr bool SwisstableAssertAccessToDestroyedTable() {
+#ifndef NDEBUG
+ return true;
+#endif
+ return SwisstableGenerationsEnabled();
+}
+
template <typename AllocType>
void SwapAlloc(AllocType& lhs, AllocType& rhs,
std::true_type /* propagate_on_container_swap */) {
@@ -322,7 +326,7 @@
// sequence and `mask` (usually the capacity of the table) as the mask to
// apply to each value in the progression.
probe_seq(size_t hash, size_t mask) {
- assert(((mask + 1) & mask) == 0 && "not a mask");
+ ABSL_SWISSTABLE_ASSERT(((mask + 1) & mask) == 0 && "not a mask");
mask_ = mask;
offset_ = hash & mask_;
}
@@ -376,166 +380,21 @@
return false;
}
-template <typename T>
-uint32_t TrailingZeros(T x) {
- ABSL_ASSUME(x != 0);
- return static_cast<uint32_t>(countr_zero(x));
-}
-
-// 8 bytes bitmask with most significant bit set for every byte.
-constexpr uint64_t kMsbs8Bytes = 0x8080808080808080ULL;
-
-// An abstract bitmask, such as that emitted by a SIMD instruction.
-//
-// Specifically, this type implements a simple bitset whose representation is
-// controlled by `SignificantBits` and `Shift`. `SignificantBits` is the number
-// of abstract bits in the bitset, while `Shift` is the log-base-two of the
-// width of an abstract bit in the representation.
-// This mask provides operations for any number of real bits set in an abstract
-// bit. To add iteration on top of that, implementation must guarantee no more
-// than the most significant real bit is set in a set abstract bit.
-template <class T, int SignificantBits, int Shift = 0>
-class NonIterableBitMask {
- public:
- explicit NonIterableBitMask(T mask) : mask_(mask) {}
-
- explicit operator bool() const { return this->mask_ != 0; }
-
- // Returns the index of the lowest *abstract* bit set in `self`.
- uint32_t LowestBitSet() const {
- return container_internal::TrailingZeros(mask_) >> Shift;
- }
-
- // Returns the index of the highest *abstract* bit set in `self`.
- uint32_t HighestBitSet() const {
- return static_cast<uint32_t>((bit_width(mask_) - 1) >> Shift);
- }
-
- // Returns the number of trailing zero *abstract* bits.
- uint32_t TrailingZeros() const {
- return container_internal::TrailingZeros(mask_) >> Shift;
- }
-
- // Returns the number of leading zero *abstract* bits.
- uint32_t LeadingZeros() const {
- constexpr int total_significant_bits = SignificantBits << Shift;
- constexpr int extra_bits = sizeof(T) * 8 - total_significant_bits;
- return static_cast<uint32_t>(
- countl_zero(static_cast<T>(mask_ << extra_bits))) >>
- Shift;
- }
-
- T mask_;
-};
-
-// Mask that can be iterable
-//
-// For example, when `SignificantBits` is 16 and `Shift` is zero, this is just
-// an ordinary 16-bit bitset occupying the low 16 bits of `mask`. When
-// `SignificantBits` is 8 and `Shift` is 3, abstract bits are represented as
-// the bytes `0x00` and `0x80`, and it occupies all 64 bits of the bitmask.
-// If NullifyBitsOnIteration is true (only allowed for Shift == 3),
-// non zero abstract bit is allowed to have additional bits
-// (e.g., `0xff`, `0x83` and `0x9c` are ok, but `0x6f` is not).
-//
-// For example:
-// for (int i : BitMask<uint32_t, 16>(0b101)) -> yields 0, 2
-// for (int i : BitMask<uint64_t, 8, 3>(0x0000000080800000)) -> yields 2, 3
-template <class T, int SignificantBits, int Shift = 0,
- bool NullifyBitsOnIteration = false>
-class BitMask : public NonIterableBitMask<T, SignificantBits, Shift> {
- using Base = NonIterableBitMask<T, SignificantBits, Shift>;
- static_assert(std::is_unsigned<T>::value, "");
- static_assert(Shift == 0 || Shift == 3, "");
- static_assert(!NullifyBitsOnIteration || Shift == 3, "");
-
- public:
- explicit BitMask(T mask) : Base(mask) {
- if (Shift == 3 && !NullifyBitsOnIteration) {
- assert(this->mask_ == (this->mask_ & kMsbs8Bytes));
- }
- }
- // BitMask is an iterator over the indices of its abstract bits.
- using value_type = int;
- using iterator = BitMask;
- using const_iterator = BitMask;
-
- BitMask& operator++() {
- if (Shift == 3 && NullifyBitsOnIteration) {
- this->mask_ &= kMsbs8Bytes;
- }
- this->mask_ &= (this->mask_ - 1);
- return *this;
- }
-
- uint32_t operator*() const { return Base::LowestBitSet(); }
-
- BitMask begin() const { return *this; }
- BitMask end() const { return BitMask(0); }
-
- private:
- friend bool operator==(const BitMask& a, const BitMask& b) {
- return a.mask_ == b.mask_;
- }
- friend bool operator!=(const BitMask& a, const BitMask& b) {
- return a.mask_ != b.mask_;
- }
-};
-
-using h2_t = uint8_t;
-
-// The values here are selected for maximum performance. See the static asserts
-// below for details.
-
-// A `ctrl_t` is a single control byte, which can have one of four
-// states: empty, deleted, full (which has an associated seven-bit h2_t value)
-// and the sentinel. They have the following bit patterns:
-//
-// empty: 1 0 0 0 0 0 0 0
-// deleted: 1 1 1 1 1 1 1 0
-// full: 0 h h h h h h h // h represents the hash bits.
-// sentinel: 1 1 1 1 1 1 1 1
-//
-// These values are specifically tuned for SSE-flavored SIMD.
-// The static_asserts below detail the source of these choices.
-//
-// We use an enum class so that when strict aliasing is enabled, the compiler
-// knows ctrl_t doesn't alias other types.
-enum class ctrl_t : int8_t {
- kEmpty = -128, // 0b10000000
- kDeleted = -2, // 0b11111110
- kSentinel = -1, // 0b11111111
-};
-static_assert(
- (static_cast<int8_t>(ctrl_t::kEmpty) &
- static_cast<int8_t>(ctrl_t::kDeleted) &
- static_cast<int8_t>(ctrl_t::kSentinel) & 0x80) != 0,
- "Special markers need to have the MSB to make checking for them efficient");
-static_assert(
- ctrl_t::kEmpty < ctrl_t::kSentinel && ctrl_t::kDeleted < ctrl_t::kSentinel,
- "ctrl_t::kEmpty and ctrl_t::kDeleted must be smaller than "
- "ctrl_t::kSentinel to make the SIMD test of IsEmptyOrDeleted() efficient");
-static_assert(
- ctrl_t::kSentinel == static_cast<ctrl_t>(-1),
- "ctrl_t::kSentinel must be -1 to elide loading it from memory into SIMD "
- "registers (pcmpeqd xmm, xmm)");
-static_assert(ctrl_t::kEmpty == static_cast<ctrl_t>(-128),
- "ctrl_t::kEmpty must be -128 to make the SIMD check for its "
- "existence efficient (psignb xmm, xmm)");
-static_assert(
- (~static_cast<int8_t>(ctrl_t::kEmpty) &
- ~static_cast<int8_t>(ctrl_t::kDeleted) &
- static_cast<int8_t>(ctrl_t::kSentinel) & 0x7F) != 0,
- "ctrl_t::kEmpty and ctrl_t::kDeleted must share an unset bit that is not "
- "shared by ctrl_t::kSentinel to make the scalar test for "
- "MaskEmptyOrDeleted() efficient");
-static_assert(ctrl_t::kDeleted == static_cast<ctrl_t>(-2),
- "ctrl_t::kDeleted must be -2 to make the implementation of "
- "ConvertSpecialToEmptyAndFullToDeleted efficient");
-
// See definition comment for why this is size 32.
ABSL_DLL extern const ctrl_t kEmptyGroup[32];
+// We use these sentinel capacity values in debug mode to indicate different
+// classes of bugs.
+enum InvalidCapacity : size_t {
+ kAboveMaxValidCapacity = ~size_t{} - 100,
+ kReentrance,
+ kDestroyed,
+
+ // These two must be last because we use `>= kMovedFrom` to mean moved-from.
+ kMovedFrom,
+ kSelfMovedFrom,
+};
+
// Returns a pointer to a control byte group that can be used by empty tables.
inline ctrl_t* EmptyGroup() {
// Const must be cast away here; no uses of this function will actually write
@@ -566,54 +425,111 @@
return *generation == SentinelEmptyGeneration();
}
-// Mixes a randomly generated per-process seed with `hash` and `ctrl` to
-// randomize insertion order within groups.
-bool ShouldInsertBackwardsForDebug(size_t capacity, size_t hash,
- const ctrl_t* ctrl);
+// We only allow a maximum of 1 SOO element, which makes the implementation
+// much simpler. Complications with multiple SOO elements include:
+// - Satisfying the guarantee that erasing one element doesn't invalidate
+// iterators to other elements means we would probably need actual SOO
+// control bytes.
+// - In order to prevent user code from depending on iteration order for small
+// tables, we would need to randomize the iteration order somehow.
+constexpr size_t SooCapacity() { return 1; }
+// Sentinel type to indicate SOO CommonFields construction.
+struct soo_tag_t {};
+// Sentinel type to indicate SOO CommonFields construction with full size.
+struct full_soo_tag_t {};
+// Sentinel type to indicate non-SOO CommonFields construction.
+struct non_soo_tag_t {};
+// Sentinel value to indicate an uninitialized value explicitly.
+struct uninitialized_tag_t {};
+// Sentinel value to indicate creation of an empty table without a seed.
+struct no_seed_empty_tag_t {};
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline bool ShouldInsertBackwards(
- ABSL_ATTRIBUTE_UNUSED size_t capacity, ABSL_ATTRIBUTE_UNUSED size_t hash,
- ABSL_ATTRIBUTE_UNUSED const ctrl_t* ctrl) {
-#if defined(NDEBUG)
- return false;
-#else
- return ShouldInsertBackwardsForDebug(capacity, hash, ctrl);
-#endif
+// Per table hash salt. This gets mixed into H1 to randomize iteration order
+// per-table.
+// The seed is needed to ensure non-determinism of iteration order.
+class PerTableSeed {
+ public:
+ // The number of bits in the seed.
+ // It is big enough to ensure non-determinism of iteration order.
+ // We store the seed inside a uint64_t together with size and other metadata.
+ // Using 16 bits allows us to save one `and` instruction in H1 (we use movzwl
+ // instead of movq+and).
+ static constexpr size_t kBitCount = 16;
+
+ // Returns the seed for the table. Only the lowest kBitCount are non zero.
+ size_t seed() const { return seed_; }
+
+ private:
+ friend class HashtableSize;
+ explicit PerTableSeed(size_t seed) : seed_(seed) {}
+
+ const size_t seed_;
+};
+
+// Returns next per-table seed.
+inline uint16_t NextSeed() {
+ static_assert(PerTableSeed::kBitCount == 16);
+ thread_local uint16_t seed =
+ static_cast<uint16_t>(reinterpret_cast<uintptr_t>(&seed));
+ seed += uint16_t{0xad53};
+ return seed;
}
-// Returns insert position for the given mask.
-// We want to add entropy even when ASLR is not enabled.
-// In debug build we will randomly insert in either the front or back of
-// the group.
-// TODO(kfm,sbenza): revisit after we do unconditional mixing
-template <class Mask>
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline auto GetInsertionOffset(
- Mask mask, ABSL_ATTRIBUTE_UNUSED size_t capacity,
- ABSL_ATTRIBUTE_UNUSED size_t hash,
- ABSL_ATTRIBUTE_UNUSED const ctrl_t* ctrl) {
-#if defined(NDEBUG)
- return mask.LowestBitSet();
-#else
- return ShouldInsertBackwardsForDebug(capacity, hash, ctrl)
- ? mask.HighestBitSet()
- : mask.LowestBitSet();
-#endif
-}
+// The size and also has additionally
+// 1) one bit that stores whether we have infoz.
+// 2) PerTableSeed::kBitCount bits for the seed.
+class HashtableSize {
+ public:
+ static constexpr size_t kSizeBitCount = 64 - PerTableSeed::kBitCount - 1;
-// Returns a per-table, hash salt, which changes on resize. This gets mixed into
-// H1 to randomize iteration order per-table.
-//
-// The seed consists of the ctrl_ pointer, which adds enough entropy to ensure
-// non-determinism of iteration order in most cases.
-inline size_t PerTableSalt(const ctrl_t* ctrl) {
- // The low bits of the pointer have little or no entropy because of
- // alignment. We shift the pointer to try to use higher entropy bits. A
- // good number seems to be 12 bits, because that aligns with page size.
- return reinterpret_cast<uintptr_t>(ctrl) >> 12;
-}
-// Extracts the H1 portion of a hash: 57 bits mixed with a per-table salt.
-inline size_t H1(size_t hash, const ctrl_t* ctrl) {
- return (hash >> 7) ^ PerTableSalt(ctrl);
+ explicit HashtableSize(uninitialized_tag_t) {}
+ explicit HashtableSize(no_seed_empty_tag_t) : data_(0) {}
+ explicit HashtableSize(full_soo_tag_t) : data_(kSizeOneNoMetadata) {}
+
+ // Returns actual size of the table.
+ size_t size() const { return static_cast<size_t>(data_ >> kSizeShift); }
+ void increment_size() { data_ += kSizeOneNoMetadata; }
+ void increment_size(size_t size) {
+ data_ += static_cast<uint64_t>(size) * kSizeOneNoMetadata;
+ }
+ void decrement_size() { data_ -= kSizeOneNoMetadata; }
+ // Returns true if the table is empty.
+ bool empty() const { return data_ < kSizeOneNoMetadata; }
+ // Sets the size to zero, but keeps all the metadata bits.
+ void set_size_to_zero_keep_metadata() { data_ = data_ & kMetadataMask; }
+
+ PerTableSeed seed() const {
+ return PerTableSeed(static_cast<size_t>(data_) & kSeedMask);
+ }
+
+ void generate_new_seed() {
+ data_ = (data_ & ~kSeedMask) ^ uint64_t{NextSeed()};
+ }
+
+ // Returns true if the table has infoz.
+ bool has_infoz() const {
+ return ABSL_PREDICT_FALSE((data_ & kHasInfozMask) != 0);
+ }
+
+ // Sets the has_infoz bit.
+ void set_has_infoz() { data_ |= kHasInfozMask; }
+
+ void set_no_seed_for_testing() { data_ &= ~kSeedMask; }
+
+ private:
+ static constexpr size_t kSizeShift = 64 - kSizeBitCount;
+ static constexpr uint64_t kSizeOneNoMetadata = uint64_t{1} << kSizeShift;
+ static constexpr uint64_t kMetadataMask = kSizeOneNoMetadata - 1;
+ static constexpr uint64_t kSeedMask =
+ (uint64_t{1} << PerTableSeed::kBitCount) - 1;
+ // The next bit after the seed.
+ static constexpr uint64_t kHasInfozMask = kSeedMask + 1;
+ uint64_t data_;
+};
+
+// Extracts the H1 portion of a hash: 57 bits mixed with a per-table seed.
+inline size_t H1(size_t hash, PerTableSeed seed) {
+ return (hash >> 7) ^ seed.seed();
}
// Extracts the H2 portion of a hash: the 7 bits not used for H1.
@@ -621,308 +537,6 @@
// These are used as an occupied control byte.
inline h2_t H2(size_t hash) { return hash & 0x7F; }
-// Helpers for checking the state of a control byte.
-inline bool IsEmpty(ctrl_t c) { return c == ctrl_t::kEmpty; }
-inline bool IsFull(ctrl_t c) {
- // Cast `c` to the underlying type instead of casting `0` to `ctrl_t` as `0`
- // is not a value in the enum. Both ways are equivalent, but this way makes
- // linters happier.
- return static_cast<std::underlying_type_t<ctrl_t>>(c) >= 0;
-}
-inline bool IsDeleted(ctrl_t c) { return c == ctrl_t::kDeleted; }
-inline bool IsEmptyOrDeleted(ctrl_t c) { return c < ctrl_t::kSentinel; }
-
-#ifdef ABSL_INTERNAL_HAVE_SSE2
-// Quick reference guide for intrinsics used below:
-//
-// * __m128i: An XMM (128-bit) word.
-//
-// * _mm_setzero_si128: Returns a zero vector.
-// * _mm_set1_epi8: Returns a vector with the same i8 in each lane.
-//
-// * _mm_subs_epi8: Saturating-subtracts two i8 vectors.
-// * _mm_and_si128: Ands two i128s together.
-// * _mm_or_si128: Ors two i128s together.
-// * _mm_andnot_si128: And-nots two i128s together.
-//
-// * _mm_cmpeq_epi8: Component-wise compares two i8 vectors for equality,
-// filling each lane with 0x00 or 0xff.
-// * _mm_cmpgt_epi8: Same as above, but using > rather than ==.
-//
-// * _mm_loadu_si128: Performs an unaligned load of an i128.
-// * _mm_storeu_si128: Performs an unaligned store of an i128.
-//
-// * _mm_sign_epi8: Retains, negates, or zeroes each i8 lane of the first
-// argument if the corresponding lane of the second
-// argument is positive, negative, or zero, respectively.
-// * _mm_movemask_epi8: Selects the sign bit out of each i8 lane and produces a
-// bitmask consisting of those bits.
-// * _mm_shuffle_epi8: Selects i8s from the first argument, using the low
-// four bits of each i8 lane in the second argument as
-// indices.
-
-// https://github.com/abseil/abseil-cpp/issues/209
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87853
-// _mm_cmpgt_epi8 is broken under GCC with -funsigned-char
-// Work around this by using the portable implementation of Group
-// when using -funsigned-char under GCC.
-inline __m128i _mm_cmpgt_epi8_fixed(__m128i a, __m128i b) {
-#if defined(__GNUC__) && !defined(__clang__)
- if (std::is_unsigned<char>::value) {
- const __m128i mask = _mm_set1_epi8(0x80);
- const __m128i diff = _mm_subs_epi8(b, a);
- return _mm_cmpeq_epi8(_mm_and_si128(diff, mask), mask);
- }
-#endif
- return _mm_cmpgt_epi8(a, b);
-}
-
-struct GroupSse2Impl {
- static constexpr size_t kWidth = 16; // the number of slots per group
-
- explicit GroupSse2Impl(const ctrl_t* pos) {
- ctrl = _mm_loadu_si128(reinterpret_cast<const __m128i*>(pos));
- }
-
- // Returns a bitmask representing the positions of slots that match hash.
- BitMask<uint16_t, kWidth> Match(h2_t hash) const {
- auto match = _mm_set1_epi8(static_cast<char>(hash));
- BitMask<uint16_t, kWidth> result = BitMask<uint16_t, kWidth>(0);
- result = BitMask<uint16_t, kWidth>(
- static_cast<uint16_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))));
- return result;
- }
-
- // Returns a bitmask representing the positions of empty slots.
- NonIterableBitMask<uint16_t, kWidth> MaskEmpty() const {
-#ifdef ABSL_INTERNAL_HAVE_SSSE3
- // This only works because ctrl_t::kEmpty is -128.
- return NonIterableBitMask<uint16_t, kWidth>(
- static_cast<uint16_t>(_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl))));
-#else
- auto match = _mm_set1_epi8(static_cast<char>(ctrl_t::kEmpty));
- return NonIterableBitMask<uint16_t, kWidth>(
- static_cast<uint16_t>(_mm_movemask_epi8(_mm_cmpeq_epi8(match, ctrl))));
-#endif
- }
-
- // Returns a bitmask representing the positions of full slots.
- // Note: for `is_small()` tables group may contain the "same" slot twice:
- // original and mirrored.
- BitMask<uint16_t, kWidth> MaskFull() const {
- return BitMask<uint16_t, kWidth>(
- static_cast<uint16_t>(_mm_movemask_epi8(ctrl) ^ 0xffff));
- }
-
- // Returns a bitmask representing the positions of non full slots.
- // Note: this includes: kEmpty, kDeleted, kSentinel.
- // It is useful in contexts when kSentinel is not present.
- auto MaskNonFull() const {
- return BitMask<uint16_t, kWidth>(
- static_cast<uint16_t>(_mm_movemask_epi8(ctrl)));
- }
-
- // Returns a bitmask representing the positions of empty or deleted slots.
- NonIterableBitMask<uint16_t, kWidth> MaskEmptyOrDeleted() const {
- auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
- return NonIterableBitMask<uint16_t, kWidth>(static_cast<uint16_t>(
- _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl))));
- }
-
- // Returns the number of trailing empty or deleted elements in the group.
- uint32_t CountLeadingEmptyOrDeleted() const {
- auto special = _mm_set1_epi8(static_cast<char>(ctrl_t::kSentinel));
- return TrailingZeros(static_cast<uint32_t>(
- _mm_movemask_epi8(_mm_cmpgt_epi8_fixed(special, ctrl)) + 1));
- }
-
- void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
- auto msbs = _mm_set1_epi8(static_cast<char>(-128));
- auto x126 = _mm_set1_epi8(126);
-#ifdef ABSL_INTERNAL_HAVE_SSSE3
- auto res = _mm_or_si128(_mm_shuffle_epi8(x126, ctrl), msbs);
-#else
- auto zero = _mm_setzero_si128();
- auto special_mask = _mm_cmpgt_epi8_fixed(zero, ctrl);
- auto res = _mm_or_si128(msbs, _mm_andnot_si128(special_mask, x126));
-#endif
- _mm_storeu_si128(reinterpret_cast<__m128i*>(dst), res);
- }
-
- __m128i ctrl;
-};
-#endif // ABSL_INTERNAL_RAW_HASH_SET_HAVE_SSE2
-
-#if defined(ABSL_INTERNAL_HAVE_ARM_NEON) && defined(ABSL_IS_LITTLE_ENDIAN)
-struct GroupAArch64Impl {
- static constexpr size_t kWidth = 8;
-
- explicit GroupAArch64Impl(const ctrl_t* pos) {
- ctrl = vld1_u8(reinterpret_cast<const uint8_t*>(pos));
- }
-
- auto Match(h2_t hash) const {
- uint8x8_t dup = vdup_n_u8(hash);
- auto mask = vceq_u8(ctrl, dup);
- return BitMask<uint64_t, kWidth, /*Shift=*/3,
- /*NullifyBitsOnIteration=*/true>(
- vget_lane_u64(vreinterpret_u64_u8(mask), 0));
- }
-
- NonIterableBitMask<uint64_t, kWidth, 3> MaskEmpty() const {
- uint64_t mask =
- vget_lane_u64(vreinterpret_u64_u8(vceq_s8(
- vdup_n_s8(static_cast<int8_t>(ctrl_t::kEmpty)),
- vreinterpret_s8_u8(ctrl))),
- 0);
- return NonIterableBitMask<uint64_t, kWidth, 3>(mask);
- }
-
- // Returns a bitmask representing the positions of full slots.
- // Note: for `is_small()` tables group may contain the "same" slot twice:
- // original and mirrored.
- auto MaskFull() const {
- uint64_t mask = vget_lane_u64(
- vreinterpret_u64_u8(vcge_s8(vreinterpret_s8_u8(ctrl),
- vdup_n_s8(static_cast<int8_t>(0)))),
- 0);
- return BitMask<uint64_t, kWidth, /*Shift=*/3,
- /*NullifyBitsOnIteration=*/true>(mask);
- }
-
- // Returns a bitmask representing the positions of non full slots.
- // Note: this includes: kEmpty, kDeleted, kSentinel.
- // It is useful in contexts when kSentinel is not present.
- auto MaskNonFull() const {
- uint64_t mask = vget_lane_u64(
- vreinterpret_u64_u8(vclt_s8(vreinterpret_s8_u8(ctrl),
- vdup_n_s8(static_cast<int8_t>(0)))),
- 0);
- return BitMask<uint64_t, kWidth, /*Shift=*/3,
- /*NullifyBitsOnIteration=*/true>(mask);
- }
-
- NonIterableBitMask<uint64_t, kWidth, 3> MaskEmptyOrDeleted() const {
- uint64_t mask =
- vget_lane_u64(vreinterpret_u64_u8(vcgt_s8(
- vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel)),
- vreinterpret_s8_u8(ctrl))),
- 0);
- return NonIterableBitMask<uint64_t, kWidth, 3>(mask);
- }
-
- uint32_t CountLeadingEmptyOrDeleted() const {
- uint64_t mask =
- vget_lane_u64(vreinterpret_u64_u8(vcle_s8(
- vdup_n_s8(static_cast<int8_t>(ctrl_t::kSentinel)),
- vreinterpret_s8_u8(ctrl))),
- 0);
- // Similar to MaskEmptyorDeleted() but we invert the logic to invert the
- // produced bitfield. We then count number of trailing zeros.
- // Clang and GCC optimize countr_zero to rbit+clz without any check for 0,
- // so we should be fine.
- return static_cast<uint32_t>(countr_zero(mask)) >> 3;
- }
-
- void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
- uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(ctrl), 0);
- constexpr uint64_t slsbs = 0x0202020202020202ULL;
- constexpr uint64_t midbs = 0x7e7e7e7e7e7e7e7eULL;
- auto x = slsbs & (mask >> 6);
- auto res = (x + midbs) | kMsbs8Bytes;
- little_endian::Store64(dst, res);
- }
-
- uint8x8_t ctrl;
-};
-#endif // ABSL_INTERNAL_HAVE_ARM_NEON && ABSL_IS_LITTLE_ENDIAN
-
-struct GroupPortableImpl {
- static constexpr size_t kWidth = 8;
-
- explicit GroupPortableImpl(const ctrl_t* pos)
- : ctrl(little_endian::Load64(pos)) {}
-
- BitMask<uint64_t, kWidth, 3> Match(h2_t hash) const {
- // For the technique, see:
- // http://graphics.stanford.edu/~seander/bithacks.html##ValueInWord
- // (Determine if a word has a byte equal to n).
- //
- // Caveat: there are false positives but:
- // - they only occur if there is a real match
- // - they never occur on ctrl_t::kEmpty, ctrl_t::kDeleted, ctrl_t::kSentinel
- // - they will be handled gracefully by subsequent checks in code
- //
- // Example:
- // v = 0x1716151413121110
- // hash = 0x12
- // retval = (v - lsbs) & ~v & msbs = 0x0000000080800000
- constexpr uint64_t lsbs = 0x0101010101010101ULL;
- auto x = ctrl ^ (lsbs * hash);
- return BitMask<uint64_t, kWidth, 3>((x - lsbs) & ~x & kMsbs8Bytes);
- }
-
- NonIterableBitMask<uint64_t, kWidth, 3> MaskEmpty() const {
- return NonIterableBitMask<uint64_t, kWidth, 3>((ctrl & ~(ctrl << 6)) &
- kMsbs8Bytes);
- }
-
- // Returns a bitmask representing the positions of full slots.
- // Note: for `is_small()` tables group may contain the "same" slot twice:
- // original and mirrored.
- BitMask<uint64_t, kWidth, 3> MaskFull() const {
- return BitMask<uint64_t, kWidth, 3>((ctrl ^ kMsbs8Bytes) & kMsbs8Bytes);
- }
-
- // Returns a bitmask representing the positions of non full slots.
- // Note: this includes: kEmpty, kDeleted, kSentinel.
- // It is useful in contexts when kSentinel is not present.
- auto MaskNonFull() const {
- return BitMask<uint64_t, kWidth, 3>(ctrl & kMsbs8Bytes);
- }
-
- NonIterableBitMask<uint64_t, kWidth, 3> MaskEmptyOrDeleted() const {
- return NonIterableBitMask<uint64_t, kWidth, 3>((ctrl & ~(ctrl << 7)) &
- kMsbs8Bytes);
- }
-
- uint32_t CountLeadingEmptyOrDeleted() const {
- // ctrl | ~(ctrl >> 7) will have the lowest bit set to zero for kEmpty and
- // kDeleted. We lower all other bits and count number of trailing zeros.
- constexpr uint64_t bits = 0x0101010101010101ULL;
- return static_cast<uint32_t>(countr_zero((ctrl | ~(ctrl >> 7)) & bits) >>
- 3);
- }
-
- void ConvertSpecialToEmptyAndFullToDeleted(ctrl_t* dst) const {
- constexpr uint64_t lsbs = 0x0101010101010101ULL;
- auto x = ctrl & kMsbs8Bytes;
- auto res = (~x + (x >> 7)) & ~lsbs;
- little_endian::Store64(dst, res);
- }
-
- uint64_t ctrl;
-};
-
-#ifdef ABSL_INTERNAL_HAVE_SSE2
-using Group = GroupSse2Impl;
-using GroupFullEmptyOrDeleted = GroupSse2Impl;
-#elif defined(ABSL_INTERNAL_HAVE_ARM_NEON) && defined(ABSL_IS_LITTLE_ENDIAN)
-using Group = GroupAArch64Impl;
-// For Aarch64, we use the portable implementation for counting and masking
-// full, empty or deleted group elements. This is to avoid the latency of moving
-// between data GPRs and Neon registers when it does not provide a benefit.
-// Using Neon is profitable when we call Match(), but is not when we don't,
-// which is the case when we do *EmptyOrDeleted and MaskFull operations.
-// It is difficult to make a similar approach beneficial on other architectures
-// such as x86 since they have much lower GPR <-> vector register transfer
-// latency and 16-wide Groups.
-using GroupFullEmptyOrDeleted = GroupPortableImpl;
-#else
-using Group = GroupPortableImpl;
-using GroupFullEmptyOrDeleted = GroupPortableImpl;
-#endif
-
// When there is an insertion with no reserved growth, we rehash with
// probability `min(1, RehashProbabilityConstant() / capacity())`. Using a
// constant divided by capacity ensures that inserting N elements is still O(N)
@@ -957,10 +571,10 @@
// references. We rehash on the first insertion after reserved_growth_ reaches
// 0 after a call to reserve. We also do a rehash with low probability
// whenever reserved_growth_ is zero.
- bool should_rehash_for_bug_detection_on_insert(const ctrl_t* ctrl,
+ bool should_rehash_for_bug_detection_on_insert(PerTableSeed seed,
size_t capacity) const;
// Similar to above, except that we don't depend on reserved_growth_.
- bool should_rehash_for_bug_detection_on_move(const ctrl_t* ctrl,
+ bool should_rehash_for_bug_detection_on_move(PerTableSeed seed,
size_t capacity) const;
void maybe_increment_generation_on_insert() {
if (reserved_growth_ == kReservedGrowthJustRanOut) reserved_growth_ = 0;
@@ -1014,10 +628,10 @@
CommonFieldsGenerationInfoDisabled& operator=(
CommonFieldsGenerationInfoDisabled&&) = default;
- bool should_rehash_for_bug_detection_on_insert(const ctrl_t*, size_t) const {
+ bool should_rehash_for_bug_detection_on_insert(PerTableSeed, size_t) const {
return false;
}
- bool should_rehash_for_bug_detection_on_move(const ctrl_t*, size_t) const {
+ bool should_rehash_for_bug_detection_on_move(PerTableSeed, size_t) const {
return false;
}
void maybe_increment_generation_on_insert() {}
@@ -1105,19 +719,20 @@
// Overwrites single empty slot with a full slot.
void OverwriteEmptyAsFull() {
- assert(GetGrowthLeft() > 0);
+ ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() > 0);
--growth_left_info_;
}
// Overwrites several empty slots with full slots.
- void OverwriteManyEmptyAsFull(size_t cnt) {
- assert(GetGrowthLeft() >= cnt);
- growth_left_info_ -= cnt;
+ void OverwriteManyEmptyAsFull(size_t count) {
+ ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() >= count);
+ growth_left_info_ -= count;
}
// Overwrites specified control element with full slot.
void OverwriteControlAsFull(ctrl_t ctrl) {
- assert(GetGrowthLeft() >= static_cast<size_t>(IsEmpty(ctrl)));
+ ABSL_SWISSTABLE_ASSERT(GetGrowthLeft() >=
+ static_cast<size_t>(IsEmpty(ctrl)));
growth_left_info_ -= static_cast<size_t>(IsEmpty(ctrl));
}
@@ -1136,7 +751,14 @@
// 2. There is no growth left.
bool HasNoGrowthLeftAndNoDeleted() const { return growth_left_info_ == 0; }
- // Returns true if table guaranteed to have no k
+ // Returns true if GetGrowthLeft() == 0, but must be called only if
+ // HasNoDeleted() is false. It is slightly more efficient.
+ bool HasNoGrowthLeftAssumingMayHaveDeleted() const {
+ ABSL_SWISSTABLE_ASSERT(!HasNoDeleted());
+ return growth_left_info_ == kDeletedBit;
+ }
+
+ // Returns true if table guaranteed to have no kDeleted slots.
bool HasNoDeleted() const {
return static_cast<std::make_signed_t<size_t>>(growth_left_info_) >= 0;
}
@@ -1157,7 +779,7 @@
// Returns whether `n` is a valid capacity (i.e., number of slots).
//
// A valid capacity is a non-zero integer `2^m - 1`.
-inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
+constexpr bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
// Returns the number of "cloned control bytes".
//
@@ -1173,26 +795,32 @@
// Computes the offset from the start of the backing allocation of control.
// infoz and growth_info are stored at the beginning of the backing array.
-inline static size_t ControlOffset(bool has_infoz) {
+constexpr size_t ControlOffset(bool has_infoz) {
return (has_infoz ? sizeof(HashtablezInfoHandle) : 0) + sizeof(GrowthInfo);
}
+// Returns the offset of the next item after `offset` that is aligned to `align`
+// bytes. `align` must be a power of two.
+constexpr size_t AlignUpTo(size_t offset, size_t align) {
+ return (offset + align - 1) & (~align + 1);
+}
+
// Helper class for computing offsets and allocation size of hash set fields.
class RawHashSetLayout {
public:
- explicit RawHashSetLayout(size_t capacity, size_t slot_align, bool has_infoz)
- : capacity_(capacity),
- control_offset_(ControlOffset(has_infoz)),
+ explicit RawHashSetLayout(size_t capacity, size_t slot_size,
+ size_t slot_align, bool has_infoz)
+ : control_offset_(ControlOffset(has_infoz)),
generation_offset_(control_offset_ + NumControlBytes(capacity)),
slot_offset_(
- (generation_offset_ + NumGenerationBytes() + slot_align - 1) &
- (~slot_align + 1)) {
- assert(IsValidCapacity(capacity));
+ AlignUpTo(generation_offset_ + NumGenerationBytes(), slot_align)),
+ alloc_size_(slot_offset_ + capacity * slot_size) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
+ ABSL_SWISSTABLE_ASSERT(
+ slot_size <=
+ ((std::numeric_limits<size_t>::max)() - slot_offset_) / capacity);
}
- // Returns the capacity of a table.
- size_t capacity() const { return capacity_; }
-
// Returns precomputed offset from the start of the backing allocation of
// control.
size_t control_offset() const { return control_offset_; }
@@ -1207,32 +835,17 @@
// Given the capacity of a table, computes the total size of the backing
// array.
- size_t alloc_size(size_t slot_size) const {
- return slot_offset_ + capacity_ * slot_size;
- }
+ size_t alloc_size() const { return alloc_size_; }
private:
- size_t capacity_;
size_t control_offset_;
size_t generation_offset_;
size_t slot_offset_;
+ size_t alloc_size_;
};
struct HashtableFreeFunctionsAccess;
-// We only allow a maximum of 1 SOO element, which makes the implementation
-// much simpler. Complications with multiple SOO elements include:
-// - Satisfying the guarantee that erasing one element doesn't invalidate
-// iterators to other elements means we would probably need actual SOO
-// control bytes.
-// - In order to prevent user code from depending on iteration order for small
-// tables, we would need to randomize the iteration order somehow.
-constexpr size_t SooCapacity() { return 1; }
-// Sentinel type to indicate SOO CommonFields construction.
-struct soo_tag_t {};
-// Sentinel type to indicate SOO CommonFields construction with full size.
-struct full_soo_tag_t {};
-
// Suppress erroneous uninitialized memory errors on GCC. For example, GCC
// thinks that the call to slot_array() in find_or_prepare_insert() is reading
// uninitialized memory, but slot_array is only called there when the table is
@@ -1260,7 +873,7 @@
};
struct HeapPtrs {
- HeapPtrs() = default;
+ explicit HeapPtrs(uninitialized_tag_t) {}
explicit HeapPtrs(ctrl_t* c) : control(c) {}
// The control bytes (and, also, a pointer near to the base of the backing
@@ -1279,10 +892,13 @@
MaybeInitializedPtr slot_array;
};
+// Returns the maximum size of the SOO slot.
+constexpr size_t MaxSooSlotSize() { return sizeof(HeapPtrs); }
+
// Manages the backing array pointers or the SOO slot. When raw_hash_set::is_soo
// is true, the SOO slot is stored in `soo_data`. Otherwise, we use `heap`.
union HeapOrSoo {
- HeapOrSoo() = default;
+ explicit HeapOrSoo(uninitialized_tag_t) : heap(uninitialized_tag_t{}) {}
explicit HeapOrSoo(ctrl_t* c) : heap(c) {}
ctrl_t*& control() {
@@ -1305,44 +921,83 @@
}
HeapPtrs heap;
- unsigned char soo_data[sizeof(HeapPtrs)];
+ unsigned char soo_data[MaxSooSlotSize()];
};
+// Returns a reference to the GrowthInfo object stored immediately before
+// `control`.
+inline GrowthInfo& GetGrowthInfoFromControl(ctrl_t* control) {
+ auto* gl_ptr = reinterpret_cast<GrowthInfo*>(control) - 1;
+ ABSL_SWISSTABLE_ASSERT(
+ reinterpret_cast<uintptr_t>(gl_ptr) % alignof(GrowthInfo) == 0);
+ return *gl_ptr;
+}
+
// CommonFields hold the fields in raw_hash_set that do not depend
// on template parameters. This allows us to conveniently pass all
// of this state to helper functions as a single argument.
class CommonFields : public CommonFieldsGenerationInfo {
public:
- CommonFields() : capacity_(0), size_(0), heap_or_soo_(EmptyGroup()) {}
- explicit CommonFields(soo_tag_t) : capacity_(SooCapacity()), size_(0) {}
+ explicit CommonFields(soo_tag_t)
+ : capacity_(SooCapacity()),
+ size_(no_seed_empty_tag_t{}),
+ heap_or_soo_(uninitialized_tag_t{}) {}
explicit CommonFields(full_soo_tag_t)
- : capacity_(SooCapacity()), size_(size_t{1} << HasInfozShift()) {}
+ : capacity_(SooCapacity()),
+ size_(full_soo_tag_t{}),
+ heap_or_soo_(uninitialized_tag_t{}) {}
+ explicit CommonFields(non_soo_tag_t)
+ : capacity_(0),
+ size_(no_seed_empty_tag_t{}),
+ heap_or_soo_(EmptyGroup()) {}
+ // For use in swapping.
+ explicit CommonFields(uninitialized_tag_t)
+ : size_(uninitialized_tag_t{}), heap_or_soo_(uninitialized_tag_t{}) {}
// Not copyable
CommonFields(const CommonFields&) = delete;
CommonFields& operator=(const CommonFields&) = delete;
+ // Copy with guarantee that it is not SOO.
+ CommonFields(non_soo_tag_t, const CommonFields& that)
+ : capacity_(that.capacity_),
+ size_(that.size_),
+ heap_or_soo_(that.heap_or_soo_) {
+ }
+
// Movable
CommonFields(CommonFields&& that) = default;
CommonFields& operator=(CommonFields&&) = default;
template <bool kSooEnabled>
static CommonFields CreateDefault() {
- return kSooEnabled ? CommonFields{soo_tag_t{}} : CommonFields{};
+ return kSooEnabled ? CommonFields{soo_tag_t{}}
+ : CommonFields{non_soo_tag_t{}};
}
// The inline data for SOO is written on top of control_/slots_.
const void* soo_data() const { return heap_or_soo_.get_soo_data(); }
void* soo_data() { return heap_or_soo_.get_soo_data(); }
- HeapOrSoo heap_or_soo() const { return heap_or_soo_; }
- const HeapOrSoo& heap_or_soo_ref() const { return heap_or_soo_; }
-
ctrl_t* control() const { return heap_or_soo_.control(); }
- void set_control(ctrl_t* c) { heap_or_soo_.control() = c; }
+
+ // When we set the control bytes, we also often want to generate a new seed.
+ // So we bundle these two operations together to make sure we don't forget to
+ // generate a new seed.
+ // The table will be invalidated if
+ // `kGenerateSeed && !empty() && !is_single_group(capacity())` because H1 is
+ // being changed. In such cases, we will need to rehash the table.
+ template <bool kGenerateSeed>
+ void set_control(ctrl_t* c) {
+ heap_or_soo_.control() = c;
+ if constexpr (kGenerateSeed) {
+ generate_new_seed();
+ }
+ }
void* backing_array_start() const {
// growth_info (and maybe infoz) is stored before control bytes.
- assert(reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
+ ABSL_SWISSTABLE_ASSERT(
+ reinterpret_cast<uintptr_t>(control()) % alignof(size_t) == 0);
return control() - ControlOffset(has_infoz());
}
@@ -1352,31 +1007,46 @@
void set_slots(void* s) { heap_or_soo_.slot_array().set(s); }
// The number of filled slots.
- size_t size() const { return size_ >> HasInfozShift(); }
- void set_size(size_t s) {
- size_ = (s << HasInfozShift()) | (size_ & HasInfozMask());
- }
+ size_t size() const { return size_.size(); }
+ // Sets the size to zero, but keeps hashinfoz bit and seed.
+ void set_size_to_zero() { size_.set_size_to_zero_keep_metadata(); }
void set_empty_soo() {
AssertInSooMode();
- size_ = 0;
+ size_ = HashtableSize(no_seed_empty_tag_t{});
}
void set_full_soo() {
AssertInSooMode();
- size_ = size_t{1} << HasInfozShift();
+ size_ = HashtableSize(full_soo_tag_t{});
}
void increment_size() {
- assert(size() < capacity());
- size_ += size_t{1} << HasInfozShift();
+ ABSL_SWISSTABLE_ASSERT(size() < capacity());
+ size_.increment_size();
+ }
+ void increment_size(size_t n) {
+ ABSL_SWISSTABLE_ASSERT(size() + n <= capacity());
+ size_.increment_size(n);
}
void decrement_size() {
- assert(size() > 0);
- size_ -= size_t{1} << HasInfozShift();
+ ABSL_SWISSTABLE_ASSERT(!empty());
+ size_.decrement_size();
}
+ bool empty() const { return size_.empty(); }
+
+ // The seed used for the H1 part of the hash function.
+ PerTableSeed seed() const { return size_.seed(); }
+ // Generates a new seed for the H1 part of the hash function.
+ // The table will be invalidated if
+ // `kGenerateSeed && !empty() && !is_single_group(capacity())` because H1 is
+ // being changed. In such cases, we will need to rehash the table.
+ void generate_new_seed() { size_.generate_new_seed(); }
+ void set_no_seed_for_testing() { size_.set_no_seed_for_testing(); }
// The total number of available slots.
size_t capacity() const { return capacity_; }
void set_capacity(size_t c) {
- assert(c == 0 || IsValidCapacity(c));
+ // We allow setting above the max valid capacity for debugging purposes.
+ ABSL_SWISSTABLE_ASSERT(c == 0 || IsValidCapacity(c) ||
+ c > kAboveMaxValidCapacity);
capacity_ = c;
}
@@ -1387,20 +1057,14 @@
size_t growth_left() const { return growth_info().GetGrowthLeft(); }
GrowthInfo& growth_info() {
- auto* gl_ptr = reinterpret_cast<GrowthInfo*>(control()) - 1;
- assert(reinterpret_cast<uintptr_t>(gl_ptr) % alignof(GrowthInfo) == 0);
- return *gl_ptr;
+ return GetGrowthInfoFromControl(control());
}
GrowthInfo growth_info() const {
return const_cast<CommonFields*>(this)->growth_info();
}
- bool has_infoz() const {
- return ABSL_PREDICT_FALSE((size_ & HasInfozMask()) != 0);
- }
- void set_has_infoz(bool has_infoz) {
- size_ = (size() << HasInfozShift()) | static_cast<size_t>(has_infoz);
- }
+ bool has_infoz() const { return size_.has_infoz(); }
+ void set_has_infoz() { size_.set_has_infoz(); }
HashtablezInfoHandle infoz() {
return has_infoz()
@@ -1408,17 +1072,23 @@
: HashtablezInfoHandle();
}
void set_infoz(HashtablezInfoHandle infoz) {
- assert(has_infoz());
+ ABSL_SWISSTABLE_ASSERT(has_infoz());
*reinterpret_cast<HashtablezInfoHandle*>(backing_array_start()) = infoz;
}
bool should_rehash_for_bug_detection_on_insert() const {
+ if constexpr (!SwisstableGenerationsEnabled()) {
+ return false;
+ }
+ // As an optimization, we avoid calling ShouldRehashForBugDetection if we
+ // will end up rehashing anyways.
+ if (growth_left() == 0) return false;
return CommonFieldsGenerationInfo::
- should_rehash_for_bug_detection_on_insert(control(), capacity());
+ should_rehash_for_bug_detection_on_insert(seed(), capacity());
}
bool should_rehash_for_bug_detection_on_move() const {
return CommonFieldsGenerationInfo::should_rehash_for_bug_detection_on_move(
- control(), capacity());
+ seed(), capacity());
}
void reset_reserved_growth(size_t reservation) {
CommonFieldsGenerationInfo::reset_reserved_growth(reservation, size());
@@ -1426,8 +1096,8 @@
// The size of the backing array allocation.
size_t alloc_size(size_t slot_size, size_t slot_align) const {
- return RawHashSetLayout(capacity(), slot_align, has_infoz())
- .alloc_size(slot_size);
+ return RawHashSetLayout(capacity(), slot_size, slot_align, has_infoz())
+ .alloc_size();
}
// Move fields other than heap_or_soo_.
@@ -1444,6 +1114,20 @@
std::count(control(), control() + capacity(), ctrl_t::kDeleted));
}
+ // Helper to enable sanitizer mode validation to protect against reentrant
+ // calls during element constructor/destructor.
+ template <typename F>
+ void RunWithReentrancyGuard(F f) {
+#ifdef NDEBUG
+ f();
+ return;
+#endif
+ const size_t cap = capacity();
+ set_capacity(InvalidCapacity::kReentrance);
+ f();
+ set_capacity(cap);
+ }
+
private:
// We store the has_infoz bit in the lowest bit of size_.
static constexpr size_t HasInfozShift() { return 1; }
@@ -1454,8 +1138,8 @@
// We can't assert that SOO is enabled because we don't have SooEnabled(), but
// we assert what we can.
void AssertInSooMode() const {
- assert(capacity() == SooCapacity());
- assert(!has_infoz());
+ ABSL_SWISSTABLE_ASSERT(capacity() == SooCapacity());
+ ABSL_SWISSTABLE_ASSERT(!has_infoz());
}
// The number of slots in the backing array. This is always 2^N-1 for an
@@ -1466,11 +1150,10 @@
// regressions, presumably because we need capacity to do find operations.
size_t capacity_;
- // The size and also has one bit that stores whether we have infoz.
// TODO(b/289225379): we could put size_ into HeapOrSoo and make capacity_
// encode the size in SOO case. We would be making size()/capacity() more
// expensive in order to have more SOO space.
- size_t size_;
+ HashtableSize size_;
// Either the control/slots pointers or the SOO slot.
HeapOrSoo heap_or_soo_;
@@ -1480,11 +1163,17 @@
class raw_hash_set;
// Returns the next valid capacity after `n`.
-inline size_t NextCapacity(size_t n) {
- assert(IsValidCapacity(n) || n == 0);
+constexpr size_t NextCapacity(size_t n) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n) || n == 0);
return n * 2 + 1;
}
+// Returns the previous valid capacity before `n`.
+constexpr size_t PreviousCapacity(size_t n) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(n));
+ return n / 2;
+}
+
// Applies the following mapping to every byte in the control array:
// * kDeleted -> kEmpty
// * kEmpty -> kEmpty
@@ -1496,7 +1185,7 @@
void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity);
// Converts `n` into the next valid capacity, per `IsValidCapacity`.
-inline size_t NormalizeCapacity(size_t n) {
+constexpr size_t NormalizeCapacity(size_t n) {
return n ? ~size_t{} >> countl_zero(n) : 1;
}
@@ -1510,8 +1199,8 @@
// Given `capacity`, applies the load factor; i.e., it returns the maximum
// number of values we should put into the table before a resizing rehash.
-inline size_t CapacityToGrowth(size_t capacity) {
- assert(IsValidCapacity(capacity));
+constexpr size_t CapacityToGrowth(size_t capacity) {
+ ABSL_SWISSTABLE_ASSERT(IsValidCapacity(capacity));
// `capacity*7/8`
if (Group::kWidth == 8 && capacity == 7) {
// x-x/8 does not work when x==7.
@@ -1520,18 +1209,28 @@
return capacity - capacity / 8;
}
-// Given `growth`, "unapplies" the load factor to find how large the capacity
+// Given `size`, "unapplies" the load factor to find how large the capacity
// should be to stay within the load factor.
//
-// This might not be a valid capacity and `NormalizeCapacity()` should be
-// called on this.
-inline size_t GrowthToLowerboundCapacity(size_t growth) {
- // `growth*8/7`
- if (Group::kWidth == 8 && growth == 7) {
- // x+(x-1)/7 does not work when x==7.
- return 8;
+// For size == 0, returns 0.
+// For other values, returns the same as `NormalizeCapacity(size*8/7)`.
+constexpr size_t SizeToCapacity(size_t size) {
+ if (size == 0) {
+ return 0;
}
- return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
+ // The minimum possible capacity is NormalizeCapacity(size).
+ // Shifting right `~size_t{}` by `leading_zeros` yields
+ // NormalizeCapacity(size).
+ int leading_zeros = absl::countl_zero(size);
+ constexpr size_t kLast3Bits = size_t{7} << (sizeof(size_t) * 8 - 3);
+ size_t max_size_for_next_capacity = kLast3Bits >> leading_zeros;
+ // Decrease shift if size is too big for the minimum capacity.
+ leading_zeros -= static_cast<int>(size > max_size_for_next_capacity);
+ if constexpr (Group::kWidth == 8) {
+ // Formula doesn't work when size==7 for 8-wide groups.
+ leading_zeros -= (size == 7);
+ }
+ return (~size_t{}) >> leading_zeros;
}
template <class InputIter>
@@ -1540,12 +1239,9 @@
if (bucket_count != 0) {
return bucket_count;
}
- using InputIterCategory =
- typename std::iterator_traits<InputIter>::iterator_category;
- if (std::is_base_of<std::random_access_iterator_tag,
- InputIterCategory>::value) {
- return GrowthToLowerboundCapacity(
- static_cast<size_t>(std::distance(first, last)));
+ if (base_internal::IsAtLeastIterator<std::random_access_iterator_tag,
+ InputIter>()) {
+ return SizeToCapacity(static_cast<size_t>(std::distance(first, last)));
}
return 0;
}
@@ -1618,7 +1314,7 @@
FATAL, "Invalid iterator comparison. The element was likely erased.");
}
} else {
- ABSL_HARDENING_ASSERT(
+ ABSL_HARDENING_ASSERT_SLOW(
ctrl_is_valid_for_comparison &&
"Invalid iterator comparison. The element might have been erased or "
"the table might have rehashed. Consider running with --config=asan to "
@@ -1703,7 +1399,7 @@
"hashtable.");
fail_if(true, "Comparing non-end() iterators from different hashtables.");
} else {
- ABSL_HARDENING_ASSERT(
+ ABSL_HARDENING_ASSERT_SLOW(
AreItersFromSameContainer(ctrl_a, ctrl_b, slot_a, slot_b) &&
"Invalid iterator comparison. The iterators may be from different "
"containers or the container might have rehashed or moved. Consider "
@@ -1716,33 +1412,22 @@
size_t probe_length;
};
-// Whether a table is "small". A small table fits entirely into a probing
-// group, i.e., has a capacity < `Group::kWidth`.
-//
-// In small mode we are able to use the whole capacity. The extra control
-// bytes give us at least one "empty" control byte to stop the iteration.
-// This is important to make 1 a valid capacity.
-//
-// In small mode only the first `capacity` control bytes after the sentinel
-// are valid. The rest contain dummy ctrl_t::kEmpty values that do not
-// represent a real slot. This is important to take into account on
-// `find_first_non_full()`, where we never try
-// `ShouldInsertBackwards()` for small tables.
-inline bool is_small(size_t capacity) { return capacity < Group::kWidth - 1; }
-
// Whether a table fits entirely into a probing group.
// Arbitrary order of elements in such tables is correct.
-inline bool is_single_group(size_t capacity) {
+constexpr bool is_single_group(size_t capacity) {
return capacity <= Group::kWidth;
}
// Begins a probing operation on `common.control`, using `hash`.
-inline probe_seq<Group::kWidth> probe(const ctrl_t* ctrl, const size_t capacity,
+inline probe_seq<Group::kWidth> probe(size_t h1, size_t capacity) {
+ return probe_seq<Group::kWidth>(h1, capacity);
+}
+inline probe_seq<Group::kWidth> probe(PerTableSeed seed, size_t capacity,
size_t hash) {
- return probe_seq<Group::kWidth>(H1(hash, ctrl), capacity);
+ return probe(H1(hash, seed), capacity);
}
inline probe_seq<Group::kWidth> probe(const CommonFields& common, size_t hash) {
- return probe(common.control(), common.capacity(), hash);
+ return probe(common.seed(), common.capacity(), hash);
}
// Probes an array of control bits using a probe sequence derived from `hash`,
@@ -1752,56 +1437,75 @@
//
// NOTE: this function must work with tables having both empty and deleted
// slots in the same group. Such tables appear during `erase()`.
+FindInfo find_first_non_full(const CommonFields& common, size_t hash);
+
+constexpr size_t kProbedElementIndexSentinel = ~size_t{};
+
+// Implementation detail of transfer_unprobed_elements_to_next_capacity_fn.
+// Tries to find the new index for an element whose hash corresponds to
+// `h1` for growth to the next capacity.
+// Returns kProbedElementIndexSentinel if full probing is required.
+//
+// If element is located in the first probing group in the table before growth,
+// returns one of two positions: `old_index` or `old_index + old_capacity + 1`.
+//
+// Otherwise, we will try to insert it into the first probe group of the new
+// table. We only attempt to do so if the first probe group is already
+// initialized.
template <typename = void>
-inline FindInfo find_first_non_full(const CommonFields& common, size_t hash) {
- auto seq = probe(common, hash);
- const ctrl_t* ctrl = common.control();
- if (IsEmptyOrDeleted(ctrl[seq.offset()]) &&
- !ShouldInsertBackwards(common.capacity(), hash, ctrl)) {
- return {seq.offset(), /*probe_length=*/0};
+inline size_t TryFindNewIndexWithoutProbing(size_t h1, size_t old_index,
+ size_t old_capacity,
+ ctrl_t* new_ctrl,
+ size_t new_capacity) {
+ size_t index_diff = old_index - h1;
+ // The first probe group starts with h1 & capacity.
+ // All following groups start at (h1 + Group::kWidth * K) & capacity.
+ // We can find an index within the floating group as index_diff modulo
+ // Group::kWidth.
+ // Both old and new capacity are larger than Group::kWidth so we can avoid
+ // computing `& capacity`.
+ size_t in_floating_group_index = index_diff & (Group::kWidth - 1);
+ // By subtracting we will get the difference between the first probe group
+ // and the probe group corresponding to old_index.
+ index_diff -= in_floating_group_index;
+ if (ABSL_PREDICT_TRUE((index_diff & old_capacity) == 0)) {
+ size_t new_index = (h1 + in_floating_group_index) & new_capacity;
+ ABSL_ASSUME(new_index != kProbedElementIndexSentinel);
+ return new_index;
}
- while (true) {
- GroupFullEmptyOrDeleted g{ctrl + seq.offset()};
- auto mask = g.MaskEmptyOrDeleted();
- if (mask) {
- return {
- seq.offset(GetInsertionOffset(mask, common.capacity(), hash, ctrl)),
- seq.index()};
- }
- seq.next();
- assert(seq.index() <= common.capacity() && "full table!");
+ ABSL_SWISSTABLE_ASSERT(((old_index - h1) & old_capacity) >= Group::kWidth);
+ // Try to insert element into the first probe group.
+ // new_ctrl is not yet fully initialized so we can't use regular search via
+ // find_first_non_full.
+
+ // We can search in the first probe group only if it is located in already
+ // initialized part of the table.
+ if (ABSL_PREDICT_FALSE((h1 & old_capacity) >= old_index)) {
+ return kProbedElementIndexSentinel;
}
+ size_t offset = h1 & new_capacity;
+ Group new_g(new_ctrl + offset);
+ if (auto mask = new_g.MaskNonFull(); ABSL_PREDICT_TRUE(mask)) {
+ size_t result = offset + mask.LowestBitSet();
+ ABSL_ASSUME(result != kProbedElementIndexSentinel);
+ return result;
+ }
+ return kProbedElementIndexSentinel;
}
-// Extern template for inline function keep possibility of inlining.
+// Extern template for inline function keeps possibility of inlining.
// When compiler decided to not inline, no symbols will be added to the
// corresponding translation unit.
-extern template FindInfo find_first_non_full(const CommonFields&, size_t);
-
-// Non-inlined version of find_first_non_full for use in less
-// performance critical routines.
-FindInfo find_first_non_full_outofline(const CommonFields&, size_t);
-
-inline void ResetGrowthLeft(CommonFields& common) {
- common.growth_info().InitGrowthLeftNoDeleted(
- CapacityToGrowth(common.capacity()) - common.size());
-}
-
-// Sets `ctrl` to `{kEmpty, kSentinel, ..., kEmpty}`, marking the entire
-// array as marked as empty.
-inline void ResetCtrl(CommonFields& common, size_t slot_size) {
- const size_t capacity = common.capacity();
- ctrl_t* ctrl = common.control();
- std::memset(ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
- capacity + 1 + NumClonedBytes());
- ctrl[capacity] = ctrl_t::kSentinel;
- SanitizerPoisonMemoryRegion(common.slot_array(), slot_size * capacity);
-}
+extern template size_t TryFindNewIndexWithoutProbing(size_t h1,
+ size_t old_index,
+ size_t old_capacity,
+ ctrl_t* new_ctrl,
+ size_t new_capacity);
// Sets sanitizer poisoning for slot corresponding to control byte being set.
inline void DoSanitizeOnSetCtrl(const CommonFields& c, size_t i, ctrl_t h,
size_t slot_size) {
- assert(i < c.capacity());
+ ABSL_SWISSTABLE_ASSERT(i < c.capacity());
auto* slot_i = static_cast<const char*>(c.slot_array()) + i * slot_size;
if (IsFull(h)) {
SanitizerUnpoisonMemoryRegion(slot_i, slot_size);
@@ -1831,7 +1535,7 @@
// setting the cloned control byte.
inline void SetCtrlInSingleGroupTable(const CommonFields& c, size_t i, ctrl_t h,
size_t slot_size) {
- assert(is_single_group(c.capacity()));
+ ABSL_SWISSTABLE_ASSERT(is_single_group(c.capacity()));
DoSanitizeOnSetCtrl(c, i, h, slot_size);
ctrl_t* ctrl = c.control();
ctrl[i] = h;
@@ -1843,6 +1547,22 @@
SetCtrlInSingleGroupTable(c, i, static_cast<ctrl_t>(h), slot_size);
}
+// Like SetCtrl, but in a table with capacity >= Group::kWidth - 1,
+// we can save some operations when setting the cloned control byte.
+inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, ctrl_t h,
+ size_t slot_size) {
+ ABSL_SWISSTABLE_ASSERT(c.capacity() >= Group::kWidth - 1);
+ DoSanitizeOnSetCtrl(c, i, h, slot_size);
+ ctrl_t* ctrl = c.control();
+ ctrl[i] = h;
+ ctrl[((i - NumClonedBytes()) & c.capacity()) + NumClonedBytes()] = h;
+}
+// Overload for setting to an occupied `h2_t` rather than a special `ctrl_t`.
+inline void SetCtrlInLargeTable(const CommonFields& c, size_t i, h2_t h,
+ size_t slot_size) {
+ SetCtrlInLargeTable(c, i, static_cast<ctrl_t>(h), slot_size);
+}
+
// growth_info (which is a size_t) is stored with the backing array.
constexpr size_t BackingArrayAlignment(size_t align_of_slot) {
return (std::max)(align_of_slot, alignof(GrowthInfo));
@@ -1855,442 +1575,283 @@
(slot * slot_size));
}
-// Iterates over all full slots and calls `cb(const ctrl_t*, SlotType*)`.
-// No insertion to the table allowed during Callback call.
+// Iterates over all full slots and calls `cb(const ctrl_t*, void*)`.
+// No insertion to the table is allowed during `cb` call.
// Erasure is allowed only for the element passed to the callback.
-template <class SlotType, class Callback>
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline void IterateOverFullSlots(
- const CommonFields& c, SlotType* slot, Callback cb) {
- const size_t cap = c.capacity();
- const ctrl_t* ctrl = c.control();
- if (is_small(cap)) {
- // Mirrored/cloned control bytes in small table are also located in the
- // first group (starting from position 0). We are taking group from position
- // `capacity` in order to avoid duplicates.
-
- // Small tables capacity fits into portable group, where
- // GroupPortableImpl::MaskFull is more efficient for the
- // capacity <= GroupPortableImpl::kWidth.
- assert(cap <= GroupPortableImpl::kWidth &&
- "unexpectedly large small capacity");
- static_assert(Group::kWidth >= GroupPortableImpl::kWidth,
- "unexpected group width");
- // Group starts from kSentinel slot, so indices in the mask will
- // be increased by 1.
- const auto mask = GroupPortableImpl(ctrl + cap).MaskFull();
- --ctrl;
- --slot;
- for (uint32_t i : mask) {
- cb(ctrl + i, slot + i);
- }
- return;
- }
- size_t remaining = c.size();
- ABSL_ATTRIBUTE_UNUSED const size_t original_size_for_assert = remaining;
- while (remaining != 0) {
- for (uint32_t i : GroupFullEmptyOrDeleted(ctrl).MaskFull()) {
- assert(IsFull(ctrl[i]) && "hash table was modified unexpectedly");
- cb(ctrl + i, slot + i);
- --remaining;
- }
- ctrl += Group::kWidth;
- slot += Group::kWidth;
- assert((remaining == 0 || *(ctrl - 1) != ctrl_t::kSentinel) &&
- "hash table was modified unexpectedly");
- }
- // NOTE: erasure of the current element is allowed in callback for
- // absl::erase_if specialization. So we use `>=`.
- assert(original_size_for_assert >= c.size() &&
- "hash table was modified unexpectedly");
-}
+// The table must not be in SOO mode.
+void IterateOverFullSlots(const CommonFields& c, size_t slot_size,
+ absl::FunctionRef<void(const ctrl_t*, void*)> cb);
template <typename CharAlloc>
-constexpr bool ShouldSampleHashtablezInfo() {
+constexpr bool ShouldSampleHashtablezInfoForAlloc() {
// Folks with custom allocators often make unwarranted assumptions about the
// behavior of their classes vis-a-vis trivial destructability and what
// calls they will or won't make. Avoid sampling for people with custom
// allocators to get us out of this mess. This is not a hard guarantee but
// a workaround while we plan the exact guarantee we want to provide.
- return std::is_same<CharAlloc, std::allocator<char>>::value;
+ return std::is_same_v<CharAlloc, std::allocator<char>>;
}
template <bool kSooEnabled>
-HashtablezInfoHandle SampleHashtablezInfo(size_t sizeof_slot, size_t sizeof_key,
- size_t sizeof_value,
- size_t old_capacity, bool was_soo,
- HashtablezInfoHandle forced_infoz,
- CommonFields& c) {
- if (forced_infoz.IsSampled()) return forced_infoz;
+bool ShouldSampleHashtablezInfoOnResize(bool force_sampling,
+ bool is_hashtablez_eligible,
+ size_t old_capacity, CommonFields& c) {
+ if (!is_hashtablez_eligible) return false;
+ // Force sampling is only allowed for SOO tables.
+ ABSL_SWISSTABLE_ASSERT(kSooEnabled || !force_sampling);
+ if (kSooEnabled && force_sampling) {
+ return true;
+ }
// In SOO, we sample on the first insertion so if this is an empty SOO case
// (e.g. when reserve is called), then we still need to sample.
- if (kSooEnabled && was_soo && c.size() == 0) {
- return Sample(sizeof_slot, sizeof_key, sizeof_value, SooCapacity());
+ if (kSooEnabled && old_capacity == SooCapacity() && c.empty()) {
+ return ShouldSampleNextTable();
}
- // For non-SOO cases, we sample whenever the capacity is increasing from zero
- // to non-zero.
if (!kSooEnabled && old_capacity == 0) {
- return Sample(sizeof_slot, sizeof_key, sizeof_value, 0);
+ return ShouldSampleNextTable();
}
- return c.infoz();
+ return false;
}
-// Helper class to perform resize of the hash set.
-//
-// It contains special optimizations for small group resizes.
-// See GrowIntoSingleGroupShuffleControlBytes for details.
-class HashSetResizeHelper {
- public:
- explicit HashSetResizeHelper(CommonFields& c, bool was_soo, bool had_soo_slot,
- HashtablezInfoHandle forced_infoz)
- : old_capacity_(c.capacity()),
- had_infoz_(c.has_infoz()),
- was_soo_(was_soo),
- had_soo_slot_(had_soo_slot),
- forced_infoz_(forced_infoz) {}
-
- // Optimized for small groups version of `find_first_non_full`.
- // Beneficial only right after calling `raw_hash_set::resize`.
- // It is safe to call in case capacity is big or was not changed, but there
- // will be no performance benefit.
- // It has implicit assumption that `resize` will call
- // `GrowSizeIntoSingleGroup*` in case `IsGrowingIntoSingleGroupApplicable`.
- // Falls back to `find_first_non_full` in case of big groups.
- static FindInfo FindFirstNonFullAfterResize(const CommonFields& c,
- size_t old_capacity,
- size_t hash) {
- if (!IsGrowingIntoSingleGroupApplicable(old_capacity, c.capacity())) {
- return find_first_non_full(c, hash);
- }
- // Find a location for the new element non-deterministically.
- // Note that any position is correct.
- // It will located at `half_old_capacity` or one of the other
- // empty slots with approximately 50% probability each.
- size_t offset = probe(c, hash).offset();
-
- // Note that we intentionally use unsigned int underflow.
- if (offset - (old_capacity + 1) >= old_capacity) {
- // Offset fall on kSentinel or into the mostly occupied first half.
- offset = old_capacity / 2;
- }
- assert(IsEmpty(c.control()[offset]));
- return FindInfo{offset, 0};
- }
-
- HeapOrSoo& old_heap_or_soo() { return old_heap_or_soo_; }
- void* old_soo_data() { return old_heap_or_soo_.get_soo_data(); }
- ctrl_t* old_ctrl() const {
- assert(!was_soo_);
- return old_heap_or_soo_.control();
- }
- void* old_slots() const {
- assert(!was_soo_);
- return old_heap_or_soo_.slot_array().get();
- }
- size_t old_capacity() const { return old_capacity_; }
-
- // Returns the index of the SOO slot when growing from SOO to non-SOO in a
- // single group. See also InitControlBytesAfterSoo(). It's important to use
- // index 1 so that when resizing from capacity 1 to 3, we can still have
- // random iteration order between the first two inserted elements.
- // I.e. it allows inserting the second element at either index 0 or 2.
- static size_t SooSlotIndex() { return 1; }
-
- // Allocates a backing array for the hashtable.
- // Reads `capacity` and updates all other fields based on the result of
- // the allocation.
- //
- // It also may do the following actions:
- // 1. initialize control bytes
- // 2. initialize slots
- // 3. deallocate old slots.
- //
- // We are bundling a lot of functionality
- // in one ABSL_ATTRIBUTE_NOINLINE function in order to minimize binary code
- // duplication in raw_hash_set<>::resize.
- //
- // `c.capacity()` must be nonzero.
- // POSTCONDITIONS:
- // 1. CommonFields is initialized.
- //
- // if IsGrowingIntoSingleGroupApplicable && TransferUsesMemcpy
- // Both control bytes and slots are fully initialized.
- // old_slots are deallocated.
- // infoz.RecordRehash is called.
- //
- // if IsGrowingIntoSingleGroupApplicable && !TransferUsesMemcpy
- // Control bytes are fully initialized.
- // infoz.RecordRehash is called.
- // GrowSizeIntoSingleGroup must be called to finish slots initialization.
- //
- // if !IsGrowingIntoSingleGroupApplicable
- // Control bytes are initialized to empty table via ResetCtrl.
- // raw_hash_set<>::resize must insert elements regularly.
- // infoz.RecordRehash is called if old_capacity == 0.
- //
- // Returns IsGrowingIntoSingleGroupApplicable result to avoid recomputation.
- template <typename Alloc, size_t SizeOfSlot, bool TransferUsesMemcpy,
- bool SooEnabled, size_t AlignOfSlot>
- ABSL_ATTRIBUTE_NOINLINE bool InitializeSlots(CommonFields& c, Alloc alloc,
- ctrl_t soo_slot_h2,
- size_t key_size,
- size_t value_size) {
- assert(c.capacity());
- HashtablezInfoHandle infoz =
- ShouldSampleHashtablezInfo<Alloc>()
- ? SampleHashtablezInfo<SooEnabled>(SizeOfSlot, key_size, value_size,
- old_capacity_, was_soo_,
- forced_infoz_, c)
- : HashtablezInfoHandle{};
-
- const bool has_infoz = infoz.IsSampled();
- RawHashSetLayout layout(c.capacity(), AlignOfSlot, has_infoz);
- char* mem = static_cast<char*>(Allocate<BackingArrayAlignment(AlignOfSlot)>(
- &alloc, layout.alloc_size(SizeOfSlot)));
- const GenerationType old_generation = c.generation();
- c.set_generation_ptr(
- reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
- c.set_generation(NextGeneration(old_generation));
- c.set_control(reinterpret_cast<ctrl_t*>(mem + layout.control_offset()));
- c.set_slots(mem + layout.slot_offset());
- ResetGrowthLeft(c);
-
- const bool grow_single_group =
- IsGrowingIntoSingleGroupApplicable(old_capacity_, layout.capacity());
- if (SooEnabled && was_soo_ && grow_single_group) {
- InitControlBytesAfterSoo(c.control(), soo_slot_h2, layout.capacity());
- if (TransferUsesMemcpy && had_soo_slot_) {
- TransferSlotAfterSoo(c, SizeOfSlot);
- }
- // SooEnabled implies that old_capacity_ != 0.
- } else if ((SooEnabled || old_capacity_ != 0) && grow_single_group) {
- if (TransferUsesMemcpy) {
- GrowSizeIntoSingleGroupTransferable(c, SizeOfSlot);
- DeallocateOld<AlignOfSlot>(alloc, SizeOfSlot);
- } else {
- GrowIntoSingleGroupShuffleControlBytes(c.control(), layout.capacity());
- }
- } else {
- ResetCtrl(c, SizeOfSlot);
- }
-
- c.set_has_infoz(has_infoz);
- if (has_infoz) {
- infoz.RecordStorageChanged(c.size(), layout.capacity());
- if ((SooEnabled && was_soo_) || grow_single_group || old_capacity_ == 0) {
- infoz.RecordRehash(0);
- }
- c.set_infoz(infoz);
- }
- return grow_single_group;
- }
-
- // Relocates slots into new single group consistent with
- // GrowIntoSingleGroupShuffleControlBytes.
- //
- // PRECONDITIONS:
- // 1. GrowIntoSingleGroupShuffleControlBytes was already called.
- template <class PolicyTraits, class Alloc>
- void GrowSizeIntoSingleGroup(CommonFields& c, Alloc& alloc_ref) {
- assert(old_capacity_ < Group::kWidth / 2);
- assert(IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()));
- using slot_type = typename PolicyTraits::slot_type;
- assert(is_single_group(c.capacity()));
-
- auto* new_slots = static_cast<slot_type*>(c.slot_array());
- auto* old_slots_ptr = static_cast<slot_type*>(old_slots());
-
- size_t shuffle_bit = old_capacity_ / 2 + 1;
- for (size_t i = 0; i < old_capacity_; ++i) {
- if (IsFull(old_ctrl()[i])) {
- size_t new_i = i ^ shuffle_bit;
- SanitizerUnpoisonMemoryRegion(new_slots + new_i, sizeof(slot_type));
- PolicyTraits::transfer(&alloc_ref, new_slots + new_i,
- old_slots_ptr + i);
- }
- }
- PoisonSingleGroupEmptySlots(c, sizeof(slot_type));
- }
-
- // Deallocates old backing array.
- template <size_t AlignOfSlot, class CharAlloc>
- void DeallocateOld(CharAlloc alloc_ref, size_t slot_size) {
- SanitizerUnpoisonMemoryRegion(old_slots(), slot_size * old_capacity_);
- auto layout = RawHashSetLayout(old_capacity_, AlignOfSlot, had_infoz_);
- Deallocate<BackingArrayAlignment(AlignOfSlot)>(
- &alloc_ref, old_ctrl() - layout.control_offset(),
- layout.alloc_size(slot_size));
- }
-
- private:
- // Returns true if `GrowSizeIntoSingleGroup` can be used for resizing.
- static bool IsGrowingIntoSingleGroupApplicable(size_t old_capacity,
- size_t new_capacity) {
- // NOTE that `old_capacity < new_capacity` in order to have
- // `old_capacity < Group::kWidth / 2` to make faster copies of 8 bytes.
- return is_single_group(new_capacity) && old_capacity < new_capacity;
- }
-
- // Relocates control bytes and slots into new single group for
- // transferable objects.
- // Must be called only if IsGrowingIntoSingleGroupApplicable returned true.
- void GrowSizeIntoSingleGroupTransferable(CommonFields& c, size_t slot_size);
-
- // If there was an SOO slot and slots are transferable, transfers the SOO slot
- // into the new heap allocation. Must be called only if
- // IsGrowingIntoSingleGroupApplicable returned true.
- void TransferSlotAfterSoo(CommonFields& c, size_t slot_size);
-
- // Shuffle control bits deterministically to the next capacity.
- // Returns offset for newly added element with given hash.
- //
- // PRECONDITIONs:
- // 1. new_ctrl is allocated for new_capacity,
- // but not initialized.
- // 2. new_capacity is a single group.
- //
- // All elements are transferred into the first `old_capacity + 1` positions
- // of the new_ctrl. Elements are rotated by `old_capacity_ / 2 + 1` positions
- // in order to change an order and keep it non deterministic.
- // Although rotation itself deterministic, position of the new added element
- // will be based on `H1` and is not deterministic.
- //
- // Examples:
- // S = kSentinel, E = kEmpty
- //
- // old_ctrl = SEEEEEEEE...
- // new_ctrl = ESEEEEEEE...
- //
- // old_ctrl = 0SEEEEEEE...
- // new_ctrl = E0ESE0EEE...
- //
- // old_ctrl = 012S012EEEEEEEEE...
- // new_ctrl = 2E01EEES2E01EEE...
- //
- // old_ctrl = 0123456S0123456EEEEEEEEEEE...
- // new_ctrl = 456E0123EEEEEES456E0123EEE...
- void GrowIntoSingleGroupShuffleControlBytes(ctrl_t* new_ctrl,
- size_t new_capacity) const;
-
- // If the table was SOO, initializes new control bytes. `h2` is the control
- // byte corresponding to the full slot. Must be called only if
- // IsGrowingIntoSingleGroupApplicable returned true.
- // Requires: `had_soo_slot_ || h2 == ctrl_t::kEmpty`.
- void InitControlBytesAfterSoo(ctrl_t* new_ctrl, ctrl_t h2,
- size_t new_capacity);
-
- // Shuffle trivially transferable slots in the way consistent with
- // GrowIntoSingleGroupShuffleControlBytes.
- //
- // PRECONDITIONs:
- // 1. old_capacity must be non-zero.
- // 2. new_ctrl is fully initialized using
- // GrowIntoSingleGroupShuffleControlBytes.
- // 3. new_slots is allocated and *not* poisoned.
- //
- // POSTCONDITIONS:
- // 1. new_slots are transferred from old_slots_ consistent with
- // GrowIntoSingleGroupShuffleControlBytes.
- // 2. Empty new_slots are *not* poisoned.
- void GrowIntoSingleGroupShuffleTransferableSlots(void* new_slots,
- size_t slot_size) const;
-
- // Poison empty slots that were transferred using the deterministic algorithm
- // described above.
- // PRECONDITIONs:
- // 1. new_ctrl is fully initialized using
- // GrowIntoSingleGroupShuffleControlBytes.
- // 2. new_slots is fully initialized consistent with
- // GrowIntoSingleGroupShuffleControlBytes.
- void PoisonSingleGroupEmptySlots(CommonFields& c, size_t slot_size) const {
- // poison non full items
- for (size_t i = 0; i < c.capacity(); ++i) {
- if (!IsFull(c.control()[i])) {
- SanitizerPoisonMemoryRegion(SlotAddress(c.slot_array(), i, slot_size),
- slot_size);
- }
- }
- }
-
- HeapOrSoo old_heap_or_soo_;
- size_t old_capacity_;
- bool had_infoz_;
- bool was_soo_;
- bool had_soo_slot_;
- // Either null infoz or a pre-sampled forced infoz for SOO tables.
- HashtablezInfoHandle forced_infoz_;
-};
-
-inline void PrepareInsertCommon(CommonFields& common) {
- common.increment_size();
- common.maybe_increment_generation_on_insert();
+// Allocates `n` bytes for a backing array.
+template <size_t AlignOfBackingArray, typename Alloc>
+ABSL_ATTRIBUTE_NOINLINE void* AllocateBackingArray(void* alloc, size_t n) {
+ return Allocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), n);
}
-// Like prepare_insert, but for the case of inserting into a full SOO table.
-size_t PrepareInsertAfterSoo(size_t hash, size_t slot_size,
- CommonFields& common);
+template <size_t AlignOfBackingArray, typename Alloc>
+ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
+ void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
+ size_t slot_align, bool had_infoz) {
+ RawHashSetLayout layout(capacity, slot_size, slot_align, had_infoz);
+ void* backing_array = ctrl - layout.control_offset();
+ // Unpoison before returning the memory to the allocator.
+ SanitizerUnpoisonMemoryRegion(backing_array, layout.alloc_size());
+ Deallocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), backing_array,
+ layout.alloc_size());
+}
// PolicyFunctions bundles together some information for a particular
// raw_hash_set<T, ...> instantiation. This information is passed to
// type-erased functions that want to do small amounts of type-specific
// work.
struct PolicyFunctions {
- size_t slot_size;
+ uint32_t key_size;
+ uint32_t value_size;
+ uint32_t slot_size;
+ uint16_t slot_align;
+ bool soo_enabled;
+ bool is_hashtablez_eligible;
// Returns the pointer to the hash function stored in the set.
- const void* (*hash_fn)(const CommonFields& common);
+ void* (*hash_fn)(CommonFields& common);
// Returns the hash of the pointed-to slot.
size_t (*hash_slot)(const void* hash_fn, void* slot);
- // Transfers the contents of src_slot to dst_slot.
- void (*transfer)(void* set, void* dst_slot, void* src_slot);
+ // Transfers the contents of `count` slots from src_slot to dst_slot.
+ // We use ability to transfer several slots in single group table growth.
+ void (*transfer_n)(void* set, void* dst_slot, void* src_slot, size_t count);
+
+ // Returns the pointer to the CharAlloc stored in the set.
+ void* (*get_char_alloc)(CommonFields& common);
+
+ // Allocates n bytes for the backing store for common.
+ void* (*alloc)(void* alloc, size_t n);
// Deallocates the backing store from common.
- void (*dealloc)(CommonFields& common, const PolicyFunctions& policy);
+ void (*dealloc)(void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
+ size_t slot_align, bool had_infoz);
- // Resizes set to the new capacity.
- // Arguments are used as in raw_hash_set::resize_impl.
- void (*resize)(CommonFields& common, size_t new_capacity,
- HashtablezInfoHandle forced_infoz);
+ // Implementation detail of GrowToNextCapacity.
+ // Iterates over all full slots and transfers unprobed elements.
+ // Initializes the new control bytes except mirrored bytes and kSentinel.
+ // Caller must finish the initialization.
+ // All slots corresponding to the full control bytes are transferred.
+ // Probed elements are reported by `encode_probed_element` callback.
+ // encode_probed_element may overwrite old_ctrl buffer till source_offset.
+ // Different encoding is used depending on the capacity of the table.
+ // See ProbedItem*Bytes classes for details.
+ void (*transfer_unprobed_elements_to_next_capacity)(
+ CommonFields& common, const ctrl_t* old_ctrl, void* old_slots,
+ // TODO(b/382423690): Try to use absl::FunctionRef here.
+ void* probed_storage,
+ void (*encode_probed_element)(void* probed_storage, h2_t h2,
+ size_t source_offset, size_t h1));
+
+ uint8_t soo_capacity() const {
+ return static_cast<uint8_t>(soo_enabled ? SooCapacity() : 0);
+ }
};
+// Returns the maximum valid size for a table with 1-byte slots.
+// This function is an utility shared by MaxValidSize and IsAboveValidSize.
+// Template parameter is only used to enable testing.
+template <size_t kSizeOfSizeT = sizeof(size_t)>
+constexpr size_t MaxValidSizeFor1ByteSlot() {
+ if constexpr (kSizeOfSizeT == 8) {
+ return CapacityToGrowth(
+ static_cast<size_t>(uint64_t{1} << HashtableSize::kSizeBitCount) - 1);
+ } else {
+ static_assert(kSizeOfSizeT == 4);
+ return CapacityToGrowth((size_t{1} << (kSizeOfSizeT * 8 - 2)) - 1);
+ }
+}
+
+// Returns the maximum valid size for a table with provided slot size.
+// Template parameter is only used to enable testing.
+template <size_t kSizeOfSizeT = sizeof(size_t)>
+constexpr size_t MaxValidSize(size_t slot_size) {
+ if constexpr (kSizeOfSizeT == 8) {
+ // For small slot sizes we are limited by HashtableSize::kSizeBitCount.
+ if (slot_size < size_t{1} << (64 - HashtableSize::kSizeBitCount)) {
+ return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
+ }
+ return (size_t{1} << (kSizeOfSizeT * 8 - 2)) / slot_size;
+ } else {
+ return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>() / slot_size;
+ }
+}
+
+// Returns true if size is larger than the maximum valid size.
+// It is an optimization to avoid the division operation in the common case.
+// Template parameter is only used to enable testing.
+template <size_t kSizeOfSizeT = sizeof(size_t)>
+constexpr bool IsAboveValidSize(size_t size, size_t slot_size) {
+ if constexpr (kSizeOfSizeT == 8) {
+ // For small slot sizes we are limited by HashtableSize::kSizeBitCount.
+ if (ABSL_PREDICT_TRUE(slot_size <
+ (size_t{1} << (64 - HashtableSize::kSizeBitCount)))) {
+ return size > MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
+ }
+ return size > MaxValidSize<kSizeOfSizeT>(slot_size);
+ } else {
+ return uint64_t{size} * slot_size >
+ MaxValidSizeFor1ByteSlot<kSizeOfSizeT>();
+ }
+}
+
+// Returns the index of the SOO slot when growing from SOO to non-SOO in a
+// single group. See also InitializeSmallControlBytesAfterSoo(). It's important
+// to use index 1 so that when resizing from capacity 1 to 3, we can still have
+// random iteration order between the first two inserted elements.
+// I.e. it allows inserting the second element at either index 0 or 2.
+constexpr size_t SooSlotIndex() { return 1; }
+
+// Maximum capacity for the algorithm for small table after SOO.
+// Note that typical size after SOO is 3, but we allow up to 7.
+// Allowing till 16 would require additional store that can be avoided.
+constexpr size_t MaxSmallAfterSooCapacity() { return 7; }
+
+// Type erased version of raw_hash_set::reserve.
+// Requires: `new_size > policy.soo_capacity`.
+void ReserveTableToFitNewSize(CommonFields& common,
+ const PolicyFunctions& policy, size_t new_size);
+
+// Resizes empty non-allocated table to the next valid capacity after
+// `bucket_count`. Requires:
+// 1. `c.capacity() == policy.soo_capacity`.
+// 2. `c.empty()`.
+// 3. `new_size > policy.soo_capacity`.
+// The table will be attempted to be sampled.
+void ReserveEmptyNonAllocatedTableToFitBucketCount(
+ CommonFields& common, const PolicyFunctions& policy, size_t bucket_count);
+
+// Type erased version of raw_hash_set::rehash.
+void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n);
+
+// Type erased version of copy constructor.
+void Copy(CommonFields& common, const PolicyFunctions& policy,
+ const CommonFields& other,
+ absl::FunctionRef<void(void*, const void*)> copy_fn);
+
+// Returns the optimal size for memcpy when transferring SOO slot.
+// Otherwise, returns the optimal size for memcpy SOO slot transfer
+// to SooSlotIndex().
+// At the destination we are allowed to copy upto twice more bytes,
+// because there is at least one more slot after SooSlotIndex().
+// The result must not exceed MaxSooSlotSize().
+// Some of the cases are merged to minimize the number of function
+// instantiations.
+constexpr size_t OptimalMemcpySizeForSooSlotTransfer(
+ size_t slot_size, size_t max_soo_slot_size = MaxSooSlotSize()) {
+ static_assert(MaxSooSlotSize() >= 8, "unexpectedly small SOO slot size");
+ if (slot_size == 1) {
+ return 1;
+ }
+ if (slot_size <= 3) {
+ return 4;
+ }
+ // We are merging 4 and 8 into one case because we expect them to be the
+ // hottest cases. Copying 8 bytes is as fast on common architectures.
+ if (slot_size <= 8) {
+ return 8;
+ }
+ if (max_soo_slot_size <= 16) {
+ return max_soo_slot_size;
+ }
+ if (slot_size <= 16) {
+ return 16;
+ }
+ if (max_soo_slot_size <= 24) {
+ return max_soo_slot_size;
+ }
+ static_assert(MaxSooSlotSize() <= 24, "unexpectedly large SOO slot size");
+ return 24;
+}
+
+// Resizes SOO table to the NextCapacity(SooCapacity()) and prepares insert for
+// the given new_hash. Returns the offset of the new element.
+// `soo_slot_ctrl` is the control byte of the SOO slot.
+// If soo_slot_ctrl is kEmpty
+// 1. The table must be empty.
+// 2. Table will be forced to be sampled.
+// All possible template combinations are defined in cc file to improve
+// compilation time.
+template <size_t SooSlotMemcpySize, bool TransferUsesMemcpy>
+size_t GrowSooTableToNextCapacityAndPrepareInsert(CommonFields& common,
+ const PolicyFunctions& policy,
+ size_t new_hash,
+ ctrl_t soo_slot_ctrl);
+
+// As `ResizeFullSooTableToNextCapacity`, except that we also force the SOO
+// table to be sampled. SOO tables need to switch from SOO to heap in order to
+// store the infoz. No-op if sampling is disabled or not possible.
+void GrowFullSooTableToNextCapacityForceSampling(CommonFields& common,
+ const PolicyFunctions& policy);
+
+// Resizes table with allocated slots and change the table seed.
+// Tables with SOO enabled must have capacity > policy.soo_capacity.
+// No sampling will be performed since table is already allocated.
+void ResizeAllocatedTableWithSeedChange(CommonFields& common,
+ const PolicyFunctions& policy,
+ size_t new_capacity);
+
// ClearBackingArray clears the backing array, either modifying it in place,
// or creating a new one based on the value of "reuse".
// REQUIRES: c.capacity > 0
void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
- bool reuse, bool soo_enabled);
+ void* alloc, bool reuse, bool soo_enabled);
// Type-erased version of raw_hash_set::erase_meta_only.
void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size);
-// Function to place in PolicyFunctions::dealloc for raw_hash_sets
-// that are using std::allocator. This allows us to share the same
-// function body for raw_hash_set instantiations that have the
-// same slot alignment.
-template <size_t AlignOfSlot>
-ABSL_ATTRIBUTE_NOINLINE void DeallocateStandard(CommonFields& common,
- const PolicyFunctions& policy) {
- // Unpoison before returning the memory to the allocator.
- SanitizerUnpoisonMemoryRegion(common.slot_array(),
- policy.slot_size * common.capacity());
-
- std::allocator<char> alloc;
- common.infoz().Unregister();
- Deallocate<BackingArrayAlignment(AlignOfSlot)>(
- &alloc, common.backing_array_start(),
- common.alloc_size(policy.slot_size, AlignOfSlot));
-}
-
// For trivially relocatable types we use memcpy directly. This allows us to
// share the same function body for raw_hash_set instantiations that have the
// same slot size as long as they are relocatable.
+// Separate function for relocating single slot cause significant binary bloat.
template <size_t SizeOfSlot>
-ABSL_ATTRIBUTE_NOINLINE void TransferRelocatable(void*, void* dst, void* src) {
- memcpy(dst, src, SizeOfSlot);
+ABSL_ATTRIBUTE_NOINLINE void TransferNRelocatable(void*, void* dst, void* src,
+ size_t count) {
+ // TODO(b/382423690): Experiment with making specialization for power of 2 and
+ // non power of 2. This would require passing the size of the slot.
+ memcpy(dst, src, SizeOfSlot * count);
}
-// Type erased raw_hash_set::get_hash_ref_fn for the empty hash function case.
-const void* GetHashRefForEmptyHasher(const CommonFields& common);
+// Returns a pointer to `common`. This is used to implement type erased
+// raw_hash_set::get_hash_ref_fn and raw_hash_set::get_alloc_ref_fn for the
+// empty class cases.
+void* GetRefForEmptyClass(CommonFields& common);
// Given the hash of a value not currently in the table and the first empty
// slot in the probe sequence, finds a viable slot index to insert it at.
@@ -2307,8 +1868,8 @@
// REQUIRES: Table is not SOO.
// REQUIRES: At least one non-full slot available.
// REQUIRES: `target` is a valid empty position to insert.
-size_t PrepareInsertNonSoo(CommonFields& common, size_t hash, FindInfo target,
- const PolicyFunctions& policy);
+size_t PrepareInsertNonSoo(CommonFields& common, const PolicyFunctions& policy,
+ size_t hash, FindInfo target);
// A SwissTable.
//
@@ -2339,9 +1900,6 @@
public:
using init_type = typename PolicyTraits::init_type;
using key_type = typename PolicyTraits::key_type;
- // TODO(sbenza): Hide slot_type as it is an implementation detail. Needs user
- // code fixes!
- using slot_type = typename PolicyTraits::slot_type;
using allocator_type = Alloc;
using size_type = size_t;
using difference_type = ptrdiff_t;
@@ -2356,6 +1914,7 @@
using const_pointer = typename absl::allocator_traits<
allocator_type>::template rebind_traits<value_type>::const_pointer;
+ private:
// Alias used for heterogeneous lookup functions.
// `key_arg<K>` evaluates to `K` when the functors are transparent and to
// `key_type` otherwise. It permits template argument deduction on `K` for the
@@ -2363,7 +1922,8 @@
template <class K>
using key_arg = typename KeyArgImpl::template type<K, key_type>;
- private:
+ using slot_type = typename PolicyTraits::slot_type;
+
// TODO(b/289225379): we could add extra SOO space inside raw_hash_set
// after CommonFields to allow inlining larger slot_types (e.g. std::string),
// but it's a bit complicated if we want to support incomplete mapped_type in
@@ -2376,6 +1936,10 @@
alignof(slot_type) <= alignof(HeapOrSoo);
}
+ constexpr static size_t DefaultCapacity() {
+ return SooEnabled() ? SooCapacity() : 0;
+ }
+
// Whether `size` fits in the SOO capacity of this table.
bool fits_in_soo(size_t size) const {
return SooEnabled() && size <= SooCapacity();
@@ -2402,23 +1966,14 @@
static_assert(std::is_lvalue_reference<reference>::value,
"Policy::element() must return a reference");
- template <typename T>
- struct SameAsElementReference
- : std::is_same<typename std::remove_cv<
- typename std::remove_reference<reference>::type>::type,
- typename std::remove_cv<
- typename std::remove_reference<T>::type>::type> {};
-
// An enabler for insert(T&&): T must be convertible to init_type or be the
// same as [cv] value_type [ref].
- // Note: we separate SameAsElementReference into its own type to avoid using
- // reference unless we need to. MSVC doesn't seem to like it in some
- // cases.
template <class T>
- using RequiresInsertable = typename std::enable_if<
- absl::disjunction<std::is_convertible<T, init_type>,
- SameAsElementReference<T>>::value,
- int>::type;
+ using Insertable = absl::disjunction<
+ std::is_same<absl::remove_cvref_t<reference>, absl::remove_cvref_t<T>>,
+ std::is_convertible<T, init_type>>;
+ template <class T>
+ using IsNotBitField = std::is_pointer<T*>;
// RequiresNotInit is a workaround for gcc prior to 7.1.
// See https://godbolt.org/g/Y4xsUh.
@@ -2429,6 +1984,17 @@
template <class... Ts>
using IsDecomposable = IsDecomposable<void, PolicyTraits, Hash, Eq, Ts...>;
+ template <class T>
+ using IsDecomposableAndInsertable =
+ IsDecomposable<std::enable_if_t<Insertable<T>::value, T>>;
+
+ // Evaluates to true if an assignment from the given type would require the
+ // source object to remain alive for the life of the element.
+ template <class U>
+ using IsLifetimeBoundAssignmentFrom = std::conditional_t<
+ policy_trait_element_is_owner<Policy>::value, std::false_type,
+ type_traits_internal::IsLifetimeBoundAssignment<init_type, U>>;
+
public:
static_assert(std::is_same<pointer, value_type*>::value,
"Allocators with custom pointer types are not supported");
@@ -2607,14 +2173,15 @@
std::is_nothrow_default_constructible<key_equal>::value &&
std::is_nothrow_default_constructible<allocator_type>::value) {}
- ABSL_ATTRIBUTE_NOINLINE explicit raw_hash_set(
+ explicit raw_hash_set(
size_t bucket_count, const hasher& hash = hasher(),
const key_equal& eq = key_equal(),
const allocator_type& alloc = allocator_type())
: settings_(CommonFields::CreateDefault<SooEnabled()>(), hash, eq,
alloc) {
- if (bucket_count > (SooEnabled() ? SooCapacity() : 0)) {
- resize(NormalizeCapacity(bucket_count));
+ if (bucket_count > DefaultCapacity()) {
+ ReserveEmptyNonAllocatedTableToFitBucketCount(
+ common(), GetPolicyFunctions(), bucket_count);
}
}
@@ -2672,7 +2239,8 @@
// absl::flat_hash_set<int> a, b{a};
//
// RequiresNotInit<T> is a workaround for gcc prior to 7.1.
- template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+ template <class T, RequiresNotInit<T> = 0,
+ std::enable_if_t<Insertable<T>::value, int> = 0>
raw_hash_set(std::initializer_list<T> init, size_t bucket_count = 0,
const hasher& hash = hasher(), const key_equal& eq = key_equal(),
const allocator_type& alloc = allocator_type())
@@ -2683,7 +2251,8 @@
const allocator_type& alloc = allocator_type())
: raw_hash_set(init.begin(), init.end(), bucket_count, hash, eq, alloc) {}
- template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+ template <class T, RequiresNotInit<T> = 0,
+ std::enable_if_t<Insertable<T>::value, int> = 0>
raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
const hasher& hash, const allocator_type& alloc)
: raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
@@ -2692,7 +2261,8 @@
const hasher& hash, const allocator_type& alloc)
: raw_hash_set(init, bucket_count, hash, key_equal(), alloc) {}
- template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+ template <class T, RequiresNotInit<T> = 0,
+ std::enable_if_t<Insertable<T>::value, int> = 0>
raw_hash_set(std::initializer_list<T> init, size_t bucket_count,
const allocator_type& alloc)
: raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
@@ -2701,7 +2271,8 @@
const allocator_type& alloc)
: raw_hash_set(init, bucket_count, hasher(), key_equal(), alloc) {}
- template <class T, RequiresNotInit<T> = 0, RequiresInsertable<T> = 0>
+ template <class T, RequiresNotInit<T> = 0,
+ std::enable_if_t<Insertable<T>::value, int> = 0>
raw_hash_set(std::initializer_list<T> init, const allocator_type& alloc)
: raw_hash_set(init, 0, hasher(), key_equal(), alloc) {}
@@ -2711,72 +2282,20 @@
raw_hash_set(const raw_hash_set& that)
: raw_hash_set(that, AllocTraits::select_on_container_copy_construction(
- that.alloc_ref())) {}
+ allocator_type(that.char_alloc_ref()))) {}
raw_hash_set(const raw_hash_set& that, const allocator_type& a)
- : raw_hash_set(GrowthToLowerboundCapacity(that.size()), that.hash_ref(),
- that.eq_ref(), a) {
- const size_t size = that.size();
- if (size == 0) {
- return;
- }
- // We don't use `that.is_soo()` here because `that` can have non-SOO
- // capacity but have a size that fits into SOO capacity.
- if (fits_in_soo(size)) {
- assert(size == 1);
- common().set_full_soo();
- emplace_at(soo_iterator(), *that.begin());
- const HashtablezInfoHandle infoz = try_sample_soo();
- if (infoz.IsSampled()) resize_with_soo_infoz(infoz);
- return;
- }
- assert(!that.is_soo());
- const size_t cap = capacity();
- // Note about single group tables:
- // 1. It is correct to have any order of elements.
- // 2. Order has to be non deterministic.
- // 3. We are assigning elements with arbitrary `shift` starting from
- // `capacity + shift` position.
- // 4. `shift` must be coprime with `capacity + 1` in order to be able to use
- // modular arithmetic to traverse all positions, instead if cycling
- // through a subset of positions. Odd numbers are coprime with any
- // `capacity + 1` (2^N).
- size_t offset = cap;
- const size_t shift =
- is_single_group(cap) ? (PerTableSalt(control()) | 1) : 0;
- IterateOverFullSlots(
- that.common(), that.slot_array(),
- [&](const ctrl_t* that_ctrl,
- slot_type* that_slot) ABSL_ATTRIBUTE_ALWAYS_INLINE {
- if (shift == 0) {
- // Big tables case. Position must be searched via probing.
- // The table is guaranteed to be empty, so we can do faster than
- // a full `insert`.
- const size_t hash = PolicyTraits::apply(
- HashElement{hash_ref()}, PolicyTraits::element(that_slot));
- FindInfo target = find_first_non_full_outofline(common(), hash);
- infoz().RecordInsert(hash, target.probe_length);
- offset = target.offset;
- } else {
- // Small tables case. Next position is computed via shift.
- offset = (offset + shift) & cap;
- }
- const h2_t h2 = static_cast<h2_t>(*that_ctrl);
- assert( // We rely that hash is not changed for small tables.
- H2(PolicyTraits::apply(HashElement{hash_ref()},
- PolicyTraits::element(that_slot))) == h2 &&
- "hash function value changed unexpectedly during the copy");
- SetCtrl(common(), offset, h2, sizeof(slot_type));
- emplace_at(iterator_at(offset), PolicyTraits::element(that_slot));
- common().maybe_increment_generation_on_insert();
- });
- if (shift != 0) {
- // On small table copy we do not record individual inserts.
- // RecordInsert requires hash, but it is unknown for small tables.
- infoz().RecordStorageChanged(size, cap);
- }
- common().set_size(size);
- growth_info().OverwriteManyEmptyAsFull(size);
+ : raw_hash_set(0, that.hash_ref(), that.eq_ref(), a) {
+ that.AssertNotDebugCapacity();
+ if (that.empty()) return;
+ Copy(common(), GetPolicyFunctions(), that.common(),
+ [this](void* dst, const void* src) {
+ // TODO(b/413598253): type erase for trivially copyable types via
+ // PolicyTraits.
+ construct(to_slot(dst),
+ PolicyTraits::element(
+ static_cast<slot_type*>(const_cast<void*>(src))));
+ });
}
ABSL_ATTRIBUTE_NOINLINE raw_hash_set(raw_hash_set&& that) noexcept(
@@ -2786,31 +2305,31 @@
: // Hash, equality and allocator are copied instead of moved because
// `that` must be left valid. If Hash is std::function<Key>, moving it
// would create a nullptr functor that cannot be called.
- // TODO(b/296061262): move instead of copying hash/eq/alloc.
// Note: we avoid using exchange for better generated code.
settings_(PolicyTraits::transfer_uses_memcpy() || !that.is_full_soo()
? std::move(that.common())
: CommonFields{full_soo_tag_t{}},
- that.hash_ref(), that.eq_ref(), that.alloc_ref()) {
+ that.hash_ref(), that.eq_ref(), that.char_alloc_ref()) {
if (!PolicyTraits::transfer_uses_memcpy() && that.is_full_soo()) {
transfer(soo_slot(), that.soo_slot());
}
that.common() = CommonFields::CreateDefault<SooEnabled()>();
- maybe_increment_generation_or_rehash_on_move();
+ annotate_for_bug_detection_on_move(that);
}
raw_hash_set(raw_hash_set&& that, const allocator_type& a)
: settings_(CommonFields::CreateDefault<SooEnabled()>(), that.hash_ref(),
that.eq_ref(), a) {
- if (a == that.alloc_ref()) {
+ if (CharAlloc(a) == that.char_alloc_ref()) {
swap_common(that);
- maybe_increment_generation_or_rehash_on_move();
+ annotate_for_bug_detection_on_move(that);
} else {
move_elements_allocs_unequal(std::move(that));
}
}
raw_hash_set& operator=(const raw_hash_set& that) {
+ that.AssertNotDebugCapacity();
if (ABSL_PREDICT_FALSE(this == &that)) return *this;
constexpr bool propagate_alloc =
AllocTraits::propagate_on_container_copy_assignment::value;
@@ -2818,7 +2337,9 @@
// is an exact match for that.size(). If this->capacity() is too big, then
// it would make iteration very slow to reuse the allocation. Maybe we can
// do the same heuristic as clear() and reuse if it's small enough.
- raw_hash_set tmp(that, propagate_alloc ? that.alloc_ref() : alloc_ref());
+ allocator_type alloc(propagate_alloc ? that.char_alloc_ref()
+ : char_alloc_ref());
+ raw_hash_set tmp(that, alloc);
// NOLINTNEXTLINE: not returning *this for performance.
return assign_impl<propagate_alloc>(std::move(tmp));
}
@@ -2835,18 +2356,24 @@
typename AllocTraits::propagate_on_container_move_assignment());
}
- ~raw_hash_set() { destructor_impl(); }
+ ~raw_hash_set() {
+ destructor_impl();
+ if constexpr (SwisstableAssertAccessToDestroyedTable()) {
+ common().set_capacity(InvalidCapacity::kDestroyed);
+ }
+ }
iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
if (ABSL_PREDICT_FALSE(empty())) return end();
- if (is_soo()) return soo_iterator();
+ if (capacity() == 1) return single_iterator();
iterator it = {control(), common().slots_union(),
common().generation_ptr()};
it.skip_empty_or_deleted();
- assert(IsFull(*it.control()));
+ ABSL_SWISSTABLE_ASSERT(IsFull(*it.control()));
return it;
}
iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ AssertNotDebugCapacity();
return iterator(common().generation_ptr());
}
@@ -2854,7 +2381,7 @@
return const_cast<raw_hash_set*>(this)->begin();
}
const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return iterator(common().generation_ptr());
+ return const_cast<raw_hash_set*>(this)->end();
}
const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return begin();
@@ -2862,18 +2389,26 @@
const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
bool empty() const { return !size(); }
- size_t size() const { return common().size(); }
+ size_t size() const {
+ AssertNotDebugCapacity();
+ return common().size();
+ }
size_t capacity() const {
const size_t cap = common().capacity();
- // Compiler complains when using functions in assume so use local variables.
- ABSL_ATTRIBUTE_UNUSED static constexpr bool kEnabled = SooEnabled();
- ABSL_ATTRIBUTE_UNUSED static constexpr size_t kCapacity = SooCapacity();
- ABSL_ASSUME(!kEnabled || cap >= kCapacity);
+ // Compiler complains when using functions in ASSUME so use local variable.
+ [[maybe_unused]] static constexpr size_t kDefaultCapacity =
+ DefaultCapacity();
+ ABSL_ASSUME(cap >= kDefaultCapacity);
return cap;
}
- size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
+ size_t max_size() const { return MaxValidSize(sizeof(slot_type)); }
ABSL_ATTRIBUTE_REINITIALIZES void clear() {
+ if (SwisstableGenerationsEnabled() &&
+ capacity() >= InvalidCapacity::kMovedFrom) {
+ common().set_capacity(DefaultCapacity());
+ }
+ AssertNotDebugCapacity();
// Iterating over this container is O(bucket_count()). When bucket_count()
// is much greater than size(), iteration becomes prohibitively expensive.
// For clear() it is more important to reuse the allocated array when the
@@ -2889,8 +2424,7 @@
common().set_empty_soo();
} else {
destroy_slots();
- ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/cap < 128,
- SooEnabled());
+ clear_backing_array(/*reuse=*/cap < 128);
}
common().set_reserved_growth(0);
common().set_reservation_size(0);
@@ -2901,15 +2435,26 @@
//
// flat_hash_map<std::string, int> m;
// m.insert(std::make_pair("abc", 42));
- // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
- // bug.
- template <class T, RequiresInsertable<T> = 0, class T2 = T,
- typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
- T* = nullptr>
+ template <class T,
+ int = std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
+ IsNotBitField<T>::value &&
+ !IsLifetimeBoundAssignmentFrom<T>::value,
+ int>()>
std::pair<iterator, bool> insert(T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return emplace(std::forward<T>(value));
}
+ template <class T, int&...,
+ std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
+ IsNotBitField<T>::value &&
+ IsLifetimeBoundAssignmentFrom<T>::value,
+ int> = 0>
+ std::pair<iterator, bool> insert(
+ T&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template insert<T, 0>(std::forward<T>(value));
+ }
+
// This overload kicks in when the argument is a bitfield or an lvalue of
// insertable and decomposable type.
//
@@ -2921,13 +2466,23 @@
// const char* p = "hello";
// s.insert(p);
//
- template <
- class T, RequiresInsertable<const T&> = 0,
- typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
+ template <class T, int = std::enable_if_t<
+ IsDecomposableAndInsertable<const T&>::value &&
+ !IsLifetimeBoundAssignmentFrom<const T&>::value,
+ int>()>
std::pair<iterator, bool> insert(const T& value)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return emplace(value);
}
+ template <class T, int&...,
+ std::enable_if_t<IsDecomposableAndInsertable<const T&>::value &&
+ IsLifetimeBoundAssignmentFrom<const T&>::value,
+ int> = 0>
+ std::pair<iterator, bool> insert(
+ const T& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template insert<T, 0>(value);
+ }
// This overload kicks in when the argument is an rvalue of init_type. Its
// purpose is to handle brace-init-list arguments.
@@ -2935,22 +2490,44 @@
// flat_hash_map<std::string, int> s;
// s.insert({"abc", 42});
std::pair<iterator, bool> insert(init_type&& value)
- ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ ABSL_ATTRIBUTE_LIFETIME_BOUND
+#if __cplusplus >= 202002L
+ requires(!IsLifetimeBoundAssignmentFrom<init_type>::value)
+#endif
+ {
return emplace(std::move(value));
}
+#if __cplusplus >= 202002L
+ std::pair<iterator, bool> insert(
+ init_type&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND
+ requires(IsLifetimeBoundAssignmentFrom<init_type>::value)
+ {
+ return emplace(std::move(value));
+ }
+#endif
- // TODO(cheshire): A type alias T2 is introduced as a workaround for the nvcc
- // bug.
- template <class T, RequiresInsertable<T> = 0, class T2 = T,
- typename std::enable_if<IsDecomposable<T2>::value, int>::type = 0,
- T* = nullptr>
+ template <class T,
+ int = std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
+ IsNotBitField<T>::value &&
+ !IsLifetimeBoundAssignmentFrom<T>::value,
+ int>()>
iterator insert(const_iterator, T&& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return insert(std::forward<T>(value)).first;
}
+ template <class T, int&...,
+ std::enable_if_t<IsDecomposableAndInsertable<T>::value &&
+ IsNotBitField<T>::value &&
+ IsLifetimeBoundAssignmentFrom<T>::value,
+ int> = 0>
+ iterator insert(const_iterator hint,
+ T&& value ABSL_INTERNAL_ATTRIBUTE_CAPTURED_BY(this))
+ ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return this->template insert<T, 0>(hint, std::forward<T>(value));
+ }
- template <
- class T, RequiresInsertable<const T&> = 0,
- typename std::enable_if<IsDecomposable<const T&>::value, int>::type = 0>
+ template <class T, std::enable_if_t<
+ IsDecomposableAndInsertable<const T&>::value, int> = 0>
iterator insert(const_iterator,
const T& value) ABSL_ATTRIBUTE_LIFETIME_BOUND {
return insert(value).first;
@@ -2966,7 +2543,8 @@
for (; first != last; ++first) emplace(*first);
}
- template <class T, RequiresNotInit<T> = 0, RequiresInsertable<const T&> = 0>
+ template <class T, RequiresNotInit<T> = 0,
+ std::enable_if_t<Insertable<const T&>::value, int> = 0>
void insert(std::initializer_list<T> ilist) {
insert(ilist.begin(), ilist.end());
}
@@ -3005,8 +2583,8 @@
// flat_hash_map<std::string, std::string> m = {{"abc", "def"}};
// // Creates no std::string copies and makes no heap allocations.
// m.emplace("abc", "xyz");
- template <class... Args, typename std::enable_if<
- IsDecomposable<Args...>::value, int>::type = 0>
+ template <class... Args,
+ std::enable_if_t<IsDecomposable<Args...>::value, int> = 0>
std::pair<iterator, bool> emplace(Args&&... args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return PolicyTraits::apply(EmplaceDecomposable{*this},
@@ -3016,8 +2594,8 @@
// This overload kicks in if we cannot deduce the key from args. It constructs
// value_type unconditionally and then either moves it into the table or
// destroys.
- template <class... Args, typename std::enable_if<
- !IsDecomposable<Args...>::value, int>::type = 0>
+ template <class... Args,
+ std::enable_if_t<!IsDecomposable<Args...>::value, int> = 0>
std::pair<iterator, bool> emplace(Args&&... args)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
alignas(slot_type) unsigned char raw[sizeof(slot_type)];
@@ -3068,7 +2646,7 @@
public:
template <class... Args>
void operator()(Args&&... args) const {
- assert(*slot_);
+ ABSL_SWISSTABLE_ASSERT(*slot_);
PolicyTraits::construct(alloc_, *slot_, std::forward<Args>(args)...);
*slot_ = nullptr;
}
@@ -3086,8 +2664,9 @@
auto res = find_or_prepare_insert(key);
if (res.second) {
slot_type* slot = res.first.slot();
- std::forward<F>(f)(constructor(&alloc_ref(), &slot));
- assert(!slot);
+ allocator_type alloc(char_alloc_ref());
+ std::forward<F>(f)(constructor(&alloc, &slot));
+ ABSL_SWISSTABLE_ASSERT(!slot);
}
return res.first;
}
@@ -3109,24 +2688,16 @@
return 1;
}
- // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`,
- // this method returns void to reduce algorithmic complexity to O(1). The
- // iterator is invalidated, so any increment should be done before calling
- // erase. In order to erase while iterating across a map, use the following
- // idiom (which also works for some standard containers):
- //
- // for (auto it = m.begin(), end = m.end(); it != end;) {
- // // `erase()` will invalidate `it`, so advance `it` first.
- // auto copy_it = it++;
- // if (<pred>) {
- // m.erase(copy_it);
- // }
- // }
+ // Erases the element pointed to by `it`. Unlike `std::unordered_set::erase`,
+ // this method returns void to reduce algorithmic complexity to O(1). The
+ // iterator is invalidated so any increment should be done before calling
+ // erase (e.g. `erase(it++)`).
void erase(const_iterator cit) { erase(cit.inner_); }
// This overload is necessary because otherwise erase<K>(const K&) would be
// a better match if non-const iterator is passed as an argument.
void erase(iterator it) {
+ AssertNotDebugCapacity();
AssertIsFull(it.control(), it.generation(), it.generation_ptr(), "erase()");
destroy(it.slot());
if (is_soo()) {
@@ -3138,7 +2709,8 @@
iterator erase(const_iterator first,
const_iterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- // We check for empty first because ClearBackingArray requires that
+ AssertNotDebugCapacity();
+ // We check for empty first because clear_backing_array requires that
// capacity() > 0 as a precondition.
if (empty()) return end();
if (first == last) return last.inner_;
@@ -3149,11 +2721,10 @@
}
if (first == begin() && last == end()) {
// TODO(ezb): we access control bytes in destroy_slots so it could make
- // sense to combine destroy_slots and ClearBackingArray to avoid cache
+ // sense to combine destroy_slots and clear_backing_array to avoid cache
// misses when the table is large. Note that we also do this in clear().
destroy_slots();
- ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/true,
- SooEnabled());
+ clear_backing_array(/*reuse=*/true);
common().set_reserved_growth(common().reservation_size());
return end();
}
@@ -3167,6 +2738,8 @@
// If the element already exists in `this`, it is left unmodified in `src`.
template <typename H, typename E>
void merge(raw_hash_set<Policy, H, E, Alloc>& src) { // NOLINT
+ AssertNotDebugCapacity();
+ src.AssertNotDebugCapacity();
assert(this != &src);
// Returns whether insertion took place.
const auto insert_slot = [this](slot_type* src_slot) {
@@ -3193,9 +2766,11 @@
}
node_type extract(const_iterator position) {
+ AssertNotDebugCapacity();
AssertIsFull(position.control(), position.inner_.generation(),
position.inner_.generation_ptr(), "extract()");
- auto node = CommonAccess::Transfer<node_type>(alloc_ref(), position.slot());
+ allocator_type alloc(char_alloc_ref());
+ auto node = CommonAccess::Transfer<node_type>(alloc, position.slot());
if (is_soo()) {
common().set_empty_soo();
} else {
@@ -3204,9 +2779,8 @@
return node;
}
- template <
- class K = key_type,
- typename std::enable_if<!std::is_same<K, iterator>::value, int>::type = 0>
+ template <class K = key_type,
+ std::enable_if_t<!std::is_same<K, iterator>::value, int> = 0>
node_type extract(const key_arg<K>& key) {
auto it = find(key);
return it == end() ? node_type() : extract(const_iterator{it});
@@ -3216,71 +2790,22 @@
IsNoThrowSwappable<hasher>() && IsNoThrowSwappable<key_equal>() &&
IsNoThrowSwappable<allocator_type>(
typename AllocTraits::propagate_on_container_swap{})) {
+ AssertNotDebugCapacity();
+ that.AssertNotDebugCapacity();
using std::swap;
swap_common(that);
swap(hash_ref(), that.hash_ref());
swap(eq_ref(), that.eq_ref());
- SwapAlloc(alloc_ref(), that.alloc_ref(),
+ SwapAlloc(char_alloc_ref(), that.char_alloc_ref(),
typename AllocTraits::propagate_on_container_swap{});
}
- void rehash(size_t n) {
- const size_t cap = capacity();
- if (n == 0) {
- if (cap == 0 || is_soo()) return;
- if (empty()) {
- ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/false,
- SooEnabled());
- return;
- }
- if (fits_in_soo(size())) {
- // When the table is already sampled, we keep it sampled.
- if (infoz().IsSampled()) {
- const size_t kInitialSampledCapacity = NextCapacity(SooCapacity());
- if (capacity() > kInitialSampledCapacity) {
- resize(kInitialSampledCapacity);
- }
- // This asserts that we didn't lose sampling coverage in `resize`.
- assert(infoz().IsSampled());
- return;
- }
- alignas(slot_type) unsigned char slot_space[sizeof(slot_type)];
- slot_type* tmp_slot = to_slot(slot_space);
- transfer(tmp_slot, begin().slot());
- ClearBackingArray(common(), GetPolicyFunctions(), /*reuse=*/false,
- SooEnabled());
- transfer(soo_slot(), tmp_slot);
- common().set_full_soo();
- return;
- }
- }
-
- // bitor is a faster way of doing `max` here. We will round up to the next
- // power-of-2-minus-1, so bitor is good enough.
- auto m = NormalizeCapacity(n | GrowthToLowerboundCapacity(size()));
- // n == 0 unconditionally rehashes as per the standard.
- if (n == 0 || m > cap) {
- resize(m);
-
- // This is after resize, to ensure that we have completed the allocation
- // and have potentially sampled the hashtable.
- infoz().RecordReservation(n);
- }
- }
+ void rehash(size_t n) { Rehash(common(), GetPolicyFunctions(), n); }
void reserve(size_t n) {
- const size_t max_size_before_growth =
- is_soo() ? SooCapacity() : size() + growth_left();
- if (n > max_size_before_growth) {
- size_t m = GrowthToLowerboundCapacity(n);
- resize(NormalizeCapacity(m));
-
- // This is after resize, to ensure that we have completed the allocation
- // and have potentially sampled the hashtable.
- infoz().RecordReservation(n);
+ if (ABSL_PREDICT_TRUE(n > DefaultCapacity())) {
+ ReserveTableToFitNewSize(common(), GetPolicyFunctions(), n);
}
- common().reset_reserved_growth(n);
- common().set_reservation_size(n);
}
// Extension API: support for heterogeneous keys.
@@ -3304,43 +2829,38 @@
// specific benchmarks indicating its importance.
template <class K = key_type>
void prefetch(const key_arg<K>& key) const {
- if (SooEnabled() ? is_soo() : capacity() == 0) return;
+ if (capacity() == DefaultCapacity()) return;
(void)key;
// Avoid probing if we won't be able to prefetch the addresses received.
#ifdef ABSL_HAVE_PREFETCH
prefetch_heap_block();
- auto seq = probe(common(), hash_ref()(key));
+ auto seq = probe(common(), hash_of(key));
PrefetchToLocalCache(control() + seq.offset());
PrefetchToLocalCache(slot_array() + seq.offset());
#endif // ABSL_HAVE_PREFETCH
}
- // The API of find() has two extensions.
- //
- // 1. The hash can be passed by the user. It must be equal to the hash of the
- // key.
- //
- // 2. The type of the key argument doesn't have to be key_type. This is so
- // called heterogeneous key support.
template <class K = key_type>
+ ABSL_DEPRECATE_AND_INLINE()
iterator find(const key_arg<K>& key,
- size_t hash) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- AssertHashEqConsistent(key);
- if (is_soo()) return find_soo(key);
- return find_non_soo(key, hash);
+ size_t) ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return find(key);
}
+ // The API of find() has one extension: the type of the key argument doesn't
+ // have to be key_type. This is so called heterogeneous key support.
template <class K = key_type>
iterator find(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- AssertHashEqConsistent(key);
- if (is_soo()) return find_soo(key);
+ AssertOnFind(key);
+ if (capacity() <= 1) return find_small(key);
prefetch_heap_block();
- return find_non_soo(key, hash_ref()(key));
+ return find_large(key, hash_of(key));
}
template <class K = key_type>
+ ABSL_DEPRECATE_AND_INLINE()
const_iterator find(const key_arg<K>& key,
- size_t hash) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return const_cast<raw_hash_set*>(this)->find(key, hash);
+ size_t) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return find(key);
}
template <class K = key_type>
const_iterator find(const key_arg<K>& key) const
@@ -3383,7 +2903,9 @@
hasher hash_function() const { return hash_ref(); }
key_equal key_eq() const { return eq_ref(); }
- allocator_type get_allocator() const { return alloc_ref(); }
+ allocator_type get_allocator() const {
+ return allocator_type(char_alloc_ref());
+ }
friend bool operator==(const raw_hash_set& a, const raw_hash_set& b) {
if (a.size() != b.size()) return false;
@@ -3392,7 +2914,16 @@
if (outer->capacity() > inner->capacity()) std::swap(outer, inner);
for (const value_type& elem : *outer) {
auto it = PolicyTraits::apply(FindElement{*inner}, elem);
- if (it == inner->end() || !(*it == elem)) return false;
+ if (it == inner->end()) return false;
+ // Note: we used key_equal to check for key equality in FindElement, but
+ // we may need to do an additional comparison using
+ // value_type::operator==. E.g. the keys could be equal and the
+ // mapped_types could be unequal in a map or even in a set, key_equal
+ // could ignore some fields that aren't ignored by operator==.
+ static constexpr bool kKeyEqIsValueEq =
+ std::is_same<key_type, value_type>::value &&
+ std::is_same<key_equal, hash_default_eq<key_type>>::value;
+ if (!kKeyEqIsValueEq && !(*it == elem)) return false;
}
return true;
}
@@ -3406,7 +2937,7 @@
H>::type
AbslHashValue(H h, const raw_hash_set& s) {
return H::combine(H::combine_unordered(std::move(h), s.begin(), s.end()),
- s.size());
+ hash_internal::WeaklyMixedInteger{s.size()});
}
friend void swap(raw_hash_set& a,
@@ -3441,7 +2972,7 @@
struct EqualElement {
template <class K2, class... Args>
bool operator()(const K2& lhs, Args&&...) const {
- return eq(lhs, rhs);
+ ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(eq(lhs, rhs));
}
const K1& rhs;
const key_equal& eq;
@@ -3476,37 +3007,51 @@
slot_type&& slot;
};
- // TODO(b/303305702): re-enable reentrant validation.
template <typename... Args>
inline void construct(slot_type* slot, Args&&... args) {
- PolicyTraits::construct(&alloc_ref(), slot, std::forward<Args>(args)...);
+ common().RunWithReentrancyGuard([&] {
+ allocator_type alloc(char_alloc_ref());
+ PolicyTraits::construct(&alloc, slot, std::forward<Args>(args)...);
+ });
}
inline void destroy(slot_type* slot) {
- PolicyTraits::destroy(&alloc_ref(), slot);
+ common().RunWithReentrancyGuard([&] {
+ allocator_type alloc(char_alloc_ref());
+ PolicyTraits::destroy(&alloc, slot);
+ });
}
inline void transfer(slot_type* to, slot_type* from) {
- PolicyTraits::transfer(&alloc_ref(), to, from);
+ common().RunWithReentrancyGuard([&] {
+ allocator_type alloc(char_alloc_ref());
+ PolicyTraits::transfer(&alloc, to, from);
+ });
}
// TODO(b/289225379): consider having a helper class that has the impls for
// SOO functionality.
template <class K = key_type>
- iterator find_soo(const key_arg<K>& key) {
- assert(is_soo());
- return empty() || !PolicyTraits::apply(EqualElement<K>{key, eq_ref()},
- PolicyTraits::element(soo_slot()))
+ iterator find_small(const key_arg<K>& key) {
+ ABSL_SWISSTABLE_ASSERT(capacity() <= 1);
+ return empty() || !PolicyTraits::apply(
+ EqualElement<K>{key, eq_ref()},
+ PolicyTraits::element(single_slot()))
? end()
- : soo_iterator();
+ : single_iterator();
}
template <class K = key_type>
- iterator find_non_soo(const key_arg<K>& key, size_t hash) {
- assert(!is_soo());
+ iterator find_large(const key_arg<K>& key, size_t hash) {
+ ABSL_SWISSTABLE_ASSERT(capacity() > 1);
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
auto seq = probe(common(), hash);
+ const h2_t h2 = H2(hash);
const ctrl_t* ctrl = control();
while (true) {
+#ifndef ABSL_HAVE_MEMORY_SANITIZER
+ absl::PrefetchToLocalCache(slot_array() + seq.offset());
+#endif
Group g{ctrl + seq.offset()};
- for (uint32_t i : g.Match(H2(hash))) {
+ for (uint32_t i : g.Match(h2)) {
if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
EqualElement<K>{key, eq_ref()},
PolicyTraits::element(slot_array() + seq.offset(i)))))
@@ -3514,40 +3059,57 @@
}
if (ABSL_PREDICT_TRUE(g.MaskEmpty())) return end();
seq.next();
- assert(seq.index() <= capacity() && "full table!");
+ ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
}
}
- // Conditionally samples hashtablez for SOO tables. This should be called on
- // insertion into an empty SOO table and in copy construction when the size
- // can fit in SOO capacity.
- inline HashtablezInfoHandle try_sample_soo() {
- assert(is_soo());
- if (!ShouldSampleHashtablezInfo<CharAlloc>()) return HashtablezInfoHandle{};
- return Sample(sizeof(slot_type), sizeof(key_type), sizeof(value_type),
- SooCapacity());
+ // Returns true if the table needs to be sampled.
+ // This should be called on insertion into an empty SOO table and in copy
+ // construction when the size can fit in SOO capacity.
+ bool should_sample_soo() const {
+ ABSL_SWISSTABLE_ASSERT(is_soo());
+ if (!ShouldSampleHashtablezInfoForAlloc<CharAlloc>()) return false;
+ return ABSL_PREDICT_FALSE(ShouldSampleNextTable());
}
- inline void destroy_slots() {
- assert(!is_soo());
+ void clear_backing_array(bool reuse) {
+ ABSL_SWISSTABLE_ASSERT(capacity() > DefaultCapacity());
+ ClearBackingArray(common(), GetPolicyFunctions(), &char_alloc_ref(), reuse,
+ SooEnabled());
+ }
+
+ void destroy_slots() {
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
if (PolicyTraits::template destroy_is_trivial<Alloc>()) return;
- IterateOverFullSlots(
- common(), slot_array(),
- [&](const ctrl_t*, slot_type* slot)
- ABSL_ATTRIBUTE_ALWAYS_INLINE { this->destroy(slot); });
+ auto destroy_slot = [&](const ctrl_t*, void* slot) {
+ this->destroy(static_cast<slot_type*>(slot));
+ };
+ if constexpr (SwisstableAssertAccessToDestroyedTable()) {
+ CommonFields common_copy(non_soo_tag_t{}, this->common());
+ common().set_capacity(InvalidCapacity::kDestroyed);
+ IterateOverFullSlots(common_copy, sizeof(slot_type), destroy_slot);
+ common().set_capacity(common_copy.capacity());
+ } else {
+ IterateOverFullSlots(common(), sizeof(slot_type), destroy_slot);
+ }
}
- inline void dealloc() {
- assert(capacity() != 0);
+ void dealloc() {
+ ABSL_SWISSTABLE_ASSERT(capacity() > DefaultCapacity());
// Unpoison before returning the memory to the allocator.
SanitizerUnpoisonMemoryRegion(slot_array(), sizeof(slot_type) * capacity());
infoz().Unregister();
- Deallocate<BackingArrayAlignment(alignof(slot_type))>(
- &alloc_ref(), common().backing_array_start(),
- common().alloc_size(sizeof(slot_type), alignof(slot_type)));
+ DeallocateBackingArray<BackingArrayAlignment(alignof(slot_type)),
+ CharAlloc>(&char_alloc_ref(), capacity(), control(),
+ sizeof(slot_type), alignof(slot_type),
+ common().has_infoz());
}
- inline void destructor_impl() {
+ void destructor_impl() {
+ if (SwisstableGenerationsEnabled() &&
+ capacity() >= InvalidCapacity::kMovedFrom) {
+ return;
+ }
if (capacity() == 0) return;
if (is_soo()) {
if (!empty()) {
@@ -3564,141 +3126,37 @@
// This merely updates the pertinent control byte. This can be used in
// conjunction with Policy::transfer to move the object to another place.
void erase_meta_only(const_iterator it) {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
EraseMetaOnly(common(), static_cast<size_t>(it.control() - control()),
sizeof(slot_type));
}
+ template <class K>
+ size_t hash_of(const K& key) const {
+ return hash_ref()(key);
+ }
size_t hash_of(slot_type* slot) const {
return PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(slot));
}
- // Resizes table to the new capacity and move all elements to the new
- // positions accordingly.
- //
- // Note that for better performance instead of
- // find_first_non_full(common(), hash),
- // HashSetResizeHelper::FindFirstNonFullAfterResize(
- // common(), old_capacity, hash)
- // can be called right after `resize`.
- void resize(size_t new_capacity) {
- raw_hash_set::resize_impl(common(), new_capacity, HashtablezInfoHandle{});
- }
-
- // As above, except that we also accept a pre-sampled, forced infoz for
- // SOO tables, since they need to switch from SOO to heap in order to
- // store the infoz.
- void resize_with_soo_infoz(HashtablezInfoHandle forced_infoz) {
- assert(forced_infoz.IsSampled());
- raw_hash_set::resize_impl(common(), NextCapacity(SooCapacity()),
- forced_infoz);
- }
-
- // Resizes set to the new capacity.
- // It is a static function in order to use its pointer in GetPolicyFunctions.
- ABSL_ATTRIBUTE_NOINLINE static void resize_impl(
- CommonFields& common, size_t new_capacity,
- HashtablezInfoHandle forced_infoz) {
- raw_hash_set* set = reinterpret_cast<raw_hash_set*>(&common);
- assert(IsValidCapacity(new_capacity));
- assert(!set->fits_in_soo(new_capacity));
- const bool was_soo = set->is_soo();
- const bool had_soo_slot = was_soo && !set->empty();
- const ctrl_t soo_slot_h2 =
- had_soo_slot ? static_cast<ctrl_t>(H2(set->hash_of(set->soo_slot())))
- : ctrl_t::kEmpty;
- HashSetResizeHelper resize_helper(common, was_soo, had_soo_slot,
- forced_infoz);
- // Initialize HashSetResizeHelper::old_heap_or_soo_. We can't do this in
- // HashSetResizeHelper constructor because it can't transfer slots when
- // transfer_uses_memcpy is false.
- // TODO(b/289225379): try to handle more of the SOO cases inside
- // InitializeSlots. See comment on cl/555990034 snapshot #63.
- if (PolicyTraits::transfer_uses_memcpy() || !had_soo_slot) {
- resize_helper.old_heap_or_soo() = common.heap_or_soo();
- } else {
- set->transfer(set->to_slot(resize_helper.old_soo_data()),
- set->soo_slot());
- }
- common.set_capacity(new_capacity);
- // Note that `InitializeSlots` does different number initialization steps
- // depending on the values of `transfer_uses_memcpy` and capacities.
- // Refer to the comment in `InitializeSlots` for more details.
- const bool grow_single_group =
- resize_helper.InitializeSlots<CharAlloc, sizeof(slot_type),
- PolicyTraits::transfer_uses_memcpy(),
- SooEnabled(), alignof(slot_type)>(
- common, CharAlloc(set->alloc_ref()), soo_slot_h2, sizeof(key_type),
- sizeof(value_type));
-
- // In the SooEnabled() case, capacity is never 0 so we don't check.
- if (!SooEnabled() && resize_helper.old_capacity() == 0) {
- // InitializeSlots did all the work including infoz().RecordRehash().
- return;
- }
- assert(resize_helper.old_capacity() > 0);
- // Nothing more to do in this case.
- if (was_soo && !had_soo_slot) return;
-
- slot_type* new_slots = set->slot_array();
- if (grow_single_group) {
- if (PolicyTraits::transfer_uses_memcpy()) {
- // InitializeSlots did all the work.
- return;
- }
- if (was_soo) {
- set->transfer(new_slots + resize_helper.SooSlotIndex(),
- to_slot(resize_helper.old_soo_data()));
- return;
- } else {
- // We want GrowSizeIntoSingleGroup to be called here in order to make
- // InitializeSlots not depend on PolicyTraits.
- resize_helper.GrowSizeIntoSingleGroup<PolicyTraits>(common,
- set->alloc_ref());
- }
- } else {
- // InitializeSlots prepares control bytes to correspond to empty table.
- const auto insert_slot = [&](slot_type* slot) {
- size_t hash = PolicyTraits::apply(HashElement{set->hash_ref()},
- PolicyTraits::element(slot));
- auto target = find_first_non_full(common, hash);
- SetCtrl(common, target.offset, H2(hash), sizeof(slot_type));
- set->transfer(new_slots + target.offset, slot);
- return target.probe_length;
- };
- if (was_soo) {
- insert_slot(to_slot(resize_helper.old_soo_data()));
- return;
- } else {
- auto* old_slots = static_cast<slot_type*>(resize_helper.old_slots());
- size_t total_probe_length = 0;
- for (size_t i = 0; i != resize_helper.old_capacity(); ++i) {
- if (IsFull(resize_helper.old_ctrl()[i])) {
- total_probe_length += insert_slot(old_slots + i);
- }
- }
- common.infoz().RecordRehash(total_probe_length);
- }
- }
- resize_helper.DeallocateOld<alignof(slot_type)>(CharAlloc(set->alloc_ref()),
- sizeof(slot_type));
- }
-
// Casting directly from e.g. char* to slot_type* can cause compilation errors
// on objective-C. This function converts to void* first, avoiding the issue.
static slot_type* to_slot(void* buf) { return static_cast<slot_type*>(buf); }
// Requires that lhs does not have a full SOO slot.
- static void move_common(bool that_is_full_soo, allocator_type& rhs_alloc,
+ static void move_common(bool rhs_is_full_soo, CharAlloc& rhs_alloc,
CommonFields& lhs, CommonFields&& rhs) {
- if (PolicyTraits::transfer_uses_memcpy() || !that_is_full_soo) {
+ if (PolicyTraits::transfer_uses_memcpy() || !rhs_is_full_soo) {
lhs = std::move(rhs);
} else {
lhs.move_non_heap_or_soo_fields(rhs);
- // TODO(b/303305702): add reentrancy guard.
- PolicyTraits::transfer(&rhs_alloc, to_slot(lhs.soo_data()),
- to_slot(rhs.soo_data()));
+ rhs.RunWithReentrancyGuard([&] {
+ lhs.RunWithReentrancyGuard([&] {
+ PolicyTraits::transfer(&rhs_alloc, to_slot(lhs.soo_data()),
+ to_slot(rhs.soo_data()));
+ });
+ });
}
}
@@ -3710,21 +3168,33 @@
swap(common(), that.common());
return;
}
- CommonFields tmp = CommonFields::CreateDefault<SooEnabled()>();
+ CommonFields tmp = CommonFields(uninitialized_tag_t{});
const bool that_is_full_soo = that.is_full_soo();
- move_common(that_is_full_soo, that.alloc_ref(), tmp,
+ move_common(that_is_full_soo, that.char_alloc_ref(), tmp,
std::move(that.common()));
- move_common(is_full_soo(), alloc_ref(), that.common(), std::move(common()));
- move_common(that_is_full_soo, that.alloc_ref(), common(), std::move(tmp));
+ move_common(is_full_soo(), char_alloc_ref(), that.common(),
+ std::move(common()));
+ move_common(that_is_full_soo, that.char_alloc_ref(), common(),
+ std::move(tmp));
}
- void maybe_increment_generation_or_rehash_on_move() {
- if (!SwisstableGenerationsEnabled() || capacity() == 0 || is_soo()) {
+ void annotate_for_bug_detection_on_move(
+ [[maybe_unused]] raw_hash_set& that) {
+ // We only enable moved-from validation when generations are enabled (rather
+ // than using NDEBUG) to avoid issues in which NDEBUG is enabled in some
+ // translation units but not in others.
+ if (SwisstableGenerationsEnabled()) {
+ that.common().set_capacity(this == &that ? InvalidCapacity::kSelfMovedFrom
+ : InvalidCapacity::kMovedFrom);
+ }
+ if (!SwisstableGenerationsEnabled() || capacity() == DefaultCapacity() ||
+ capacity() > kAboveMaxValidCapacity) {
return;
}
common().increment_generation();
if (!empty() && common().should_rehash_for_bug_detection_on_move()) {
- resize(capacity());
+ ResizeAllocatedTableWithSeedChange(common(), GetPolicyFunctions(),
+ capacity());
}
}
@@ -3733,15 +3203,14 @@
// We don't bother checking for this/that aliasing. We just need to avoid
// breaking the invariants in that case.
destructor_impl();
- move_common(that.is_full_soo(), that.alloc_ref(), common(),
+ move_common(that.is_full_soo(), that.char_alloc_ref(), common(),
std::move(that.common()));
- // TODO(b/296061262): move instead of copying hash/eq/alloc.
hash_ref() = that.hash_ref();
eq_ref() = that.eq_ref();
- CopyAlloc(alloc_ref(), that.alloc_ref(),
+ CopyAlloc(char_alloc_ref(), that.char_alloc_ref(),
std::integral_constant<bool, propagate_alloc>());
that.common() = CommonFields::CreateDefault<SooEnabled()>();
- maybe_increment_generation_or_rehash_on_move();
+ annotate_for_bug_detection_on_move(that);
return *this;
}
@@ -3755,7 +3224,7 @@
}
if (!that.is_soo()) that.dealloc();
that.common() = CommonFields::CreateDefault<SooEnabled()>();
- maybe_increment_generation_or_rehash_on_move();
+ annotate_for_bug_detection_on_move(that);
return *this;
}
@@ -3765,7 +3234,7 @@
}
raw_hash_set& move_assign(raw_hash_set&& that,
std::false_type /*propagate_alloc*/) {
- if (alloc_ref() == that.alloc_ref()) {
+ if (char_alloc_ref() == that.char_alloc_ref()) {
return assign_impl<false>(std::move(that));
}
// Aliasing can't happen here because allocs would compare equal above.
@@ -3774,7 +3243,6 @@
// We can't take over that's memory so we need to move each element.
// While moving elements, this should have that's hash/eq so copy hash/eq
// before moving elements.
- // TODO(b/296061262): move instead of copying hash/eq.
hash_ref() = that.hash_ref();
eq_ref() = that.eq_ref();
return move_elements_allocs_unequal(std::move(that));
@@ -3782,35 +3250,42 @@
template <class K>
std::pair<iterator, bool> find_or_prepare_insert_soo(const K& key) {
+ ctrl_t soo_slot_ctrl;
if (empty()) {
- const HashtablezInfoHandle infoz = try_sample_soo();
- if (infoz.IsSampled()) {
- resize_with_soo_infoz(infoz);
- } else {
+ if (!should_sample_soo()) {
common().set_full_soo();
return {soo_iterator(), true};
}
+ soo_slot_ctrl = ctrl_t::kEmpty;
} else if (PolicyTraits::apply(EqualElement<K>{key, eq_ref()},
PolicyTraits::element(soo_slot()))) {
return {soo_iterator(), false};
} else {
- resize(NextCapacity(SooCapacity()));
+ soo_slot_ctrl = static_cast<ctrl_t>(H2(hash_of(soo_slot())));
}
- const size_t index =
- PrepareInsertAfterSoo(hash_ref()(key), sizeof(slot_type), common());
+ constexpr bool kUseMemcpy =
+ PolicyTraits::transfer_uses_memcpy() && SooEnabled();
+ size_t index = GrowSooTableToNextCapacityAndPrepareInsert<
+ kUseMemcpy ? OptimalMemcpySizeForSooSlotTransfer(sizeof(slot_type)) : 0,
+ kUseMemcpy>(common(), GetPolicyFunctions(), hash_of(key),
+ soo_slot_ctrl);
return {iterator_at(index), true};
}
template <class K>
std::pair<iterator, bool> find_or_prepare_insert_non_soo(const K& key) {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
prefetch_heap_block();
- auto hash = hash_ref()(key);
+ const size_t hash = hash_of(key);
auto seq = probe(common(), hash);
+ const h2_t h2 = H2(hash);
const ctrl_t* ctrl = control();
while (true) {
+#ifndef ABSL_HAVE_MEMORY_SANITIZER
+ absl::PrefetchToLocalCache(slot_array() + seq.offset());
+#endif
Group g{ctrl + seq.offset()};
- for (uint32_t i : g.Match(H2(hash))) {
+ for (uint32_t i : g.Match(h2)) {
if (ABSL_PREDICT_TRUE(PolicyTraits::apply(
EqualElement<K>{key, eq_ref()},
PolicyTraits::element(slot_array() + seq.offset(i)))))
@@ -3818,50 +3293,86 @@
}
auto mask_empty = g.MaskEmpty();
if (ABSL_PREDICT_TRUE(mask_empty)) {
- size_t target = seq.offset(
- GetInsertionOffset(mask_empty, capacity(), hash, control()));
- return {iterator_at(PrepareInsertNonSoo(common(), hash,
- FindInfo{target, seq.index()},
- GetPolicyFunctions())),
+ size_t target = seq.offset(mask_empty.LowestBitSet());
+ return {iterator_at(PrepareInsertNonSoo(common(), GetPolicyFunctions(),
+ hash,
+ FindInfo{target, seq.index()})),
true};
}
seq.next();
- assert(seq.index() <= capacity() && "full table!");
+ ABSL_SWISSTABLE_ASSERT(seq.index() <= capacity() && "full table!");
}
}
protected:
+ // Asserts for correctness that we run on find/find_or_prepare_insert.
+ template <class K>
+ void AssertOnFind([[maybe_unused]] const K& key) {
+ AssertHashEqConsistent(key);
+ AssertNotDebugCapacity();
+ }
+
+ // Asserts that the capacity is not a sentinel invalid value.
+ void AssertNotDebugCapacity() const {
+#ifdef NDEBUG
+ if (!SwisstableGenerationsEnabled()) {
+ return;
+ }
+#endif
+ if (ABSL_PREDICT_TRUE(capacity() <
+ InvalidCapacity::kAboveMaxValidCapacity)) {
+ return;
+ }
+ assert(capacity() != InvalidCapacity::kReentrance &&
+ "Reentrant container access during element construction/destruction "
+ "is not allowed.");
+ if constexpr (SwisstableAssertAccessToDestroyedTable()) {
+ if (capacity() == InvalidCapacity::kDestroyed) {
+ ABSL_RAW_LOG(FATAL, "Use of destroyed hash table.");
+ }
+ }
+ if (SwisstableGenerationsEnabled() &&
+ ABSL_PREDICT_FALSE(capacity() >= InvalidCapacity::kMovedFrom)) {
+ if (capacity() == InvalidCapacity::kSelfMovedFrom) {
+ // If this log triggers, then a hash table was move-assigned to itself
+ // and then used again later without being reinitialized.
+ ABSL_RAW_LOG(FATAL, "Use of self-move-assigned hash table.");
+ }
+ ABSL_RAW_LOG(FATAL, "Use of moved-from hash table.");
+ }
+ }
+
// Asserts that hash and equal functors provided by the user are consistent,
// meaning that `eq(k1, k2)` implies `hash(k1)==hash(k2)`.
template <class K>
- void AssertHashEqConsistent(ABSL_ATTRIBUTE_UNUSED const K& key) {
-#ifndef NDEBUG
+ void AssertHashEqConsistent(const K& key) {
+#ifdef NDEBUG
+ return;
+#endif
+ // If the hash/eq functors are known to be consistent, then skip validation.
+ if (std::is_same<hasher, absl::container_internal::StringHash>::value &&
+ std::is_same<key_equal, absl::container_internal::StringEq>::value) {
+ return;
+ }
+ if (std::is_scalar<key_type>::value &&
+ std::is_same<hasher, absl::Hash<key_type>>::value &&
+ std::is_same<key_equal, std::equal_to<key_type>>::value) {
+ return;
+ }
if (empty()) return;
- const size_t hash_of_arg = hash_ref()(key);
- const auto assert_consistent = [&](const ctrl_t*, slot_type* slot) {
- const value_type& element = PolicyTraits::element(slot);
+ const size_t hash_of_arg = hash_of(key);
+ const auto assert_consistent = [&](const ctrl_t*, void* slot) {
+ const value_type& element =
+ PolicyTraits::element(static_cast<slot_type*>(slot));
const bool is_key_equal =
PolicyTraits::apply(EqualElement<K>{key, eq_ref()}, element);
if (!is_key_equal) return;
const size_t hash_of_slot =
PolicyTraits::apply(HashElement{hash_ref()}, element);
- const bool is_hash_equal = hash_of_arg == hash_of_slot;
- if (!is_hash_equal) {
- // In this case, we're going to crash. Do a couple of other checks for
- // idempotence issues. Recalculating hash/eq here is also convenient for
- // debugging with gdb/lldb.
- const size_t once_more_hash_arg = hash_ref()(key);
- assert(hash_of_arg == once_more_hash_arg && "hash is not idempotent.");
- const size_t once_more_hash_slot =
- PolicyTraits::apply(HashElement{hash_ref()}, element);
- assert(hash_of_slot == once_more_hash_slot &&
- "hash is not idempotent.");
- const bool once_more_eq =
- PolicyTraits::apply(EqualElement<K>{key, eq_ref()}, element);
- assert(is_key_equal == once_more_eq && "equality is not idempotent.");
- }
+ [[maybe_unused]] const bool is_hash_equal =
+ hash_of_arg == hash_of_slot;
assert((!is_key_equal || is_hash_equal) &&
"eq(k1, k2) must imply that hash(k1) == hash(k2). "
"hash/eq functors are inconsistent.");
@@ -3873,8 +3384,7 @@
}
// We only do validation for small tables so that it's constant time.
if (capacity() > 16) return;
- IterateOverFullSlots(common(), slot_array(), assert_consistent);
-#endif
+ IterateOverFullSlots(common(), sizeof(slot_type), assert_consistent);
}
// Attempts to find `key` in the table; if it isn't found, returns an iterator
@@ -3882,7 +3392,7 @@
// `key`'s H2. Returns a bool indicating whether an insertion can take place.
template <class K>
std::pair<iterator, bool> find_or_prepare_insert(const K& key) {
- AssertHashEqConsistent(key);
+ AssertOnFind(key);
if (is_soo()) return find_or_prepare_insert_soo(key);
return find_or_prepare_insert_non_soo(key);
}
@@ -3899,7 +3409,10 @@
void emplace_at(iterator iter, Args&&... args) {
construct(iter.slot(), std::forward<Args>(args)...);
- assert(PolicyTraits::apply(FindElement{*this}, *iter) == iter &&
+ // When capacity is 1, find calls find_small and if size is 0, then it will
+ // return an end iterator. This can happen in the raw_hash_set copy ctor.
+ assert((capacity() == 1 ||
+ PolicyTraits::apply(FindElement{*this}, *iter) == iter) &&
"constructed value does not match the lookup key");
}
@@ -3926,16 +3439,16 @@
//
// See `CapacityToGrowth()`.
size_t growth_left() const {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return common().growth_left();
}
GrowthInfo& growth_info() {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return common().growth_info();
}
GrowthInfo growth_info() const {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return common().growth_info();
}
@@ -3943,7 +3456,7 @@
// cache misses. This is intended to overlap with execution of calculating the
// hash for a key.
void prefetch_heap_block() const {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
__builtin_prefetch(control(), 0, 1);
#endif
@@ -3953,19 +3466,21 @@
const CommonFields& common() const { return settings_.template get<0>(); }
ctrl_t* control() const {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return common().control();
}
slot_type* slot_array() const {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return static_cast<slot_type*>(common().slot_array());
}
slot_type* soo_slot() {
- assert(is_soo());
- return static_cast<slot_type*>(common().soo_data());
+ ABSL_SWISSTABLE_ASSERT(is_soo());
+ ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(
+ static_cast<slot_type*>(common().soo_data()));
}
const slot_type* soo_slot() const {
- return const_cast<raw_hash_set*>(this)->soo_slot();
+ ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN(
+ const_cast<raw_hash_set*>(this)->soo_slot());
}
iterator soo_iterator() {
return {SooControl(), soo_slot(), common().generation_ptr()};
@@ -3973,8 +3488,22 @@
const_iterator soo_iterator() const {
return const_cast<raw_hash_set*>(this)->soo_iterator();
}
+ slot_type* single_slot() {
+ ABSL_SWISSTABLE_ASSERT(capacity() <= 1);
+ return SooEnabled() ? soo_slot() : slot_array();
+ }
+ const slot_type* single_slot() const {
+ return const_cast<raw_hash_set*>(this)->single_slot();
+ }
+ iterator single_iterator() {
+ return {SooEnabled() ? SooControl() : control(), single_slot(),
+ common().generation_ptr()};
+ }
+ const_iterator single_iterator() const {
+ return const_cast<raw_hash_set*>(this)->single_iterator();
+ }
HashtablezInfoHandle infoz() {
- assert(!is_soo());
+ ABSL_SWISSTABLE_ASSERT(!is_soo());
return common().infoz();
}
@@ -3982,49 +3511,118 @@
const hasher& hash_ref() const { return settings_.template get<1>(); }
key_equal& eq_ref() { return settings_.template get<2>(); }
const key_equal& eq_ref() const { return settings_.template get<2>(); }
- allocator_type& alloc_ref() { return settings_.template get<3>(); }
- const allocator_type& alloc_ref() const {
+ CharAlloc& char_alloc_ref() { return settings_.template get<3>(); }
+ const CharAlloc& char_alloc_ref() const {
return settings_.template get<3>();
}
- static const void* get_hash_ref_fn(const CommonFields& common) {
- auto* h = reinterpret_cast<const raw_hash_set*>(&common);
- return &h->hash_ref();
+ static void* get_char_alloc_ref_fn(CommonFields& common) {
+ auto* h = reinterpret_cast<raw_hash_set*>(&common);
+ return &h->char_alloc_ref();
}
- static void transfer_slot_fn(void* set, void* dst, void* src) {
+ static void* get_hash_ref_fn(CommonFields& common) {
+ auto* h = reinterpret_cast<raw_hash_set*>(&common);
+ // TODO(b/397453582): Remove support for const hasher.
+ return const_cast<std::remove_const_t<hasher>*>(&h->hash_ref());
+ }
+ static void transfer_n_slots_fn(void* set, void* dst, void* src,
+ size_t count) {
+ auto* src_slot = to_slot(src);
+ auto* dst_slot = to_slot(dst);
+
auto* h = static_cast<raw_hash_set*>(set);
- h->transfer(static_cast<slot_type*>(dst), static_cast<slot_type*>(src));
+ for (; count > 0; --count, ++src_slot, ++dst_slot) {
+ h->transfer(dst_slot, src_slot);
+ }
}
- // Note: dealloc_fn will only be used if we have a non-standard allocator.
- static void dealloc_fn(CommonFields& common, const PolicyFunctions&) {
+
+ // TODO(b/382423690): Try to type erase entire function or at least type erase
+ // by GetKey + Hash for memcpyable types.
+ // TODO(b/382423690): Try to type erase for big slots: sizeof(slot_type) > 16.
+ static void transfer_unprobed_elements_to_next_capacity_fn(
+ CommonFields& common, const ctrl_t* old_ctrl, void* old_slots,
+ void* probed_storage,
+ void (*encode_probed_element)(void* probed_storage, h2_t h2,
+ size_t source_offset, size_t h1)) {
+ const size_t new_capacity = common.capacity();
+ const size_t old_capacity = PreviousCapacity(new_capacity);
+ ABSL_ASSUME(old_capacity + 1 >= Group::kWidth);
+ ABSL_ASSUME((old_capacity + 1) % Group::kWidth == 0);
+
auto* set = reinterpret_cast<raw_hash_set*>(&common);
+ slot_type* old_slots_ptr = to_slot(old_slots);
+ ctrl_t* new_ctrl = common.control();
+ slot_type* new_slots = set->slot_array();
- // Unpoison before returning the memory to the allocator.
- SanitizerUnpoisonMemoryRegion(common.slot_array(),
- sizeof(slot_type) * common.capacity());
+ const PerTableSeed seed = common.seed();
- common.infoz().Unregister();
- Deallocate<BackingArrayAlignment(alignof(slot_type))>(
- &set->alloc_ref(), common.backing_array_start(),
- common.alloc_size(sizeof(slot_type), alignof(slot_type)));
+ for (size_t group_index = 0; group_index < old_capacity;
+ group_index += Group::kWidth) {
+ GroupFullEmptyOrDeleted old_g(old_ctrl + group_index);
+ std::memset(new_ctrl + group_index, static_cast<int8_t>(ctrl_t::kEmpty),
+ Group::kWidth);
+ std::memset(new_ctrl + group_index + old_capacity + 1,
+ static_cast<int8_t>(ctrl_t::kEmpty), Group::kWidth);
+ // TODO(b/382423690): try to type erase everything outside of the loop.
+ // We will share a lot of code in expense of one function call per group.
+ for (auto in_fixed_group_index : old_g.MaskFull()) {
+ size_t old_index = group_index + in_fixed_group_index;
+ slot_type* old_slot = old_slots_ptr + old_index;
+ // TODO(b/382423690): try to avoid entire hash calculation since we need
+ // only one new bit of h1.
+ size_t hash = set->hash_of(old_slot);
+ size_t h1 = H1(hash, seed);
+ h2_t h2 = H2(hash);
+ size_t new_index = TryFindNewIndexWithoutProbing(
+ h1, old_index, old_capacity, new_ctrl, new_capacity);
+ // Note that encode_probed_element is allowed to use old_ctrl buffer
+ // till and included the old_index.
+ if (ABSL_PREDICT_FALSE(new_index == kProbedElementIndexSentinel)) {
+ encode_probed_element(probed_storage, h2, old_index, h1);
+ continue;
+ }
+ ABSL_SWISSTABLE_ASSERT((new_index & old_capacity) <= old_index);
+ ABSL_SWISSTABLE_ASSERT(IsEmpty(new_ctrl[new_index]));
+ new_ctrl[new_index] = static_cast<ctrl_t>(h2);
+ auto* new_slot = new_slots + new_index;
+ SanitizerUnpoisonMemoryRegion(new_slot, sizeof(slot_type));
+ set->transfer(new_slot, old_slot);
+ SanitizerPoisonMemoryRegion(old_slot, sizeof(slot_type));
+ }
+ }
}
static const PolicyFunctions& GetPolicyFunctions() {
+ static_assert(sizeof(slot_type) <= (std::numeric_limits<uint32_t>::max)(),
+ "Slot size is too large. Use std::unique_ptr for value type "
+ "or use absl::node_hash_{map,set}.");
+ static_assert(alignof(slot_type) <=
+ size_t{(std::numeric_limits<uint16_t>::max)()});
+ static_assert(sizeof(key_type) <=
+ size_t{(std::numeric_limits<uint32_t>::max)()});
+ static_assert(sizeof(value_type) <=
+ size_t{(std::numeric_limits<uint32_t>::max)()});
+ static constexpr size_t kBackingArrayAlignment =
+ BackingArrayAlignment(alignof(slot_type));
static constexpr PolicyFunctions value = {
- sizeof(slot_type),
+ static_cast<uint32_t>(sizeof(key_type)),
+ static_cast<uint32_t>(sizeof(value_type)),
+ static_cast<uint32_t>(sizeof(slot_type)),
+ static_cast<uint16_t>(alignof(slot_type)), SooEnabled(),
+ ShouldSampleHashtablezInfoForAlloc<CharAlloc>(),
// TODO(b/328722020): try to type erase
// for standard layout and alignof(Hash) <= alignof(CommonFields).
- std::is_empty<hasher>::value ? &GetHashRefForEmptyHasher
- : &raw_hash_set::get_hash_ref_fn,
+ std::is_empty_v<hasher> ? &GetRefForEmptyClass
+ : &raw_hash_set::get_hash_ref_fn,
PolicyTraits::template get_hash_slot_fn<hasher>(),
PolicyTraits::transfer_uses_memcpy()
- ? TransferRelocatable<sizeof(slot_type)>
- : &raw_hash_set::transfer_slot_fn,
- (std::is_same<SlotAlloc, std::allocator<slot_type>>::value
- ? &DeallocateStandard<alignof(slot_type)>
- : &raw_hash_set::dealloc_fn),
- &raw_hash_set::resize_impl,
- };
+ ? TransferNRelocatable<sizeof(slot_type)>
+ : &raw_hash_set::transfer_n_slots_fn,
+ std::is_empty_v<Alloc> ? &GetRefForEmptyClass
+ : &raw_hash_set::get_char_alloc_ref_fn,
+ &AllocateBackingArray<kBackingArrayAlignment, CharAlloc>,
+ &DeallocateBackingArray<kBackingArrayAlignment, CharAlloc>,
+ &raw_hash_set::transfer_unprobed_elements_to_next_capacity_fn};
return value;
}
@@ -4032,9 +3630,9 @@
// CompressedTuple will ensure that sizeof is not affected by any of the empty
// fields that occur after CommonFields.
absl::container_internal::CompressedTuple<CommonFields, hasher, key_equal,
- allocator_type>
+ CharAlloc>
settings_{CommonFields::CreateDefault<SooEnabled()>(), hasher{},
- key_equal{}, allocator_type{}};
+ key_equal{}, CharAlloc{}};
};
// Friend access for free functions in raw_hash_set.h.
@@ -4047,17 +3645,21 @@
if (c->is_soo()) {
auto it = c->soo_iterator();
if (!pred(*it)) {
- assert(c->size() == 1 && "hash table was modified unexpectedly");
+ ABSL_SWISSTABLE_ASSERT(c->size() == 1 &&
+ "hash table was modified unexpectedly");
return 0;
}
c->destroy(it.slot());
c->common().set_empty_soo();
return 1;
}
- ABSL_ATTRIBUTE_UNUSED const size_t original_size_for_assert = c->size();
+ [[maybe_unused]] const size_t original_size_for_assert = c->size();
size_t num_deleted = 0;
+ using SlotType = typename Set::slot_type;
IterateOverFullSlots(
- c->common(), c->slot_array(), [&](const ctrl_t* ctrl, auto* slot) {
+ c->common(), sizeof(SlotType),
+ [&](const ctrl_t* ctrl, void* slot_void) {
+ auto* slot = static_cast<SlotType*>(slot_void);
if (pred(Set::PolicyTraits::element(slot))) {
c->destroy(slot);
EraseMetaOnly(c->common(), static_cast<size_t>(ctrl - c->control()),
@@ -4067,8 +3669,9 @@
});
// NOTE: IterateOverFullSlots allow removal of the current element, so we
// verify the size additionally here.
- assert(original_size_for_assert - num_deleted == c->size() &&
- "hash table was modified unexpectedly");
+ ABSL_SWISSTABLE_ASSERT(original_size_for_assert - num_deleted ==
+ c->size() &&
+ "hash table was modified unexpectedly");
return num_deleted;
}
@@ -4081,10 +3684,12 @@
cb(*c->soo_iterator());
return;
}
+ using SlotType = typename Set::slot_type;
using ElementTypeWithConstness = decltype(*c->begin());
IterateOverFullSlots(
- c->common(), c->slot_array(), [&cb](const ctrl_t*, auto* slot) {
- ElementTypeWithConstness& element = Set::PolicyTraits::element(slot);
+ c->common(), sizeof(SlotType), [&cb](const ctrl_t*, void* slot) {
+ ElementTypeWithConstness& element =
+ Set::PolicyTraits::element(static_cast<SlotType*>(slot));
cb(element);
});
}
@@ -4117,12 +3722,13 @@
const typename Set::key_type& key) {
if (set.is_soo()) return 0;
size_t num_probes = 0;
- size_t hash = set.hash_ref()(key);
+ const size_t hash = set.hash_of(key);
auto seq = probe(set.common(), hash);
+ const h2_t h2 = H2(hash);
const ctrl_t* ctrl = set.control();
while (true) {
container_internal::Group g{ctrl + seq.offset()};
- for (uint32_t i : g.Match(container_internal::H2(hash))) {
+ for (uint32_t i : g.Match(h2)) {
if (Traits::apply(
typename Set::template EqualElement<typename Set::key_type>{
key, set.eq_ref()},
@@ -4155,6 +3761,22 @@
};
} // namespace hashtable_debug_internal
+
+// Extern template instantiations reduce binary size and linker input size.
+// Function definition is in raw_hash_set.cc.
+extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<0, false>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<1, true>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<4, true>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<8, true>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+#if UINTPTR_MAX == UINT64_MAX
+extern template size_t GrowSooTableToNextCapacityAndPrepareInsert<16, true>(
+ CommonFields&, const PolicyFunctions&, size_t, ctrl_t);
+#endif
+
} // namespace container_internal
ABSL_NAMESPACE_END
} // namespace absl
@@ -4162,5 +3784,6 @@
#undef ABSL_SWISSTABLE_ENABLE_GENERATIONS
#undef ABSL_SWISSTABLE_IGNORE_UNINITIALIZED
#undef ABSL_SWISSTABLE_IGNORE_UNINITIALIZED_RETURN
+#undef ABSL_SWISSTABLE_ASSERT
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
diff --git a/absl/container/internal/raw_hash_set_benchmark.cc b/absl/container/internal/raw_hash_set_benchmark.cc
index 424b72c..ac94877 100644
--- a/absl/container/internal/raw_hash_set_benchmark.cc
+++ b/absl/container/internal/raw_hash_set_benchmark.cc
@@ -172,8 +172,7 @@
//
// On a table of size N, keep deleting the LRU entry and add a random one.
void BM_CacheInSteadyState(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
string_generator gen{12};
StringTable t;
std::deque<std::string> keys;
@@ -250,8 +249,7 @@
BENCHMARK(BM_EndComparison);
void BM_Iteration(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
string_generator gen{12};
StringTable t;
@@ -293,8 +291,7 @@
->ArgPair(1000, 10);
void BM_CopyCtorSparseInt(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
IntTable t;
std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
@@ -312,8 +309,7 @@
BENCHMARK(BM_CopyCtorSparseInt)->Range(1, 4096);
void BM_CopyCtorInt(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
IntTable t;
std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
@@ -330,8 +326,7 @@
BENCHMARK(BM_CopyCtorInt)->Range(0, 4096);
void BM_CopyCtorString(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
StringTable t;
std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
@@ -348,8 +343,7 @@
BENCHMARK(BM_CopyCtorString)->Range(0, 4096);
void BM_CopyAssign(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
IntTable t;
std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
while (t.size() < state.range(0)) {
@@ -365,8 +359,7 @@
BENCHMARK(BM_CopyAssign)->Range(128, 4096);
void BM_RangeCtor(benchmark::State& state) {
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
std::uniform_int_distribution<uint64_t> dist(0, ~uint64_t{});
std::vector<int> values;
const size_t desired_size = state.range(0);
@@ -418,7 +411,17 @@
}
}
}
-BENCHMARK(BM_ReserveIntTable)->Range(1, 64);
+BENCHMARK(BM_ReserveIntTable)
+ ->Arg(1)
+ ->Arg(2)
+ ->Arg(4)
+ ->Arg(8)
+ ->Arg(16)
+ ->Arg(32)
+ ->Arg(64)
+ ->Arg(128)
+ ->Arg(256)
+ ->Arg(512);
void BM_ReserveStringTable(benchmark::State& state) {
constexpr size_t kBatchSize = 1024;
@@ -437,7 +440,17 @@
}
}
}
-BENCHMARK(BM_ReserveStringTable)->Range(1, 64);
+BENCHMARK(BM_ReserveStringTable)
+ ->Arg(1)
+ ->Arg(2)
+ ->Arg(4)
+ ->Arg(8)
+ ->Arg(16)
+ ->Arg(32)
+ ->Arg(64)
+ ->Arg(128)
+ ->Arg(256)
+ ->Arg(512);
// Like std::iota, except that ctrl_t doesn't support operator++.
template <typename CtrlIter>
diff --git a/absl/container/internal/raw_hash_set_probe_benchmark.cc b/absl/container/internal/raw_hash_set_probe_benchmark.cc
index 8f36305..e56648f 100644
--- a/absl/container/internal/raw_hash_set_probe_benchmark.cc
+++ b/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -245,13 +245,28 @@
}
};
-constexpr char kStringFormat[] = "/path/to/file/name-%07d-of-9999999.txt";
+enum class StringSize { kSmall, kMedium, kLarge, kExtraLarge };
+constexpr char kStringFormat[] = "%s/name-%07d-of-9999999.txt";
-template <bool small>
+template <StringSize size>
struct String {
std::string value;
static std::string Make(uint32_t v) {
- return {small ? absl::StrCat(v) : absl::StrFormat(kStringFormat, v)};
+ switch (size) {
+ case StringSize::kSmall:
+ return absl::StrCat(v);
+ case StringSize::kMedium: // < 32 bytes
+ return absl::StrFormat(kStringFormat, "/path", v);
+ case StringSize::kLarge: // 33-64 bytes
+ return absl::StrFormat(kStringFormat, "/path/to/file", v);
+ case StringSize::kExtraLarge: // > 64 bytes
+ return absl::StrFormat(kStringFormat,
+ "/path/to/a/very/long/file/name/so/that/total/"
+ "length/is/larger/than/64/bytes",
+ v);
+ default:
+ return "";
+ }
}
};
@@ -285,10 +300,9 @@
mutable uintptr_t current = PointerForAlignment<Align>();
};
-
-template <bool small>
-struct Sequential<String<small>> {
- std::string operator()() const { return String<small>::Make(current++); }
+template <StringSize size>
+struct Sequential<String<size>> {
+ std::string operator()() const { return String<size>::Make(current++); }
mutable uint32_t current = 0;
};
@@ -389,10 +403,10 @@
}
};
-template <class Dist, bool small>
-struct Random<String<small>, Dist> {
+template <class Dist, StringSize size>
+struct Random<String<size>, Dist> {
std::string operator()() const {
- return String<small>::Make(Random<uint32_t, Dist>{}());
+ return String<size>::Make(Random<uint32_t, Dist>{}());
}
};
@@ -421,9 +435,20 @@
return absl::StrCat("PtrIdentity", Align);
}
-template <bool small>
-std::string Name(String<small>*) {
- return small ? "StrS" : "StrL";
+template <StringSize size>
+std::string Name(String<size>*) {
+ switch (size) {
+ case StringSize::kSmall:
+ return "StrS";
+ case StringSize::kMedium:
+ return "StrM";
+ case StringSize::kLarge:
+ return "StrL";
+ case StringSize::kExtraLarge:
+ return "StrXL";
+ default:
+ return "";
+ }
}
template <class T, class U>
@@ -543,12 +568,18 @@
RunForType<PtrIdentity<32>>(results);
RunForType<PtrIdentity<64>>(results);
RunForType<std::pair<uint32_t, uint32_t>>(results);
- RunForType<String<true>>(results);
- RunForType<String<false>>(results);
- RunForType<std::pair<uint64_t, String<true>>>(results);
- RunForType<std::pair<String<true>, uint64_t>>(results);
- RunForType<std::pair<uint64_t, String<false>>>(results);
- RunForType<std::pair<String<false>, uint64_t>>(results);
+ RunForType<String<StringSize::kSmall>>(results);
+ RunForType<String<StringSize::kMedium>>(results);
+ RunForType<String<StringSize::kLarge>>(results);
+ RunForType<String<StringSize::kExtraLarge>>(results);
+ RunForType<std::pair<uint64_t, String<StringSize::kSmall>>>(results);
+ RunForType<std::pair<String<StringSize::kSmall>, uint64_t>>(results);
+ RunForType<std::pair<uint64_t, String<StringSize::kMedium>>>(results);
+ RunForType<std::pair<String<StringSize::kMedium>, uint64_t>>(results);
+ RunForType<std::pair<uint64_t, String<StringSize::kLarge>>>(results);
+ RunForType<std::pair<String<StringSize::kLarge>, uint64_t>>(results);
+ RunForType<std::pair<uint64_t, String<StringSize::kExtraLarge>>>(results);
+ RunForType<std::pair<String<StringSize::kExtraLarge>, uint64_t>>(results);
switch (output()) {
case OutputStyle::kRegular:
diff --git a/absl/container/internal/raw_hash_set_resize_impl.h b/absl/container/internal/raw_hash_set_resize_impl.h
new file mode 100644
index 0000000..149d9e8
--- /dev/null
+++ b/absl/container/internal/raw_hash_set_resize_impl.h
@@ -0,0 +1,80 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// This is a private implementation detail of resize algorithm of
+// raw_hash_set. It is exposed in a separate file for testing purposes.
+
+#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_RESIZE_IMPL_H_
+#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_RESIZE_IMPL_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+
+// Encoding for probed elements used for smaller tables.
+// Data is encoded into single integer.
+// Storage format for 4 bytes:
+// - 7 bits for h2
+// - 12 bits for source_offset
+// - 13 bits for h1
+// Storage format for 8 bytes:
+// - 7 bits for h2
+// - 28 bits for source_offset
+// - 29 bits for h1
+// Storage format for 16 bytes:
+// - 7 bits for h2
+// - 57 bits for source_offset
+// - 58 bits for h1
+template <typename IntType, size_t kTotalBits>
+struct ProbedItemImpl {
+ static constexpr IntType kH2Bits = 7;
+
+ static constexpr IntType kMaxOldBits = (kTotalBits - kH2Bits) / 2;
+ static constexpr IntType kMaxOldCapacity = (IntType{1} << kMaxOldBits) - 1;
+
+ // We always have one bit more for h1.
+ static constexpr IntType kMaxNewBits = kMaxOldBits + 1;
+ static constexpr IntType kMaxNewCapacity = (IntType{1} << kMaxNewBits) - 1;
+
+ static constexpr IntType kH2Shift = (kTotalBits - kH2Bits);
+ static_assert(kMaxNewBits + kMaxOldBits + kH2Bits == kTotalBits);
+
+ ProbedItemImpl() = default;
+ ProbedItemImpl(uint8_t h2_arg, size_t source_offset_arg, size_t h1_arg)
+ : h2(h2_arg),
+ source_offset(static_cast<IntType>(source_offset_arg)),
+ h1(static_cast<IntType>(h1_arg)) {}
+
+ IntType h2 : kH2Bits;
+ IntType source_offset : kMaxOldBits;
+ IntType h1 : kMaxNewBits;
+};
+
+using ProbedItem4Bytes = ProbedItemImpl<uint32_t, 32>;
+static_assert(sizeof(ProbedItem4Bytes) == 4);
+using ProbedItem8Bytes = ProbedItemImpl<uint64_t, 64>;
+static_assert(sizeof(ProbedItem8Bytes) == 8);
+using ProbedItem16Bytes = ProbedItemImpl<uint64_t, 7 + 57 + 58>;
+static_assert(sizeof(ProbedItem16Bytes) == 16);
+
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_RESIZE_IMPL_H_
diff --git a/absl/container/internal/raw_hash_set_resize_impl_test.cc b/absl/container/internal/raw_hash_set_resize_impl_test.cc
new file mode 100644
index 0000000..5020fca
--- /dev/null
+++ b/absl/container/internal/raw_hash_set_resize_impl_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/container/internal/raw_hash_set_resize_impl.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace container_internal {
+namespace {
+
+constexpr size_t kSmallSourceOffset = 17;
+constexpr size_t kSmallH1 = 25;
+
+template <class Encoder>
+class EncoderTest : public testing::Test {};
+
+using ProbedItemTypes =
+ ::testing::Types<ProbedItem4Bytes, ProbedItem8Bytes, ProbedItem16Bytes>;
+TYPED_TEST_SUITE(EncoderTest, ProbedItemTypes);
+
+TYPED_TEST(EncoderTest, EncodeDecodeSmall) {
+ using ProbedItem = TypeParam;
+ for (uint8_t h2 = 0; h2 < 128; ++h2) {
+ ProbedItem item(h2, kSmallSourceOffset, kSmallH1);
+ EXPECT_EQ(item.h2, h2);
+ EXPECT_EQ(item.source_offset, kSmallSourceOffset);
+ EXPECT_EQ(item.h1 & ProbedItem::kMaxNewCapacity, kSmallH1);
+ }
+}
+
+TYPED_TEST(EncoderTest, EncodeDecodeMax) {
+ using ProbedItem = TypeParam;
+ for (uint8_t h2 = 0; h2 < 128; ++h2) {
+ size_t source_offset = static_cast<size_t>(std::min<uint64_t>(
+ ProbedItem::kMaxOldCapacity, (std::numeric_limits<size_t>::max)()));
+ size_t h1 = static_cast<size_t>(std::min<uint64_t>(
+ ProbedItem::kMaxNewCapacity, (std::numeric_limits<size_t>::max)()));
+ ProbedItem item(h2, source_offset, h1);
+ EXPECT_EQ(item.h2, h2);
+ EXPECT_EQ(item.source_offset, source_offset);
+ EXPECT_EQ(item.h1 & ProbedItem::kMaxNewCapacity, h1);
+ }
+}
+
+} // namespace
+} // namespace container_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index f1257d4..9a323c4 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -17,19 +17,23 @@
#include <algorithm>
#include <array>
#include <atomic>
+#include <bitset>
#include <cmath>
#include <cstddef>
#include <cstdint>
+#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <iterator>
+#include <limits>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <ostream>
#include <random>
+#include <set>
#include <string>
#include <tuple>
#include <type_traits>
@@ -49,8 +53,13 @@
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h"
#include "absl/container/internal/hash_policy_testing.h"
+#include "absl/random/random.h"
+// TODO(b/382423690): Separate tests that depend only on
+// hashtable_control_bytes.
+#include "absl/container/internal/hashtable_control_bytes.h"
#include "absl/container/internal/hashtable_debug.h"
#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/container/internal/raw_hash_set_resize_impl.h"
#include "absl/container/internal/test_allocator.h"
#include "absl/container/internal/test_instance_tracker.h"
#include "absl/container/node_hash_set.h"
@@ -60,8 +69,10 @@
#include "absl/log/log.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -69,8 +80,8 @@
struct RawHashSetTestOnlyAccess {
template <typename C>
- static auto GetCommon(const C& c) -> decltype(c.common()) {
- return c.common();
+ static auto GetCommon(C&& c) -> decltype(std::forward<C>(c).common()) {
+ return std::forward<C>(c).common();
}
template <typename C>
static auto GetSlots(const C& c) -> decltype(c.slot_array()) {
@@ -91,10 +102,28 @@
using ::testing::Lt;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
+using ::testing::UnorderedElementsAreArray;
// Convenience function to static cast to ctrl_t.
ctrl_t CtrlT(int i) { return static_cast<ctrl_t>(i); }
+// Enables sampling with 1 percent sampling rate and
+// resets the rate counter for the current thread.
+void SetSamplingRateTo1Percent() {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100); // Sample ~1% of tables.
+ // Reset rate counter for the current thread.
+ TestOnlyRefreshSamplingStateForCurrentThread();
+}
+
+// Disables sampling and resets the rate counter for the current thread.
+void DisableSampling() {
+ SetHashtablezEnabled(false);
+ SetHashtablezSampleParameter(1 << 16);
+ // Reset rate counter for the current thread.
+ TestOnlyRefreshSamplingStateForCurrentThread();
+}
+
TEST(GrowthInfoTest, GetGrowthLeft) {
GrowthInfo gi;
gi.InitGrowthLeftNoDeleted(5);
@@ -183,6 +212,60 @@
EXPECT_FALSE(gi.HasNoDeleted());
}
+TEST(GrowthInfoTest, HasNoGrowthLeftAssumingMayHaveDeleted) {
+ GrowthInfo gi;
+ gi.InitGrowthLeftNoDeleted(1);
+ gi.OverwriteFullAsDeleted();
+ EXPECT_EQ(gi.GetGrowthLeft(), 1);
+ EXPECT_FALSE(gi.HasNoGrowthLeftAssumingMayHaveDeleted());
+ gi.OverwriteControlAsFull(ctrl_t::kDeleted);
+ EXPECT_EQ(gi.GetGrowthLeft(), 1);
+ EXPECT_FALSE(gi.HasNoGrowthLeftAssumingMayHaveDeleted());
+ gi.OverwriteFullAsEmpty();
+ EXPECT_EQ(gi.GetGrowthLeft(), 2);
+ EXPECT_FALSE(gi.HasNoGrowthLeftAssumingMayHaveDeleted());
+ gi.OverwriteEmptyAsFull();
+ EXPECT_EQ(gi.GetGrowthLeft(), 1);
+ EXPECT_FALSE(gi.HasNoGrowthLeftAssumingMayHaveDeleted());
+ gi.OverwriteEmptyAsFull();
+ EXPECT_EQ(gi.GetGrowthLeft(), 0);
+ EXPECT_TRUE(gi.HasNoGrowthLeftAssumingMayHaveDeleted());
+}
+
+TEST(Util, OptimalMemcpySizeForSooSlotTransfer) {
+ EXPECT_EQ(1, OptimalMemcpySizeForSooSlotTransfer(1));
+ ASSERT_EQ(4, OptimalMemcpySizeForSooSlotTransfer(2));
+ ASSERT_EQ(4, OptimalMemcpySizeForSooSlotTransfer(3));
+ for (size_t slot_size = 4; slot_size <= 8; ++slot_size) {
+ ASSERT_EQ(8, OptimalMemcpySizeForSooSlotTransfer(slot_size));
+ }
+ // If maximum amount of memory is 16, then we can copy up to 16 bytes.
+ for (size_t slot_size = 9; slot_size <= 16; ++slot_size) {
+ ASSERT_EQ(16,
+ OptimalMemcpySizeForSooSlotTransfer(slot_size,
+ /*max_soo_slot_size=*/16));
+ ASSERT_EQ(16,
+ OptimalMemcpySizeForSooSlotTransfer(slot_size,
+ /*max_soo_slot_size=*/24));
+ }
+ // But we shouldn't try to copy more than maximum amount of memory.
+ for (size_t slot_size = 9; slot_size <= 12; ++slot_size) {
+ ASSERT_EQ(12, OptimalMemcpySizeForSooSlotTransfer(
+ slot_size, /*max_soo_slot_size=*/12));
+ }
+ for (size_t slot_size = 17; slot_size <= 24; ++slot_size) {
+ ASSERT_EQ(24,
+ OptimalMemcpySizeForSooSlotTransfer(slot_size,
+ /*max_soo_slot_size=*/24));
+ }
+ // We shouldn't copy more than maximum.
+ for (size_t slot_size = 17; slot_size <= 20; ++slot_size) {
+ ASSERT_EQ(20,
+ OptimalMemcpySizeForSooSlotTransfer(slot_size,
+ /*max_soo_slot_size=*/20));
+ }
+}
+
TEST(Util, NormalizeCapacity) {
EXPECT_EQ(1, NormalizeCapacity(0));
EXPECT_EQ(1, NormalizeCapacity(1));
@@ -199,9 +282,14 @@
TEST(Util, GrowthAndCapacity) {
// Verify that GrowthToCapacity gives the minimum capacity that has enough
// growth.
- for (size_t growth = 0; growth < 10000; ++growth) {
+ EXPECT_EQ(SizeToCapacity(0), 0);
+ EXPECT_EQ(SizeToCapacity(1), 1);
+ EXPECT_EQ(SizeToCapacity(2), 3);
+ EXPECT_EQ(SizeToCapacity(3), 3);
+ for (size_t growth = 1; growth < 10000; ++growth) {
SCOPED_TRACE(growth);
- size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
+ size_t capacity = SizeToCapacity(growth);
+ ASSERT_TRUE(IsValidCapacity(capacity));
// The capacity is large enough for `growth`.
EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
// For (capacity+1) < kWidth, growth should equal capacity.
@@ -221,8 +309,8 @@
SCOPED_TRACE(capacity);
size_t growth = CapacityToGrowth(capacity);
EXPECT_THAT(growth, Lt(capacity));
- EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity);
- EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity);
+ EXPECT_EQ(SizeToCapacity(growth), capacity);
+ EXPECT_EQ(NormalizeCapacity(SizeToCapacity(growth)), capacity);
}
}
@@ -533,8 +621,6 @@
using IntPolicy = ValuePolicy<int64_t>;
using Uint8Policy = ValuePolicy<uint8_t>;
-using TranferableIntPolicy = ValuePolicy<int64_t, /*kTransferable=*/true>;
-
// For testing SOO.
template <int N>
class SizedValue {
@@ -573,6 +659,48 @@
using SizedValuePolicy =
ValuePolicy<SizedValue<N>, /*kTransferable=*/true, kSoo>;
+// Value is aligned as type T and contains N copies of it.
+template <typename T, int N>
+class AlignedValue {
+ public:
+ AlignedValue(int64_t v) { // NOLINT
+ for (int i = 0; i < N; ++i) {
+ vals_[i] = v;
+ if (sizeof(T) < sizeof(int64_t)) {
+ v >>= (8 * sizeof(T));
+ } else {
+ v = 0;
+ }
+ }
+ }
+ AlignedValue() : AlignedValue(0) {}
+ AlignedValue(const AlignedValue&) = default;
+ AlignedValue& operator=(const AlignedValue&) = default;
+
+ int64_t operator*() const {
+ if (sizeof(T) == sizeof(int64_t)) {
+ return vals_[0];
+ }
+ int64_t result = 0;
+ for (int i = N - 1; i >= 0; --i) {
+ result <<= (8 * sizeof(T));
+ result += vals_[i];
+ }
+ return result;
+ }
+ explicit operator int() const { return **this; }
+ explicit operator int64_t() const { return **this; }
+
+ template <typename H>
+ friend H AbslHashValue(H h, AlignedValue sv) {
+ return H::combine(std::move(h), *sv);
+ }
+ bool operator==(const AlignedValue& rhs) const { return **this == *rhs; }
+
+ private:
+ T vals_[N];
+};
+
class StringPolicy {
template <class F, class K, class V,
class = typename std::enable_if<
@@ -650,10 +778,11 @@
using Base::Base;
};
-template <typename T, bool kTransferable = false, bool kSoo = false>
+template <typename T, bool kTransferable = false, bool kSoo = false,
+ class Alloc = std::allocator<T>>
struct ValueTable
: raw_hash_set<ValuePolicy<T, kTransferable, kSoo>, hash_default_hash<T>,
- std::equal_to<T>, std::allocator<T>> {
+ std::equal_to<T>, Alloc> {
using Base = typename ValueTable::raw_hash_set;
using Base::Base;
};
@@ -663,11 +792,6 @@
using TransferableIntTable = ValueTable<int64_t, /*kTransferable=*/true>;
-constexpr size_t kNonSooSize = sizeof(HeapOrSoo) + 8;
-static_assert(sizeof(SizedValue<kNonSooSize>) >= kNonSooSize, "too small");
-using NonSooIntTable = ValueTable<SizedValue<kNonSooSize>>;
-using SooIntTable = ValueTable<int64_t, /*kTransferable=*/true, /*kSoo=*/true>;
-
template <typename T>
struct CustomAlloc : std::allocator<T> {
CustomAlloc() = default;
@@ -688,6 +812,50 @@
using Base::Base;
};
+template <typename T>
+struct ChangingSizeAndTrackingTypeAlloc : std::allocator<T> {
+ ChangingSizeAndTrackingTypeAlloc() = default;
+
+ template <typename U>
+ explicit ChangingSizeAndTrackingTypeAlloc(
+ const ChangingSizeAndTrackingTypeAlloc<U>& other) {
+ EXPECT_EQ(other.type_id,
+ ChangingSizeAndTrackingTypeAlloc<U>::ComputeTypeId());
+ }
+
+ template <class U>
+ struct rebind {
+ using other = ChangingSizeAndTrackingTypeAlloc<U>;
+ };
+
+ T* allocate(size_t n) {
+ EXPECT_EQ(type_id, ComputeTypeId());
+ return std::allocator<T>::allocate(n);
+ }
+
+ void deallocate(T* p, std::size_t n) {
+ EXPECT_EQ(type_id, ComputeTypeId());
+ return std::allocator<T>::deallocate(p, n);
+ }
+
+ static size_t ComputeTypeId() { return absl::HashOf(typeid(T).name()); }
+
+ // We add extra data to make the allocator size being changed.
+ // This also make type_id positioned differently, so that assertions in the
+ // allocator can catch bugs more likely.
+ char data_before[sizeof(T) * 3] = {0};
+ size_t type_id = ComputeTypeId();
+ char data_after[sizeof(T) * 5] = {0};
+};
+
+struct ChangingSizeAllocIntTable
+ : raw_hash_set<IntPolicy, hash_default_hash<int64_t>,
+ std::equal_to<int64_t>,
+ ChangingSizeAndTrackingTypeAlloc<int64_t>> {
+ using Base = typename ChangingSizeAllocIntTable::raw_hash_set;
+ using Base::Base;
+};
+
struct MinimumAlignmentUint8Table
: raw_hash_set<Uint8Policy, hash_default_hash<uint8_t>,
std::equal_to<uint8_t>, MinimumAlignmentAlloc<uint8_t>> {
@@ -741,28 +909,44 @@
using Base::Base;
};
-struct BadTable : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int>,
+struct BadTable : raw_hash_set<IntPolicy, BadFastHash, std::equal_to<int64_t>,
std::allocator<int>> {
using Base = typename BadTable::raw_hash_set;
BadTable() = default;
using Base::Base;
};
+constexpr size_t kNonSooSize = sizeof(HeapOrSoo) + 8;
+using NonSooIntTableSlotType = SizedValue<kNonSooSize>;
+static_assert(sizeof(NonSooIntTableSlotType) >= kNonSooSize, "too small");
+using NonSooIntTable = ValueTable<NonSooIntTableSlotType>;
+using SooInt32Table =
+ ValueTable<int32_t, /*kTransferable=*/true, /*kSoo=*/true>;
+using SooIntTable = ValueTable<int64_t, /*kTransferable=*/true, /*kSoo=*/true>;
+using NonMemcpyableSooIntTable =
+ ValueTable<int64_t, /*kTransferable=*/false, /*kSoo=*/true>;
+using MemcpyableSooIntCustomAllocTable =
+ ValueTable<int64_t, /*kTransferable=*/true, /*kSoo=*/true,
+ ChangingSizeAndTrackingTypeAlloc<int64_t>>;
+using NonMemcpyableSooIntCustomAllocTable =
+ ValueTable<int64_t, /*kTransferable=*/false, /*kSoo=*/true,
+ ChangingSizeAndTrackingTypeAlloc<int64_t>>;
+
TEST(Table, EmptyFunctorOptimization) {
static_assert(std::is_empty<std::equal_to<absl::string_view>>::value, "");
static_assert(std::is_empty<std::allocator<int>>::value, "");
struct MockTable {
+ size_t capacity;
+ uint64_t size;
void* ctrl;
void* slots;
- size_t size;
- size_t capacity;
};
struct StatelessHash {
size_t operator()(absl::string_view) const { return 0; }
};
struct StatefulHash : StatelessHash {
- size_t dummy;
+ uint64_t dummy;
};
struct GenerationData {
@@ -800,7 +984,10 @@
template <class TableType>
class SooTest : public testing::Test {};
-using SooTableTypes = ::testing::Types<SooIntTable, NonSooIntTable>;
+using SooTableTypes =
+ ::testing::Types<SooIntTable, NonSooIntTable, NonMemcpyableSooIntTable,
+ MemcpyableSooIntCustomAllocTable,
+ NonMemcpyableSooIntCustomAllocTable>;
TYPED_TEST_SUITE(SooTest, SooTableTypes);
TYPED_TEST(SooTest, Empty) {
@@ -809,6 +996,21 @@
EXPECT_TRUE(t.empty());
}
+TEST(Table, Prefetch) {
+ IntTable t;
+ t.emplace(1);
+ // Works for both present and absent keys.
+ t.prefetch(1);
+ t.prefetch(2);
+
+ static constexpr int size = 10;
+ for (int i = 0; i < size; ++i) t.insert(i);
+ for (int i = 0; i < size; ++i) {
+ t.prefetch(i);
+ ASSERT_TRUE(t.find(i) != t.end()) << i;
+ }
+}
+
TYPED_TEST(SooTest, LookupEmpty) {
TypeParam t;
auto it = t.find(0);
@@ -939,8 +1141,41 @@
template <class TableType>
class SmallTableResizeTest : public testing::Test {};
-using SmallTableTypes =
- ::testing::Types<IntTable, TransferableIntTable, SooIntTable>;
+using SmallTableTypes = ::testing::Types<
+ IntTable, TransferableIntTable, SooIntTable,
+ // int8
+ ValueTable<int8_t, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<int8_t, /*kTransferable=*/false, /*kSoo=*/true>,
+ // int16
+ ValueTable<int16_t, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<int16_t, /*kTransferable=*/false, /*kSoo=*/true>,
+ // int128
+ ValueTable<SizedValue<16>, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<SizedValue<16>, /*kTransferable=*/false, /*kSoo=*/true>,
+ // int192
+ ValueTable<SizedValue<24>, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<SizedValue<24>, /*kTransferable=*/false, /*kSoo=*/true>,
+ // Special tables.
+ MinimumAlignmentUint8Table, CustomAllocIntTable, ChangingSizeAllocIntTable,
+ BadTable,
+ // alignment 1, size 2.
+ ValueTable<AlignedValue<uint8_t, 2>, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<AlignedValue<uint8_t, 2>, /*kTransferable=*/false,
+ /*kSoo=*/true>,
+ // alignment 1, size 7.
+ ValueTable<AlignedValue<uint8_t, 7>, /*kTransferable=*/true, /*kSoo=*/true>,
+ ValueTable<AlignedValue<uint8_t, 7>, /*kTransferable=*/false,
+ /*kSoo=*/true>,
+ // alignment 2, size 6.
+ ValueTable<AlignedValue<uint16_t, 3>, /*kTransferable=*/true,
+ /*kSoo=*/true>,
+ ValueTable<AlignedValue<uint16_t, 3>, /*kTransferable=*/false,
+ /*kSoo=*/true>,
+ // alignment 2, size 10.
+ ValueTable<AlignedValue<uint16_t, 5>, /*kTransferable=*/true,
+ /*kSoo=*/true>,
+ ValueTable<AlignedValue<uint16_t, 5>, /*kTransferable=*/false,
+ /*kSoo=*/true>>;
TYPED_TEST_SUITE(SmallTableResizeTest, SmallTableTypes);
TYPED_TEST(SmallTableResizeTest, InsertIntoSmallTable) {
@@ -959,6 +1194,9 @@
for (size_t source_size = 0; source_size < 32; ++source_size) {
for (size_t target_size = source_size; target_size < 32; ++target_size) {
for (bool rehash : {false, true}) {
+ SCOPED_TRACE(absl::StrCat("source_size: ", source_size,
+ ", target_size: ", target_size,
+ ", rehash: ", rehash));
TypeParam t;
for (size_t i = 0; i < source_size; ++i) {
t.insert(static_cast<int>(i));
@@ -978,6 +1216,7 @@
}
TYPED_TEST(SmallTableResizeTest, ResizeReduceSmallTables) {
+ DisableSampling();
for (size_t source_size = 0; source_size < 32; ++source_size) {
for (size_t target_size = 0; target_size <= source_size; ++target_size) {
TypeParam t;
@@ -1281,7 +1520,7 @@
};
struct Modulo1000HashTable
- : public raw_hash_set<IntPolicy, Modulo1000Hash, std::equal_to<int>,
+ : public raw_hash_set<IntPolicy, Modulo1000Hash, std::equal_to<int64_t>,
std::allocator<int>> {};
// Test that rehash with no resize happen in case of many deleted slots.
@@ -1335,18 +1574,18 @@
TYPED_TEST(SooTest, InsertEraseStressTest) {
TypeParam t;
- const size_t kMinElementCount = 250;
+ const size_t kMinElementCount = 50;
std::deque<int> keys;
size_t i = 0;
for (; i < MaxDensitySize(kMinElementCount); ++i) {
- t.emplace(i);
+ t.emplace(static_cast<int64_t>(i));
keys.push_back(i);
}
- const size_t kNumIterations = 1000000;
+ const size_t kNumIterations = 20000;
for (; i < kNumIterations; ++i) {
ASSERT_EQ(1, t.erase(keys.front()));
keys.pop_front();
- t.emplace(i);
+ t.emplace(static_cast<int64_t>(i));
keys.push_back(i);
}
}
@@ -1364,8 +1603,11 @@
TYPED_TEST(SooTest, LargeTable) {
TypeParam t;
- for (int64_t i = 0; i != 100000; ++i) t.emplace(i << 40);
- for (int64_t i = 0; i != 100000; ++i)
+ for (int64_t i = 0; i != 10000; ++i) {
+ t.emplace(i << 40);
+ ASSERT_EQ(t.size(), i + 1);
+ }
+ for (int64_t i = 0; i != 10000; ++i)
ASSERT_EQ(i << 40, static_cast<int64_t>(*t.find(i << 40)));
}
@@ -1696,8 +1938,7 @@
const std::vector<int64_t>& keys, size_t num_iters) {
ProbeStats stats;
- std::random_device rd;
- std::mt19937 rng(rd());
+ absl::InsecureBitGen rng;
auto linear_transform = [](size_t x, size_t y) { return x * 17 + y * 13; };
std::uniform_int_distribution<size_t> dist(0, keys.size() - 1);
while (num_iters--) {
@@ -1963,6 +2204,43 @@
}
}
+TYPED_TEST(SooTest, CopyAssignment) {
+ std::vector<size_t> sizes = {0, 1, 7, 25};
+ for (size_t source_size : sizes) {
+ for (size_t target_size : sizes) {
+ SCOPED_TRACE(absl::StrCat("source_size: ", source_size,
+ " target_size: ", target_size));
+ TypeParam source;
+ std::vector<int> source_elements;
+ for (size_t i = 0; i < source_size; ++i) {
+ source.emplace(static_cast<int>(i) * 2);
+ source_elements.push_back(static_cast<int>(i) * 2);
+ }
+ TypeParam target;
+ for (size_t i = 0; i < target_size; ++i) {
+ target.emplace(static_cast<int>(i) * 3);
+ }
+ target = source;
+ ASSERT_EQ(target.size(), source_size);
+ ASSERT_THAT(target, UnorderedElementsAreArray(source_elements));
+ }
+ }
+}
+
+TYPED_TEST(SooTest, CopyConstructWithSampling) {
+ SetSamplingRateTo1Percent();
+ for (int i = 0; i < 10000; ++i) {
+ TypeParam t;
+ t.emplace(0);
+ EXPECT_EQ(1, t.size());
+ {
+ TypeParam u(t);
+ EXPECT_EQ(1, u.size());
+ EXPECT_THAT(*u.find(0), 0);
+ }
+ }
+}
+
TYPED_TEST(SooTest, CopyDifferentSizes) {
TypeParam t;
@@ -2090,6 +2368,10 @@
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
t = std::move(*&t);
+ if (SwisstableGenerationsEnabled()) {
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t.contains("a"), "self-move-assigned");
+ }
// As long as we don't crash, it's fine.
}
@@ -2146,7 +2428,7 @@
TYPED_TEST(SooTest, ReplacingDeletedSlotDoesNotRehash) {
// We need to disable hashtablez to avoid issues related to SOO and sampling.
- SetHashtablezEnabled(false);
+ DisableSampling();
size_t n;
{
@@ -2429,8 +2711,9 @@
}
template <typename T>
-T MakeSimpleTable(size_t size) {
+T MakeSimpleTable(size_t size, bool do_reserve) {
T t;
+ if (do_reserve) t.reserve(size);
while (t.size() < size) t.insert(t.size());
return t;
}
@@ -2442,58 +2725,78 @@
return res;
}
-// These IterationOrderChanges tests depend on non-deterministic behavior.
-// We are injecting non-determinism from the pointer of the table, but do so in
-// a way that only the page matters. We have to retry enough times to make sure
-// we are touching different memory pages to cause the ordering to change.
-// We also need to keep the old tables around to avoid getting the same memory
-// blocks over and over.
-TYPED_TEST(SooTest, IterationOrderChangesByInstance) {
- for (size_t size : {2, 6, 12, 20}) {
- const auto reference_table = MakeSimpleTable<TypeParam>(size);
- const auto reference = OrderOfIteration(reference_table);
+// Generate irrelevant seeds to avoid being stuck in the same last bit
+// in seed.
+void GenerateIrrelevantSeeds(int cnt) {
+ for (int i = cnt % 17; i > 0; --i) {
+ NextSeed();
+ }
+}
- std::vector<TypeParam> tables;
- bool found_difference = false;
- for (int i = 0; !found_difference && i < 5000; ++i) {
- tables.push_back(MakeSimpleTable<TypeParam>(size));
- found_difference = OrderOfIteration(tables.back()) != reference;
- }
- if (!found_difference) {
- FAIL()
- << "Iteration order remained the same across many attempts with size "
- << size;
+// These IterationOrderChanges tests depend on non-deterministic behavior.
+// We are injecting non-determinism to the table.
+// We have to retry enough times to make sure that the seed changes in bits that
+// matter for the iteration order.
+TYPED_TEST(SooTest, IterationOrderChangesByInstance) {
+ DisableSampling(); // We do not want test to pass only because of sampling.
+ for (bool do_reserve : {false, true}) {
+ for (size_t size : {2u, 6u, 12u, 20u}) {
+ SCOPED_TRACE(absl::StrCat("size: ", size, " do_reserve: ", do_reserve));
+ const auto reference_table = MakeSimpleTable<TypeParam>(size, do_reserve);
+ const auto reference = OrderOfIteration(reference_table);
+
+ bool found_difference = false;
+ for (int i = 0; !found_difference && i < 500; ++i) {
+ auto new_table = MakeSimpleTable<TypeParam>(size, do_reserve);
+ found_difference = OrderOfIteration(new_table) != reference;
+ GenerateIrrelevantSeeds(i);
+ }
+ if (!found_difference) {
+ FAIL() << "Iteration order remained the same across many attempts.";
+ }
}
}
}
TYPED_TEST(SooTest, IterationOrderChangesOnRehash) {
+ DisableSampling(); // We do not want test to pass only because of sampling.
+
// We test different sizes with many small numbers, because small table
// resize has a different codepath.
// Note: iteration order for size() <= 1 is always the same.
- for (size_t size : std::vector<size_t>{2, 3, 6, 7, 12, 15, 20, 50}) {
- for (size_t rehash_size : {
- size_t{0}, // Force rehash is guaranteed.
- size * 10 // Rehash to the larger capacity is guaranteed.
- }) {
- std::vector<TypeParam> garbage;
- bool ok = false;
- for (int i = 0; i < 5000; ++i) {
- auto t = MakeSimpleTable<TypeParam>(size);
- const auto reference = OrderOfIteration(t);
- // Force rehash.
- t.rehash(rehash_size);
- auto trial = OrderOfIteration(t);
- if (trial != reference) {
- // We are done.
- ok = true;
- break;
+ for (bool do_reserve : {false, true}) {
+ for (size_t size : {2u, 3u, 6u, 7u, 12u, 15u, 20u, 50u}) {
+ for (size_t rehash_size : {
+ size_t{0}, // Force rehash is guaranteed.
+ size * 10 // Rehash to the larger capacity is guaranteed.
+ }) {
+ SCOPED_TRACE(absl::StrCat("size: ", size, " rehash_size: ", rehash_size,
+ " do_reserve: ", do_reserve));
+ bool ok = false;
+ auto t = MakeSimpleTable<TypeParam>(size, do_reserve);
+ const size_t original_capacity = t.capacity();
+ auto reference = OrderOfIteration(t);
+ for (int i = 0; i < 500; ++i) {
+ if (i > 0 && rehash_size != 0) {
+ // Rehash back to original size.
+ t.rehash(0);
+ ASSERT_EQ(t.capacity(), original_capacity);
+ reference = OrderOfIteration(t);
+ }
+ // Force rehash.
+ t.rehash(rehash_size);
+ auto trial = OrderOfIteration(t);
+ if (trial != reference) {
+ // We are done.
+ ok = true;
+ break;
+ }
+ GenerateIrrelevantSeeds(i);
}
- garbage.push_back(std::move(t));
+ EXPECT_TRUE(ok)
+ << "Iteration order remained the same across many attempts " << size
+ << "->" << rehash_size << ".";
}
- EXPECT_TRUE(ok)
- << "Iteration order remained the same across many attempts " << size
- << "->" << rehash_size << ".";
}
}
}
@@ -2502,7 +2805,7 @@
// This prevents dependency on pointer stability on small tables.
TYPED_TEST(SooTest, UnstablePointers) {
// We need to disable hashtablez to avoid issues related to SOO and sampling.
- SetHashtablezEnabled(false);
+ DisableSampling();
TypeParam table;
@@ -2634,18 +2937,29 @@
template <typename T>
class RawHashSamplerTest : public testing::Test {};
-using RawHashSamplerTestTypes = ::testing::Types<SooIntTable, NonSooIntTable>;
+using RawHashSamplerTestTypes = ::testing::Types<
+ // 32 bits to make sure that table is Soo for 32 bits platform as well.
+ // 64 bits table is not SOO due to alignment.
+ SooInt32Table,
+ NonSooIntTable>;
TYPED_TEST_SUITE(RawHashSamplerTest, RawHashSamplerTestTypes);
TYPED_TEST(RawHashSamplerTest, Sample) {
- constexpr bool soo_enabled = std::is_same<SooIntTable, TypeParam>::value;
+ constexpr bool soo_enabled = std::is_same<SooInt32Table, TypeParam>::value;
// Enable the feature even if the prod default is off.
- SetHashtablezEnabled(true);
- SetHashtablezSampleParameter(100); // Sample ~1% of tables.
+ SetSamplingRateTo1Percent();
+
+ ASSERT_EQ(TypeParam().capacity(), soo_enabled ? SooCapacity() : 0);
auto& sampler = GlobalHashtablezSampler();
size_t start_size = 0;
- absl::flat_hash_set<const HashtablezInfo*> preexisting_info;
+
+ // Reserve these utility tables, so that if they sampled, they'll be
+ // preexisting.
+ absl::flat_hash_set<const HashtablezInfo*> preexisting_info(10);
+ absl::flat_hash_map<size_t, int> observed_checksums(10);
+ absl::flat_hash_map<ssize_t, int> reservations(10);
+
start_size += sampler.Iterate([&](const HashtablezInfo& info) {
preexisting_info.insert(&info);
++start_size;
@@ -2672,8 +2986,6 @@
}
}
size_t end_size = 0;
- absl::flat_hash_map<size_t, int> observed_checksums;
- absl::flat_hash_map<ssize_t, int> reservations;
end_size += sampler.Iterate([&](const HashtablezInfo& info) {
++end_size;
if (preexisting_info.contains(&info)) return;
@@ -2710,25 +3022,25 @@
}
std::vector<const HashtablezInfo*> SampleSooMutation(
- absl::FunctionRef<void(SooIntTable&)> mutate_table) {
+ absl::FunctionRef<void(SooInt32Table&)> mutate_table) {
// Enable the feature even if the prod default is off.
- SetHashtablezEnabled(true);
- SetHashtablezSampleParameter(100); // Sample ~1% of tables.
+ SetSamplingRateTo1Percent();
auto& sampler = GlobalHashtablezSampler();
- size_t start_size = 0;
- absl::flat_hash_set<const HashtablezInfo*> preexisting_info;
+ int64_t start_size = 0;
+ // Reserve the table, so that if it sampled, it'll be preexisting.
+ absl::flat_hash_set<const HashtablezInfo*> preexisting_info(10);
start_size += sampler.Iterate([&](const HashtablezInfo& info) {
preexisting_info.insert(&info);
++start_size;
});
- std::vector<SooIntTable> tables;
+ std::vector<SooInt32Table> tables;
for (int i = 0; i < 1000000; ++i) {
tables.emplace_back();
mutate_table(tables.back());
}
- size_t end_size = 0;
+ int64_t end_size = 0;
std::vector<const HashtablezInfo*> infos;
end_size += sampler.Iterate([&](const HashtablezInfo& info) {
++end_size;
@@ -2743,16 +3055,16 @@
}
TEST(RawHashSamplerTest, SooTableInsertToEmpty) {
- if (SooIntTable().capacity() != SooCapacity()) {
+ if (SooInt32Table().capacity() != SooCapacity()) {
CHECK_LT(sizeof(void*), 8) << "missing SOO coverage";
GTEST_SKIP() << "not SOO on this platform";
}
std::vector<const HashtablezInfo*> infos =
- SampleSooMutation([](SooIntTable& t) { t.insert(1); });
+ SampleSooMutation([](SooInt32Table& t) { t.insert(1); });
for (const HashtablezInfo* info : infos) {
ASSERT_EQ(info->inline_element_size,
- sizeof(typename SooIntTable::value_type));
+ sizeof(typename SooInt32Table::value_type));
ASSERT_EQ(info->soo_capacity, SooCapacity());
ASSERT_EQ(info->capacity, NextCapacity(SooCapacity()));
ASSERT_EQ(info->size, 1);
@@ -2764,16 +3076,16 @@
}
TEST(RawHashSamplerTest, SooTableReserveToEmpty) {
- if (SooIntTable().capacity() != SooCapacity()) {
+ if (SooInt32Table().capacity() != SooCapacity()) {
CHECK_LT(sizeof(void*), 8) << "missing SOO coverage";
GTEST_SKIP() << "not SOO on this platform";
}
std::vector<const HashtablezInfo*> infos =
- SampleSooMutation([](SooIntTable& t) { t.reserve(100); });
+ SampleSooMutation([](SooInt32Table& t) { t.reserve(100); });
for (const HashtablezInfo* info : infos) {
ASSERT_EQ(info->inline_element_size,
- sizeof(typename SooIntTable::value_type));
+ sizeof(typename SooInt32Table::value_type));
ASSERT_EQ(info->soo_capacity, SooCapacity());
ASSERT_GE(info->capacity, 100);
ASSERT_EQ(info->size, 0);
@@ -2787,19 +3099,19 @@
// This tests that reserve on a full SOO table doesn't incorrectly result in new
// (over-)sampling.
TEST(RawHashSamplerTest, SooTableReserveToFullSoo) {
- if (SooIntTable().capacity() != SooCapacity()) {
+ if (SooInt32Table().capacity() != SooCapacity()) {
CHECK_LT(sizeof(void*), 8) << "missing SOO coverage";
GTEST_SKIP() << "not SOO on this platform";
}
std::vector<const HashtablezInfo*> infos =
- SampleSooMutation([](SooIntTable& t) {
+ SampleSooMutation([](SooInt32Table& t) {
t.insert(1);
t.reserve(100);
});
for (const HashtablezInfo* info : infos) {
ASSERT_EQ(info->inline_element_size,
- sizeof(typename SooIntTable::value_type));
+ sizeof(typename SooInt32Table::value_type));
ASSERT_EQ(info->soo_capacity, SooCapacity());
ASSERT_GE(info->capacity, 100);
ASSERT_EQ(info->size, 1);
@@ -2810,15 +3122,38 @@
}
}
+TEST(RawHashSamplerTest, SooTableSampleOnCopy) {
+ if (SooInt32Table().capacity() != SooCapacity()) {
+ CHECK_LT(sizeof(void*), 8) << "missing SOO coverage";
+ GTEST_SKIP() << "not SOO on this platform";
+ }
+
+ SooInt32Table t_orig;
+ t_orig.insert(1);
+
+ std::vector<const HashtablezInfo*> infos =
+ SampleSooMutation([&t_orig](SooInt32Table& t) {
+ t = t_orig;
+ });
+
+ for (const HashtablezInfo* info : infos) {
+ ASSERT_EQ(info->inline_element_size,
+ sizeof(typename SooInt32Table::value_type));
+ ASSERT_EQ(info->soo_capacity, SooCapacity());
+ ASSERT_EQ(info->capacity, NextCapacity(SooCapacity()));
+ ASSERT_EQ(info->size, 1);
+ }
+}
+
// This tests that rehash(0) on a sampled table with size that fits in SOO
// doesn't incorrectly result in losing sampling.
TEST(RawHashSamplerTest, SooTableRehashShrinkWhenSizeFitsInSoo) {
- if (SooIntTable().capacity() != SooCapacity()) {
+ if (SooInt32Table().capacity() != SooCapacity()) {
CHECK_LT(sizeof(void*), 8) << "missing SOO coverage";
GTEST_SKIP() << "not SOO on this platform";
}
std::vector<const HashtablezInfo*> infos =
- SampleSooMutation([](SooIntTable& t) {
+ SampleSooMutation([](SooInt32Table& t) {
t.reserve(100);
t.insert(1);
EXPECT_GE(t.capacity(), 100);
@@ -2827,7 +3162,7 @@
for (const HashtablezInfo* info : infos) {
ASSERT_EQ(info->inline_element_size,
- sizeof(typename SooIntTable::value_type));
+ sizeof(typename SooInt32Table::value_type));
ASSERT_EQ(info->soo_capacity, SooCapacity());
ASSERT_EQ(info->capacity, NextCapacity(SooCapacity()));
ASSERT_EQ(info->size, 1);
@@ -2841,19 +3176,19 @@
TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
// Enable the feature even if the prod default is off.
- SetHashtablezEnabled(true);
- SetHashtablezSampleParameter(100); // Sample ~1% of tables.
+ SetSamplingRateTo1Percent();
auto& sampler = GlobalHashtablezSampler();
- size_t start_size = 0;
+ int64_t start_size = 0;
start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
std::vector<CustomAllocIntTable> tables;
- for (int i = 0; i < 1000000; ++i) {
+ for (int i = 0; i < 100000; ++i) {
tables.emplace_back();
tables.back().insert(1);
+ tables.push_back(tables.back()); // Copies the table.
}
- size_t end_size = 0;
+ int64_t end_size = 0;
end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
@@ -2885,6 +3220,20 @@
}
}
+TYPED_TEST(SanitizerTest, PoisoningUnusedOnGrowth) {
+ TypeParam t;
+ for (int64_t i = 0; i < 100; ++i) {
+ t.insert(i);
+
+ int64_t* slots = RawHashSetTestOnlyAccess::GetSlots(t);
+ int poisoned = 0;
+ for (size_t i = 0; i < t.capacity(); ++i) {
+ poisoned += static_cast<int>(__asan_address_is_poisoned(slots + i));
+ }
+ ASSERT_EQ(poisoned, t.capacity() - t.size());
+ }
+}
+
// TODO(b/289225379): poison inline space when empty SOO.
TEST(Sanitizer, PoisoningOnErase) {
NonSooIntTable t;
@@ -2907,28 +3256,27 @@
// first slot when alignof(value_type) is 1. We test repeated
// insertions/erases and verify that the behavior is correct.
TypeParam t;
- std::unordered_set<uint8_t> verifier; // NOLINT
+ std::bitset<256> verifier;
// Do repeated insertions/erases from the table.
- for (int64_t i = 0; i < 100000; ++i) {
+ for (int64_t i = 0; i < 10000; ++i) {
SCOPED_TRACE(i);
const uint8_t u = (i * -i) & 0xFF;
auto it = t.find(u);
- auto verifier_it = verifier.find(u);
if (it == t.end()) {
- ASSERT_EQ(verifier_it, verifier.end());
+ ASSERT_FALSE(verifier.test(u));
t.insert(u);
- verifier.insert(u);
+ verifier.set(u);
} else {
- ASSERT_NE(verifier_it, verifier.end());
+ ASSERT_TRUE(verifier.test(u));
t.erase(it);
- verifier.erase(verifier_it);
+ verifier.reset(u);
}
}
- EXPECT_EQ(t.size(), verifier.size());
+ EXPECT_EQ(t.size(), verifier.count());
for (uint8_t u : t) {
- EXPECT_EQ(verifier.count(u), 1);
+ ASSERT_TRUE(verifier.test(u));
}
}
@@ -3351,16 +3699,16 @@
t.insert(1);
EXPECT_EQ(HashCount(t), 1);
t.erase(1);
- EXPECT_EQ(HashCount(t), 2);
+ EXPECT_LE(HashCount(t), 2);
}
{
Table t;
t.insert(3);
EXPECT_EQ(HashCount(t), 1);
auto node = t.extract(3);
- EXPECT_EQ(HashCount(t), 2);
+ EXPECT_LE(HashCount(t), 2);
t.insert(std::move(node));
- EXPECT_EQ(HashCount(t), 3);
+ EXPECT_LE(HashCount(t), 3);
}
{
Table t;
@@ -3379,22 +3727,22 @@
// IterateOverFullSlots doesn't support SOO.
TEST(Table, IterateOverFullSlotsEmpty) {
NonSooIntTable t;
- auto fail_if_any = [](const ctrl_t*, auto* i) {
- FAIL() << "expected no slots " << **i;
+ using SlotType = NonSooIntTableSlotType;
+ auto fail_if_any = [](const ctrl_t*, void* i) {
+ FAIL() << "expected no slots " << **static_cast<SlotType*>(i);
};
container_internal::IterateOverFullSlots(
- RawHashSetTestOnlyAccess::GetCommon(t),
- RawHashSetTestOnlyAccess::GetSlots(t), fail_if_any);
+ RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType), fail_if_any);
for (size_t i = 0; i < 256; ++i) {
t.reserve(i);
container_internal::IterateOverFullSlots(
- RawHashSetTestOnlyAccess::GetCommon(t),
- RawHashSetTestOnlyAccess::GetSlots(t), fail_if_any);
+ RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType), fail_if_any);
}
}
TEST(Table, IterateOverFullSlotsFull) {
NonSooIntTable t;
+ using SlotType = NonSooIntTableSlotType;
std::vector<int64_t> expected_slots;
for (int64_t idx = 0; idx < 128; ++idx) {
@@ -3403,9 +3751,9 @@
std::vector<int64_t> slots;
container_internal::IterateOverFullSlots(
- RawHashSetTestOnlyAccess::GetCommon(t),
- RawHashSetTestOnlyAccess::GetSlots(t),
- [&t, &slots](const ctrl_t* ctrl, auto* i) {
+ RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType),
+ [&t, &slots](const ctrl_t* ctrl, void* slot) {
+ SlotType* i = static_cast<SlotType*>(slot);
ptrdiff_t ctrl_offset =
ctrl - RawHashSetTestOnlyAccess::GetCommon(t).control();
ptrdiff_t slot_offset = i - RawHashSetTestOnlyAccess::GetSlots(t);
@@ -3424,16 +3772,16 @@
if (reserve_size == -1) reserve_size = size;
for (int64_t idx = 0; idx < size; ++idx) {
NonSooIntTable t;
+ using SlotType = NonSooIntTableSlotType;
t.reserve(static_cast<size_t>(reserve_size));
for (int val = 0; val <= idx; ++val) {
t.insert(val);
}
container_internal::IterateOverFullSlots(
- RawHashSetTestOnlyAccess::GetCommon(t),
- RawHashSetTestOnlyAccess::GetSlots(t),
- [&t](const ctrl_t*, auto* i) {
- int64_t value = **i;
+ RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType),
+ [&t](const ctrl_t*, void* slot) {
+ int64_t value = **static_cast<SlotType*>(slot);
// Erase the other element from 2*k and 2*k+1 pair.
t.erase(value ^ 1);
});
@@ -3459,16 +3807,16 @@
int64_t size = reserve_size / size_divisor;
for (int64_t idx = 1; idx <= size; ++idx) {
NonSooIntTable t;
+ using SlotType = NonSooIntTableSlotType;
t.reserve(static_cast<size_t>(reserve_size));
for (int val = 1; val <= idx; ++val) {
t.insert(val);
}
container_internal::IterateOverFullSlots(
- RawHashSetTestOnlyAccess::GetCommon(t),
- RawHashSetTestOnlyAccess::GetSlots(t),
- [&t](const ctrl_t*, auto* i) {
- int64_t value = **i;
+ RawHashSetTestOnlyAccess::GetCommon(t), sizeof(SlotType),
+ [&t](const ctrl_t*, void* slot) {
+ int64_t value = **static_cast<SlotType*>(slot);
t.insert(-value);
});
}
@@ -3531,7 +3879,7 @@
// We disable hashtablez sampling for this test to ensure that the table isn't
// sampled. When the table is sampled, it won't rehash down to SOO.
- SetHashtablezEnabled(false);
+ DisableSampling();
t.reserve(100);
t.insert(0);
@@ -3547,7 +3895,7 @@
}
TEST(Table, ReserveToNonSoo) {
- for (int reserve_capacity : {8, 100000}) {
+ for (size_t reserve_capacity : {2u, 8u, 100000u}) {
SooIntTable t;
t.insert(0);
@@ -3594,6 +3942,328 @@
"hash/eq functors are inconsistent.");
}
+struct ConstructCaller {
+ explicit ConstructCaller(int v) : val(v) {}
+ ConstructCaller(int v, absl::FunctionRef<void()> func) : val(v) { func(); }
+ template <typename H>
+ friend H AbslHashValue(H h, const ConstructCaller& d) {
+ return H::combine(std::move(h), d.val);
+ }
+ bool operator==(const ConstructCaller& c) const { return val == c.val; }
+
+ int val;
+};
+
+struct DestroyCaller {
+ explicit DestroyCaller(int v) : val(v) {}
+ DestroyCaller(int v, absl::FunctionRef<void()> func)
+ : val(v), destroy_func(func) {}
+ DestroyCaller(DestroyCaller&& that)
+ : val(that.val), destroy_func(std::move(that.destroy_func)) {
+ that.Deactivate();
+ }
+ ~DestroyCaller() {
+ if (destroy_func) (*destroy_func)();
+ }
+ void Deactivate() { destroy_func = absl::nullopt; }
+
+ template <typename H>
+ friend H AbslHashValue(H h, const DestroyCaller& d) {
+ return H::combine(std::move(h), d.val);
+ }
+ bool operator==(const DestroyCaller& d) const { return val == d.val; }
+
+ int val;
+ absl::optional<absl::FunctionRef<void()>> destroy_func;
+};
+
+TEST(Table, ReentrantCallsFail) {
+#ifdef NDEBUG
+ GTEST_SKIP() << "Reentrant checks only enabled in debug mode.";
+#else
+ {
+ ValueTable<ConstructCaller> t;
+ t.insert(ConstructCaller{0});
+ auto erase_begin = [&] { t.erase(t.begin()); };
+ EXPECT_DEATH_IF_SUPPORTED(t.emplace(1, erase_begin), "");
+ }
+ {
+ ValueTable<DestroyCaller> t;
+ t.insert(DestroyCaller{0});
+ auto find_0 = [&] { t.find(DestroyCaller{0}); };
+ t.insert(DestroyCaller{1, find_0});
+ for (int i = 10; i < 20; ++i) t.insert(DestroyCaller{i});
+ EXPECT_DEATH_IF_SUPPORTED(t.clear(), "");
+ for (auto& elem : t) elem.Deactivate();
+ }
+ {
+ ValueTable<DestroyCaller> t;
+ t.insert(DestroyCaller{0});
+ auto insert_1 = [&] { t.insert(DestroyCaller{1}); };
+ t.insert(DestroyCaller{1, insert_1});
+ for (int i = 10; i < 20; ++i) t.insert(DestroyCaller{i});
+ EXPECT_DEATH_IF_SUPPORTED(t.clear(), "");
+ for (auto& elem : t) elem.Deactivate();
+ }
+#endif
+}
+
+// TODO(b/328794765): this check is very useful to run with ASAN in opt mode.
+TEST(Table, DestroyedCallsFail) {
+#ifdef NDEBUG
+ ASSERT_EQ(SwisstableAssertAccessToDestroyedTable(),
+ SwisstableGenerationsEnabled());
+#else
+ ASSERT_TRUE(SwisstableAssertAccessToDestroyedTable());
+#endif
+ if (!SwisstableAssertAccessToDestroyedTable()) {
+ GTEST_SKIP() << "Validation not enabled.";
+ }
+#if !defined(__clang__) && defined(__GNUC__)
+ GTEST_SKIP() << "Flaky on GCC.";
+#endif
+ absl::optional<IntTable> t;
+ t.emplace({1});
+ IntTable* t_ptr = &*t;
+ EXPECT_TRUE(t_ptr->contains(1));
+ t.reset();
+ std::string expected_death_message =
+#if defined(ABSL_HAVE_MEMORY_SANITIZER)
+ "use-of-uninitialized-value";
+#else
+ "destroyed hash table";
+#endif
+ EXPECT_DEATH_IF_SUPPORTED(t_ptr->contains(1), expected_death_message);
+}
+
+TEST(Table, DestroyedCallsFailDuringDestruction) {
+ if (!SwisstableAssertAccessToDestroyedTable()) {
+ GTEST_SKIP() << "Validation not enabled.";
+ }
+#if !defined(__clang__) && defined(__GNUC__)
+ GTEST_SKIP() << "Flaky on GCC.";
+#endif
+ // When EXPECT_DEATH_IF_SUPPORTED is not executed, the code after it is not
+ // executed as well.
+ // We need to destruct the table correctly in such a case.
+ // Must be defined before the table for correct destruction order.
+ bool do_lookup = false;
+
+ using Table = absl::flat_hash_map<int, std::shared_ptr<int>>;
+ absl::optional<Table> t = Table();
+ Table* t_ptr = &*t;
+ auto destroy = [&](int* ptr) {
+ if (do_lookup) {
+ ASSERT_TRUE(t_ptr->contains(*ptr));
+ }
+ delete ptr;
+ };
+ t->insert({0, std::shared_ptr<int>(new int(0), destroy)});
+ auto destroy_with_lookup = [&] {
+ do_lookup = true;
+ t.reset();
+ };
+ std::string expected_death_message =
+#ifdef NDEBUG
+ "destroyed hash table";
+#else
+ "Reentrant container access";
+#endif
+ EXPECT_DEATH_IF_SUPPORTED(destroy_with_lookup(), expected_death_message);
+}
+
+TEST(Table, MovedFromCallsFail) {
+ if (!SwisstableGenerationsEnabled()) {
+ GTEST_SKIP() << "Moved-from checks only enabled in sanitizer mode.";
+ return;
+ }
+
+ {
+ ABSL_ATTRIBUTE_UNUSED IntTable t1, t2, t3;
+ t1.insert(1);
+ t2 = std::move(t1);
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.contains(1), "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.swap(t3), "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.merge(t3), "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(IntTable{t1}, "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.begin(), "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.end(), "moved-from");
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.size(), "moved-from");
+ }
+ {
+ ABSL_ATTRIBUTE_UNUSED IntTable t1;
+ t1.insert(1);
+ ABSL_ATTRIBUTE_UNUSED IntTable t2(std::move(t1));
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ EXPECT_DEATH_IF_SUPPORTED(t1.contains(1), "moved-from");
+ t1.clear(); // Clearing a moved-from table is allowed.
+ }
+ {
+ // Test that using a table (t3) that was moved-to from a moved-from table
+ // (t1) fails.
+ ABSL_ATTRIBUTE_UNUSED IntTable t1, t2, t3;
+ t1.insert(1);
+ t2 = std::move(t1);
+ // NOLINTNEXTLINE(bugprone-use-after-move)
+ t3 = std::move(t1);
+ EXPECT_DEATH_IF_SUPPORTED(t3.contains(1), "moved-from");
+ }
+}
+
+TEST(HashtableSize, GenerateNewSeedDoesntChangeSize) {
+ size_t size = 1;
+ do {
+ HashtableSize hs(no_seed_empty_tag_t{});
+ hs.increment_size(size);
+ EXPECT_EQ(hs.size(), size);
+ hs.generate_new_seed();
+ EXPECT_EQ(hs.size(), size);
+ size = size * 2 + 1;
+ } while (size < MaxValidSizeFor1ByteSlot());
+}
+
+TEST(Table, MaxValidSize) {
+ IntTable t;
+ EXPECT_EQ(MaxValidSize(sizeof(IntTable::value_type)), t.max_size());
+ if constexpr (sizeof(size_t) == 8) {
+ for (size_t i = 0; i < 35; ++i) {
+ SCOPED_TRACE(i);
+ size_t slot_size = size_t{1} << i;
+ size_t max_size = MaxValidSize(slot_size);
+ ASSERT_FALSE(IsAboveValidSize(max_size, slot_size));
+ ASSERT_TRUE(IsAboveValidSize(max_size + 1, slot_size));
+ ASSERT_LT(max_size, uint64_t{1} << 60);
+ // For non gigantic slot sizes we expect max size to be at least 2^40.
+ if (i <= 22) {
+ ASSERT_FALSE(IsAboveValidSize(size_t{1} << 40, slot_size));
+ ASSERT_GE(max_size, uint64_t{1} << 40);
+ }
+ ASSERT_LT(SizeToCapacity(max_size),
+ uint64_t{1} << HashtableSize::kSizeBitCount);
+ ASSERT_LT(absl::uint128(max_size) * slot_size, uint64_t{1} << 63);
+ }
+ }
+ EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(1), 1 << 30);
+ EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(2), 1 << 29);
+ for (size_t i = 0; i < 29; ++i) {
+ size_t slot_size = size_t{1} << i;
+ size_t max_size = MaxValidSize</*kSizeOfSizeT=*/4>(slot_size);
+ ASSERT_FALSE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size, slot_size));
+ ASSERT_TRUE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size + 1, slot_size));
+ ASSERT_LT(max_size, 1 << 30);
+ size_t max_capacity = SizeToCapacity(max_size);
+ ASSERT_LT(max_capacity, (size_t{1} << 31) / slot_size);
+ ASSERT_GT(max_capacity, (1 << 29) / slot_size);
+ ASSERT_LT(max_capacity * slot_size, size_t{1} << 31);
+ }
+}
+
+TEST(Table, MaxSizeOverflow) {
+ size_t overflow = (std::numeric_limits<size_t>::max)();
+ EXPECT_DEATH_IF_SUPPORTED(IntTable t(overflow), "Hash table size overflow");
+ IntTable t;
+ EXPECT_DEATH_IF_SUPPORTED(t.reserve(overflow), "Hash table size overflow");
+ EXPECT_DEATH_IF_SUPPORTED(t.rehash(overflow), "Hash table size overflow");
+ size_t slightly_overflow = MaxValidSize(sizeof(IntTable::value_type)) + 1;
+ size_t slightly_overflow_capacity =
+ NextCapacity(NormalizeCapacity(slightly_overflow));
+ EXPECT_DEATH_IF_SUPPORTED(IntTable t2(slightly_overflow_capacity - 10),
+ "Hash table size overflow");
+ EXPECT_DEATH_IF_SUPPORTED(t.reserve(slightly_overflow),
+ "Hash table size overflow");
+ EXPECT_DEATH_IF_SUPPORTED(t.rehash(slightly_overflow),
+ "Hash table size overflow");
+ IntTable non_empty_table;
+ non_empty_table.insert(0);
+ EXPECT_DEATH_IF_SUPPORTED(non_empty_table.reserve(slightly_overflow),
+ "Hash table size overflow");
+}
+
+// TODO(b/397453582): Remove support for const hasher and remove this test.
+TEST(Table, ConstLambdaHash) {
+ int64_t multiplier = 17;
+ // Make sure that code compiles and work OK with non-empty hasher with const
+ // qualifier.
+ const auto hash = [multiplier](SizedValue<64> value) -> size_t {
+ return static_cast<size_t>(static_cast<int64_t>(value) * multiplier);
+ };
+ static_assert(!std::is_empty_v<decltype(hash)>);
+ absl::flat_hash_set<SizedValue<64>, decltype(hash)> t(0, hash);
+ t.insert(1);
+ EXPECT_EQ(t.size(), 1);
+ EXPECT_EQ(t.find(1), t.begin());
+ EXPECT_EQ(t.find(2), t.end());
+ t.insert(2);
+ EXPECT_EQ(t.size(), 2);
+ EXPECT_NE(t.find(1), t.end());
+ EXPECT_NE(t.find(2), t.end());
+ EXPECT_EQ(t.find(3), t.end());
+}
+
+struct ConstUint8Hash {
+ size_t operator()(uint8_t) const { return *value; }
+ size_t* value;
+};
+
+// This test is imitating growth of a very big table and triggers all buffer
+// overflows.
+// We try to insert all elements into the first probe group.
+// So the resize codepath in test does the following:
+// 1. Insert 16 elements into the first probe group. No other elements will be
+// inserted into the first probe group.
+// 2. There will be enough elements to fill up the local buffer even for
+// encoding with 4 bytes.
+// 3. After local buffer is full, we will fill up the control buffer till
+// some point.
+// 4. Then a few times we will extend control buffer end.
+// 5. Finally we will catch up and go to overflow codepath.
+TEST(Table, GrowExtremelyLargeTable) {
+ constexpr size_t kTargetCapacity =
+#if defined(__wasm__) || defined(__asmjs__)
+ NextCapacity(ProbedItem4Bytes::kMaxNewCapacity); // OOMs on WASM.
+#else
+ NextCapacity(ProbedItem8Bytes::kMaxNewCapacity);
+#endif
+
+ size_t hash = 0;
+ // In order to save memory we use 1 byte slot.
+ // There are not enough different values to achieve big capacity, so we
+ // artificially update growth info to force resize.
+ absl::flat_hash_set<uint8_t, ConstUint8Hash> t(63, ConstUint8Hash{&hash});
+ CommonFields& common = RawHashSetTestOnlyAccess::GetCommon(t);
+ // Set 0 seed so that H1 is always 0.
+ common.set_no_seed_for_testing();
+ ASSERT_EQ(H1(t.hash_function()(75), common.seed()), 0);
+ uint8_t inserted_till = 210;
+ for (uint8_t i = 0; i < inserted_till; ++i) {
+ t.insert(i);
+ }
+ for (uint8_t i = 0; i < inserted_till; ++i) {
+ ASSERT_TRUE(t.contains(i));
+ }
+
+ for (size_t cap = t.capacity(); cap < kTargetCapacity;
+ cap = NextCapacity(cap)) {
+ ASSERT_EQ(t.capacity(), cap);
+ // Update growth info to force resize on the next insert.
+ common.growth_info().OverwriteManyEmptyAsFull(CapacityToGrowth(cap) -
+ t.size());
+ t.insert(inserted_till++);
+ ASSERT_EQ(t.capacity(), NextCapacity(cap));
+ for (uint8_t i = 0; i < inserted_till; ++i) {
+ ASSERT_TRUE(t.contains(i));
+ }
+ }
+ EXPECT_EQ(t.capacity(), kTargetCapacity);
+}
+
} // namespace
} // namespace container_internal
ABSL_NAMESPACE_END
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 5615e49..8aed18b 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -99,6 +99,11 @@
// In most cases `T` needs only to provide the `absl_container_hash`. In this
// case `std::equal_to<void>` will be used instead of `eq` part.
//
+// PERFORMANCE WARNING: Erasure & sparsity can negatively affect performance:
+// * Iteration takes O(capacity) time, not O(size).
+// * erase() slows down begin() and ++iterator.
+// * Capacity only shrinks on rehash() or clear() -- not on erase().
+//
// Example:
//
// // Create a node hash map of three strings (that map to strings)
@@ -120,7 +125,7 @@
template <class Key, class Value, class Hash = DefaultHashContainerHash<Key>,
class Eq = DefaultHashContainerEq<Key>,
class Alloc = std::allocator<std::pair<const Key, Value>>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER node_hash_map
+class ABSL_ATTRIBUTE_OWNER node_hash_map
: public absl::container_internal::raw_hash_map<
absl::container_internal::NodeHashMapPolicy<Key, Value>, Hash, Eq,
Alloc> {
@@ -236,8 +241,13 @@
// Erases the element at `position` of the `node_hash_map`, returning
// `void`.
//
- // NOTE: this return behavior is different than that of STL containers in
- // general and `std::unordered_map` in particular.
+ // NOTE: Returning `void` in this case is different than that of STL
+ // containers in general and `std::unordered_map` in particular (which
+ // return an iterator to the element following the erased element). If that
+ // iterator is needed, simply post increment the iterator:
+ //
+ // map.erase(it++);
+ //
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -417,8 +427,7 @@
// node_hash_map::swap(node_hash_map& other)
//
// Exchanges the contents of this `node_hash_map` with those of the `other`
- // node hash map, avoiding invocation of any move, copy, or swap operations on
- // individual elements.
+ // node hash map.
//
// All iterators and references on the `node_hash_map` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
@@ -558,6 +567,21 @@
return container_internal::EraseIf(pred, &c);
}
+// swap(node_hash_map<>, node_hash_map<>)
+//
+// Swaps the contents of two `node_hash_map` containers.
+//
+// NOTE: we need to define this function template in order for
+// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
+// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
+// derived-to-base conversion, whereas `std::swap` is a function template so
+// `std::swap` will be preferred by compiler.
+template <typename K, typename V, typename H, typename E, typename A>
+void swap(node_hash_map<K, V, H, E, A>& x,
+ node_hash_map<K, V, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
+ return x.swap(y);
+}
+
namespace container_internal {
// c_for_each_fast(node_hash_map<>, Function)
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
index 4ad5d0d..c67d81f 100644
--- a/absl/container/node_hash_map_test.cc
+++ b/absl/container/node_hash_map_test.cc
@@ -322,8 +322,6 @@
}
}
-// This test requires std::launder for mutable key access in node handles.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
TEST(NodeHashMap, NodeHandleMutableKeyAccess) {
node_hash_map<std::string, std::string> map;
@@ -335,7 +333,6 @@
EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
}
-#endif
TEST(NodeHashMap, RecursiveTypeCompiles) {
struct RecursiveType {
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index 53435ae..6240e2d 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -97,6 +97,11 @@
// In most cases `T` needs only to provide the `absl_container_hash`. In this
// case `std::equal_to<void>` will be used instead of `eq` part.
//
+// PERFORMANCE WARNING: Erasure & sparsity can negatively affect performance:
+// * Iteration takes O(capacity) time, not O(size).
+// * erase() slows down begin() and ++iterator.
+// * Capacity only shrinks on rehash() or clear() -- not on erase().
+//
// Example:
//
// // Create a node hash set of three strings
@@ -115,7 +120,7 @@
// }
template <class T, class Hash = DefaultHashContainerHash<T>,
class Eq = DefaultHashContainerEq<T>, class Alloc = std::allocator<T>>
-class ABSL_INTERNAL_ATTRIBUTE_OWNER node_hash_set
+class ABSL_ATTRIBUTE_OWNER node_hash_set
: public absl::container_internal::raw_hash_set<
absl::container_internal::NodeHashSetPolicy<T>, Hash, Eq, Alloc> {
using Base = typename node_hash_set::raw_hash_set;
@@ -230,8 +235,13 @@
// Erases the element at `position` of the `node_hash_set`, returning
// `void`.
//
- // NOTE: this return behavior is different than that of STL containers in
- // general and `std::unordered_set` in particular.
+ // NOTE: Returning `void` in this case is different than that of STL
+ // containers in general and `std::unordered_map` in particular (which
+ // return an iterator to the element following the erased element). If that
+ // iterator is needed, simply post increment the iterator:
+ //
+ // map.erase(it++);
+ //
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -349,8 +359,7 @@
// node_hash_set::swap(node_hash_set& other)
//
// Exchanges the contents of this `node_hash_set` with those of the `other`
- // node hash set, avoiding invocation of any move, copy, or swap operations on
- // individual elements.
+ // node hash set.
//
// All iterators and references on the `node_hash_set` remain valid, excepting
// for the past-the-end iterator, which is invalidated.
@@ -467,6 +476,21 @@
return container_internal::EraseIf(pred, &c);
}
+// swap(node_hash_set<>, node_hash_set<>)
+//
+// Swaps the contents of two `node_hash_set` containers.
+//
+// NOTE: we need to define this function template in order for
+// `flat_hash_set::swap` to be called instead of `std::swap`. Even though we
+// have `swap(raw_hash_set&, raw_hash_set&)` defined, that function requires a
+// derived-to-base conversion, whereas `std::swap` is a function template so
+// `std::swap` will be preferred by compiler.
+template <typename T, typename H, typename E, typename A>
+void swap(node_hash_set<T, H, E, A>& x,
+ node_hash_set<T, H, E, A>& y) noexcept(noexcept(x.swap(y))) {
+ return x.swap(y);
+}
+
namespace container_internal {
// c_for_each_fast(node_hash_set<>, Function)
diff --git a/absl/container/sample_element_size_test.cc b/absl/container/sample_element_size_test.cc
index 22470b4..ccc616f 100644
--- a/absl/container/sample_element_size_test.cc
+++ b/absl/container/sample_element_size_test.cc
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
+#include "absl/container/internal/hashtablez_sampler.h"
#include "absl/container/node_hash_map.h"
#include "absl/container/node_hash_set.h"
@@ -46,6 +47,7 @@
std::vector<Table>& tables,
const std::vector<typename Table::value_type>& values,
size_t expected_element_size) {
+ EXPECT_GT(values.size(), 0);
for (int i = 0; i < 10; ++i) {
// We create a new table and must store it somewhere so that when we store
// a pointer to the resulting `HashtablezInfo` into `preexisting_info`
@@ -82,6 +84,7 @@
// Enable sampling even if the prod default is off.
SetHashtablezEnabled(true);
SetHashtablezSampleParameter(1);
+ TestOnlyRefreshSamplingStateForCurrentThread();
auto& sampler = GlobalHashtablezSampler();
std::vector<flat_hash_map<int, bigstruct>> flat_map_tables;
@@ -92,14 +95,6 @@
std::vector<std::pair<const int, bigstruct>> map_values = {{0, bigstruct{}},
{1, bigstruct{}}};
- // It takes thousands of new tables after changing the sampling parameters
- // before you actually get some instrumentation. And if you must actually
- // put something into those tables.
- for (int i = 0; i < 10000; ++i) {
- flat_map_tables.emplace_back();
- flat_map_tables.back()[i] = bigstruct{};
- }
-
// clang-tidy gives a false positive on this declaration. This unordered set
// cannot be a flat_hash_set, however, since that would introduce a mutex
// deadlock.
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
index a618199..f1d8b26 100644
--- a/absl/copts/AbseilConfigureCopts.cmake
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -71,7 +71,7 @@
endif()
-if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "QCC")
set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_GCC_TEST_FLAGS}")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # MATCHES so we get both Clang and AppleClang
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
index da2282f..7d8af92 100644
--- a/absl/copts/GENERATED_AbseilCopts.cmake
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -23,6 +23,7 @@
"-Wno-implicit-int-conversion"
"-Wno-missing-prototypes"
"-Wno-missing-variable-declarations"
+ "-Wno-nullability-completeness"
"-Wno-shadow"
"-Wno-shorten-64-to-32"
"-Wno-sign-compare"
@@ -97,6 +98,7 @@
"-Winvalid-constexpr"
"-Wliteral-conversion"
"-Wmissing-declarations"
+ "-Wnullability-completeness"
"-Woverlength-strings"
"-Wpointer-arith"
"-Wself-assign"
@@ -106,6 +108,7 @@
"-Wstring-conversion"
"-Wtautological-overlap-compare"
"-Wtautological-unsigned-zero-compare"
+ "-Wthread-safety"
"-Wundef"
"-Wuninitialized"
"-Wunreachable-code"
@@ -144,6 +147,7 @@
"-Wstring-conversion"
"-Wtautological-overlap-compare"
"-Wtautological-unsigned-zero-compare"
+ "-Wthread-safety"
"-Wundef"
"-Wuninitialized"
"-Wunreachable-code"
@@ -161,6 +165,7 @@
"-Wno-implicit-int-conversion"
"-Wno-missing-prototypes"
"-Wno-missing-variable-declarations"
+ "-Wno-nullability-completeness"
"-Wno-shadow"
"-Wno-shorten-64-to-32"
"-Wno-sign-compare"
@@ -181,8 +186,6 @@
"/wd4005"
"/wd4068"
"/wd4180"
- "/wd4244"
- "/wd4267"
"/wd4503"
"/wd4800"
"/DNOMINMAX"
@@ -202,8 +205,6 @@
"/wd4005"
"/wd4068"
"/wd4180"
- "/wd4244"
- "/wd4267"
"/wd4503"
"/wd4800"
"/DNOMINMAX"
@@ -213,23 +214,9 @@
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
"/wd4018"
"/wd4101"
+ "/wd4244"
+ "/wd4267"
"/wd4503"
"/wd4996"
"/DNOMINMAX"
)
-
-list(APPEND ABSL_RANDOM_HWAES_ARM32_FLAGS
- "-mfpu=neon"
-)
-
-list(APPEND ABSL_RANDOM_HWAES_ARM64_FLAGS
- "-march=armv8-a+crypto"
-)
-
-list(APPEND ABSL_RANDOM_HWAES_MSVC_X64_FLAGS
-)
-
-list(APPEND ABSL_RANDOM_HWAES_X64_FLAGS
- "-maes"
- "-msse4.1"
-)
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
index b9e0071..23896e9 100644
--- a/absl/copts/GENERATED_copts.bzl
+++ b/absl/copts/GENERATED_copts.bzl
@@ -24,6 +24,7 @@
"-Wno-implicit-int-conversion",
"-Wno-missing-prototypes",
"-Wno-missing-variable-declarations",
+ "-Wno-nullability-completeness",
"-Wno-shadow",
"-Wno-shorten-64-to-32",
"-Wno-sign-compare",
@@ -98,6 +99,7 @@
"-Winvalid-constexpr",
"-Wliteral-conversion",
"-Wmissing-declarations",
+ "-Wnullability-completeness",
"-Woverlength-strings",
"-Wpointer-arith",
"-Wself-assign",
@@ -107,6 +109,7 @@
"-Wstring-conversion",
"-Wtautological-overlap-compare",
"-Wtautological-unsigned-zero-compare",
+ "-Wthread-safety",
"-Wundef",
"-Wuninitialized",
"-Wunreachable-code",
@@ -145,6 +148,7 @@
"-Wstring-conversion",
"-Wtautological-overlap-compare",
"-Wtautological-unsigned-zero-compare",
+ "-Wthread-safety",
"-Wundef",
"-Wuninitialized",
"-Wunreachable-code",
@@ -162,6 +166,7 @@
"-Wno-implicit-int-conversion",
"-Wno-missing-prototypes",
"-Wno-missing-variable-declarations",
+ "-Wno-nullability-completeness",
"-Wno-shadow",
"-Wno-shorten-64-to-32",
"-Wno-sign-compare",
@@ -182,8 +187,6 @@
"/wd4005",
"/wd4068",
"/wd4180",
- "/wd4244",
- "/wd4267",
"/wd4503",
"/wd4800",
"/DNOMINMAX",
@@ -203,8 +206,6 @@
"/wd4005",
"/wd4068",
"/wd4180",
- "/wd4244",
- "/wd4267",
"/wd4503",
"/wd4800",
"/DNOMINMAX",
@@ -214,23 +215,9 @@
"/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
"/wd4018",
"/wd4101",
+ "/wd4244",
+ "/wd4267",
"/wd4503",
"/wd4996",
"/DNOMINMAX",
]
-
-ABSL_RANDOM_HWAES_ARM32_FLAGS = [
- "-mfpu=neon",
-]
-
-ABSL_RANDOM_HWAES_ARM64_FLAGS = [
- "-march=armv8-a+crypto",
-]
-
-ABSL_RANDOM_HWAES_MSVC_X64_FLAGS = [
-]
-
-ABSL_RANDOM_HWAES_X64_FLAGS = [
- "-maes",
- "-msse4.1",
-]
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
index ca5f26d..9e0be28 100644
--- a/absl/copts/configure_copts.bzl
+++ b/absl/copts/configure_copts.bzl
@@ -15,68 +15,25 @@
"ABSL_MSVC_FLAGS",
"ABSL_MSVC_LINKOPTS",
"ABSL_MSVC_TEST_FLAGS",
- "ABSL_RANDOM_HWAES_ARM32_FLAGS",
- "ABSL_RANDOM_HWAES_ARM64_FLAGS",
- "ABSL_RANDOM_HWAES_MSVC_X64_FLAGS",
- "ABSL_RANDOM_HWAES_X64_FLAGS",
)
ABSL_DEFAULT_COPTS = select({
- "//absl:msvc_compiler": ABSL_MSVC_FLAGS,
- "//absl:clang-cl_compiler": ABSL_CLANG_CL_FLAGS,
- "//absl:clang_compiler": ABSL_LLVM_FLAGS,
- "//absl:gcc_compiler": ABSL_GCC_FLAGS,
- "//conditions:default": ABSL_GCC_FLAGS,
+ "@rules_cc//cc/compiler:msvc-cl": ABSL_MSVC_FLAGS,
+ "@rules_cc//cc/compiler:clang-cl": ABSL_CLANG_CL_FLAGS,
+ "@rules_cc//cc/compiler:clang": ABSL_LLVM_FLAGS,
+ "@rules_cc//cc/compiler:gcc": ABSL_GCC_FLAGS,
+ "//conditions:default": [],
})
ABSL_TEST_COPTS = select({
- "//absl:msvc_compiler": ABSL_MSVC_TEST_FLAGS,
- "//absl:clang-cl_compiler": ABSL_CLANG_CL_TEST_FLAGS,
- "//absl:clang_compiler": ABSL_LLVM_TEST_FLAGS,
- "//absl:gcc_compiler": ABSL_GCC_TEST_FLAGS,
- "//conditions:default": ABSL_GCC_TEST_FLAGS,
+ "@rules_cc//cc/compiler:msvc-cl": ABSL_MSVC_TEST_FLAGS,
+ "@rules_cc//cc/compiler:clang-cl": ABSL_CLANG_CL_TEST_FLAGS,
+ "@rules_cc//cc/compiler:clang": ABSL_LLVM_TEST_FLAGS,
+ "@rules_cc//cc/compiler:gcc": ABSL_GCC_TEST_FLAGS,
+ "//conditions:default": [],
})
ABSL_DEFAULT_LINKOPTS = select({
- "//absl:msvc_compiler": ABSL_MSVC_LINKOPTS,
+ "@rules_cc//cc/compiler:msvc-cl": ABSL_MSVC_LINKOPTS,
"//conditions:default": [],
})
-
-# ABSL_RANDOM_RANDEN_COPTS blaze copts flags which are required by each
-# environment to build an accelerated RandenHwAes library.
-ABSL_RANDOM_RANDEN_COPTS = select({
- # APPLE
- ":cpu_darwin_x86_64": ABSL_RANDOM_HWAES_X64_FLAGS,
- ":cpu_darwin": ABSL_RANDOM_HWAES_X64_FLAGS,
- ":cpu_x64_windows_msvc": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
- ":cpu_x64_windows": ABSL_RANDOM_HWAES_MSVC_X64_FLAGS,
- ":cpu_k8": ABSL_RANDOM_HWAES_X64_FLAGS,
- ":cpu_ppc": ["-mcrypto"],
- ":cpu_aarch64": ABSL_RANDOM_HWAES_ARM64_FLAGS,
-
- # Supported by default or unsupported.
- "//conditions:default": [],
-})
-
-# absl_random_randen_copts_init:
-# Initialize the config targets based on cpu, os, etc. used to select
-# the required values for ABSL_RANDOM_RANDEN_COPTS
-def absl_random_randen_copts_init():
- """Initialize the config_settings used by ABSL_RANDOM_RANDEN_COPTS."""
-
- # CPU configs.
- # These configs have consistent flags to enable HWAES intsructions.
- cpu_configs = [
- "ppc",
- "k8",
- "darwin_x86_64",
- "darwin",
- "x64_windows_msvc",
- "x64_windows",
- "aarch64",
- ]
- for cpu in cpu_configs:
- native.config_setting(
- name = "cpu_%s" % cpu,
- values = {"cpu": cpu},
- )
diff --git a/absl/copts/copts.py b/absl/copts/copts.py
index 2d85ac7..8cf8f31 100644
--- a/absl/copts/copts.py
+++ b/absl/copts/copts.py
@@ -57,6 +57,7 @@
"-Winvalid-constexpr",
"-Wliteral-conversion",
"-Wmissing-declarations",
+ "-Wnullability-completeness",
"-Woverlength-strings",
"-Wpointer-arith",
"-Wself-assign",
@@ -66,6 +67,7 @@
"-Wstring-conversion",
"-Wtautological-overlap-compare",
"-Wtautological-unsigned-zero-compare",
+ "-Wthread-safety",
"-Wundef",
"-Wuninitialized",
"-Wunreachable-code",
@@ -91,6 +93,7 @@
"-Wno-implicit-int-conversion",
"-Wno-missing-prototypes",
"-Wno-missing-variable-declarations",
+ "-Wno-nullability-completeness",
"-Wno-shadow",
"-Wno-shorten-64-to-32",
"-Wno-sign-compare",
@@ -118,10 +121,6 @@
"/wd4068", # unknown pragma
# qualifier applied to function type has no meaning; ignored
"/wd4180",
- # conversion from 'type1' to 'type2', possible loss of data
- "/wd4244",
- # conversion from 'size_t' to 'type', possible loss of data
- "/wd4267",
# The decorated name was longer than the compiler limit
"/wd4503",
# forcing value to bool 'true' or 'false' (performance warning)
@@ -158,37 +157,35 @@
COPT_VARS = {
"ABSL_GCC_FLAGS": ABSL_GCC_FLAGS,
"ABSL_GCC_TEST_FLAGS": GccStyleFilterAndCombine(
- ABSL_GCC_FLAGS, ABSL_GCC_TEST_ADDITIONAL_FLAGS),
+ ABSL_GCC_FLAGS, ABSL_GCC_TEST_ADDITIONAL_FLAGS
+ ),
"ABSL_LLVM_FLAGS": ABSL_LLVM_FLAGS,
"ABSL_LLVM_TEST_FLAGS": GccStyleFilterAndCombine(
- ABSL_LLVM_FLAGS, ABSL_LLVM_TEST_ADDITIONAL_FLAGS),
- "ABSL_CLANG_CL_FLAGS":
- MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES,
- "ABSL_CLANG_CL_TEST_FLAGS":
- MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + ABSL_LLVM_TEST_ADDITIONAL_FLAGS,
- "ABSL_MSVC_FLAGS":
- MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES,
- "ABSL_MSVC_TEST_FLAGS":
- MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES + [
+ ABSL_LLVM_FLAGS, ABSL_LLVM_TEST_ADDITIONAL_FLAGS
+ ),
+ "ABSL_CLANG_CL_FLAGS": MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES,
+ "ABSL_CLANG_CL_TEST_FLAGS": (
+ MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + ABSL_LLVM_TEST_ADDITIONAL_FLAGS
+ ),
+ "ABSL_MSVC_FLAGS": (
+ MSVC_BIG_WARNING_FLAGS + MSVC_WARNING_FLAGS + MSVC_DEFINES
+ ),
+ "ABSL_MSVC_TEST_FLAGS": (
+ MSVC_BIG_WARNING_FLAGS
+ + MSVC_WARNING_FLAGS
+ + MSVC_DEFINES
+ + [
"/wd4018", # signed/unsigned mismatch
"/wd4101", # unreferenced local variable
+ "/wd4244", # shortening conversion
+ "/wd4267", # shortening conversion
"/wd4503", # decorated name length exceeded, name was truncated
"/wd4996", # use of deprecated symbol
"/DNOMINMAX", # disable the min() and max() macros from <windows.h>
- ],
+ ]
+ ),
"ABSL_MSVC_LINKOPTS": [
# Object file doesn't export any previously undefined symbols
"-ignore:4221",
],
- # "HWAES" is an abbreviation for "hardware AES" (AES - Advanced Encryption
- # Standard). These flags are used for detecting whether or not the target
- # architecture has hardware support for AES instructions which can be used
- # to improve performance of some random bit generators.
- "ABSL_RANDOM_HWAES_ARM64_FLAGS": ["-march=armv8-a+crypto"],
- "ABSL_RANDOM_HWAES_ARM32_FLAGS": ["-mfpu=neon"],
- "ABSL_RANDOM_HWAES_X64_FLAGS": [
- "-maes",
- "-msse4.1",
- ],
- "ABSL_RANDOM_HWAES_MSVC_X64_FLAGS": [],
}
diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel
index 890d637..b659a7e 100644
--- a/absl/crc/BUILD.bazel
+++ b/absl/crc/BUILD.bazel
@@ -42,6 +42,7 @@
deps = [
"//absl/base",
"//absl/base:config",
+ "//absl/types:optional",
],
)
@@ -111,8 +112,8 @@
":crc32c",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -158,8 +159,8 @@
"//absl/random",
"//absl/random:distributions",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -171,8 +172,8 @@
visibility = ["//visibility:private"],
deps = [
":non_temporal_memcpy",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -200,8 +201,8 @@
deps = [
":crc32c",
":crc_cord_state",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -219,6 +220,6 @@
":crc32c",
"//absl/memory",
"//absl/strings",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt
index d52a1bc..f068e54 100644
--- a/absl/crc/CMakeLists.txt
+++ b/absl/crc/CMakeLists.txt
@@ -25,6 +25,7 @@
DEPS
absl::base
absl::config
+ absl::optional
)
# Internal-only target, do not depend on directly.
diff --git a/absl/crc/crc32c.cc b/absl/crc/crc32c.cc
index 468c1b3..9b1ef7e 100644
--- a/absl/crc/crc32c.cc
+++ b/absl/crc/crc32c.cc
@@ -54,10 +54,6 @@
} // namespace crc_internal
-crc32c_t ComputeCrc32c(absl::string_view buf) {
- return ExtendCrc32c(crc32c_t{0}, buf);
-}
-
crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length) {
uint32_t crc = static_cast<uint32_t>(initial_crc) ^ kCRC32Xor;
CrcEngine()->ExtendByZeroes(&crc, length);
diff --git a/absl/crc/crc32c.h b/absl/crc/crc32c.h
index 362861e..5ecc6b3 100644
--- a/absl/crc/crc32c.h
+++ b/absl/crc/crc32c.h
@@ -83,11 +83,6 @@
// CRC32C Computation Functions
// -----------------------------------------------------------------------------
-// ComputeCrc32c()
-//
-// Returns the CRC32C value of the provided string.
-crc32c_t ComputeCrc32c(absl::string_view buf);
-
// ExtendCrc32c()
//
// Computes a CRC32C value from an `initial_crc` CRC32C value including the
@@ -112,6 +107,13 @@
return crc_internal::ExtendCrc32cInternal(initial_crc, buf_to_add);
}
+// ComputeCrc32c()
+//
+// Returns the CRC32C value of the provided string.
+inline crc32c_t ComputeCrc32c(absl::string_view buf) {
+ return ExtendCrc32c(crc32c_t{0}, buf);
+}
+
// ExtendCrc32cByZeroes()
//
// Computes a CRC32C value for a buffer with an `initial_crc` CRC32C value,
diff --git a/absl/crc/crc32c_benchmark.cc b/absl/crc/crc32c_benchmark.cc
index 3b46ef3..d7cecc3 100644
--- a/absl/crc/crc32c_benchmark.cc
+++ b/absl/crc/crc32c_benchmark.cc
@@ -40,7 +40,13 @@
benchmark::DoNotOptimize(crc);
}
}
-BENCHMARK(BM_Calculate)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000);
+BENCHMARK(BM_Calculate)
+ ->Arg(0)
+ ->Arg(1)
+ ->Arg(100)
+ ->Arg(2048)
+ ->Arg(10000)
+ ->Arg(500000);
void BM_Extend(benchmark::State& state) {
int len = state.range(0);
@@ -53,8 +59,14 @@
benchmark::DoNotOptimize(crc);
}
}
-BENCHMARK(BM_Extend)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000)->Arg(
- 100 * 1000 * 1000);
+BENCHMARK(BM_Extend)
+ ->Arg(0)
+ ->Arg(1)
+ ->Arg(100)
+ ->Arg(2048)
+ ->Arg(10000)
+ ->Arg(500000)
+ ->Arg(100 * 1000 * 1000);
// Make working set >> CPU cache size to benchmark prefetches better
void BM_ExtendCacheMiss(benchmark::State& state) {
@@ -147,7 +159,8 @@
state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) *
state.range(0));
}
-BENCHMARK(BM_Memcpy)->Arg(0)->Arg(1)->Arg(100)->Arg(10000)->Arg(500000);
+BENCHMARK(BM_Memcpy)->Arg(0)->Arg(1)->Arg(100)->Arg(2048)->Arg(10000)->Arg(
+ 500000);
void BM_RemoveSuffix(benchmark::State& state) {
int full_string_len = state.range(0);
diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc
index d7eedd1..c59f773 100644
--- a/absl/crc/internal/cpu_detect.cc
+++ b/absl/crc/internal/cpu_detect.cc
@@ -18,12 +18,21 @@
#include <string>
#include "absl/base/config.h"
+#include "absl/types/optional.h" // IWYU pragma: keep
#if defined(__aarch64__) && defined(__linux__)
#include <asm/hwcap.h>
#include <sys/auxv.h>
#endif
+#if defined(__aarch64__) && defined(__APPLE__)
+#if defined(__has_include) && __has_include(<arm/cpu_capabilities_public.h>)
+#include <arm/cpu_capabilities_public.h>
+#endif
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#endif
+
#if defined(_WIN32) || defined(_WIN64)
#include <intrin.h>
#endif
@@ -269,8 +278,55 @@
}
bool SupportsArmCRC32PMULL() {
+#if defined(HWCAP_CRC32) && defined(HWCAP_PMULL)
uint64_t hwcaps = getauxval(AT_HWCAP);
return (hwcaps & HWCAP_CRC32) && (hwcaps & HWCAP_PMULL);
+#else
+ return false;
+#endif
+}
+
+#elif defined(__aarch64__) && defined(__APPLE__)
+
+CpuType GetCpuType() { return CpuType::kUnknown; }
+
+template <typename T>
+static absl::optional<T> ReadSysctlByName(const char* name) {
+ T val;
+ size_t val_size = sizeof(T);
+ int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
+ if (ret == -1) {
+ return absl::nullopt;
+ }
+ return val;
+}
+
+bool SupportsArmCRC32PMULL() {
+ // Newer XNU kernels support querying all capabilities in a single
+ // sysctlbyname.
+#if defined(CAP_BIT_CRC32) && defined(CAP_BIT_FEAT_PMULL)
+ static const absl::optional<uint64_t> caps =
+ ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
+ if (caps.has_value()) {
+ constexpr uint64_t kCrc32AndPmullCaps =
+ (uint64_t{1} << CAP_BIT_CRC32) | (uint64_t{1} << CAP_BIT_FEAT_PMULL);
+ return (*caps & kCrc32AndPmullCaps) == kCrc32AndPmullCaps;
+ }
+#endif
+
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619
+ static const absl::optional<int> armv8_crc32 =
+ ReadSysctlByName<int>("hw.optional.armv8_crc32");
+ if (armv8_crc32.value_or(0) == 0) {
+ return false;
+ }
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
+ static const absl::optional<int> feat_pmull =
+ ReadSysctlByName<int>("hw.optional.arm.FEAT_PMULL");
+ if (feat_pmull.value_or(0) == 0) {
+ return false;
+ }
+ return true;
}
#else
diff --git a/absl/crc/internal/crc32_x86_arm_combined_simd.h b/absl/crc/internal/crc32_x86_arm_combined_simd.h
index 0f6e347..5a9b61a 100644
--- a/absl/crc/internal/crc32_x86_arm_combined_simd.h
+++ b/absl/crc/internal/crc32_x86_arm_combined_simd.h
@@ -99,19 +99,12 @@
// Produces a XOR operation of |l| and |r|.
V128 V128_Xor(const V128 l, const V128 r);
-// Produces an AND operation of |l| and |r|.
-V128 V128_And(const V128 l, const V128 r);
-
// Sets the lower half of a 128 bit register to the given 64-bit value and
// zeroes the upper half.
// dst[63:0] := |r|
// dst[127:64] := |0|
V128 V128_From64WithZeroFill(const uint64_t r);
-// Shift |l| right by |imm| bytes while shifting in zeros.
-template <int imm>
-V128 V128_ShiftRight(const V128 l);
-
// Extracts a 32-bit integer from |l|, selected with |imm|.
template <int imm>
int V128_Extract32(const V128 l);
@@ -170,18 +163,11 @@
inline V128 V128_Xor(const V128 l, const V128 r) { return _mm_xor_si128(l, r); }
-inline V128 V128_And(const V128 l, const V128 r) { return _mm_and_si128(l, r); }
-
inline V128 V128_From64WithZeroFill(const uint64_t r) {
return _mm_set_epi64x(static_cast<int64_t>(0), static_cast<int64_t>(r));
}
template <int imm>
-inline V128 V128_ShiftRight(const V128 l) {
- return _mm_srli_si128(l, imm);
-}
-
-template <int imm>
inline int V128_Extract32(const V128 l) {
return _mm_extract_epi32(l, imm);
}
@@ -261,8 +247,6 @@
inline V128 V128_Xor(const V128 l, const V128 r) { return veorq_u64(l, r); }
-inline V128 V128_And(const V128 l, const V128 r) { return vandq_u64(l, r); }
-
inline V128 V128_From64WithZeroFill(const uint64_t r){
constexpr uint64x2_t kZero = {0, 0};
return vsetq_lane_u64(r, kZero, 0);
@@ -270,12 +254,6 @@
template <int imm>
-inline V128 V128_ShiftRight(const V128 l) {
- return vreinterpretq_u64_s8(
- vextq_s8(vreinterpretq_s8_u64(l), vdupq_n_s8(0), imm));
-}
-
-template <int imm>
inline int V128_Extract32(const V128 l) {
return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm);
}
diff --git a/absl/crc/internal/crc_x86_arm_combined.cc b/absl/crc/internal/crc_x86_arm_combined.cc
index 79dace3..3194bec 100644
--- a/absl/crc/internal/crc_x86_arm_combined.cc
+++ b/absl/crc/internal/crc_x86_arm_combined.cc
@@ -64,27 +64,27 @@
constexpr size_t kSmallCutoff = 256;
constexpr size_t kMediumCutoff = 2048;
-#define ABSL_INTERNAL_STEP1(crc) \
+#define ABSL_INTERNAL_STEP1(crc, p) \
do { \
crc = CRC32_u8(static_cast<uint32_t>(crc), *p++); \
} while (0)
-#define ABSL_INTERNAL_STEP2(crc) \
+#define ABSL_INTERNAL_STEP2(crc, p) \
do { \
crc = \
CRC32_u16(static_cast<uint32_t>(crc), absl::little_endian::Load16(p)); \
p += 2; \
} while (0)
-#define ABSL_INTERNAL_STEP4(crc) \
+#define ABSL_INTERNAL_STEP4(crc, p) \
do { \
crc = \
CRC32_u32(static_cast<uint32_t>(crc), absl::little_endian::Load32(p)); \
p += 4; \
} while (0)
-#define ABSL_INTERNAL_STEP8(crc, data) \
- do { \
- crc = CRC32_u64(static_cast<uint32_t>(crc), \
- absl::little_endian::Load64(data)); \
- data += 8; \
+#define ABSL_INTERNAL_STEP8(crc, p) \
+ do { \
+ crc = \
+ CRC32_u64(static_cast<uint32_t>(crc), absl::little_endian::Load64(p)); \
+ p += 8; \
} while (0)
#define ABSL_INTERNAL_STEP8BY2(crc0, crc1, p0, p1) \
do { \
@@ -221,7 +221,8 @@
// We are applying it to CRC32C polynomial.
ABSL_ATTRIBUTE_ALWAYS_INLINE void Process64BytesPclmul(
const uint8_t* p, V128* partialCRC) const {
- V128 loopMultiplicands = V128_Load(reinterpret_cast<const V128*>(k1k2));
+ V128 loopMultiplicands =
+ V128_Load(reinterpret_cast<const V128*>(kFoldAcross512Bits));
V128 partialCRC1 = partialCRC[0];
V128 partialCRC2 = partialCRC[1];
@@ -265,53 +266,33 @@
// Combine 4 vectors of partial crc into a single vector.
V128 reductionMultiplicands =
- V128_Load(reinterpret_cast<const V128*>(k5k6));
+ V128_Load(reinterpret_cast<const V128*>(kFoldAcross256Bits));
V128 low = V128_PMulLow(reductionMultiplicands, partialCRC1);
V128 high = V128_PMulHi(reductionMultiplicands, partialCRC1);
partialCRC1 = V128_Xor(low, high);
- partialCRC1 = V128_Xor(partialCRC1, partialCRC2);
+ partialCRC1 = V128_Xor(partialCRC1, partialCRC3);
- low = V128_PMulLow(reductionMultiplicands, partialCRC3);
- high = V128_PMulHi(reductionMultiplicands, partialCRC3);
+ low = V128_PMulLow(reductionMultiplicands, partialCRC2);
+ high = V128_PMulHi(reductionMultiplicands, partialCRC2);
- partialCRC3 = V128_Xor(low, high);
- partialCRC3 = V128_Xor(partialCRC3, partialCRC4);
+ partialCRC2 = V128_Xor(low, high);
+ partialCRC2 = V128_Xor(partialCRC2, partialCRC4);
- reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k3k4));
+ reductionMultiplicands =
+ V128_Load(reinterpret_cast<const V128*>(kFoldAcross128Bits));
low = V128_PMulLow(reductionMultiplicands, partialCRC1);
high = V128_PMulHi(reductionMultiplicands, partialCRC1);
V128 fullCRC = V128_Xor(low, high);
- fullCRC = V128_Xor(fullCRC, partialCRC3);
+ fullCRC = V128_Xor(fullCRC, partialCRC2);
// Reduce fullCRC into scalar value.
- reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k5k6));
-
- V128 mask = V128_Load(reinterpret_cast<const V128*>(kMask));
-
- V128 tmp = V128_PMul01(reductionMultiplicands, fullCRC);
- fullCRC = V128_ShiftRight<8>(fullCRC);
- fullCRC = V128_Xor(fullCRC, tmp);
-
- reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(k7k0));
-
- tmp = V128_ShiftRight<4>(fullCRC);
- fullCRC = V128_And(fullCRC, mask);
- fullCRC = V128_PMulLow(reductionMultiplicands, fullCRC);
- fullCRC = V128_Xor(tmp, fullCRC);
-
- reductionMultiplicands = V128_Load(reinterpret_cast<const V128*>(kPoly));
-
- tmp = V128_And(fullCRC, mask);
- tmp = V128_PMul01(reductionMultiplicands, tmp);
- tmp = V128_And(tmp, mask);
- tmp = V128_PMulLow(reductionMultiplicands, tmp);
-
- fullCRC = V128_Xor(tmp, fullCRC);
-
- return static_cast<uint64_t>(V128_Extract32<1>(fullCRC));
+ uint32_t crc = 0;
+ crc = CRC32_u64(crc, V128_Extract64<0>(fullCRC));
+ crc = CRC32_u64(crc, V128_Extract64<1>(fullCRC));
+ return crc;
}
// Update crc with 64 bytes of data from p.
@@ -325,15 +306,23 @@
return crc;
}
- // Generated by crc32c_x86_test --crc32c_generate_constants=true
- // and verified against constants in linux kernel for S390:
- // https://github.com/torvalds/linux/blob/master/arch/s390/crypto/crc32le-vx.S
- alignas(16) static constexpr uint64_t k1k2[2] = {0x0740eef02, 0x09e4addf8};
- alignas(16) static constexpr uint64_t k3k4[2] = {0x1384aa63a, 0x0ba4fc28e};
- alignas(16) static constexpr uint64_t k5k6[2] = {0x0f20c0dfe, 0x14cd00bd6};
- alignas(16) static constexpr uint64_t k7k0[2] = {0x0dd45aab8, 0x000000000};
- alignas(16) static constexpr uint64_t kPoly[2] = {0x105ec76f0, 0x0dea713f1};
- alignas(16) static constexpr uint32_t kMask[4] = {~0u, 0u, ~0u, 0u};
+ // Constants generated by './scripts/gen-crc-consts.py x86_pclmul
+ // crc32_lsb_0x82f63b78' from the Linux kernel.
+ alignas(16) static constexpr uint64_t kFoldAcross512Bits[2] = {
+ // (x^543 mod G) * x^32
+ 0x00000000740eef02,
+ // (x^479 mod G) * x^32
+ 0x000000009e4addf8};
+ alignas(16) static constexpr uint64_t kFoldAcross256Bits[2] = {
+ // (x^287 mod G) * x^32
+ 0x000000003da6d0cb,
+ // (x^223 mod G) * x^32
+ 0x00000000ba4fc28e};
+ alignas(16) static constexpr uint64_t kFoldAcross128Bits[2] = {
+ // (x^159 mod G) * x^32
+ 0x00000000f20c0dfe,
+ // (x^95 mod G) * x^32
+ 0x00000000493c7d27};
// Medium runs of bytes are broken into groups of kGroupsSmall blocks of same
// size. Each group is CRCed in parallel then combined at the end of the
@@ -345,24 +334,6 @@
static constexpr size_t kMaxStreams = 3;
};
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-alignas(16) constexpr uint64_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k1k2[2];
-alignas(16) constexpr uint64_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k3k4[2];
-alignas(16) constexpr uint64_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k5k6[2];
-alignas(16) constexpr uint64_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::k7k0[2];
-alignas(16) constexpr uint64_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kPoly[2];
-alignas(16) constexpr uint32_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMask[4];
-constexpr size_t
- CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kGroupsSmall;
-constexpr size_t CRC32AcceleratedX86ARMCombinedMultipleStreamsBase::kMaxStreams;
-#endif // ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-
template <size_t num_crc_streams, size_t num_pclmul_streams,
CutoffStrategy strategy>
class CRC32AcceleratedX86ARMCombinedMultipleStreams
@@ -384,15 +355,15 @@
length &= ~size_t{8};
}
if (length & 4) {
- ABSL_INTERNAL_STEP4(l);
+ ABSL_INTERNAL_STEP4(l, p);
length &= ~size_t{4};
}
if (length & 2) {
- ABSL_INTERNAL_STEP2(l);
+ ABSL_INTERNAL_STEP2(l, p);
length &= ~size_t{2};
}
if (length & 1) {
- ABSL_INTERNAL_STEP1(l);
+ ABSL_INTERNAL_STEP1(l, p);
length &= ~size_t{1};
}
if (length == 0) {
@@ -478,7 +449,7 @@
const uint8_t* x = RoundUp<8>(p);
// Process bytes until p is 8-byte aligned, if that isn't past the end.
while (p != x) {
- ABSL_INTERNAL_STEP1(l);
+ ABSL_INTERNAL_STEP1(l, p);
}
size_t bs = static_cast<size_t>(e - p) /
@@ -597,7 +568,7 @@
}
// Process the last few bytes
while (p != e) {
- ABSL_INTERNAL_STEP1(l);
+ ABSL_INTERNAL_STEP1(l, p);
}
#undef ABSL_INTERNAL_STEP8BY3
diff --git a/absl/crc/internal/non_temporal_memcpy.h b/absl/crc/internal/non_temporal_memcpy.h
index 7ae83bd..5d3e4e3 100644
--- a/absl/crc/internal/non_temporal_memcpy.h
+++ b/absl/crc/internal/non_temporal_memcpy.h
@@ -111,20 +111,31 @@
#endif // __SSE3__ || __aarch64__ || (_MSC_VER && __AVX__)
}
+// We try to force non_temporal_store_memcpy_avx to use AVX instructions
+// so that we can select it at runtime when AVX is available.
+// Clang on Windows has gnu::target but does not make AVX types like __m256i
+// available when trying to force specific functions to use AVX compiles.
+#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::target) && !defined(_MSC_VER) && \
+ (defined(__x86_64__) || defined(__i386__))
+#define ABSL_INTERNAL_CAN_FORCE_AVX 1
+#endif
+
// If the objects overlap, the behavior is undefined. Uses regular memcpy
// instead of non-temporal memcpy if the required CPU intrinsics are unavailable
// at compile time.
-#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::target) && \
- (defined(__x86_64__) || defined(__i386__))
+#ifdef ABSL_INTERNAL_CAN_FORCE_AVX
[[gnu::target("avx")]]
#endif
inline void *non_temporal_store_memcpy_avx(void *__restrict dst,
const void *__restrict src,
size_t len) {
- // This function requires AVX. For clang and gcc we compile it with AVX even
- // if the translation unit isn't built with AVX support. This works because we
- // only select this implementation at runtime if the CPU supports AVX.
-#if defined(__SSE3__) || (defined(_MSC_VER) && defined(__AVX__))
+ // This function requires AVX. If possible we compile it with AVX even if the
+ // translation unit isn't built with AVX support. This works because we only
+ // select this implementation at runtime if the CPU supports AVX.
+ // MSVC AVX support implies SSE3 support.
+#if ((defined(__AVX__) || defined(ABSL_INTERNAL_CAN_FORCE_AVX)) && \
+ defined(__SSE3__)) || \
+ (defined(_MSC_VER) && defined(__AVX__))
uint8_t *d = reinterpret_cast<uint8_t *>(dst);
const uint8_t *s = reinterpret_cast<const uint8_t *>(src);
@@ -170,10 +181,13 @@
}
return dst;
#else
+ // Fallback to regular memcpy so that this function compiles.
return memcpy(dst, src, len);
-#endif // __SSE3__ || (_MSC_VER && __AVX__)
+#endif
}
+#undef ABSL_INTERNAL_CAN_FORCE_AVX
+
} // namespace crc_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/crc/internal/non_temporal_memcpy_test.cc b/absl/crc/internal/non_temporal_memcpy_test.cc
index eb07a55..b2b19d3 100644
--- a/absl/crc/internal/non_temporal_memcpy_test.cc
+++ b/absl/crc/internal/non_temporal_memcpy_test.cc
@@ -57,6 +57,7 @@
}
}
+#ifdef __AVX__
TEST_P(NonTemporalMemcpyTest, AVXEquality) {
uint8_t* src = a_.data() + GetParam().src_offset;
uint8_t* dst = b_.data() + GetParam().dst_offset;
@@ -67,6 +68,7 @@
EXPECT_EQ(src[i], dst[i]);
}
}
+#endif
// 63B is smaller than one cacheline operation thus the non-temporal routine
// will not be called.
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index 52b407c..cd0f1de 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -66,9 +66,11 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":stacktrace",
+ "//absl/base:config",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/types:span",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -88,8 +90,8 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS + select({
- "//absl:msvc_compiler": ["-DEFAULTLIB:dbghelp.lib"],
- "//absl:clang-cl_compiler": ["-DEFAULTLIB:dbghelp.lib"],
+ "@rules_cc//cc/compiler:msvc-cl": ["-DEFAULTLIB:dbghelp.lib"],
+ "@rules_cc//cc/compiler:clang-cl": ["-DEFAULTLIB:dbghelp.lib"],
"//absl:mingw_compiler": [
"-DEFAULTLIB:dbghelp.lib",
"-ldbghelp",
@@ -113,13 +115,13 @@
name = "symbolize_test",
srcs = ["symbolize_test.cc"],
copts = ABSL_TEST_COPTS + select({
- "//absl:msvc_compiler": ["/Z7"],
- "//absl:clang-cl_compiler": ["/Z7"],
+ "@rules_cc//cc/compiler:msvc-cl": ["/Z7"],
+ "@rules_cc//cc/compiler:clang-cl": ["/Z7"],
"//conditions:default": [],
}),
linkopts = ABSL_DEFAULT_LINKOPTS + select({
- "//absl:msvc_compiler": ["/DEBUG"],
- "//absl:clang-cl_compiler": ["/DEBUG"],
+ "@rules_cc//cc/compiler:msvc-cl": ["/DEBUG"],
+ "@rules_cc//cc/compiler:clang-cl": ["/DEBUG"],
"//conditions:default": [],
}),
deps = [
@@ -132,7 +134,7 @@
"//absl/log:check",
"//absl/memory",
"//absl/strings",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -177,9 +179,9 @@
srcs = ["failure_signal_handler_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = select({
- "//absl:msvc_compiler": [],
- "//absl:clang-cl_compiler": [],
- "//absl:wasm": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
+ "@rules_cc//cc/compiler:clang-cl": [],
+ "@rules_cc//cc/compiler:emscripten": [],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
deps = [
@@ -189,7 +191,7 @@
"//absl/base:raw_logging_internal",
"//absl/log:check",
"//absl/strings",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -202,6 +204,7 @@
],
hdrs = [
"internal/address_is_readable.h",
+ "internal/addresses.h",
"internal/elf_mem_image.h",
"internal/vdso_support.h",
],
@@ -249,8 +252,8 @@
"//absl/base:core_headers",
"//absl/log",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -273,8 +276,8 @@
deps = [
":bounded_utf8_length_sequence",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -300,8 +303,8 @@
deps = [
":decode_rust_punycode",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -327,8 +330,8 @@
":demangle_rust",
"//absl/base:config",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -349,8 +352,8 @@
deps = [
":utf8_for_code_point",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -376,8 +379,8 @@
":leak_check",
"//absl/base:config",
"//absl/log",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -394,8 +397,8 @@
deps = [
":leak_check",
"//absl/log",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -424,8 +427,8 @@
":stack_consumption",
"//absl/base:core_headers",
"//absl/log",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -440,6 +443,6 @@
":stacktrace",
"//absl/base:config",
"//absl/base:core_headers",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index a96b4f3..60b138a 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -55,7 +55,9 @@
${ABSL_TEST_COPTS}
DEPS
absl::stacktrace
+ absl::config
absl::core_headers
+ absl::span
GTest::gmock_main
)
@@ -174,6 +176,7 @@
debugging_internal
HDRS
"internal/address_is_readable.h"
+ "internal/addresses.h"
"internal/elf_mem_image.h"
"internal/vdso_support.h"
SRCS
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index 570d1e5..d31f5a1 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -21,6 +21,7 @@
#ifdef _WIN32
#include <windows.h>
#else
+#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#endif
@@ -65,6 +66,23 @@
#endif
#endif
+// ABSL_HAVE_PTHREAD_CPU_NUMBER_NP
+//
+// Checks whether pthread_cpu_number_np is available.
+#ifdef ABSL_HAVE_PTHREAD_CPU_NUMBER_NP
+#error ABSL_HAVE_PTHREAD_CPU_NUMBER_NP cannot be directly set
+#elif defined(__APPLE__) && defined(__has_include) && \
+ ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 110000) || \
+ (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 140200) || \
+ (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 70100) || \
+ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 140200))
+#define ABSL_HAVE_PTHREAD_CPU_NUMBER_NP 1
+#endif
+
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -330,6 +348,20 @@
using GetTidType = decltype(absl::base_internal::GetTID());
ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
+static int GetCpuNumber() {
+#ifdef ABSL_HAVE_SCHED_GETCPU
+ return sched_getcpu();
+#elif defined(ABSL_HAVE_PTHREAD_CPU_NUMBER_NP)
+ size_t cpu_num;
+ if (pthread_cpu_number_np(&cpu_num) == 0) {
+ return static_cast<int>(cpu_num);
+ }
+ return -1;
+#else
+ return -1;
+#endif
+}
+
#ifndef ABSL_HAVE_SIGACTION
static void AbslFailureSignalHandler(int signo) {
void* ucontext = nullptr;
@@ -360,10 +392,7 @@
// Increase the chance that the CPU we report was the same CPU on which the
// signal was received by doing this as early as possible, i.e. after
// verifying that this is not a recursive signal handler invocation.
- int my_cpu = -1;
-#ifdef ABSL_HAVE_SCHED_GETCPU
- my_cpu = sched_getcpu();
-#endif
+ int my_cpu = GetCpuNumber();
#ifdef ABSL_HAVE_ALARM
// Set an alarm to abort the program in case this code hangs or deadlocks.
diff --git a/absl/debugging/internal/addresses.h b/absl/debugging/internal/addresses.h
new file mode 100644
index 0000000..504fd6f
--- /dev/null
+++ b/absl/debugging/internal/addresses.h
@@ -0,0 +1,57 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESSES_H_
+#define ABSL_DEBUGGING_INTERNAL_ADDRESSES_H_
+
+#include <stdint.h>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace debugging_internal {
+
+// Removes any metadata (tag bits) from the given pointer, converting it into a
+// user-readable address.
+inline uintptr_t StripPointerMetadata(uintptr_t ptr) {
+#if defined(__aarch64__)
+ // When PAC-RET (-mbranch-protection=pac-ret) is enabled, return addresses
+ // stored on the stack will be signed, which means that pointer bits outside
+ // of the virtual address range are potentially set. Since the stacktrace code
+ // is expected to return normal code pointers, this function clears those
+ // bits.
+ register uintptr_t x30 __asm__("x30") = ptr;
+ // The normal instruction for clearing PAC bits is XPACI, but for
+ // compatibility with ARM platforms that do not support pointer
+ // authentication, we use the hint space instruction XPACLRI instead. Hint
+ // space instructions behave as NOPs on unsupported platforms.
+#define ABSL_XPACLRI_HINT "hint #0x7;"
+ asm(ABSL_XPACLRI_HINT : "+r"(x30)); // asm("xpaclri" : "+r"(x30));
+#undef ABSL_XPACLRI_HINT
+ return x30;
+#else
+ return ptr;
+#endif
+}
+
+inline uintptr_t StripPointerMetadata(void* ptr) {
+ return StripPointerMetadata(reinterpret_cast<uintptr_t>(ptr));
+}
+
+} // namespace debugging_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_DEBUGGING_INTERNAL_ADDRESSES_H_
diff --git a/absl/debugging/internal/decode_rust_punycode.cc b/absl/debugging/internal/decode_rust_punycode.cc
index 43b46bf..6652dc2 100644
--- a/absl/debugging/internal/decode_rust_punycode.cc
+++ b/absl/debugging/internal/decode_rust_punycode.cc
@@ -172,7 +172,7 @@
} // namespace
-absl::Nullable<char*> DecodeRustPunycode(DecodeRustPunycodeOptions options) {
+char* absl_nullable DecodeRustPunycode(DecodeRustPunycodeOptions options) {
const char* punycode_begin = options.punycode_begin;
const char* const punycode_end = options.punycode_end;
char* const out_begin = options.out_begin;
diff --git a/absl/debugging/internal/decode_rust_punycode.h b/absl/debugging/internal/decode_rust_punycode.h
index 0ae53ff..44aad8a 100644
--- a/absl/debugging/internal/decode_rust_punycode.h
+++ b/absl/debugging/internal/decode_rust_punycode.h
@@ -23,10 +23,10 @@
namespace debugging_internal {
struct DecodeRustPunycodeOptions {
- const char* punycode_begin;
- const char* punycode_end;
- char* out_begin;
- char* out_end;
+ const char* absl_nonnull punycode_begin;
+ const char* absl_nonnull punycode_end;
+ char* absl_nonnull out_begin;
+ char* absl_nonnull out_end;
};
// Given Rust Punycode in `punycode_begin .. punycode_end`, writes the
@@ -46,7 +46,7 @@
// DecodeRustPunycode is async-signal-safe with bounded runtime and a small
// stack footprint, making it suitable for use in demangling Rust symbol names
// from a signal handler.
-absl::Nullable<char*> DecodeRustPunycode(DecodeRustPunycodeOptions options);
+char* absl_nullable DecodeRustPunycode(DecodeRustPunycodeOptions options);
} // namespace debugging_internal
ABSL_NAMESPACE_END
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index caac763..5f62ebb 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -484,36 +484,6 @@
static bool IsDigit(char c) { return c >= '0' && c <= '9'; }
-// Returns true if "str" is a function clone suffix. These suffixes are used
-// by GCC 4.5.x and later versions (and our locally-modified version of GCC
-// 4.4.x) to indicate functions which have been cloned during optimization.
-// We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix.
-// Additionally, '_' is allowed along with the alphanumeric sequence.
-static bool IsFunctionCloneSuffix(const char *str) {
- size_t i = 0;
- while (str[i] != '\0') {
- bool parsed = false;
- // Consume a single [.<alpha> | _]*[.<digit>]* sequence.
- if (str[i] == '.' && (IsAlpha(str[i + 1]) || str[i + 1] == '_')) {
- parsed = true;
- i += 2;
- while (IsAlpha(str[i]) || str[i] == '_') {
- ++i;
- }
- }
- if (str[i] == '.' && IsDigit(str[i + 1])) {
- parsed = true;
- i += 2;
- while (IsDigit(str[i])) {
- ++i;
- }
- }
- if (!parsed)
- return false;
- }
- return true; // Consumed everything in "str".
-}
-
static bool EndsWith(State *state, const char chr) {
return state->parse_state.out_cur_idx > 0 &&
state->parse_state.out_cur_idx < state->out_end_idx &&
@@ -1039,7 +1009,8 @@
number = ~number + 1;
}
if (p != RemainingInput(state)) { // Conversion succeeded.
- state->parse_state.mangled_idx += p - RemainingInput(state);
+ state->parse_state.mangled_idx +=
+ static_cast<int>(p - RemainingInput(state));
UpdateHighWaterMark(state);
if (number_out != nullptr) {
// Note: possibly truncate "number".
@@ -1062,7 +1033,8 @@
}
}
if (p != RemainingInput(state)) { // Conversion succeeded.
- state->parse_state.mangled_idx += p - RemainingInput(state);
+ state->parse_state.mangled_idx +=
+ static_cast<int>(p - RemainingInput(state));
UpdateHighWaterMark(state);
return true;
}
@@ -1081,7 +1053,8 @@
}
}
if (p != RemainingInput(state)) { // Conversion succeeded.
- state->parse_state.mangled_idx += p - RemainingInput(state);
+ state->parse_state.mangled_idx +=
+ static_cast<int>(p - RemainingInput(state));
UpdateHighWaterMark(state);
return true;
}
@@ -1100,7 +1073,7 @@
} else {
MaybeAppendWithLength(state, RemainingInput(state), length);
}
- state->parse_state.mangled_idx += length;
+ state->parse_state.mangled_idx += static_cast<int>(length);
UpdateHighWaterMark(state);
return true;
}
@@ -2816,7 +2789,8 @@
// On late parse failure, roll back not only the input but also the output,
// whose trailing NUL was overwritten.
state->parse_state = copy;
- if (state->parse_state.append) {
+ if (state->parse_state.append &&
+ state->parse_state.out_cur_idx < state->out_end_idx) {
state->out[state->parse_state.out_cur_idx] = '\0';
}
return false;
@@ -2829,7 +2803,8 @@
return true;
}
state->parse_state = copy;
- if (state->parse_state.append) {
+ if (state->parse_state.append &&
+ state->parse_state.out_cur_idx < state->out_end_idx) {
state->out[state->parse_state.out_cur_idx] = '\0';
}
@@ -2927,7 +2902,7 @@
if (ParseMangledName(state)) {
if (RemainingInput(state)[0] != '\0') {
// Drop trailing function clone suffix, if any.
- if (IsFunctionCloneSuffix(RemainingInput(state))) {
+ if (RemainingInput(state)[0] == '.') {
return true;
}
// Append trailing version suffix if any.
diff --git a/absl/debugging/internal/demangle_rust.cc b/absl/debugging/internal/demangle_rust.cc
index 4309bd8..f7f6713 100644
--- a/absl/debugging/internal/demangle_rust.cc
+++ b/absl/debugging/internal/demangle_rust.cc
@@ -84,7 +84,7 @@
// structure was not recognized or exceeded implementation limits, such as by
// nesting structures too deep. In either case *this should not be used
// again.
- ABSL_MUST_USE_RESULT bool Parse() && {
+ [[nodiscard]] bool Parse() && {
// Recursively parses the grammar production named by callee, then resumes
// execution at the next statement.
//
@@ -564,7 +564,7 @@
// If the next input character is the given character, consumes it and returns
// true; otherwise returns false without consuming a character.
- ABSL_MUST_USE_RESULT bool Eat(char want) {
+ [[nodiscard]] bool Eat(char want) {
if (encoding_[pos_] != want) return false;
++pos_;
return true;
@@ -573,7 +573,7 @@
// Provided there is enough remaining output space, appends c to the output,
// writing a fresh NUL terminator afterward, and returns true. Returns false
// if the output buffer had less than two bytes free.
- ABSL_MUST_USE_RESULT bool EmitChar(char c) {
+ [[nodiscard]] bool EmitChar(char c) {
if (silence_depth_ > 0) return true;
if (out_end_ - out_ < 2) return false;
*out_++ = c;
@@ -584,7 +584,7 @@
// Provided there is enough remaining output space, appends the C string token
// to the output, followed by a NUL character, and returns true. Returns
// false if not everything fit into the output buffer.
- ABSL_MUST_USE_RESULT bool Emit(const char* token) {
+ [[nodiscard]] bool Emit(const char* token) {
if (silence_depth_ > 0) return true;
const size_t token_length = std::strlen(token);
const size_t bytes_to_copy = token_length + 1; // token and final NUL
@@ -598,7 +598,7 @@
// of disambiguator (if it's nonnegative) or "?" (if it's negative) to the
// output, followed by a NUL character, and returns true. Returns false if
// not everything fit into the output buffer.
- ABSL_MUST_USE_RESULT bool EmitDisambiguator(int disambiguator) {
+ [[nodiscard]] bool EmitDisambiguator(int disambiguator) {
if (disambiguator < 0) return EmitChar('?'); // parsed but too large
if (disambiguator == 0) return EmitChar('0');
// Convert disambiguator to decimal text. Three digits per byte is enough
@@ -618,7 +618,7 @@
// On success returns true and fills value with the encoded value if it was
// not too big, otherwise with -1. If the optional disambiguator was omitted,
// value is 0. On parse failure returns false and sets value to -1.
- ABSL_MUST_USE_RESULT bool ParseDisambiguator(int& value) {
+ [[nodiscard]] bool ParseDisambiguator(int& value) {
value = -1;
// disambiguator = s base-62-number
@@ -639,7 +639,7 @@
// On success returns true and fills value with the encoded value if it was
// not too big, otherwise with -1. On parse failure returns false and sets
// value to -1.
- ABSL_MUST_USE_RESULT bool ParseBase62Number(int& value) {
+ [[nodiscard]] bool ParseBase62Number(int& value) {
value = -1;
// base-62-number = (digit | lower | upper)* _
@@ -686,7 +686,7 @@
// A nonzero uppercase_namespace specifies the character after the N in a
// nested-identifier, e.g., 'C' for a closure, allowing ParseIdentifier to
// write out the name with the conventional decoration for that namespace.
- ABSL_MUST_USE_RESULT bool ParseIdentifier(char uppercase_namespace = '\0') {
+ [[nodiscard]] bool ParseIdentifier(char uppercase_namespace = '\0') {
// identifier -> disambiguator? undisambiguated-identifier
int disambiguator = 0;
if (!ParseDisambiguator(disambiguator)) return false;
@@ -703,7 +703,7 @@
//
// At other appearances of undisambiguated-identifier in the grammar, this
// treatment is not applicable, and the call site omits both arguments.
- ABSL_MUST_USE_RESULT bool ParseUndisambiguatedIdentifier(
+ [[nodiscard]] bool ParseUndisambiguatedIdentifier(
char uppercase_namespace = '\0', int disambiguator = 0) {
// undisambiguated-identifier -> u? decimal-number _? bytes
const bool is_punycoded = Eat('u');
@@ -766,7 +766,7 @@
// Consumes a decimal number like 0 or 123 from the input. On success returns
// true and fills value with the encoded value. If the encoded value is too
// large or otherwise unparsable, returns false and sets value to -1.
- ABSL_MUST_USE_RESULT bool ParseDecimalNumber(int& value) {
+ [[nodiscard]] bool ParseDecimalNumber(int& value) {
value = -1;
if (!IsDigit(Peek())) return false;
int encoded_number = Take() - '0';
@@ -788,7 +788,7 @@
// Consumes a binder of higher-ranked lifetimes if one is present. On success
// returns true and discards the encoded lifetime count. On parse failure
// returns false.
- ABSL_MUST_USE_RESULT bool ParseOptionalBinder() {
+ [[nodiscard]] bool ParseOptionalBinder() {
// binder -> G base-62-number
if (!Eat('G')) return true;
int ignored_binding_count;
@@ -802,7 +802,7 @@
// things we omit from output, such as the entire contents of generic-args.
//
// On parse failure returns false.
- ABSL_MUST_USE_RESULT bool ParseOptionalLifetime() {
+ [[nodiscard]] bool ParseOptionalLifetime() {
// lifetime -> L base-62-number
if (!Eat('L')) return true;
int ignored_de_bruijn_index;
@@ -811,14 +811,14 @@
// Consumes a lifetime just like ParseOptionalLifetime, but returns false if
// there is no lifetime here.
- ABSL_MUST_USE_RESULT bool ParseRequiredLifetime() {
+ [[nodiscard]] bool ParseRequiredLifetime() {
if (Peek() != 'L') return false;
return ParseOptionalLifetime();
}
// Pushes ns onto the namespace stack and returns true if the stack is not
// full, else returns false.
- ABSL_MUST_USE_RESULT bool PushNamespace(char ns) {
+ [[nodiscard]] bool PushNamespace(char ns) {
if (namespace_depth_ == kNamespaceStackSize) return false;
namespace_stack_[namespace_depth_++] = ns;
return true;
@@ -830,7 +830,7 @@
// Pushes position onto the position stack and returns true if the stack is
// not full, else returns false.
- ABSL_MUST_USE_RESULT bool PushPosition(int position) {
+ [[nodiscard]] bool PushPosition(int position) {
if (position_depth_ == kPositionStackSize) return false;
position_stack_[position_depth_++] = position;
return true;
@@ -845,7 +845,7 @@
// beginning of the backref target. Returns true on success. Returns false
// if parsing failed, the stack is exhausted, or the backref target position
// is out of range.
- ABSL_MUST_USE_RESULT bool BeginBackref() {
+ [[nodiscard]] bool BeginBackref() {
// backref = B base-62-number (B already consumed)
//
// Reject backrefs that don't parse, overflow int, or don't point backward.
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index 5579221..2012184 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -556,14 +556,15 @@
EXPECT_TRUE(Demangle("_ZL3Foov.part.9.165493.constprop.775.31805", tmp,
sizeof(tmp)));
EXPECT_STREQ("Foo()", tmp);
- // Invalid (. without anything else), should not demangle.
- EXPECT_FALSE(Demangle("_ZL3Foov.", tmp, sizeof(tmp)));
- // Invalid (. with mix of alpha and digits), should not demangle.
- EXPECT_FALSE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp)));
- // Invalid (.clone. not followed by number), should not demangle.
- EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
- // Invalid (.constprop. not followed by number), should not demangle.
- EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
+ // Other suffixes should demangle too.
+ EXPECT_TRUE(Demangle("_ZL3Foov.", tmp, sizeof(tmp)));
+ EXPECT_STREQ("Foo()", tmp);
+ EXPECT_TRUE(Demangle("_ZL3Foov.abc123", tmp, sizeof(tmp)));
+ EXPECT_STREQ("Foo()", tmp);
+ EXPECT_TRUE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp)));
+ EXPECT_STREQ("Foo()", tmp);
+ EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp)));
+ EXPECT_STREQ("Foo()", tmp);
}
TEST(Demangle, Discriminators) {
@@ -2017,6 +2018,13 @@
TestOnInput(data.c_str());
}
+TEST(DemangleRegression, ShortOutputBuffer) {
+ // This should not crash.
+ char buffer[1];
+ EXPECT_FALSE(
+ absl::debugging_internal::Demangle("_ZZ2wwE", buffer, sizeof(buffer)));
+}
+
struct Base {
virtual ~Base() = default;
};
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 19c4952..1fac29c 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -35,7 +35,7 @@
#if defined(__ELF__) && !defined(__OpenBSD__) && !defined(__QNX__) && \
!defined(__native_client__) && !defined(__asmjs__) && \
!defined(__wasm__) && !defined(__HAIKU__) && !defined(__sun) && \
- !defined(__VXWORKS__) && !defined(__hexagon__)
+ !defined(__VXWORKS__) && !defined(__hexagon__) && !defined(__XTENSA__)
#define ABSL_HAVE_ELF_MEM_IMAGE 1
#endif
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h
index f41b64c..f5ba557 100644
--- a/absl/debugging/internal/stack_consumption.h
+++ b/absl/debugging/internal/stack_consumption.h
@@ -24,7 +24,7 @@
// Use this feature test macro to detect its availability.
#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly
-#elif !defined(__APPLE__) && !defined(_WIN32) && \
+#elif !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__) && \
(defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || \
defined(__aarch64__) || defined(__riscv))
#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index b123479..1746b5d 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -18,6 +18,7 @@
#include "absl/base/attributes.h"
#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/addresses.h"
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
#include "absl/debugging/stacktrace.h"
@@ -101,7 +102,8 @@
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
-ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
static void **NextStackFrame(void **old_frame_pointer, const void *uc,
const StackInfo *stack_info) {
void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer);
@@ -124,6 +126,7 @@
if (pre_signal_frame_pointer >= old_frame_pointer) {
new_frame_pointer = pre_signal_frame_pointer;
}
+ }
}
#endif
@@ -131,17 +134,13 @@
if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 7) != 0)
return nullptr;
- // Check that alleged frame pointer is actually readable. This is to
- // prevent "double fault" in case we hit the first fault due to e.g.
- // stack corruption.
- if (!absl::debugging_internal::AddressIsReadable(
- new_frame_pointer))
- return nullptr;
- }
-
+ uintptr_t new_fp_comparable = reinterpret_cast<uintptr_t>(new_frame_pointer);
// Only check the size if both frames are in the same stack.
- if (InsideSignalStack(new_frame_pointer, stack_info) ==
- InsideSignalStack(old_frame_pointer, stack_info)) {
+ const bool old_inside_signal_stack =
+ InsideSignalStack(old_frame_pointer, stack_info);
+ const bool new_inside_signal_stack =
+ InsideSignalStack(new_frame_pointer, stack_info);
+ if (new_inside_signal_stack == old_inside_signal_stack) {
// Check frame size. In strict mode, we assume frames to be under
// 100,000 bytes. In non-strict mode, we relax the limit to 1MB.
const size_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
@@ -155,16 +154,15 @@
if (frame_size > max_size) {
size_t stack_low = stack_info->stack_low;
size_t stack_high = stack_info->stack_high;
- if (InsideSignalStack(new_frame_pointer, stack_info)) {
+ if (new_inside_signal_stack) {
stack_low = stack_info->sig_stack_low;
stack_high = stack_info->sig_stack_high;
}
if (stack_high < kUnknownStackEnd &&
static_cast<size_t>(getpagesize()) < stack_low) {
- const uintptr_t new_fp_u =
- reinterpret_cast<uintptr_t>(new_frame_pointer);
// Stack bounds are known.
- if (!(stack_low < new_fp_u && new_fp_u <= stack_high)) {
+ if (!(stack_low < new_fp_comparable &&
+ new_fp_comparable <= stack_high)) {
// new_frame_pointer is not within a known stack.
return nullptr;
}
@@ -174,8 +172,19 @@
}
}
}
+ // New frame pointer is valid if it is inside either known stack or readable.
+ // This assumes that everything within either known stack is readable. Outside
+ // either known stack but readable is unexpected, and possibly corrupt, but
+ // for now assume it is valid. If it isn't actually valid, the next frame will
+ // be corrupt and we will detect that next iteration.
+ if (new_inside_signal_stack ||
+ (new_fp_comparable >= stack_info->stack_low &&
+ new_fp_comparable < stack_info->stack_high) ||
+ absl::debugging_internal::AddressIsReadable(new_frame_pointer)) {
+ return new_frame_pointer;
+ }
- return new_frame_pointer;
+ return nullptr;
}
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
@@ -184,8 +193,10 @@
ABSL_ATTRIBUTE_NOINLINE
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
-static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void *ucp,
+ int *min_dropped_frames) {
#ifdef __GNUC__
void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0));
#else
@@ -219,10 +230,18 @@
if (skip_count > 0) {
skip_count--;
} else {
- result[n] = prev_return_address;
+ result[n] = reinterpret_cast<void *>(
+ absl::debugging_internal::StripPointerMetadata(prev_return_address));
if (IS_STACK_FRAMES) {
- sizes[n] = static_cast<int>(
- ComputeStackFrameSize(prev_frame_pointer, frame_pointer));
+ if (frames != nullptr) {
+ frames[n] = absl::debugging_internal::StripPointerMetadata(
+ prev_frame_pointer) +
+ 2 * sizeof(void *) /* go past the return address */;
+ }
+ if (sizes != nullptr) {
+ sizes[n] = static_cast<int>(
+ ComputeStackFrameSize(prev_frame_pointer, frame_pointer));
+ }
}
n++;
}
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
index 102a2a1..3feb521 100644
--- a/absl/debugging/internal/stacktrace_arm-inl.inc
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -19,6 +19,7 @@
#include <cstdint>
+#include "absl/debugging/internal/addresses.h"
#include "absl/debugging/stacktrace.h"
// WARNING:
@@ -67,8 +68,9 @@
#endif
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
- const void * /* ucp */, int *min_dropped_frames) {
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void * /* ucp */,
+ int *min_dropped_frames) {
#ifdef __GNUC__
void **sp = reinterpret_cast<void**>(__builtin_frame_address(0));
#else
@@ -97,11 +99,18 @@
result[n] = *sp;
if (IS_STACK_FRAMES) {
- if (next_sp > sp) {
- sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
- } else {
- // A frame-size of 0 is used to indicate unknown frame size.
- sizes[n] = 0;
+ if (frames != nullptr) {
+ frames[n] = absl::debugging_internal::StripPointerMetadata(sp) +
+ 1 * sizeof(void *) /* go past the return address */;
+ }
+ if (sizes != nullptr) {
+ if (next_sp > sp) {
+ sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) -
+ absl::debugging_internal::StripPointerMetadata(sp);
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
}
}
n++;
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index 3929b1b..8f84a87 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -42,6 +42,12 @@
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_emscripten-inl.inc"
+#elif defined(__ANDROID__)
+#if defined(ABSL_HAVE_THREAD_LOCAL)
+#define ABSL_STACKTRACE_INL_HEADER \
+ "absl/debugging/internal/stacktrace_generic-inl.inc"
+#endif
+
#elif defined(__linux__) && !defined(__ANDROID__)
#if defined(NO_FRAME_POINTER) && \
@@ -52,11 +58,11 @@
"absl/debugging/internal/stacktrace_libunwind-inl.inc"
#define STACKTRACE_USES_LIBUNWIND 1
#elif defined(NO_FRAME_POINTER) && defined(__has_include)
-#if __has_include(<execinfo.h>)
+#if __has_include(<execinfo.h>) && defined(ABSL_HAVE_THREAD_LOCAL)
// Note: When using glibc this may require -funwind-tables to function properly.
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_generic-inl.inc"
-#endif // __has_include(<execinfo.h>)
+#endif // __has_include(<execinfo.h>) && defined(ABSL_HAVE_THREAD_LOCAL)
#elif defined(__i386__) || defined(__x86_64__)
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_x86-inl.inc"
@@ -70,11 +76,11 @@
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_riscv-inl.inc"
#elif defined(__has_include)
-#if __has_include(<execinfo.h>)
+#if __has_include(<execinfo.h>) && defined(ABSL_HAVE_THREAD_LOCAL)
// Note: When using glibc this may require -funwind-tables to function properly.
#define ABSL_STACKTRACE_INL_HEADER \
"absl/debugging/internal/stacktrace_generic-inl.inc"
-#endif // __has_include(<execinfo.h>)
+#endif // __has_include(<execinfo.h>) && defined(ABSL_HAVE_THREAD_LOCAL)
#endif // defined(__has_include)
#endif // defined(__linux__) && !defined(__ANDROID__)
diff --git a/absl/debugging/internal/stacktrace_emscripten-inl.inc b/absl/debugging/internal/stacktrace_emscripten-inl.inc
index 0f44451..2f39c70 100644
--- a/absl/debugging/internal/stacktrace_emscripten-inl.inc
+++ b/absl/debugging/internal/stacktrace_emscripten-inl.inc
@@ -21,8 +21,10 @@
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_EMSCRIPTEN_INL_H_
#include <emscripten.h>
+#include <stdint.h>
#include <atomic>
+#include <cstddef>
#include <cstring>
#include "absl/base/attributes.h"
@@ -62,8 +64,9 @@
}();
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void *ucp,
+ int *min_dropped_frames) {
if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
return 0;
}
@@ -75,7 +78,8 @@
int size;
uintptr_t pc = emscripten_stack_snapshot();
- size = emscripten_stack_unwind_buffer(pc, stack, kStackLength);
+ size =
+ static_cast<int>(emscripten_stack_unwind_buffer(pc, stack, kStackLength));
int result_count = size - skip_count;
if (result_count < 0) result_count = 0;
@@ -83,8 +87,13 @@
for (int i = 0; i < result_count; i++) result[i] = stack[i + skip_count];
if (IS_STACK_FRAMES) {
- // No implementation for finding out the stack frame sizes yet.
- memset(sizes, 0, sizeof(*sizes) * result_count);
+ // No implementation for finding out the stack frames yet.
+ if (frames != nullptr) {
+ memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count));
+ }
+ if (sizes != nullptr) {
+ memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count));
+ }
}
if (min_dropped_frames != nullptr) {
if (size - skip_count - max_depth > 0) {
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
index 5fa169a..4d5ba37 100644
--- a/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -20,13 +20,26 @@
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
+#ifndef __ANDROID__
#include <execinfo.h>
+#endif
+
#include <atomic>
+#include <cstdint>
#include <cstring>
#include "absl/debugging/stacktrace.h"
#include "absl/base/attributes.h"
+// Android local modification: locally declare backtrace() as a weak symbol.
+// Normally we would use NDK's weak symbol mode, but for an unclear reason it
+// causes backtrace() to be strongly linked into some tests even when we set
+// sdk_version to 29, which breaks Mainline backwards compatibility tests.
+// TODO: b/432562276 - investigate root cause and remove this workaround.
+#ifdef __ANDROID__
+int backtrace(void** buffer, int size) ABSL_ATTRIBUTE_WEAK;
+#endif
+
// Sometimes, we can try to get a stack trace from within a stack
// trace, because we don't block signals inside this code (which would be too
// expensive: the two extra system calls per stack trace do matter here).
@@ -46,6 +59,11 @@
// Waiting until static initializers run seems to be late enough.
// This file is included into stacktrace.cc so this will only run once.
ABSL_ATTRIBUTE_UNUSED static int stacktraces_enabler = []() {
+#ifdef __ANDROID__
+ if (&backtrace == nullptr) {
+ return 0;
+ }
+#endif
void* unused_stack[1];
// Force the first backtrace to happen early to get the one-time shared lib
// loading (allocation) out of the way. After the first call it is much safer
@@ -56,8 +74,9 @@
}();
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+static int UnwindImpl(void** result, uintptr_t* frames, int* sizes,
+ int max_depth, int skip_count, const void* ucp,
+ int* min_dropped_frames) {
if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
return 0;
}
@@ -79,8 +98,13 @@
result[i] = stack[i + skip_count];
if (IS_STACK_FRAMES) {
- // No implementation for finding out the stack frame sizes yet.
- memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count));
+ // No implementation for finding out the stack frames yet.
+ if (frames != nullptr) {
+ memset(frames, 0, sizeof(*frames) * static_cast<size_t>(result_count));
+ }
+ if (sizes != nullptr) {
+ memset(sizes, 0, sizeof(*sizes) * static_cast<size_t>(result_count));
+ }
}
if (min_dropped_frames != nullptr) {
if (size - skip_count - max_depth > 0) {
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
index a49ed2f..f82ca8f 100644
--- a/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -21,6 +21,7 @@
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
+#include "absl/debugging/internal/addresses.h"
#if defined(__linux__)
#include <asm/ptrace.h> // for PT_NIP.
#include <ucontext.h> // for ucontext_t
@@ -40,22 +41,22 @@
// Given a stack pointer, return the saved link register value.
// Note that this is the link register for a callee.
-static inline void *StacktracePowerPCGetLR(void **sp) {
+static inline void **StacktracePowerPCGetLRPtr(void **sp) {
// PowerPC has 3 main ABIs, which say where in the stack the
// Link Register is. For DARWIN and AIX (used by apple and
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
// it's in sp[1].
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
- return *(sp+2);
+ return (sp + 2);
#elif defined(_CALL_SYSV)
- return *(sp+1);
+ return (sp + 1);
#elif defined(__APPLE__) || defined(__FreeBSD__) || \
(defined(__linux__) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc.
- return *(sp+2);
+ return (sp + 2);
#elif defined(__linux)
// This check is in case the compiler doesn't define _CALL_SYSV.
- return *(sp+1);
+ return (sp + 1);
#else
#error Need to specify the PPC ABI for your architecture.
#endif
@@ -68,6 +69,7 @@
template<bool STRICT_UNWINDING, bool IS_WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
static void **NextStackFrame(void **old_sp, const void *uc) {
void **new_sp = (void **) *old_sp;
enum { kStackAlignment = 16 };
@@ -125,9 +127,8 @@
}
}
- if (new_sp != nullptr &&
- kernel_symbol_status == kAddressValid &&
- StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) {
+ if (new_sp != nullptr && kernel_symbol_status == kAddressValid &&
+ *StacktracePowerPCGetLRPtr(new_sp) == kernel_sigtramp_rt64_address) {
const ucontext_t* signal_context =
reinterpret_cast<const ucontext_t*>(uc);
void **const sp_before_signal =
@@ -164,8 +165,10 @@
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
-static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void *ucp,
+ int *min_dropped_frames) {
void **sp;
// Apple macOS uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
@@ -211,13 +214,21 @@
if (skip_count > 0) {
skip_count--;
} else {
- result[n] = StacktracePowerPCGetLR(sp);
+ void **lr = StacktracePowerPCGetLRPtr(sp);
+ result[n] = *lr;
if (IS_STACK_FRAMES) {
- if (next_sp > sp) {
- sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
- } else {
- // A frame-size of 0 is used to indicate unknown frame size.
- sizes[n] = 0;
+ if (frames != nullptr) {
+ frames[n] = absl::debugging_internal::StripPointerMetadata(lr) +
+ 1 * sizeof(void *) /* go past the return address */;
+ }
+ if (sizes != nullptr) {
+ if (next_sp > sp) {
+ sizes[n] = absl::debugging_internal::StripPointerMetadata(next_sp) -
+ absl::debugging_internal::StripPointerMetadata(sp);
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
}
}
n++;
diff --git a/absl/debugging/internal/stacktrace_riscv-inl.inc b/absl/debugging/internal/stacktrace_riscv-inl.inc
index 20183fa..f9919c6 100644
--- a/absl/debugging/internal/stacktrace_riscv-inl.inc
+++ b/absl/debugging/internal/stacktrace_riscv-inl.inc
@@ -20,6 +20,7 @@
#include <sys/ucontext.h>
#include "absl/base/config.h"
+#include "absl/debugging/internal/addresses.h"
#if defined(__linux__)
#include <sys/mman.h>
#include <ucontext.h>
@@ -36,15 +37,16 @@
#include "absl/base/attributes.h"
#include "absl/debugging/stacktrace.h"
-static const uintptr_t kUnknownFrameSize = 0;
+static constexpr ptrdiff_t kUnknownFrameSize = 0;
// Compute the size of a stack frame in [low..high). We assume that low < high.
// Return size of kUnknownFrameSize.
template <typename T>
-static inline uintptr_t ComputeStackFrameSize(const T *low, const T *high) {
+static inline ptrdiff_t ComputeStackFrameSize(const T *low, const T *high) {
const char *low_char_ptr = reinterpret_cast<const char *>(low);
const char *high_char_ptr = reinterpret_cast<const char *>(high);
- return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize;
+ return low < high ? static_cast<ptrdiff_t>(high_char_ptr - low_char_ptr)
+ : kUnknownFrameSize;
}
// Given a pointer to a stack frame, locate and return the calling stackframe,
@@ -54,6 +56,7 @@
template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
static void ** NextStackFrame(void **old_frame_pointer, const void *uc,
const std::pair<size_t, size_t> range) {
// .
@@ -93,8 +96,8 @@
// Check frame size. In strict mode, we assume frames to be under 100,000
// bytes. In non-strict mode, we relax the limit to 1MB.
- const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
- const uintptr_t frame_size =
+ const ptrdiff_t max_size = STRICT_UNWINDING ? 100000 : 1000000;
+ const ptrdiff_t frame_size =
ComputeStackFrameSize(old_frame_pointer, new_frame_pointer);
if (frame_size == kUnknownFrameSize) {
if (STRICT_UNWINDING)
@@ -116,8 +119,10 @@
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
-static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void *ucp,
+ int *min_dropped_frames) {
// The `frame_pointer` that is computed here points to the top of the frame.
// The two words preceding the address are the return address and the previous
// frame pointer.
@@ -151,7 +156,14 @@
} else {
result[n] = return_address;
if (IS_STACK_FRAMES) {
- sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+ // NextStackFrame() has already checked that frame size fits to int
+ if (frames != nullptr) {
+ frames[n] =
+ absl::debugging_internal::StripPointerMetadata(frame_pointer);
+ }
+ if (sizes != nullptr) {
+ sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer);
+ }
}
n++;
}
diff --git a/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
index 5b8fb19..ec63940 100644
--- a/absl/debugging/internal/stacktrace_unimplemented-inl.inc
+++ b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -2,9 +2,10 @@
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-static int UnwindImpl(void** /* result */, int* /* sizes */,
- int /* max_depth */, int /* skip_count */,
- const void* /* ucp */, int *min_dropped_frames) {
+static int UnwindImpl(void** /* result */, uintptr_t* /* frames */,
+ int* /* sizes */, int /* max_depth */,
+ int /* skip_count */, const void* /* ucp */,
+ int* min_dropped_frames) {
if (min_dropped_frames != nullptr) {
*min_dropped_frames = 0;
}
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
index ef2b973..f57c187 100644
--- a/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -37,42 +37,29 @@
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
-#include <windows.h> // for GetProcAddress and GetModuleHandle
+#include <windows.h> // CaptureStackBackTrace
+
#include <cassert>
-typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
- IN ULONG frames_to_skip,
- IN ULONG frames_to_capture,
- OUT PVOID *backtrace,
- OUT PULONG backtrace_hash);
-
-// It is not possible to load RtlCaptureStackBackTrace at static init time in
-// UWP. CaptureStackBackTrace is the public version of RtlCaptureStackBackTrace
-#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
- !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
- &::CaptureStackBackTrace;
-#else
-// Load the function we need at static init time, where we don't have
-// to worry about someone else holding the loader's lock.
-static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
- (RtlCaptureStackBackTrace_Function*)GetProcAddress(
- GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
-#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
-
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
- const void*, int* min_dropped_frames) {
+static int UnwindImpl(void** result, uintptr_t* frames, int* sizes,
+ int max_depth, int skip_count, const void*,
+ int* min_dropped_frames) {
USHORT n = 0;
- if (!RtlCaptureStackBackTrace_fn || skip_count < 0 || max_depth < 0) {
+ if (skip_count < 0 || max_depth < 0) {
// can't get a stacktrace with no function/invalid args
} else {
- n = RtlCaptureStackBackTrace_fn(static_cast<ULONG>(skip_count) + 2,
- static_cast<ULONG>(max_depth), result, 0);
+ n = CaptureStackBackTrace(static_cast<ULONG>(skip_count) + 2,
+ static_cast<ULONG>(max_depth), result, 0);
}
if (IS_STACK_FRAMES) {
- // No implementation for finding out the stack frame sizes yet.
- memset(sizes, 0, sizeof(*sizes) * n);
+ // No implementation for finding out the stack frames yet.
+ if (frames != nullptr) {
+ memset(frames, 0, sizeof(*frames) * n);
+ }
+ if (sizes != nullptr) {
+ memset(sizes, 0, sizeof(*sizes) * n);
+ }
}
if (min_dropped_frames != nullptr) {
// Not implemented.
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
index 1975ba7..96b128e 100644
--- a/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -33,6 +33,7 @@
#include "absl/base/macros.h"
#include "absl/base/port.h"
#include "absl/debugging/internal/address_is_readable.h"
+#include "absl/debugging/internal/addresses.h"
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
#include "absl/debugging/stacktrace.h"
@@ -163,6 +164,7 @@
template <bool STRICT_UNWINDING, bool WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
static void **NextStackFrame(void **old_fp, const void *uc,
size_t stack_low, size_t stack_high) {
void **new_fp = (void **)*old_fp;
@@ -326,9 +328,11 @@
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ABSL_ATTRIBUTE_NO_SANITIZE_THREAD // May read random elements from stack.
ABSL_ATTRIBUTE_NOINLINE
-static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
- const void *ucp, int *min_dropped_frames) {
+static int UnwindImpl(void **result, uintptr_t *frames, int *sizes,
+ int max_depth, int skip_count, const void *ucp,
+ int *min_dropped_frames) {
int n = 0;
void **fp = reinterpret_cast<void **>(__builtin_frame_address(0));
@@ -349,13 +353,19 @@
} else {
result[n] = *(fp + 1);
if (IS_STACK_FRAMES) {
- if (next_fp > fp) {
- sizes[n] = static_cast<int>(
- reinterpret_cast<uintptr_t>(next_fp) -
- reinterpret_cast<uintptr_t>(fp));
- } else {
- // A frame-size of 0 is used to indicate unknown frame size.
- sizes[n] = 0;
+ if (frames) {
+ frames[n] = absl::debugging_internal::StripPointerMetadata(fp) +
+ 2 * sizeof(void *) /* go past the return address */;
+ }
+ if (sizes) {
+ if (next_fp > fp) {
+ sizes[n] = static_cast<int>(
+ absl::debugging_internal::StripPointerMetadata(next_fp) -
+ absl::debugging_internal::StripPointerMetadata(fp));
+ } else {
+ // A frame-size of 0 is used to indicate unknown frame size.
+ sizes[n] = 0;
+ }
}
}
n++;
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
index fdb8798..1370bcc 100644
--- a/absl/debugging/leak_check.cc
+++ b/absl/debugging/leak_check.cc
@@ -28,7 +28,7 @@
#include <sanitizer/lsan_interface.h>
#if ABSL_HAVE_ATTRIBUTE_WEAK
-extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off();
+extern "C" ABSL_ATTRIBUTE_WEAK int __lsan_is_turned_off() { return 0; }
#endif
namespace absl {
@@ -37,13 +37,13 @@
#if ABSL_HAVE_ATTRIBUTE_WEAK
bool LeakCheckerIsActive() {
- return !(&__lsan_is_turned_off && __lsan_is_turned_off());
+ return __lsan_is_turned_off() == 0;
}
#else
bool LeakCheckerIsActive() { return true; }
#endif
-bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check(); }
+bool FindAndReportLeaks() { return __lsan_do_recoverable_leak_check() != 0; }
void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
void RegisterLivePointers(const void* ptr, size_t size) {
__lsan_register_root_region(ptr, size);
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
index ff8069f..f71e80c 100644
--- a/absl/debugging/stacktrace.cc
+++ b/absl/debugging/stacktrace.cc
@@ -36,12 +36,42 @@
#include "absl/debugging/stacktrace.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
#include <atomic>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/debugging/internal/stacktrace_config.h"
+#ifdef ABSL_INTERNAL_HAVE_ALLOCA
+#error ABSL_INTERNAL_HAVE_ALLOCA cannot be directly set
+#endif
+
+#ifdef _WIN32
+#include <malloc.h>
+#define ABSL_INTERNAL_HAVE_ALLOCA 1
+#else
+#ifdef __has_include
+#if __has_include(<alloca.h>)
+#include <alloca.h>
+#define ABSL_INTERNAL_HAVE_ALLOCA 1
+#elif !defined(alloca)
+static void* alloca(size_t) noexcept { return nullptr; }
+#endif
+#endif
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_ALLOCA
+static constexpr bool kHaveAlloca = true;
+#else
+static constexpr bool kHaveAlloca = false;
+#endif
+
#if defined(ABSL_STACKTRACE_INL_HEADER)
#include ABSL_STACKTRACE_INL_HEADER
#else
@@ -66,59 +96,111 @@
std::atomic<Unwinder> custom;
template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes,
- int max_depth, int skip_count,
- const void* uc,
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, uintptr_t* frames,
+ int* sizes, int max_depth,
+ int skip_count, const void* uc,
int* min_dropped_frames) {
- Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>;
Unwinder g = custom.load(std::memory_order_acquire);
- if (g != nullptr) f = g;
-
+ int size;
// Add 1 to skip count for the unwinder function itself
- int size = (*f)(result, sizes, max_depth, skip_count + 1, uc,
- min_dropped_frames);
- // To disable tail call to (*f)(...)
+ ++skip_count;
+ if (g != nullptr) {
+ size = (*g)(result, sizes, max_depth, skip_count, uc, min_dropped_frames);
+ // Frame pointers aren't returned by existing hooks, so clear them.
+ if (frames != nullptr) {
+ std::fill(frames, frames + size, uintptr_t());
+ }
+ } else {
+ size = UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>(
+ result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames);
+ }
ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
return size;
}
} // anonymous namespace
-ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackFrames(
- void** result, int* sizes, int max_depth, int skip_count) {
- return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr,
- nullptr);
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+internal_stacktrace::GetStackFrames(void** result, uintptr_t* frames,
+ int* sizes, int max_depth, int skip_count) {
+ if (internal_stacktrace::ShouldFixUpStack()) {
+ size_t depth = static_cast<size_t>(Unwind<true, true>(
+ result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
+ internal_stacktrace::FixUpStack(result, frames, sizes,
+ static_cast<size_t>(max_depth), depth);
+ return static_cast<int>(depth);
+ }
+
+ return Unwind<true, false>(result, frames, sizes, max_depth, skip_count,
+ nullptr, nullptr);
}
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
-GetStackFramesWithContext(void** result, int* sizes, int max_depth,
- int skip_count, const void* uc,
- int* min_dropped_frames) {
- return Unwind<true, true>(result, sizes, max_depth, skip_count, uc,
+internal_stacktrace::GetStackFramesWithContext(void** result, uintptr_t* frames,
+ int* sizes, int max_depth,
+ int skip_count, const void* uc,
+ int* min_dropped_frames) {
+ if (internal_stacktrace::ShouldFixUpStack()) {
+ size_t depth = static_cast<size_t>(Unwind<true, true>(
+ result, frames, sizes, max_depth, skip_count, uc, min_dropped_frames));
+ internal_stacktrace::FixUpStack(result, frames, sizes,
+ static_cast<size_t>(max_depth), depth);
+ return static_cast<int>(depth);
+ }
+
+ return Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
min_dropped_frames);
}
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int GetStackTrace(
void** result, int max_depth, int skip_count) {
- return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr,
- nullptr);
+ if (internal_stacktrace::ShouldFixUpStack()) {
+ if constexpr (kHaveAlloca) {
+ const size_t nmax = static_cast<size_t>(max_depth);
+ uintptr_t* frames =
+ static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
+ int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
+ size_t depth = static_cast<size_t>(Unwind<true, false>(
+ result, frames, sizes, max_depth, skip_count, nullptr, nullptr));
+ internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
+ return static_cast<int>(depth);
+ }
+ }
+
+ return Unwind<false, false>(result, nullptr, nullptr, max_depth, skip_count,
+ nullptr, nullptr);
}
ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
GetStackTraceWithContext(void** result, int max_depth, int skip_count,
const void* uc, int* min_dropped_frames) {
- return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc,
- min_dropped_frames);
+ if (internal_stacktrace::ShouldFixUpStack()) {
+ if constexpr (kHaveAlloca) {
+ const size_t nmax = static_cast<size_t>(max_depth);
+ uintptr_t* frames =
+ static_cast<uintptr_t*>(alloca(nmax * sizeof(*frames)));
+ int* sizes = static_cast<int*>(alloca(nmax * sizeof(*sizes)));
+ size_t depth = static_cast<size_t>(
+ Unwind<true, true>(result, frames, sizes, max_depth, skip_count, uc,
+ min_dropped_frames));
+ internal_stacktrace::FixUpStack(result, frames, sizes, nmax, depth);
+ return static_cast<int>(depth);
+ }
+ }
+
+ return Unwind<false, true>(result, nullptr, nullptr, max_depth, skip_count,
+ uc, min_dropped_frames);
}
void SetStackUnwinder(Unwinder w) {
custom.store(w, std::memory_order_release);
}
-int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
- const void* uc, int* min_dropped_frames) {
+ABSL_ATTRIBUTE_ALWAYS_INLINE static inline int DefaultStackUnwinderImpl(
+ void** pcs, uintptr_t* frames, int* sizes, int depth, int skip,
+ const void* uc, int* min_dropped_frames) {
skip++; // For this function
- Unwinder f = nullptr;
+ decltype(&UnwindImpl<false, false>) f;
if (sizes == nullptr) {
if (uc == nullptr) {
f = &UnwindImpl<false, false>;
@@ -132,11 +214,46 @@
f = &UnwindImpl<true, true>;
}
}
- volatile int x = 0;
- int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames);
- x = 1; (void) x; // To disable tail call to (*f)(...)
+ return (*f)(pcs, frames, sizes, depth, skip, uc, min_dropped_frames);
+}
+
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int
+internal_stacktrace::DefaultStackUnwinder(void** pcs, uintptr_t* frames,
+ int* sizes, int depth, int skip,
+ const void* uc,
+ int* min_dropped_frames) {
+ int n = DefaultStackUnwinderImpl(pcs, frames, sizes, depth, skip, uc,
+ min_dropped_frames);
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
return n;
}
+ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL int DefaultStackUnwinder(
+ void** pcs, int* sizes, int depth, int skip, const void* uc,
+ int* min_dropped_frames) {
+ int n = DefaultStackUnwinderImpl(pcs, nullptr, sizes, depth, skip, uc,
+ min_dropped_frames);
+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
+ return n;
+}
+
+ABSL_ATTRIBUTE_WEAK bool internal_stacktrace::ShouldFixUpStack() {
+ return false;
+}
+
+// Fixes up the stack trace of the current thread, in the first `depth` frames
+// of each buffer. The buffers need to be larger than `depth`, to accommodate
+// any newly inserted elements. `depth` is updated to reflect the new number of
+// elements valid across all the buffers. (It is therefore recommended that all
+// buffer sizes be equal.)
+//
+// The `frames` and `sizes` parameters denote the bounds of the stack frame
+// corresponding to each instruction pointer in the `pcs`.
+// Any elements inside these buffers may be zero or null, in which case that
+// information is assumed to be absent/unavailable.
+ABSL_ATTRIBUTE_WEAK void internal_stacktrace::FixUpStack(void**, uintptr_t*,
+ int*, size_t,
+ size_t&) {}
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
index 0ec0ffd..8777172 100644
--- a/absl/debugging/stacktrace.h
+++ b/absl/debugging/stacktrace.h
@@ -31,11 +31,53 @@
#ifndef ABSL_DEBUGGING_STACKTRACE_H_
#define ABSL_DEBUGGING_STACKTRACE_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
+namespace internal_stacktrace {
+
+// Same as `absl::GetStackFrames`, but with an optional `frames` parameter to
+// allow callers to receive the raw stack frame addresses.
+// This is internal for now; use `absl::GetStackFrames()` instead.
+extern int GetStackFrames(void** result, uintptr_t* frames, int* sizes,
+ int max_depth, int skip_count);
+
+// Same as `absl::GetStackFramesWithContext`, but with an optional `frames`
+// parameter to allow callers to receive a start address for each stack frame.
+// The address may be zero in cases where it cannot be computed.
+//
+// DO NOT use this function without consulting the owners of absl/debuggging.
+// There is NO GUARANTEE on the precise frame addresses returned on any given
+// platform. It is only intended to provide sufficient non-overlapping bounds on
+// the local variables of a stack frame when used in conjunction with the
+// returned frame sizes. The actual pointers may be ABI-dependent, may vary at
+// run time, and are subject to breakage without notice.
+//
+// Implementation note:
+// Currently, we *attempt* to return the Canonical Frame Address (CFA) in DWARF
+// on most platforms. This is the value of the stack pointer just before the
+// 'call' instruction is executed in the caller.
+// Not all platforms and toolchains support this exact address, so this should
+// not be relied on for correctness.
+extern int GetStackFramesWithContext(void** result, uintptr_t* frames,
+ int* sizes, int max_depth, int skip_count,
+ const void* uc, int* min_dropped_frames);
+
+// Same as `absl::DefaultStackUnwinder`, but with an optional `frames` parameter
+// to allow callers to receive the raw stack frame addresses.
+// This is internal for now; do not depend on this externally.
+extern int DefaultStackUnwinder(void** pcs, uintptr_t* frames, int* sizes,
+ int max_depth, int skip_count, const void* uc,
+ int* min_dropped_frames);
+
+} // namespace internal_stacktrace
+
// GetStackFrames()
//
// Records program counter values for up to `max_depth` frames, skipping the
@@ -78,8 +120,13 @@
//
// This routine may return fewer stack frame entries than are
// available. Also note that `result` and `sizes` must both be non-null.
-extern int GetStackFrames(void** result, int* sizes, int max_depth,
- int skip_count);
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFrames(void** result,
+ int* sizes,
+ int max_depth,
+ int skip_count) {
+ return internal_stacktrace::GetStackFrames(result, nullptr, sizes, max_depth,
+ skip_count);
+}
// GetStackFramesWithContext()
//
@@ -102,9 +149,12 @@
// or other reasons. (This value will be set to `0` if no frames were dropped.)
// The number of total stack frames is guaranteed to be >= skip_count +
// max_depth + *min_dropped_frames.
-extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
- int skip_count, const void* uc,
- int* min_dropped_frames);
+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int GetStackFramesWithContext(
+ void** result, int* sizes, int max_depth, int skip_count, const void* uc,
+ int* min_dropped_frames) {
+ return internal_stacktrace::GetStackFramesWithContext(
+ result, nullptr, sizes, max_depth, skip_count, uc, min_dropped_frames);
+}
// GetStackTrace()
//
@@ -225,6 +275,24 @@
// working.
extern bool StackTraceWorksForTest();
} // namespace debugging_internal
+
+namespace internal_stacktrace {
+extern bool ShouldFixUpStack();
+
+// Fixes up the stack trace of the current thread, in the first `depth` frames
+// of each buffer. The buffers need to be larger than `depth`, to accommodate
+// any newly inserted elements. `depth` is updated to reflect the new number of
+// elements valid across all the buffers. (It is therefore recommended that all
+// buffer sizes be equal.)
+//
+// The `frames` and `sizes` parameters denote the bounds of the stack frame
+// corresponding to each instruction pointer in the `pcs`.
+// Any elements inside these buffers may be zero or null, in which case that
+// information is assumed to be absent/unavailable.
+extern void FixUpStack(void** pcs, uintptr_t* frames, int* sizes,
+ size_t capacity, size_t& depth);
+} // namespace internal_stacktrace
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/debugging/stacktrace_test.cc b/absl/debugging/stacktrace_test.cc
index 31f7723..4477d84 100644
--- a/absl/debugging/stacktrace_test.cc
+++ b/absl/debugging/stacktrace_test.cc
@@ -14,12 +14,48 @@
#include "absl/debugging/stacktrace.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "absl/base/macros.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/optimization.h"
+#include "absl/types/span.h"
+
+static int g_should_fixup_calls = 0;
+static int g_fixup_calls = 0;
+static bool g_enable_fixup = false;
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+bool absl::internal_stacktrace::ShouldFixUpStack() {
+ ++g_should_fixup_calls;
+ return g_enable_fixup;
+}
+
+void absl::internal_stacktrace::FixUpStack(void**, uintptr_t*, int*, size_t,
+ size_t&) {
+ ++g_fixup_calls;
+}
+#endif
namespace {
+using ::testing::ContainerEq;
+using ::testing::Contains;
+using ::testing::internal::Cleanup;
+
+struct StackTrace {
+ static constexpr int kStackCount = 64;
+ int depth;
+ void* result[kStackCount];
+ uintptr_t frames[kStackCount];
+ int sizes[kStackCount];
+};
+
// This test is currently only known to pass on Linux x86_64/aarch64.
#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
ABSL_ATTRIBUTE_NOINLINE void Unwind(void* p) {
@@ -44,4 +80,219 @@
}
#endif
+// This is a separate function to avoid inlining.
+ABSL_ATTRIBUTE_NOINLINE static void FixupNoFixupEquivalenceNoInline() {
+#if defined(__riscv)
+ GTEST_SKIP() << "Skipping test on RISC-V due to pre-existing failure";
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+ // This test is known not to pass on MSVC (due to weak symbols)
+
+ const Cleanup restore_state([enable_fixup = g_enable_fixup,
+ fixup_calls = g_fixup_calls,
+ should_fixup_calls = g_should_fixup_calls]() {
+ g_enable_fixup = enable_fixup;
+ g_fixup_calls = fixup_calls;
+ g_should_fixup_calls = should_fixup_calls;
+ });
+
+ constexpr int kSkip = 1; // Skip our own frame, whose return PCs won't match
+ constexpr auto kStackCount = 1;
+
+ StackTrace a;
+ StackTrace b;
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::GetStackTrace(a.result, kStackCount, kSkip);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::GetStackTrace(b.result, kStackCount, kSkip);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::GetStackFrames(a.result, a.sizes, kStackCount, kSkip);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::GetStackFrames(b.result, b.sizes, kStackCount, kSkip);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::GetStackTraceWithContext(a.result, kStackCount, kSkip,
+ nullptr, nullptr);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::GetStackTraceWithContext(b.result, kStackCount, kSkip,
+ nullptr, nullptr);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::GetStackFramesWithContext(a.result, a.sizes, kStackCount,
+ kSkip, nullptr, nullptr);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::GetStackFramesWithContext(b.result, b.sizes, kStackCount,
+ kSkip, nullptr, nullptr);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::internal_stacktrace::GetStackFrames(
+ a.result, a.frames, a.sizes, kStackCount, kSkip);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::internal_stacktrace::GetStackFrames(
+ b.result, b.frames, b.sizes, kStackCount, kSkip);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.frames, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.frames, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+
+ g_fixup_calls = 0;
+ g_should_fixup_calls = 0;
+ a.depth = absl::internal_stacktrace::GetStackFramesWithContext(
+ a.result, a.frames, a.sizes, kStackCount, kSkip, nullptr, nullptr);
+ g_enable_fixup = !g_enable_fixup;
+ b.depth = absl::internal_stacktrace::GetStackFramesWithContext(
+ b.result, b.frames, b.sizes, kStackCount, kSkip, nullptr, nullptr);
+ EXPECT_THAT(
+ absl::MakeSpan(a.result, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.result, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.sizes, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.sizes, static_cast<size_t>(b.depth))));
+ EXPECT_THAT(
+ absl::MakeSpan(a.frames, static_cast<size_t>(a.depth)),
+ ContainerEq(absl::MakeSpan(b.frames, static_cast<size_t>(b.depth))));
+ EXPECT_GT(g_should_fixup_calls, 0);
+ EXPECT_GE(g_should_fixup_calls, g_fixup_calls);
+
+ // ==========================================================================
+#else
+ GTEST_SKIP() << "Need weak symbol support";
+#endif
+}
+
+TEST(StackTrace, FixupNoFixupEquivalence) { FixupNoFixupEquivalenceNoInline(); }
+
+#if ABSL_HAVE_BUILTIN(__builtin_frame_address)
+struct FrameInfo {
+ const void* return_address;
+ uintptr_t frame_address;
+};
+
+// Returns the canonical frame address and return address for the current stack
+// frame, while capturing the stack trace at the same time.
+// This performs any platform-specific adjustments necessary to convert from the
+// compiler built-ins to the expected API outputs.
+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack.
+ ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack.
+ ABSL_ATTRIBUTE_NOINLINE static FrameInfo
+ CaptureBacktraceNoInline(StackTrace& backtrace) {
+ FrameInfo result;
+ result.return_address = __builtin_return_address(0);
+ // Large enough to cover all realistic slots the return address could be in
+ const int kMaxReturnAddressIndex = 5;
+ void* const* bfa = static_cast<void* const*>(__builtin_frame_address(0));
+ backtrace.depth = absl::internal_stacktrace::GetStackFramesWithContext(
+ backtrace.result, backtrace.frames, backtrace.sizes,
+ StackTrace::kStackCount, /*skip_count=*/0,
+ /*uc=*/nullptr, /*min_dropped_frames=*/nullptr);
+ // Make sure the return address is at a reasonable location in the frame
+ ptrdiff_t i;
+ for (i = 0; i < kMaxReturnAddressIndex; ++i) {
+ // Avoid std::find() here, since it lacks no-sanitize attributes.
+ if (bfa[i] == result.return_address) {
+ break;
+ }
+ }
+ result.frame_address =
+ i < kMaxReturnAddressIndex
+ ? reinterpret_cast<uintptr_t>(
+ bfa + i + 1 /* get the Canonical Frame Address (CFA) */)
+ : 0;
+ return result;
+}
+
+TEST(StackTrace, CanonicalFrameAddresses) {
+ // Now capture a stack trace and verify that the return addresses and frame
+ // addresses line up for one frame.
+ StackTrace backtrace;
+ const auto [return_address, frame_address] =
+ CaptureBacktraceNoInline(backtrace);
+ auto return_addresses = absl::MakeSpan(backtrace.result)
+ .subspan(0, static_cast<size_t>(backtrace.depth));
+ auto frame_addresses = absl::MakeSpan(backtrace.frames)
+ .subspan(0, static_cast<size_t>(backtrace.depth));
+
+ // Many platforms don't support this by default.
+ bool support_is_expected = false;
+
+ if (support_is_expected) {
+ // If all zeros were returned, that is valid per the function's contract.
+ // It just means we don't support returning frame addresses on this
+ // platform.
+ bool supported = static_cast<size_t>(std::count(frame_addresses.begin(),
+ frame_addresses.end(), 0)) <
+ frame_addresses.size();
+ EXPECT_TRUE(supported);
+ if (supported) {
+ ASSERT_TRUE(frame_address)
+ << "unable to obtain frame address corresponding to return address";
+ EXPECT_THAT(return_addresses, Contains(return_address).Times(1));
+ EXPECT_THAT(frame_addresses, Contains(frame_address).Times(1));
+ ptrdiff_t ifound = std::find(return_addresses.begin(),
+ return_addresses.end(), return_address) -
+ return_addresses.begin();
+ // Make sure we found the frame in the first place.
+ ASSERT_LT(ifound, backtrace.depth);
+ // Make sure the frame address actually corresponds to the return
+ // address.
+ EXPECT_EQ(frame_addresses[static_cast<size_t>(ifound)], frame_address);
+ // Make sure the addresses only appear once.
+ }
+ }
+}
+#endif
+
} // namespace
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index 638d395..344436f 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#include "absl/debugging/symbolize.h"
#ifdef _WIN32
#include <winapifamily.h>
-#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)) || \
- WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// UWP doesn't have access to win32 APIs.
#define ABSL_INTERNAL_HAVE_SYMBOLIZE_WIN32
#endif
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index ae75cd4..9836c93 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -52,6 +52,7 @@
#include <elf.h>
#include <fcntl.h>
#include <link.h> // For ElfW() macro.
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -124,12 +125,20 @@
// Some platforms use a special .opd section to store function pointers.
const char kOpdSectionName[] = ".opd";
-#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64)
+#if defined(__powerpc64__) && defined(_CALL_ELF)
+#if _CALL_ELF <= 1
+#define ABSL_INTERNAL_HAVE_PPC64_ELFV1_ABI 1
+#endif
+#endif
+#if defined(ABSL_INTERNAL_HAVE_PPC64_ELFV1_ABI) || defined(__ia64)
// Use opd section for function descriptors on these platforms, the function
// address is the first word of the descriptor.
-enum { kPlatformUsesOPDSections = 1 };
-#else // not PPC or IA64
-enum { kPlatformUsesOPDSections = 0 };
+//
+// https://maskray.me/blog/2023-02-26-linker-notes-on-power-isa notes that
+// opd sections are used on 64-bit PowerPC with the ELFv1 ABI.
+inline constexpr bool kPlatformUsesOPDSections = true;
+#else
+inline constexpr bool kPlatformUsesOPDSections = false;
#endif
// This works for PowerPC & IA64 only. A function descriptor consist of two
@@ -376,6 +385,46 @@
SymbolCacheLine symbol_cache_[SYMBOL_CACHE_LINES];
};
+// Protect against client code closing low-valued file descriptors it doesn't
+// actually own.
+int OpenReadOnlyWithHighFD(const char *fname) {
+ static int high_fd = [] {
+ struct rlimit rlim{};
+ const int rc = getrlimit(RLIMIT_NOFILE, &rlim);
+ if (rc == 0 && rlim.rlim_cur >= 2000) {
+ const int max_fd = static_cast<int>(rlim.rlim_cur);
+
+ // This will return 2000 on reasonably-configured systems.
+ return std::min<int>(2000, max_fd - 1000);
+ }
+ ABSL_RAW_LOG(WARNING, "Unable to get high fd: rc=%d, limit=%ld", //
+ rc, static_cast<long>(rlim.rlim_cur));
+ return -1;
+ }();
+ constexpr int kOpenFlags = O_RDONLY | O_CLOEXEC;
+ if (high_fd >= 1000) {
+ const int fd = open(fname, kOpenFlags);
+ if (fd != -1 && fd < high_fd) {
+ // Try to relocate fd to high range.
+ static_assert(kOpenFlags & O_CLOEXEC,
+ "F_DUPFD_CLOEXEC assumes O_CLOEXEC");
+ const int fd2 = fcntl(fd, F_DUPFD_CLOEXEC, high_fd);
+ if (fd2 != -1) {
+ // Successfully obtained high fd. Use it.
+ close(fd);
+ return fd2;
+ } else {
+ ABSL_RAW_LOG(WARNING, "Unable to dup fd=%d above %d, errno=%d", fd,
+ high_fd, errno);
+ }
+ }
+ // Either open failed and fd==-1, or fd is already above high_fd, or fcntl
+ // failed and fd is valid (but low).
+ return fd;
+ }
+ return open(fname, kOpenFlags);
+}
+
static std::atomic<Symbolizer *> g_cached_symbolizer;
} // namespace
@@ -541,11 +590,9 @@
(buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes;
const off_t offset = sh_offset + static_cast<off_t>(i * sizeof(buf[0]));
const ssize_t len = file->ReadFromOffset(buf, num_bytes_to_read, offset);
- if (len < 0) {
- ABSL_RAW_LOG(
- WARNING,
- "Reading %zu bytes from offset %ju returned %zd which is negative.",
- num_bytes_to_read, static_cast<intmax_t>(offset), len);
+ if (len <= 0) {
+ ABSL_RAW_LOG(WARNING, "Reading %zu bytes from offset %ju returned %zd.",
+ num_bytes_to_read, static_cast<intmax_t>(offset), len);
return false;
}
if (static_cast<size_t>(len) % sizeof(buf[0]) != 0) {
@@ -1066,7 +1113,7 @@
snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid());
int maps_fd;
- NO_INTR(maps_fd = open(maps_path, O_RDONLY));
+ NO_INTR(maps_fd = OpenReadOnlyWithHighFD(maps_path));
FileDescriptor wrapped_maps_fd(maps_fd);
if (wrapped_maps_fd.get() < 0) {
ABSL_RAW_LOG(WARNING, "%s: errno=%d", maps_path, errno);
@@ -1340,7 +1387,7 @@
if (memcmp(obj->start_addr, ELFMAG, SELFMAG) != 0) {
return;
}
- int fd = open("/proc/self/exe", O_RDONLY);
+ int fd = OpenReadOnlyWithHighFD("/proc/self/exe");
if (fd == -1) {
return;
}
@@ -1364,7 +1411,7 @@
static bool MaybeInitializeObjFile(ObjFile *obj) {
if (obj->fd < 0) {
- obj->fd = open(obj->filename, O_RDONLY);
+ obj->fd = OpenReadOnlyWithHighFD(obj->filename);
if (obj->fd < 0) {
// Getting /proc/self/exe here means that we were hinted.
@@ -1372,7 +1419,7 @@
// /proc/self/exe may be inaccessible (due to setuid, etc.), so try
// accessing the binary via argv0.
if (argv0_value != nullptr) {
- obj->fd = open(argv0_value, O_RDONLY);
+ obj->fd = OpenReadOnlyWithHighFD(argv0_value);
}
} else {
MaybeOpenFdFromSelfExe(obj);
@@ -1412,11 +1459,11 @@
}
phoff += phentsize;
-#if defined(__powerpc__) && !(_CALL_ELF > 1)
- // On the PowerPC ELF v1 ABI, function pointers actually point to function
- // descriptors. These descriptors are stored in an .opd section, which is
- // mapped read-only. We thus need to look at all readable segments, not
- // just the executable ones.
+#ifdef ABSL_INTERNAL_HAVE_PPC64_ELFV1_ABI
+ // On the PowerPC 64-bit ELFv1 ABI, function pointers actually point to
+ // function descriptors. These descriptors are stored in an .opd section,
+ // which is mapped read-only. We thus need to look at all readable
+ // segments, not just the executable ones.
constexpr int interesting = PF_R;
#else
constexpr int interesting = PF_X | PF_R;
@@ -1723,3 +1770,5 @@
return absl::debugging_internal::GetFileMappingHint(start, end, offset,
filename);
}
+
+#undef ABSL_INTERNAL_HAVE_PPC64_ELFV1_ABI
diff --git a/absl/debugging/symbolize_emscripten.inc b/absl/debugging/symbolize_emscripten.inc
index a0f344d..f6da0ac 100644
--- a/absl/debugging/symbolize_emscripten.inc
+++ b/absl/debugging/symbolize_emscripten.inc
@@ -58,12 +58,13 @@
return false;
}
- strncpy(out, func_name, out_size);
+ strncpy(out, func_name, static_cast<size_t>(out_size));
if (out[out_size - 1] != '\0') {
// strncpy() does not '\0' terminate when it truncates.
static constexpr char kEllipsis[] = "...";
- int ellipsis_size = std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
+ size_t ellipsis_size =
+ std::min(sizeof(kEllipsis) - 1, static_cast<size_t>(out_size) - 1);
memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
out[out_size - 1] = '\0';
}
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index d0feab2..69b0a26 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -167,9 +167,8 @@
#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
void *return_address = __builtin_return_address(0);
const char *symbol = TrySymbolize(return_address);
- CHECK_NE(symbol, nullptr) << "TestWithReturnAddress failed";
- CHECK_STREQ(symbol, "main") << "TestWithReturnAddress failed";
- std::cout << "TestWithReturnAddress passed" << std::endl;
+ ASSERT_NE(symbol, nullptr) << "TestWithReturnAddress failed";
+ EXPECT_STREQ(symbol, "main") << "TestWithReturnAddress failed";
#endif
}
@@ -490,10 +489,9 @@
(defined(__i386__) || defined(__x86_64__))
void *pc = non_inline_func();
const char *symbol = TrySymbolize(pc);
- CHECK_NE(symbol, nullptr) << "TestWithPCInsideNonInlineFunction failed";
- CHECK_STREQ(symbol, "non_inline_func")
+ ASSERT_NE(symbol, nullptr) << "TestWithPCInsideNonInlineFunction failed";
+ EXPECT_STREQ(symbol, "non_inline_func")
<< "TestWithPCInsideNonInlineFunction failed";
- std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl;
#endif
}
@@ -502,9 +500,8 @@
(defined(__i386__) || defined(__x86_64__))
void *pc = inline_func(); // Must be inlined.
const char *symbol = TrySymbolize(pc);
- CHECK_NE(symbol, nullptr) << "TestWithPCInsideInlineFunction failed";
- CHECK_STREQ(symbol, __FUNCTION__) << "TestWithPCInsideInlineFunction failed";
- std::cout << "TestWithPCInsideInlineFunction passed" << std::endl;
+ ASSERT_NE(symbol, nullptr) << "TestWithPCInsideInlineFunction failed";
+ EXPECT_STREQ(symbol, __FUNCTION__) << "TestWithPCInsideInlineFunction failed";
#endif
}
}
@@ -545,9 +542,8 @@
void ABSL_ATTRIBUTE_NOINLINE TestArmThumbOverlap() {
#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE)
const char *symbol = TrySymbolize((void *)&ArmThumbOverlapArm);
- CHECK_NE(symbol, nullptr) << "TestArmThumbOverlap failed";
- CHECK_STREQ("ArmThumbOverlapArm()", symbol) << "TestArmThumbOverlap failed";
- std::cout << "TestArmThumbOverlap passed" << std::endl;
+ ASSERT_NE(symbol, nullptr) << "TestArmThumbOverlap failed";
+ EXPECT_STREQ("ArmThumbOverlapArm()", symbol) << "TestArmThumbOverlap failed";
#endif
}
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index 53a099a..589890f 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -15,7 +15,9 @@
// See "Retrieving Symbol Information by Address":
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
+#include <ntstatus.h>
#include <windows.h>
+#include <winternl.h>
// MSVC header dbghelp.h has a warning for an ignored typedef.
#pragma warning(push)
@@ -45,13 +47,30 @@
// symbols be loaded. This is the fastest, most efficient way to use
// the symbol handler.
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
- if (!SymInitialize(process, nullptr, true)) {
- // GetLastError() returns a Win32 DWORD, but we assign to
- // unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform
- // initialization guarantees this is not a narrowing conversion.
- const unsigned long long error{GetLastError()}; // NOLINT(runtime/int)
- ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
+ DWORD syminitialize_error;
+ constexpr int kSymInitializeRetries = 5;
+ for (int i = 0; i < kSymInitializeRetries; ++i) {
+ if (SymInitialize(process, nullptr, true)) {
+ return;
+ }
+
+ // SymInitialize can fail sometimes with a STATUS_INFO_LENGTH_MISMATCH
+ // NTSTATUS (0xC0000004), which can happen when a module load occurs during
+ // the SymInitialize call. In this case, we should try calling SymInitialize
+ // again.
+ syminitialize_error = GetLastError();
+ // Both NTSTATUS and DWORD are 32-bit numbers, which makes the cast safe.
+ if (syminitialize_error !=
+ static_cast<DWORD>(STATUS_INFO_LENGTH_MISMATCH)) {
+ break;
+ }
}
+
+ // GetLastError() returns a Win32 DWORD, but we assign to
+ // unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform
+ // initialization guarantees this is not a narrowing conversion.
+ const unsigned long long error{syminitialize_error};
+ ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
}
bool Symbolize(const void* pc, char* out, int out_size) {
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 7a8ec7e..620af2b 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -66,6 +66,7 @@
":path_util",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:no_destructor",
"//absl/strings",
"//absl/synchronization",
],
@@ -87,6 +88,7 @@
":program_name",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:no_destructor",
"//absl/strings",
"//absl/synchronization",
],
@@ -190,6 +192,7 @@
":private_handle_accessor",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:fast_type_id",
"//absl/base:no_destructor",
"//absl/container:flat_hash_map",
"//absl/strings",
@@ -219,6 +222,8 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
+ "//absl/base:fast_type_id",
+ "//absl/base:no_destructor",
"//absl/memory",
"//absl/meta:type_traits",
"//absl/strings",
@@ -242,6 +247,7 @@
":reflection",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:nullability",
"//absl/strings",
],
)
@@ -270,6 +276,7 @@
":reflection",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:no_destructor",
"//absl/strings",
"//absl/synchronization",
],
@@ -318,6 +325,7 @@
"//absl/algorithm:container",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:no_destructor",
"//absl/strings",
"//absl/synchronization",
],
@@ -349,8 +357,8 @@
":reflection",
"//absl/memory",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -364,8 +372,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -399,8 +407,8 @@
"//absl/strings",
"//absl/time",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -425,7 +433,7 @@
"//absl/strings",
"//absl/time",
"//absl/types:optional",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -439,8 +447,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":marshalling",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -470,8 +478,8 @@
"//absl/log",
"//absl/strings",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -485,8 +493,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":path_util",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -498,12 +506,15 @@
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- tags = ["no_test_wasm"],
+ tags = [
+ "no_test_fuchsia_x64",
+ "no_test_wasm",
+ ],
deps = [
":program_name",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -528,8 +539,8 @@
":reflection",
"//absl/memory",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -549,8 +560,8 @@
"//absl/base",
"//absl/container:fixed_array",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -567,8 +578,8 @@
":path_util",
":program_name",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -597,6 +608,6 @@
":usage",
":usage_internal",
"//absl/strings",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
index 7376d11..d0ea452 100644
--- a/absl/flags/CMakeLists.txt
+++ b/absl/flags/CMakeLists.txt
@@ -45,6 +45,7 @@
DEPS
absl::config
absl::core_headers
+ absl::no_destructor
absl::flags_path_util
absl::strings
absl::synchronization
@@ -68,6 +69,7 @@
absl::flags_path_util
absl::flags_program_name
absl::core_headers
+ absl::no_destructor
absl::strings
absl::synchronization
)
@@ -163,6 +165,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
+ absl::fast_type_id
absl::flags_commandlineflag
absl::flags_private_handle_accessor
absl::flags_config
@@ -188,10 +191,12 @@
DEPS
absl::base
absl::config
+ absl::fast_type_id
absl::flags_commandlineflag
absl::flags_commandlineflag_internal
absl::flags_config
absl::flags_marshalling
+ absl::no_destructor
absl::synchronization
absl::meta
absl::utility
@@ -215,6 +220,7 @@
absl::flags_internal
absl::flags_reflection
absl::core_headers
+ absl::nullability
absl::strings
)
@@ -259,6 +265,7 @@
absl::config
absl::core_headers
absl::flags_usage_internal
+ absl::no_destructor
absl::raw_logging_internal
absl::strings
absl::synchronization
@@ -289,6 +296,7 @@
absl::flags_program_name
absl::flags_reflection
absl::flags_usage
+ absl::no_destructor
absl::strings
absl::synchronization
)
diff --git a/absl/flags/commandlineflag.cc b/absl/flags/commandlineflag.cc
index 9f3b4a5..4140230 100644
--- a/absl/flags/commandlineflag.cc
+++ b/absl/flags/commandlineflag.cc
@@ -24,6 +24,7 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
+absl::string_view CommandLineFlag::TypeName() const { return ""; }
bool CommandLineFlag::IsRetired() const { return false; }
bool CommandLineFlag::ParseFrom(absl::string_view value, std::string* error) {
return ParseFrom(value, flags_internal::SET_FLAGS_VALUE,
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h
index 26ec0e7..9098b4c 100644
--- a/absl/flags/commandlineflag.h
+++ b/absl/flags/commandlineflag.h
@@ -30,7 +30,7 @@
#include <string>
#include "absl/base/config.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/fast_type_id.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@@ -80,7 +80,7 @@
// Return true iff flag has type T.
template <typename T>
inline bool IsOfType() const {
- return TypeId() == base_internal::FastTypeId<T>();
+ return TypeId() == FastTypeId<T>();
}
// absl::CommandLineFlag::TryGet()
@@ -200,6 +200,13 @@
// Checks that flags default value can be converted to string and back to the
// flag's value type.
virtual void CheckDefaultValueParsingRoundtrip() const = 0;
+
+ // absl::CommandLineFlag::TypeName()
+ //
+ // Returns string representation of the type of this flag
+ // (the way it is spelled in the ABSL_FLAG macro).
+ // The default implementation returns the empty string.
+ virtual absl::string_view TypeName() const;
};
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index a8e0e93..e052d5f 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -35,6 +35,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
+#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/flags/commandlineflag.h"
#include "absl/flags/config.h"
@@ -94,7 +95,7 @@
// // FLAGS_firstname is a Flag of type `std::string`
// std::string first_name = absl::GetFlag(FLAGS_firstname);
template <typename T>
-ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag) {
+[[nodiscard]] T GetFlag(const absl::Flag<T>& flag) {
return flags_internal::FlagImplPeer::InvokeGet<T>(flag);
}
@@ -106,7 +107,7 @@
// thread-safe, but is potentially expensive. Avoid setting flags in general,
// but especially within performance-critical code.
template <typename T>
-void SetFlag(absl::Flag<T>* flag, const T& v) {
+void SetFlag(absl::Flag<T>* absl_nonnull flag, const T& v) {
flags_internal::FlagImplPeer::InvokeSet(*flag, v);
}
@@ -114,7 +115,7 @@
// convertible to `T`. E.g., use this overload to pass a "const char*" when `T`
// is `std::string`.
template <typename T, typename V>
-void SetFlag(absl::Flag<T>* flag, const V& v) {
+void SetFlag(absl::Flag<T>* absl_nonnull flag, const V& v) {
T value(v);
flags_internal::FlagImplPeer::InvokeSet(*flag, value);
}
@@ -204,12 +205,14 @@
#if ABSL_FLAGS_STRIP_NAMES
#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
+#define ABSL_FLAG_IMPL_TYPENAME(txt) ""
#define ABSL_FLAG_IMPL_FILENAME() ""
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
absl::flags_internal::FlagRegistrar<T, false>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
nullptr)
#else
#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
+#define ABSL_FLAG_IMPL_TYPENAME(txt) txt
#define ABSL_FLAG_IMPL_FILENAME() __FILE__
#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
absl::flags_internal::FlagRegistrar<T, true>(ABSL_FLAG_IMPL_FLAG_PTR(flag), \
@@ -261,16 +264,17 @@
// Note: Name of registrar object is not arbitrary. It is used to "grab"
// global name for FLAGS_no<flag_name> symbol, thus preventing the possibility
// of defining two flags with names foo and nofoo.
-#define ABSL_FLAG_IMPL(Type, name, default_value, help) \
- extern ::absl::Flag<Type> FLAGS_##name; \
- namespace absl /* block flags in namespaces */ {} \
- ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
- ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \
- ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \
- ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_FILENAME(), \
- ABSL_FLAG_IMPL_HELP_ARG(name), ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
- extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \
- absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \
+#define ABSL_FLAG_IMPL(Type, name, default_value, help) \
+ extern ::absl::Flag<Type> FLAGS_##name; \
+ namespace absl /* block flags in namespaces */ {} \
+ ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
+ ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, help) \
+ ABSL_CONST_INIT absl::Flag<Type> FLAGS_##name{ \
+ ABSL_FLAG_IMPL_FLAGNAME(#name), ABSL_FLAG_IMPL_TYPENAME(#Type), \
+ ABSL_FLAG_IMPL_FILENAME(), ABSL_FLAG_IMPL_HELP_ARG(name), \
+ ABSL_FLAG_IMPL_DEFAULT_ARG(Type, name)}; \
+ extern absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name; \
+ absl::flags_internal::FlagRegistrarEmpty FLAGS_no##name = \
ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
// ABSL_RETIRED_FLAG
@@ -290,8 +294,7 @@
// arguments unchanged (unless of course you actually want to retire the flag
// type at this time as well).
//
-// `default_value` is only used as a double check on the type. `explanation` is
-// unused.
+// `default_value` and `explanation` are unused.
// TODO(rogeeff): replace RETIRED_FLAGS with FLAGS once forward declarations of
// retired flags are cleaned up.
#define ABSL_RETIRED_FLAG(type, name, default_value, explanation) \
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
index 8af5bf7..e3ab24c 100644
--- a/absl/flags/flag_test.cc
+++ b/absl/flags/flag_test.cc
@@ -149,9 +149,9 @@
#define DEFINE_CONSTRUCTED_FLAG(T, dflt, dflt_kind) \
constexpr flags::FlagDefaultArg f1default##T{ \
flags::FlagDefaultSrc{dflt}, flags::FlagDefaultKind::dflt_kind}; \
- constexpr absl::Flag<T> f1##T{"f1", "file", help_arg, f1default##T}; \
+ constexpr absl::Flag<T> f1##T{"f1", #T, "file", help_arg, f1default##T}; \
ABSL_CONST_INIT absl::Flag<T> f2##T { \
- "f2", "file", \
+ "f2", #T, "file", \
{flags::FlagHelpMsg(&TestHelpMsg), flags::FlagHelpKind::kGenFunc}, \
flags::FlagDefaultArg { \
flags::FlagDefaultSrc(&TestMakeDflt<T>), \
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index ebfe81b..daef4e3 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -17,7 +17,7 @@
#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
#include "absl/base/config.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/fast_type_id.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -28,7 +28,7 @@
// cases this id is enough to uniquely identify the flag's value type. In a few
// cases we'll have to resort to using actual RTTI implementation if it is
// available.
-using FlagFastTypeId = absl::base_internal::FastTypeIdType;
+using FlagFastTypeId = absl::FastTypeIdType;
// Options that control SetCommandLineOptionWithMode.
enum FlagSettingMode {
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc
index 981f19f..37f6ef1 100644
--- a/absl/flags/internal/flag.cc
+++ b/absl/flags/internal/flag.cc
@@ -34,7 +34,10 @@
#include "absl/base/config.h"
#include "absl/base/const_init.h"
#include "absl/base/dynamic_annotations.h"
+#include "absl/base/fast_type_id.h"
+#include "absl/base/no_destructor.h"
#include "absl/base/optimization.h"
+#include "absl/base/thread_annotations.h"
#include "absl/flags/config.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/flags/usage_config.h"
@@ -57,7 +60,7 @@
// Currently we only validate flag values for user-defined flag types.
bool ShouldValidateFlagValue(FlagFastTypeId flag_type_id) {
#define DONT_VALIDATE(T, _) \
- if (flag_type_id == base_internal::FastTypeId<T>()) return false;
+ if (flag_type_id == absl::FastTypeId<T>()) return false;
ABSL_FLAGS_INTERNAL_SUPPORTED_TYPES(DONT_VALIDATE)
#undef DONT_VALIDATE
@@ -85,11 +88,15 @@
// we move the memory to the freelist where it lives indefinitely, so it can
// still be safely accessed. This also prevents leak checkers from complaining
// about the leaked memory that can no longer be accessed through any pointer.
-ABSL_CONST_INIT absl::Mutex s_freelist_guard(absl::kConstInit);
-ABSL_CONST_INIT std::vector<void*>* s_freelist = nullptr;
+absl::Mutex* FreelistMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
+ABSL_CONST_INIT std::vector<void*>* s_freelist ABSL_GUARDED_BY(FreelistMutex())
+ ABSL_PT_GUARDED_BY(FreelistMutex()) = nullptr;
void AddToFreelist(void* p) {
- absl::MutexLock l(&s_freelist_guard);
+ absl::MutexLock l(FreelistMutex());
if (!s_freelist) {
s_freelist = new std::vector<void*>;
}
@@ -101,7 +108,7 @@
///////////////////////////////////////////////////////////////////////////////
uint64_t NumLeakedFlagValues() {
- absl::MutexLock l(&s_freelist_guard);
+ absl::MutexLock l(FreelistMutex());
return s_freelist == nullptr ? 0u : s_freelist->size();
}
@@ -336,6 +343,8 @@
absl::string_view FlagImpl::Name() const { return name_; }
+absl::string_view FlagImpl::TypeName() const { return type_name_; }
+
std::string FlagImpl::Filename() const {
return flags_internal::GetUsageConfig().normalize_filename(filename_);
}
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index a0be31d..b61a247 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -57,7 +57,7 @@
using Flag = flags_internal::Flag<T>;
template <typename T>
-ABSL_MUST_USE_RESULT T GetFlag(const absl::Flag<T>& flag);
+[[nodiscard]] T GetFlag(const absl::Flag<T>& flag);
template <typename T>
void SetFlag(absl::Flag<T>* flag, const T& v);
@@ -373,9 +373,13 @@
static constexpr int RequiredAlignment() { return 4; }
+ constexpr MaskedPointer() : ptr_(nullptr) {}
constexpr explicit MaskedPointer(ptr_t rhs) : ptr_(rhs) {}
MaskedPointer(ptr_t rhs, bool is_candidate);
+ MaskedPointer(const MaskedPointer& rhs) = default;
+ MaskedPointer& operator=(const MaskedPointer& rhs) = default;
+
void* Ptr() const {
return reinterpret_cast<void*>(reinterpret_cast<mask_t>(ptr_) &
kPtrValueMask);
@@ -578,10 +582,12 @@
#endif
class FlagImpl final : public CommandLineFlag {
public:
- constexpr FlagImpl(const char* name, const char* filename, FlagOpFn op,
- FlagHelpArg help, FlagValueStorageKind value_kind,
+ constexpr FlagImpl(const char* name, const char* type_name,
+ const char* filename, FlagOpFn op, FlagHelpArg help,
+ FlagValueStorageKind value_kind,
FlagDefaultArg default_arg)
: name_(name),
+ type_name_(type_name),
filename_(filename),
op_(op),
help_(help.source),
@@ -694,6 +700,7 @@
// CommandLineFlag interface implementation
absl::string_view Name() const override;
+ absl::string_view TypeName() const override;
std::string Filename() const override;
std::string Help() const override;
FlagFastTypeId TypeId() const override;
@@ -727,6 +734,10 @@
// Flags name passed to ABSL_FLAG as second arg.
const char* const name_;
+
+ // Flags type passed to ABSL_FLAG as first arg.
+ const char* const type_name_;
+
// The file name where ABSL_FLAG resides.
const char* const filename_;
// Type-specific operations vtable.
@@ -772,7 +783,7 @@
// heap allocation during initialization, which is both slows program startup
// and can fail. Using reserved space + placement new allows us to avoid both
// problems.
- alignas(absl::Mutex) mutable char data_guard_[sizeof(absl::Mutex)];
+ alignas(absl::Mutex) mutable unsigned char data_guard_[sizeof(absl::Mutex)];
};
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
@@ -785,9 +796,9 @@
template <typename T>
class Flag {
public:
- constexpr Flag(const char* name, const char* filename, FlagHelpArg help,
- const FlagDefaultArg default_arg)
- : impl_(name, filename, &FlagOps<T>, help,
+ constexpr Flag(const char* name, const char* type_name, const char* filename,
+ FlagHelpArg help, const FlagDefaultArg default_arg)
+ : impl_(name, type_name, filename, &FlagOps<T>, help,
flags_internal::StorageKind<T>(), default_arg),
value_() {}
@@ -817,7 +828,7 @@
U u;
#if !defined(NDEBUG)
- impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+ impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>);
#endif
if (ABSL_PREDICT_FALSE(!value_.Get(impl_.seq_lock_, u.value))) {
@@ -826,7 +837,7 @@
return std::move(u.value);
}
void Set(const T& v) {
- impl_.AssertValidType(base_internal::FastTypeId<T>(), &GenRuntimeTypeId<T>);
+ impl_.AssertValidType(absl::FastTypeId<T>(), &GenRuntimeTypeId<T>);
impl_.Write(&v);
}
@@ -865,7 +876,8 @@
template <typename T>
void* FlagOps(FlagOp op, const void* v1, void* v2, void* v3) {
struct AlignedSpace {
- alignas(MaskedPointer::RequiredAlignment()) alignas(T) char buf[sizeof(T)];
+ alignas(MaskedPointer::RequiredAlignment()) alignas(
+ T) unsigned char buf[sizeof(T)];
};
using Allocator = std::allocator<AlignedSpace>;
switch (op) {
@@ -890,7 +902,7 @@
case FlagOp::kSizeof:
return reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(T)));
case FlagOp::kFastTypeId:
- return const_cast<void*>(base_internal::FastTypeId<T>());
+ return const_cast<void*>(absl::FastTypeId<T>());
case FlagOp::kRuntimeTypeId:
return const_cast<std::type_info*>(GenRuntimeTypeId<T>());
case FlagOp::kParse: {
diff --git a/absl/flags/internal/private_handle_accessor.cc b/absl/flags/internal/private_handle_accessor.cc
index a7eb58b..610d1ff 100644
--- a/absl/flags/internal/private_handle_accessor.cc
+++ b/absl/flags/internal/private_handle_accessor.cc
@@ -59,6 +59,10 @@
return flag.ParseFrom(value, set_mode, source, error);
}
+absl::string_view PrivateHandleAccessor::TypeName(const CommandLineFlag& flag) {
+ return flag.TypeName();
+}
+
} // namespace flags_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/flags/internal/private_handle_accessor.h b/absl/flags/internal/private_handle_accessor.h
index c64435c..bf4154c 100644
--- a/absl/flags/internal/private_handle_accessor.h
+++ b/absl/flags/internal/private_handle_accessor.h
@@ -52,6 +52,9 @@
static bool ParseFrom(CommandLineFlag& flag, absl::string_view value,
flags_internal::FlagSettingMode set_mode,
flags_internal::ValueSource source, std::string& error);
+
+ // Access to CommandLineFlag::TypeName.
+ static absl::string_view TypeName(const CommandLineFlag& flag);
};
} // namespace flags_internal
diff --git a/absl/flags/internal/program_name.cc b/absl/flags/internal/program_name.cc
index 51d698d..fb06643 100644
--- a/absl/flags/internal/program_name.cc
+++ b/absl/flags/internal/program_name.cc
@@ -19,7 +19,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
-#include "absl/base/const_init.h"
+#include "absl/base/no_destructor.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/internal/path_util.h"
#include "absl/strings/string_view.h"
@@ -29,30 +29,31 @@
ABSL_NAMESPACE_BEGIN
namespace flags_internal {
-ABSL_CONST_INIT static absl::Mutex program_name_guard(absl::kConstInit);
-ABSL_CONST_INIT static std::string* program_name
- ABSL_GUARDED_BY(program_name_guard) = nullptr;
+static absl::Mutex* ProgramNameMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
+ABSL_CONST_INIT static std::string* program_name ABSL_GUARDED_BY(
+ ProgramNameMutex()) ABSL_PT_GUARDED_BY(ProgramNameMutex()) = nullptr;
std::string ProgramInvocationName() {
- absl::MutexLock l(&program_name_guard);
-
+ absl::MutexLock l(ProgramNameMutex());
return program_name ? *program_name : "UNKNOWN";
}
std::string ShortProgramInvocationName() {
- absl::MutexLock l(&program_name_guard);
-
+ absl::MutexLock l(ProgramNameMutex());
return program_name ? std::string(flags_internal::Basename(*program_name))
: "UNKNOWN";
}
void SetProgramInvocationName(absl::string_view prog_name_str) {
- absl::MutexLock l(&program_name_guard);
-
- if (!program_name)
+ absl::MutexLock l(ProgramNameMutex());
+ if (!program_name) {
program_name = new std::string(prog_name_str);
- else
+ } else {
program_name->assign(prog_name_str.data(), prog_name_str.size());
+ }
}
} // namespace flags_internal
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
index 4b68c85..be9aacc 100644
--- a/absl/flags/internal/registry.h
+++ b/absl/flags/internal/registry.h
@@ -19,6 +19,7 @@
#include <functional>
#include "absl/base/config.h"
+#include "absl/base/fast_type_id.h"
#include "absl/flags/commandlineflag.h"
#include "absl/flags/internal/commandlineflag.h"
#include "absl/strings/string_view.h"
@@ -73,7 +74,7 @@
//
// Retire flag with name "name" and type indicated by ops.
-void Retire(const char* name, FlagFastTypeId type_id, char* buf);
+void Retire(const char* name, FlagFastTypeId type_id, unsigned char* buf);
constexpr size_t kRetiredFlagObjSize = 3 * sizeof(void*);
constexpr size_t kRetiredFlagObjAlignment = alignof(void*);
@@ -83,11 +84,11 @@
class RetiredFlag {
public:
void Retire(const char* flag_name) {
- flags_internal::Retire(flag_name, base_internal::FastTypeId<T>(), buf_);
+ flags_internal::Retire(flag_name, absl::FastTypeId<T>(), buf_);
}
private:
- alignas(kRetiredFlagObjAlignment) char buf_[kRetiredFlagObjSize];
+ alignas(kRetiredFlagObjAlignment) unsigned char buf_[kRetiredFlagObjSize];
};
} // namespace flags_internal
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index 8b169bc..fc68b03 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -29,7 +29,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
-#include "absl/base/const_init.h"
+#include "absl/base/no_destructor.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/commandlineflag.h"
#include "absl/flags/flag.h"
@@ -434,45 +434,48 @@
namespace {
-ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
-ABSL_CONST_INIT std::string* match_substr
- ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
-ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
+absl::Mutex* HelpAttributesMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
+ABSL_CONST_INIT std::string* match_substr ABSL_GUARDED_BY(HelpAttributesMutex())
+ ABSL_PT_GUARDED_BY(HelpAttributesMutex()) = nullptr;
+ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(HelpAttributesMutex()) =
HelpMode::kNone;
-ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
+ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(HelpAttributesMutex()) =
HelpFormat::kHumanReadable;
} // namespace
std::string GetFlagsHelpMatchSubstr() {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
if (match_substr == nullptr) return "";
return *match_substr;
}
void SetFlagsHelpMatchSubstr(absl::string_view substr) {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
if (match_substr == nullptr) match_substr = new std::string;
match_substr->assign(substr.data(), substr.size());
}
HelpMode GetFlagsHelpMode() {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
return help_mode;
}
void SetFlagsHelpMode(HelpMode mode) {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
help_mode = mode;
}
HelpFormat GetFlagsHelpFormat() {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
return help_format;
}
void SetFlagsHelpFormat(HelpFormat format) {
- absl::MutexLock l(&help_attributes_guard);
+ absl::MutexLock l(HelpAttributesMutex());
help_format = format;
}
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
index 526b61d..c87cacd 100644
--- a/absl/flags/parse.cc
+++ b/absl/flags/parse.cc
@@ -35,7 +35,7 @@
#include "absl/algorithm/container.h"
#include "absl/base/attributes.h"
#include "absl/base/config.h"
-#include "absl/base/const_init.h"
+#include "absl/base/no_destructor.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/commandlineflag.h"
#include "absl/flags/config.h"
@@ -64,18 +64,25 @@
namespace flags_internal {
namespace {
-ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
+absl::Mutex* ProcessingChecksMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
ABSL_CONST_INIT bool flagfile_needs_processing
- ABSL_GUARDED_BY(processing_checks_guard) = false;
+ ABSL_GUARDED_BY(ProcessingChecksMutex()) = false;
ABSL_CONST_INIT bool fromenv_needs_processing
- ABSL_GUARDED_BY(processing_checks_guard) = false;
+ ABSL_GUARDED_BY(ProcessingChecksMutex()) = false;
ABSL_CONST_INIT bool tryfromenv_needs_processing
- ABSL_GUARDED_BY(processing_checks_guard) = false;
+ ABSL_GUARDED_BY(ProcessingChecksMutex()) = false;
-ABSL_CONST_INIT absl::Mutex specified_flags_guard(absl::kConstInit);
+absl::Mutex* SpecifiedFlagsMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
+
ABSL_CONST_INIT std::vector<const CommandLineFlag*>* specified_flags
- ABSL_GUARDED_BY(specified_flags_guard) = nullptr;
+ ABSL_GUARDED_BY(SpecifiedFlagsMutex()) = nullptr;
// Suggesting at most kMaxHints flags in case of misspellings.
ABSL_CONST_INIT const size_t kMaxHints = 100;
@@ -106,7 +113,7 @@
.OnUpdate([]() {
if (absl::GetFlag(FLAGS_flagfile).empty()) return;
- absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+ absl::MutexLock l(absl::flags_internal::ProcessingChecksMutex());
// Setting this flag twice before it is handled most likely an internal
// error and should be reviewed by developers.
@@ -122,7 +129,7 @@
.OnUpdate([]() {
if (absl::GetFlag(FLAGS_fromenv).empty()) return;
- absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+ absl::MutexLock l(absl::flags_internal::ProcessingChecksMutex());
// Setting this flag twice before it is handled most likely an internal
// error and should be reviewed by developers.
@@ -138,7 +145,7 @@
.OnUpdate([]() {
if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
- absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+ absl::MutexLock l(absl::flags_internal::ProcessingChecksMutex());
// Setting this flag twice before it is handled most likely an internal
// error and should be reviewed by developers.
@@ -415,7 +422,7 @@
std::vector<std::string>& flagfile_value) {
bool success = true;
- absl::MutexLock l(&flags_internal::processing_checks_guard);
+ absl::MutexLock l(flags_internal::ProcessingChecksMutex());
// flagfile could have been set either on a command line or
// programmatically before invoking ParseCommandLine. Note that we do not
@@ -478,7 +485,7 @@
// going to be {"f1", "f2"}
if (!flagfile_value.empty()) {
absl::SetFlag(&FLAGS_flagfile, flagfile_value);
- absl::MutexLock l(&flags_internal::processing_checks_guard);
+ absl::MutexLock l(flags_internal::ProcessingChecksMutex());
flags_internal::flagfile_needs_processing = false;
}
@@ -490,7 +497,7 @@
absl::SetFlag(&FLAGS_tryfromenv, {});
}
- absl::MutexLock l(&flags_internal::processing_checks_guard);
+ absl::MutexLock l(flags_internal::ProcessingChecksMutex());
flags_internal::fromenv_needs_processing = false;
flags_internal::tryfromenv_needs_processing = false;
}
@@ -637,7 +644,7 @@
// --------------------------------------------------------------------
bool WasPresentOnCommandLine(absl::string_view flag_name) {
- absl::ReaderMutexLock l(&specified_flags_guard);
+ absl::ReaderMutexLock l(SpecifiedFlagsMutex());
ABSL_INTERNAL_CHECK(specified_flags != nullptr,
"ParseCommandLine is not invoked yet");
@@ -764,7 +771,7 @@
}
positional_args.push_back(argv[0]);
- absl::MutexLock l(&flags_internal::specified_flags_guard);
+ absl::MutexLock l(flags_internal::SpecifiedFlagsMutex());
if (specified_flags == nullptr) {
specified_flags = new std::vector<const CommandLineFlag*>;
} else {
diff --git a/absl/flags/reflection.cc b/absl/flags/reflection.cc
index ea856ff..b8b4a2e 100644
--- a/absl/flags/reflection.cc
+++ b/absl/flags/reflection.cc
@@ -289,11 +289,10 @@
} // namespace
-void Retire(const char* name, FlagFastTypeId type_id, char* buf) {
+void Retire(const char* name, FlagFastTypeId type_id, unsigned char* buf) {
static_assert(sizeof(RetiredFlagObj) == kRetiredFlagObjSize, "");
static_assert(alignof(RetiredFlagObj) == kRetiredFlagObjAlignment, "");
- auto* flag = ::new (static_cast<void*>(buf))
- flags_internal::RetiredFlagObj(name, type_id);
+ auto* flag = ::new (buf) flags_internal::RetiredFlagObj(name, type_id);
FlagRegistry::GlobalRegistry().RegisterFlag(*flag, nullptr);
}
diff --git a/absl/flags/usage_config.cc b/absl/flags/usage_config.cc
index 5d7426d..5922c5e 100644
--- a/absl/flags/usage_config.cc
+++ b/absl/flags/usage_config.cc
@@ -22,6 +22,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/const_init.h"
+#include "absl/base/no_destructor.h"
#include "absl/base/thread_annotations.h"
#include "absl/flags/internal/path_util.h"
#include "absl/flags/internal/program_name.h"
@@ -104,14 +105,18 @@
// --------------------------------------------------------------------
-ABSL_CONST_INIT absl::Mutex custom_usage_config_guard(absl::kConstInit);
+absl::Mutex* CustomUsageConfigMutex() {
+ static absl::NoDestructor<absl::Mutex> mutex;
+ return mutex.get();
+}
ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config
- ABSL_GUARDED_BY(custom_usage_config_guard) = nullptr;
+ ABSL_GUARDED_BY(CustomUsageConfigMutex())
+ ABSL_PT_GUARDED_BY(CustomUsageConfigMutex()) = nullptr;
} // namespace
FlagsUsageConfig GetUsageConfig() {
- absl::MutexLock l(&custom_usage_config_guard);
+ absl::MutexLock l(CustomUsageConfigMutex());
if (custom_usage_config) return *custom_usage_config;
@@ -136,7 +141,7 @@
} // namespace flags_internal
void SetFlagsUsageConfig(FlagsUsageConfig usage_config) {
- absl::MutexLock l(&flags_internal::custom_usage_config_guard);
+ absl::MutexLock l(flags_internal::CustomUsageConfigMutex());
if (!usage_config.contains_helpshort_flags)
usage_config.contains_helpshort_flags =
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel
index 1a18af2..aeed3b6 100644
--- a/absl/functional/BUILD.bazel
+++ b/absl/functional/BUILD.bazel
@@ -39,7 +39,6 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- "//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/meta:type_traits",
@@ -57,13 +56,12 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":any_invocable",
- "//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/meta:type_traits",
"//absl/utility",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -74,7 +72,6 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- "//absl/base:base_internal",
"//absl/container:compressed_tuple",
"//absl/meta:type_traits",
"//absl/utility",
@@ -89,8 +86,8 @@
deps = [
":bind_front",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -102,7 +99,6 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":any_invocable",
- "//absl/base:base_internal",
"//absl/base:core_headers",
"//absl/meta:type_traits",
],
@@ -118,8 +114,8 @@
":function_ref",
"//absl/container:test_instance_tracker",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -145,13 +141,14 @@
"//absl/strings",
"//absl/strings:string_view",
"//absl/types:variant",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "function_type_benchmark",
+ testonly = True,
srcs = [
"function_type_benchmark.cc",
],
@@ -162,7 +159,6 @@
":any_invocable",
":function_ref",
"//absl/base:core_headers",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt
index 38fea8b..91939db 100644
--- a/absl/functional/CMakeLists.txt
+++ b/absl/functional/CMakeLists.txt
@@ -24,7 +24,6 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::config
absl::core_headers
absl::type_traits
@@ -42,7 +41,6 @@
${ABSL_TEST_COPTS}
DEPS
absl::any_invocable
- absl::base_internal
absl::config
absl::core_headers
absl::type_traits
@@ -60,7 +58,6 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::compressed_tuple
PUBLIC
)
@@ -88,7 +85,6 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::core_headers
absl::any_invocable
absl::meta
diff --git a/absl/functional/any_invocable.h b/absl/functional/any_invocable.h
index 3acb9fd..43ea9af 100644
--- a/absl/functional/any_invocable.h
+++ b/absl/functional/any_invocable.h
@@ -25,7 +25,7 @@
//
// NOTE: `absl::AnyInvocable` is similar to the C++23 `std::move_only_function`
// abstraction, but has a slightly different API and is not designed to be a
-// drop-in replacement or C++11-compatible backfill of that type.
+// drop-in replacement or backfill of that type.
//
// Credits to Matt Calabrese (https://github.com/mattcalabrese) for the original
// implementation.
@@ -97,11 +97,10 @@
// my_func(std::move(func6));
//
// `AnyInvocable` also properly respects `const` qualifiers, reference
-// qualifiers, and the `noexcept` specification (only in C++ 17 and beyond) as
-// part of the user-specified function type (e.g.
-// `AnyInvocable<void() const && noexcept>`). These qualifiers will be applied
-// to the `AnyInvocable` object's `operator()`, and the underlying invocable
-// must be compatible with those qualifiers.
+// qualifiers, and the `noexcept` specification as part of the user-specified
+// function type (e.g. `AnyInvocable<void() const && noexcept>`). These
+// qualifiers will be applied to the `AnyInvocable` object's `operator()`, and
+// the underlying invocable must be compatible with those qualifiers.
//
// Comparison of const and non-const function types:
//
@@ -280,11 +279,10 @@
//
// WARNING: An `AnyInvocable` that wraps an empty `std::function` is not
// itself empty. This behavior is consistent with the standard equivalent
- // `std::move_only_function`.
- //
- // In other words:
+ // `std::move_only_function`. In the following example, `a()` will actually
+ // invoke `f()`, leading to an `std::bad_function_call` exception:
// std::function<void()> f; // empty
- // absl::AnyInvocable<void()> a = std::move(f); // not empty
+ // absl::AnyInvocable<void()> a = f; // not empty
//
// Invoking an empty `AnyInvocable` results in undefined behavior.
explicit operator bool() const noexcept { return this->HasValue(); }
diff --git a/absl/functional/any_invocable_test.cc b/absl/functional/any_invocable_test.cc
index a740faa..6ad6323 100644
--- a/absl/functional/any_invocable_test.cc
+++ b/absl/functional/any_invocable_test.cc
@@ -31,15 +31,6 @@
namespace {
-// Helper macro used to avoid spelling `noexcept` in language versions older
-// than C++17, where it is not part of the type system, in order to avoid
-// compilation failures and internal compiler errors.
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) noexcept(noex)
-#else
-#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex)
-#endif
-
// A dummy type we use when passing qualifiers to metafunctions
struct _ {};
@@ -104,9 +95,6 @@
absl::conditional_t<std::is_const<T>::value, R(P...) const&&, R(P...) &&>;
};
-// If noexcept is a part of the type system, then provide the noexcept forms.
-#if defined(__cpp_noexcept_function_type)
-
template <class T, class R, class... P>
struct GiveQualifiersToFunImpl<T, R(P...) noexcept> {
using type = absl::conditional_t<std::is_const<T>::value,
@@ -127,8 +115,6 @@
R(P...) && noexcept>;
};
-#endif // defined(__cpp_noexcept_function_type)
-
template <class T, class Fun>
using GiveQualifiersToFun = typename GiveQualifiersToFunImpl<T, Fun>::type;
@@ -200,7 +186,7 @@
tail) {} \
add(add&& other) = default; /*NOLINT*/ \
Int operator()(int a, int b, int c) qual \
- ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \
+ noexcept(CallExceptionSpec == NothrowCall::yes) { \
return state + a + b + c; \
} \
int state; \
@@ -218,7 +204,7 @@
~add() noexcept {} \
add(add&& other) = default; /*NOLINT*/ \
Int operator()(int a, int b, int c) qual \
- ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes) { \
+ noexcept(CallExceptionSpec == NothrowCall::yes) { \
return state + a + b + c; \
} \
int state; \
@@ -322,8 +308,8 @@
static constexpr ObjAlign kAlignment = Alignment;
// These types are used when testing with member object pointer Invocables
- using UnqualifiedUnaryFunType = int(Int const&&)
- ABSL_INTERNAL_NOEXCEPT_SPEC(CallExceptionSpec == NothrowCall::yes);
+ using UnqualifiedUnaryFunType = int(Int const&&) noexcept(CallExceptionSpec ==
+ NothrowCall::yes);
using UnaryFunType = GiveQualifiersToFun<Qualifiers, UnqualifiedUnaryFunType>;
using MemObjPtrType = int(Int::*);
using UnaryAnyInvType = AnyInvocable<UnaryFunType>;
@@ -1233,9 +1219,6 @@
TYPED_TEST_SUITE_P(AnyInvTestNoexceptTrue);
TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionConstructionConstraints) {
-#if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
- GTEST_SKIP() << "Noexcept was not part of the type system before C++17.";
-#else
using AnyInvType = typename TypeParam::AnyInvType;
EXPECT_FALSE((std::is_constructible<
@@ -1244,13 +1227,9 @@
EXPECT_FALSE((
std::is_constructible<AnyInvType,
typename TypeParam::IncompatibleInvocable>::value));
-#endif
}
TYPED_TEST_P(AnyInvTestNoexceptTrue, ConversionAssignConstraints) {
-#if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
- GTEST_SKIP() << "Noexcept was not part of the type system before C++17.";
-#else
using AnyInvType = typename TypeParam::AnyInvType;
EXPECT_FALSE((std::is_assignable<
@@ -1259,7 +1238,6 @@
EXPECT_FALSE(
(std::is_assignable<AnyInvType&,
typename TypeParam::IncompatibleInvocable>::value));
-#endif
}
template <class T>
@@ -1283,9 +1261,6 @@
}
TYPED_TEST_P(AnyInvTestNonRvalue, NonMoveableResultType) {
-#if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
- GTEST_SKIP() << "Copy/move elision was not standard before C++17";
-#else
// Define a result type that cannot be copy- or move-constructed.
struct Result {
int x;
@@ -1312,7 +1287,6 @@
AnyInvocable<Fun> any_inv(return_17);
EXPECT_EQ(17, any_inv().x);
-#endif
}
TYPED_TEST_P(AnyInvTestNonRvalue, ConversionAssignReferenceWrapperEmptyLhs) {
@@ -1367,9 +1341,6 @@
}
TYPED_TEST_P(AnyInvTestRvalue, NonMoveableResultType) {
-#if ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
- GTEST_SKIP() << "Copy/move elision was not standard before C++17";
-#else
// Define a result type that cannot be copy- or move-constructed.
struct Result {
int x;
@@ -1395,7 +1366,6 @@
GiveQualifiersToFun<typename TypeParam::Qualifiers, UnqualifiedFun>;
EXPECT_EQ(17, AnyInvocable<Fun>(return_17)().x);
-#endif
}
TYPED_TEST_P(AnyInvTestRvalue, ConversionAssignReferenceWrapper) {
@@ -1507,9 +1477,6 @@
TestParams<Movable::yes, Destructible::nothrow, _, NothrowCall::no,
ObjSize::large, ObjAlign::normal> //
-// Dynamic memory allocation for over-aligned data was introduced in C++17.
-// See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r4.html
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
// Types that must use remote storage because of a large alignment.
,
TestParams<Movable::trivial, Destructible::trivial, _, NothrowCall::no,
@@ -1520,7 +1487,6 @@
ObjSize::small, ObjAlign::large>, //
TestParams<Movable::nothrow, Destructible::nothrow, _, NothrowCall::no,
ObjSize::small, ObjAlign::large> //
-#endif
>;
using TestParameterListRemoteNonMovable = ::testing::Types<
// "Normal" aligned types that are large and have trivial destructors
@@ -1714,6 +1680,4 @@
static_assert(!std::is_convertible<void*, absl::AnyInvocable<void() &&>>::value,
"");
-#undef ABSL_INTERNAL_NOEXCEPT_SPEC
-
} // namespace
diff --git a/absl/functional/bind_front_test.cc b/absl/functional/bind_front_test.cc
index 4801a81..5d94ecc 100644
--- a/absl/functional/bind_front_test.cc
+++ b/absl/functional/bind_front_test.cc
@@ -210,13 +210,9 @@
constexpr auto plus5 = absl::bind_front(Plus, five);
EXPECT_EQ(plus5(1), 6);
- // There seems to be a bug in MSVC dealing constexpr construction of
- // char[]. Notice 'plus5' above; 'int' works just fine.
-#if !(defined(_MSC_VER) && _MSC_VER < 1910)
static constexpr char data[] = "DEF";
constexpr auto g = absl::bind_front(CharAt, data);
EXPECT_EQ(g(1), 'E');
-#endif
}
struct ManglingCall {
diff --git a/absl/functional/function_ref.h b/absl/functional/function_ref.h
index 96cece5..f1d087a 100644
--- a/absl/functional/function_ref.h
+++ b/absl/functional/function_ref.h
@@ -82,17 +82,12 @@
// // replaced by an `absl::FunctionRef`:
// bool Visitor(absl::FunctionRef<void(my_proto&, absl::string_view)>
// callback);
-//
-// Note: the assignment operator within an `absl::FunctionRef` is intentionally
-// deleted to prevent misuse; because the `absl::FunctionRef` does not own the
-// underlying type, assignment likely indicates misuse.
template <typename R, typename... Args>
class FunctionRef<R(Args...)> {
private:
// Used to disable constructors for objects that are not compatible with the
// signature of this FunctionRef.
- template <typename F,
- typename FR = absl::base_internal::invoke_result_t<F, Args&&...>>
+ template <typename F, typename FR = std::invoke_result_t<F, Args&&...>>
using EnableIfCompatible =
typename std::enable_if<std::is_void<R>::value ||
std::is_convertible<FR, R>::value>::type;
@@ -122,9 +117,7 @@
ptr_.fun = reinterpret_cast<decltype(ptr_.fun)>(f);
}
- // To help prevent subtle lifetime bugs, FunctionRef is not assignable.
- // Typically, it should only be used as an argument type.
- FunctionRef& operator=(const FunctionRef& rhs) = delete;
+ FunctionRef& operator=(const FunctionRef& rhs) = default;
FunctionRef(const FunctionRef& rhs) = default;
// Call the underlying object.
diff --git a/absl/functional/function_ref_test.cc b/absl/functional/function_ref_test.cc
index c021113..98d11f7 100644
--- a/absl/functional/function_ref_test.cc
+++ b/absl/functional/function_ref_test.cc
@@ -52,6 +52,16 @@
EXPECT_EQ(1337, ref());
}
+TEST(FunctionRefTest, CopyAssignment) {
+ FunctionRef<int()> a = +[]() -> int {
+ ADD_FAILURE() << "Unexpectedly called";
+ return 0;
+ };
+ FunctionRef<int()> b = +[] { return 1337; };
+ a = b;
+ EXPECT_EQ(1337, a());
+}
+
int NoExceptFunction() noexcept { return 1337; }
// TODO(jdennett): Add a test for noexcept member functions.
diff --git a/absl/functional/function_type_benchmark.cc b/absl/functional/function_type_benchmark.cc
index 03dc31d..513233b 100644
--- a/absl/functional/function_type_benchmark.cc
+++ b/absl/functional/function_type_benchmark.cc
@@ -16,10 +16,10 @@
#include <memory>
#include <string>
-#include "benchmark/benchmark.h"
#include "absl/base/attributes.h"
#include "absl/functional/any_invocable.h"
#include "absl/functional/function_ref.h"
+#include "benchmark/benchmark.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/functional/internal/any_invocable.h b/absl/functional/internal/any_invocable.h
index c2d8cd4..167d947 100644
--- a/absl/functional/internal/any_invocable.h
+++ b/absl/functional/internal/any_invocable.h
@@ -65,7 +65,6 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
-#include "absl/base/internal/invoke.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
#include "absl/meta/type_traits.h"
@@ -74,15 +73,6 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-// Helper macro used to prevent spelling `noexcept` in language versions older
-// than C++17, where it is not part of the type system, in order to avoid
-// compilation failures and internal compiler errors.
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex) noexcept(noex)
-#else
-#define ABSL_INTERNAL_NOEXCEPT_SPEC(noex)
-#endif
-
// Defined in functional/any_invocable.h
template <class Sig>
class AnyInvocable;
@@ -107,44 +97,30 @@
//
////////////////////////////////////////////////////////////////////////////////
-// A type trait that tells us whether or not a target function type should be
+// A metafunction that tells us whether or not a target function type should be
// stored locally in the small object optimization storage
template <class T>
-using IsStoredLocally = std::integral_constant<
- bool, sizeof(T) <= kStorageSize && alignof(T) <= kAlignment &&
- kAlignment % alignof(T) == 0 &&
- std::is_nothrow_move_constructible<T>::value>;
+constexpr bool IsStoredLocally() {
+ if constexpr (sizeof(T) <= kStorageSize && alignof(T) <= kAlignment &&
+ kAlignment % alignof(T) == 0) {
+ return std::is_nothrow_move_constructible<T>::value;
+ }
+ return false;
+}
// An implementation of std::remove_cvref_t of C++20.
template <class T>
using RemoveCVRef =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
-////////////////////////////////////////////////////////////////////////////////
-//
-// An implementation of the C++ standard INVOKE<R> pseudo-macro, operation is
-// equivalent to std::invoke except that it forces an implicit conversion to the
-// specified return type. If "R" is void, the function is executed and the
-// return value is simply ignored.
-template <class ReturnType, class F, class... P,
- typename = absl::enable_if_t<std::is_void<ReturnType>::value>>
-void InvokeR(F&& f, P&&... args) {
- absl::base_internal::invoke(std::forward<F>(f), std::forward<P>(args)...);
-}
-
-template <class ReturnType, class F, class... P,
- absl::enable_if_t<!std::is_void<ReturnType>::value, int> = 0>
+// An implementation of std::invoke_r of C++23.
+template <class ReturnType, class F, class... P>
ReturnType InvokeR(F&& f, P&&... args) {
- // GCC 12 has a false-positive -Wmaybe-uninitialized warning here.
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
- return absl::base_internal::invoke(std::forward<F>(f),
- std::forward<P>(args)...);
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic pop
-#endif
+ if constexpr (std::is_void_v<ReturnType>) {
+ std::invoke(std::forward<F>(f), std::forward<P>(args)...);
+ } else {
+ return std::invoke(std::forward<F>(f), std::forward<P>(args)...);
+ }
}
//
@@ -198,32 +174,14 @@
} remote;
// Local-storage for the type-erased object when small and trivial enough
- alignas(kAlignment) char storage[kStorageSize];
+ alignas(kAlignment) unsigned char storage[kStorageSize];
};
// A typed accessor for the object in `TypeErasedState` storage
template <class T>
T& ObjectInLocalStorage(TypeErasedState* const state) {
// We launder here because the storage may be reused with the same type.
-#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
return *std::launder(reinterpret_cast<T*>(&state->storage));
-#elif ABSL_HAVE_BUILTIN(__builtin_launder)
- return *__builtin_launder(reinterpret_cast<T*>(&state->storage));
-#else
-
- // When `std::launder` or equivalent are not available, we rely on undefined
- // behavior, which works as intended on Abseil's officially supported
- // platforms as of Q2 2022.
-#if !defined(__clang__) && defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wstrict-aliasing"
-#endif
- return *reinterpret_cast<T*>(&state->storage);
-#if !defined(__clang__) && defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-
-#endif
}
// The type for functions issuing lifetime-related operations: move and dispose
@@ -231,14 +189,14 @@
// NOTE: When specifying `FunctionToCall::`dispose, the same state must be
// passed as both "from" and "to".
using ManagerType = void(FunctionToCall /*operation*/,
- TypeErasedState* /*from*/, TypeErasedState* /*to*/)
- ABSL_INTERNAL_NOEXCEPT_SPEC(true);
+ TypeErasedState* /*from*/,
+ TypeErasedState* /*to*/) noexcept(true);
// The type for functions issuing the actual invocation of the object
// A pointer to such a function is contained in each AnyInvocable instance.
template <bool SigIsNoexcept, class ReturnType, class... P>
-using InvokerType = ReturnType(TypeErasedState*, ForwardedParameterType<P>...)
- ABSL_INTERNAL_NOEXCEPT_SPEC(SigIsNoexcept);
+using InvokerType = ReturnType(
+ TypeErasedState*, ForwardedParameterType<P>...) noexcept(SigIsNoexcept);
// The manager that is used when AnyInvocable is empty
inline void EmptyManager(FunctionToCall /*operation*/,
@@ -275,7 +233,7 @@
void LocalManagerNontrivial(FunctionToCall operation,
TypeErasedState* const from,
TypeErasedState* const to) noexcept {
- static_assert(IsStoredLocally<T>::value,
+ static_assert(IsStoredLocally<T>(),
"Local storage must only be used for supported types.");
static_assert(!std::is_trivially_copyable<T>::value,
"Locally stored types must be trivially copyable.");
@@ -303,7 +261,7 @@
ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) {
using RawT = RemoveCVRef<QualTRef>;
static_assert(
- IsStoredLocally<RawT>::value,
+ IsStoredLocally<RawT>(),
"Target object must be in local storage in order to be invoked from it.");
auto& f = (ObjectInLocalStorage<RawT>)(state);
@@ -338,7 +296,7 @@
void RemoteManagerNontrivial(FunctionToCall operation,
TypeErasedState* const from,
TypeErasedState* const to) noexcept {
- static_assert(!IsStoredLocally<T>::value,
+ static_assert(!IsStoredLocally<T>(),
"Remote storage must only be used for types that do not "
"qualify for local storage.");
@@ -360,7 +318,7 @@
TypeErasedState* const state,
ForwardedParameterType<P>... args) noexcept(SigIsNoexcept) {
using RawT = RemoveCVRef<QualTRef>;
- static_assert(!IsStoredLocally<RawT>::value,
+ static_assert(!IsStoredLocally<RawT>(),
"Target object must be in remote storage in order to be "
"invoked from it.");
@@ -440,13 +398,6 @@
CoreImpl() noexcept : manager_(EmptyManager), invoker_(nullptr) {}
- enum class TargetType {
- kPointer,
- kCompatibleAnyInvocable,
- kIncompatibleAnyInvocable,
- kOther,
- };
-
// Note: QualDecayedTRef here includes the cv-ref qualifiers associated with
// the invocation of the Invocable. The unqualified type is the target object
// type to be stored.
@@ -454,19 +405,47 @@
explicit CoreImpl(TypedConversionConstruct<QualDecayedTRef>, F&& f) {
using DecayedT = RemoveCVRef<QualDecayedTRef>;
- constexpr TargetType kTargetType =
- (std::is_pointer<DecayedT>::value ||
- std::is_member_pointer<DecayedT>::value)
- ? TargetType::kPointer
- : IsCompatibleAnyInvocable<DecayedT>::value
- ? TargetType::kCompatibleAnyInvocable
- : IsAnyInvocable<DecayedT>::value
- ? TargetType::kIncompatibleAnyInvocable
- : TargetType::kOther;
- // NOTE: We only use integers instead of enums as template parameters in
- // order to work around a bug on C++14 under MSVC 2017.
- // See b/236131881.
- Initialize<kTargetType, QualDecayedTRef>(std::forward<F>(f));
+ if constexpr (std::is_pointer<DecayedT>::value ||
+ std::is_member_pointer<DecayedT>::value) {
+ // This condition handles types that decay into pointers. This includes
+ // function references, which cannot be null. GCC warns against comparing
+ // their decayed form with nullptr (https://godbolt.org/z/9r9TMTcPK).
+ // We could work around this warning with constexpr programming, using
+ // std::is_function_v<std::remove_reference_t<F>>, but we choose to ignore
+ // it instead of writing more code.
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Waddress"
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+#endif
+ if (static_cast<DecayedT>(f) == nullptr) {
+#if !defined(__clang__) && defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
+ manager_ = EmptyManager;
+ invoker_ = nullptr;
+ } else {
+ InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
+ }
+ } else if constexpr (IsCompatibleAnyInvocable<DecayedT>::value) {
+ // In this case we can "steal the guts" of the other AnyInvocable.
+ f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_);
+ manager_ = f.manager_;
+ invoker_ = f.invoker_;
+
+ f.manager_ = EmptyManager;
+ f.invoker_ = nullptr;
+ } else if constexpr (IsAnyInvocable<DecayedT>::value) {
+ if (f.HasValue()) {
+ InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
+ } else {
+ manager_ = EmptyManager;
+ invoker_ = nullptr;
+ }
+ } else {
+ InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
+ }
}
// Note: QualTRef here includes the cv-ref qualifiers associated with the
@@ -517,122 +496,43 @@
invoker_ = nullptr;
}
- template <TargetType target_type, class QualDecayedTRef, class F,
- absl::enable_if_t<target_type == TargetType::kPointer, int> = 0>
- void Initialize(F&& f) {
-// This condition handles types that decay into pointers, which includes
-// function references. Since function references cannot be null, GCC warns
-// against comparing their decayed form with nullptr.
-// Since this is template-heavy code, we prefer to disable these warnings
-// locally instead of adding yet another overload of this function.
-#if !defined(__clang__) && defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpragmas"
-#pragma GCC diagnostic ignored "-Waddress"
-#pragma GCC diagnostic ignored "-Wnonnull-compare"
-#endif
- if (static_cast<RemoveCVRef<QualDecayedTRef>>(f) == nullptr) {
-#if !defined(__clang__) && defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
- manager_ = EmptyManager;
- invoker_ = nullptr;
- return;
- }
- InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
- }
-
- template <TargetType target_type, class QualDecayedTRef, class F,
- absl::enable_if_t<
- target_type == TargetType::kCompatibleAnyInvocable, int> = 0>
- void Initialize(F&& f) {
- // In this case we can "steal the guts" of the other AnyInvocable.
- f.manager_(FunctionToCall::relocate_from_to, &f.state_, &state_);
- manager_ = f.manager_;
- invoker_ = f.invoker_;
-
- f.manager_ = EmptyManager;
- f.invoker_ = nullptr;
- }
-
- template <TargetType target_type, class QualDecayedTRef, class F,
- absl::enable_if_t<
- target_type == TargetType::kIncompatibleAnyInvocable, int> = 0>
- void Initialize(F&& f) {
- if (f.HasValue()) {
- InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
- } else {
- manager_ = EmptyManager;
- invoker_ = nullptr;
- }
- }
-
- template <TargetType target_type, class QualDecayedTRef, class F,
- typename = absl::enable_if_t<target_type == TargetType::kOther>>
- void Initialize(F&& f) {
- InitializeStorage<QualDecayedTRef>(std::forward<F>(f));
- }
-
// Use local (inline) storage for applicable target object types.
- template <class QualTRef, class... Args,
- typename = absl::enable_if_t<
- IsStoredLocally<RemoveCVRef<QualTRef>>::value>>
+ template <class QualTRef, class... Args>
void InitializeStorage(Args&&... args) {
using RawT = RemoveCVRef<QualTRef>;
- ::new (static_cast<void*>(&state_.storage))
- RawT(std::forward<Args>(args)...);
-
- invoker_ = LocalInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
- // We can simplify our manager if we know the type is trivially copyable.
- InitializeLocalManager<RawT>();
+ if constexpr (IsStoredLocally<RawT>()) {
+ ::new (static_cast<void*>(&state_.storage))
+ RawT(std::forward<Args>(args)...);
+ invoker_ = LocalInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
+ // We can simplify our manager if we know the type is trivially copyable.
+ if constexpr (std::is_trivially_copyable_v<RawT>) {
+ manager_ = LocalManagerTrivial;
+ } else {
+ manager_ = LocalManagerNontrivial<RawT>;
+ }
+ } else {
+ InitializeRemoteManager<RawT>(std::forward<Args>(args)...);
+ // This is set after everything else in case an exception is thrown in an
+ // earlier step of the initialization.
+ invoker_ = RemoteInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
+ }
}
- // Use remote storage for target objects that cannot be stored locally.
- template <class QualTRef, class... Args,
- absl::enable_if_t<!IsStoredLocally<RemoveCVRef<QualTRef>>::value,
- int> = 0>
- void InitializeStorage(Args&&... args) {
- InitializeRemoteManager<RemoveCVRef<QualTRef>>(std::forward<Args>(args)...);
- // This is set after everything else in case an exception is thrown in an
- // earlier step of the initialization.
- invoker_ = RemoteInvoker<SigIsNoexcept, ReturnType, QualTRef, P...>;
- }
-
- template <class T,
- typename = absl::enable_if_t<std::is_trivially_copyable<T>::value>>
- void InitializeLocalManager() {
- manager_ = LocalManagerTrivial;
- }
-
- template <class T,
- absl::enable_if_t<!std::is_trivially_copyable<T>::value, int> = 0>
- void InitializeLocalManager() {
- manager_ = LocalManagerNontrivial<T>;
- }
-
- template <class T>
- using HasTrivialRemoteStorage =
- std::integral_constant<bool, std::is_trivially_destructible<T>::value &&
- alignof(T) <=
- ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT>;
-
- template <class T, class... Args,
- typename = absl::enable_if_t<HasTrivialRemoteStorage<T>::value>>
+ template <class T, class... Args>
void InitializeRemoteManager(Args&&... args) {
- // unique_ptr is used for exception-safety in case construction throws.
- std::unique_ptr<void, TrivialDeleter> uninitialized_target(
- ::operator new(sizeof(T)), TrivialDeleter(sizeof(T)));
- ::new (uninitialized_target.get()) T(std::forward<Args>(args)...);
- state_.remote.target = uninitialized_target.release();
- state_.remote.size = sizeof(T);
- manager_ = RemoteManagerTrivial;
- }
-
- template <class T, class... Args,
- absl::enable_if_t<!HasTrivialRemoteStorage<T>::value, int> = 0>
- void InitializeRemoteManager(Args&&... args) {
- state_.remote.target = ::new T(std::forward<Args>(args)...);
- manager_ = RemoteManagerNontrivial<T>;
+ if constexpr (std::is_trivially_destructible_v<T> &&
+ alignof(T) <= ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT) {
+ // unique_ptr is used for exception-safety in case construction throws.
+ std::unique_ptr<void, TrivialDeleter> uninitialized_target(
+ ::operator new(sizeof(T)), TrivialDeleter(sizeof(T)));
+ ::new (uninitialized_target.get()) T(std::forward<Args>(args)...);
+ state_.remote.target = uninitialized_target.release();
+ state_.remote.size = sizeof(T);
+ manager_ = RemoteManagerTrivial;
+ } else {
+ state_.remote.target = ::new T(std::forward<Args>(args)...);
+ manager_ = RemoteManagerNontrivial<T>;
+ }
}
//////////////////////////////////////////////////////////////////////////////
@@ -734,17 +634,12 @@
absl::enable_if_t<Impl<Sig>::template CallIsNoexceptIfSigIsNoexcept<
std::reference_wrapper<F>>::value>>;
-////////////////////////////////////////////////////////////////////////////////
-//
// The constraint for checking whether or not a call meets the noexcept
-// callability requirements. This is a preprocessor macro because specifying it
+// callability requirements. We use a preprocessor macro because specifying it
// this way as opposed to a disjunction/branch can improve the user-side error
// messages and avoids an instantiation of std::is_nothrow_invocable_r in the
// cases where the user did not specify a noexcept function type.
//
-#define ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT(inv_quals, noex) \
- ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_##noex(inv_quals)
-
// The disjunction below is because we can't rely on std::is_nothrow_invocable_r
// to give the right result when ReturnType is non-moveable in toolchains that
// don't treat non-moveable result types correctly. For example this was the
@@ -759,7 +654,7 @@
UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, P...>, \
std::is_same< \
ReturnType, \
- absl::base_internal::invoke_result_t< \
+ std::invoke_result_t< \
UnwrapStdReferenceWrapper<absl::decay_t<F>> inv_quals, \
P...>>>>::value>
@@ -775,13 +670,13 @@
// noex is "true" if the function type is noexcept, or false if it is not.
//
// The CallIsValid condition is more complicated than simply using
-// absl::base_internal::is_invocable_r because we can't rely on it to give the
-// right result when ReturnType is non-moveable in toolchains that don't treat
-// non-moveable result types correctly. For example this was the case in libc++
-// before commit c3a24882 (2022-05).
+// std::is_invocable_r because we can't rely on it to give the right result
+// when ReturnType is non-moveable in toolchains that don't treat non-moveable
+// result types correctly. For example this was the case in libc++ before commit
+// c3a24882 (2022-05).
#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, noex) \
template <class ReturnType, class... P> \
- class Impl<ReturnType(P...) cv ref ABSL_INTERNAL_NOEXCEPT_SPEC(noex)> \
+ class Impl<ReturnType(P...) cv ref noexcept(noex)> \
: public CoreImpl<noex, ReturnType, P...> { \
public: \
/*The base class, which contains the datamembers and core operations*/ \
@@ -790,17 +685,16 @@
/*SFINAE constraint to check if F is invocable with the proper signature*/ \
template <class F> \
using CallIsValid = TrueAlias<absl::enable_if_t<absl::disjunction< \
- absl::base_internal::is_invocable_r<ReturnType, \
- absl::decay_t<F> inv_quals, P...>, \
- std::is_same<ReturnType, \
- absl::base_internal::invoke_result_t< \
- absl::decay_t<F> inv_quals, P...>>>::value>>; \
+ std::is_invocable_r<ReturnType, absl::decay_t<F> inv_quals, P...>, \
+ std::is_same< \
+ ReturnType, \
+ std::invoke_result_t<absl::decay_t<F> inv_quals, P...>>>::value>>; \
\
/*SFINAE constraint to check if F is nothrow-invocable when necessary*/ \
template <class F> \
using CallIsNoexceptIfSigIsNoexcept = \
- TrueAlias<ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT(inv_quals, \
- noex)>; \
+ TrueAlias<ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_##noex( \
+ inv_quals)>; \
\
/*Put the AnyInvocable into an empty state.*/ \
Impl() = default; \
@@ -822,8 +716,7 @@
\
/*Raises a fatal error when the AnyInvocable is invoked after a move*/ \
static ReturnType InvokedAfterMove( \
- TypeErasedState*, \
- ForwardedParameterType<P>...) noexcept(noex) { \
+ TypeErasedState*, ForwardedParameterType<P>...) noexcept(noex) { \
ABSL_HARDENING_ASSERT(false && "AnyInvocable use-after-move"); \
std::terminate(); \
} \
@@ -851,18 +744,11 @@
} \
}
-// Define the `noexcept(true)` specialization only for C++17 and beyond, when
-// `noexcept` is part of the type system.
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
// A convenience macro that defines specializations for the noexcept(true) and
// noexcept(false) forms, given the other properties.
#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals) \
ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false); \
ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, true)
-#else
-#define ABSL_INTERNAL_ANY_INVOCABLE_IMPL(cv, ref, inv_quals) \
- ABSL_INTERNAL_ANY_INVOCABLE_IMPL_(cv, ref, inv_quals, false)
-#endif
// Non-ref-qualified partial specializations
ABSL_INTERNAL_ANY_INVOCABLE_IMPL(, , &);
@@ -881,8 +767,6 @@
#undef ABSL_INTERNAL_ANY_INVOCABLE_IMPL_
#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_false
#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT_true
-#undef ABSL_INTERNAL_ANY_INVOCABLE_NOEXCEPT_CONSTRAINT
-#undef ABSL_INTERNAL_NOEXCEPT_SPEC
} // namespace internal_any_invocable
ABSL_NAMESPACE_END
diff --git a/absl/functional/internal/front_binder.h b/absl/functional/internal/front_binder.h
index 44a5492..62f373f 100644
--- a/absl/functional/internal/front_binder.h
+++ b/absl/functional/internal/front_binder.h
@@ -21,7 +21,6 @@
#include <type_traits>
#include <utility>
-#include "absl/base/internal/invoke.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/meta/type_traits.h"
#include "absl/utility/utility.h"
@@ -33,9 +32,8 @@
// Invoke the method, expanding the tuple of bound arguments.
template <class R, class Tuple, size_t... Idx, class... Args>
R Apply(Tuple&& bound, absl::index_sequence<Idx...>, Args&&... free) {
- return base_internal::invoke(
- std::forward<Tuple>(bound).template get<Idx>()...,
- std::forward<Args>(free)...);
+ return std::invoke(std::forward<Tuple>(bound).template get<Idx>()...,
+ std::forward<Args>(free)...);
}
template <class F, class... BoundArgs>
@@ -50,23 +48,23 @@
constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts)
: bound_args_(std::forward<Ts>(ts)...) {}
- template <class... FreeArgs, class R = base_internal::invoke_result_t<
- F&, BoundArgs&..., FreeArgs&&...>>
+ template <class... FreeArgs,
+ class R = std::invoke_result_t<F&, BoundArgs&..., FreeArgs&&...>>
R operator()(FreeArgs&&... free_args) & {
return functional_internal::Apply<R>(bound_args_, Idx(),
std::forward<FreeArgs>(free_args)...);
}
template <class... FreeArgs,
- class R = base_internal::invoke_result_t<
- const F&, const BoundArgs&..., FreeArgs&&...>>
+ class R = std::invoke_result_t<const F&, const BoundArgs&...,
+ FreeArgs&&...>>
R operator()(FreeArgs&&... free_args) const& {
return functional_internal::Apply<R>(bound_args_, Idx(),
std::forward<FreeArgs>(free_args)...);
}
- template <class... FreeArgs, class R = base_internal::invoke_result_t<
- F&&, BoundArgs&&..., FreeArgs&&...>>
+ template <class... FreeArgs,
+ class R = std::invoke_result_t<F&&, BoundArgs&&..., FreeArgs&&...>>
R operator()(FreeArgs&&... free_args) && {
// This overload is called when *this is an rvalue. If some of the bound
// arguments are stored by value or rvalue reference, we move them.
@@ -75,8 +73,8 @@
}
template <class... FreeArgs,
- class R = base_internal::invoke_result_t<
- const F&&, const BoundArgs&&..., FreeArgs&&...>>
+ class R = std::invoke_result_t<const F&&, const BoundArgs&&...,
+ FreeArgs&&...>>
R operator()(FreeArgs&&... free_args) const&& {
// This overload is called when *this is an rvalue. If some of the bound
// arguments are stored by value or rvalue reference, we move them.
diff --git a/absl/functional/internal/function_ref.h b/absl/functional/internal/function_ref.h
index 1cd34a3..27d45b8 100644
--- a/absl/functional/internal/function_ref.h
+++ b/absl/functional/internal/function_ref.h
@@ -19,7 +19,6 @@
#include <functional>
#include <type_traits>
-#include "absl/base/internal/invoke.h"
#include "absl/functional/any_invocable.h"
#include "absl/meta/type_traits.h"
@@ -74,15 +73,13 @@
template <typename Obj, typename R, typename... Args>
R InvokeObject(VoidPtr ptr, typename ForwardT<Args>::type... args) {
auto o = static_cast<const Obj*>(ptr.obj);
- return static_cast<R>(
- absl::base_internal::invoke(*o, std::forward<Args>(args)...));
+ return static_cast<R>(std::invoke(*o, std::forward<Args>(args)...));
}
template <typename Fun, typename R, typename... Args>
R InvokeFunction(VoidPtr ptr, typename ForwardT<Args>::type... args) {
auto f = reinterpret_cast<Fun>(ptr.fun);
- return static_cast<R>(
- absl::base_internal::invoke(f, std::forward<Args>(args)...));
+ return static_cast<R>(std::invoke(f, std::forward<Args>(args)...));
}
template <typename Sig>
diff --git a/absl/functional/overload.h b/absl/functional/overload.h
index 7e19e70..35eec96 100644
--- a/absl/functional/overload.h
+++ b/absl/functional/overload.h
@@ -23,8 +23,6 @@
// Before using this function, consider whether named function overloads would
// be a better design.
//
-// Note: absl::Overload requires C++17.
-//
// Example:
//
// std::variant<std::string, int32_t, int64_t> v(int32_t{1});
@@ -46,9 +44,6 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-
template <typename... T>
struct Overload final : T... {
using T::operator()...;
@@ -71,21 +66,6 @@
template <typename... T>
Overload(T...) -> Overload<T...>;
-#else
-
-namespace functional_internal {
-template <typename T>
-constexpr bool kDependentFalse = false;
-}
-
-template <typename Dependent = int, typename... T>
-auto Overload(T&&...) {
- static_assert(functional_internal::kDependentFalse<Dependent>,
- "Overload is only usable with C++17 or above.");
-}
-
-#endif
-
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/functional/overload_test.cc b/absl/functional/overload_test.cc
index fa49d29..802e11f 100644
--- a/absl/functional/overload_test.cc
+++ b/absl/functional/overload_test.cc
@@ -18,16 +18,12 @@
#include <string>
#include <type_traits>
+#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/variant.h"
-#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
- ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
-
-#include "gtest/gtest.h"
-
namespace {
TEST(OverloadTest, DispatchConsidersTypeWithAutoFallback) {
@@ -209,5 +205,3 @@
}
} // namespace
-
-#endif
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index fe567e9..b2ffcd0 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -44,6 +44,7 @@
deps = [
":city",
":low_level_hash",
+ ":weakly_mixed_integer",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
@@ -69,7 +70,7 @@
"//absl/meta:type_traits",
"//absl/strings",
"//absl/types:variant",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -86,21 +87,17 @@
":hash_testing",
":spy_hash_state",
"//absl/base:config",
- "//absl/base:core_headers",
- "//absl/container:btree",
"//absl/container:flat_hash_map",
"//absl/container:flat_hash_set",
- "//absl/container:node_hash_map",
- "//absl/container:node_hash_set",
"//absl/memory",
"//absl/meta:type_traits",
- "//absl/numeric:int128",
+ "//absl/numeric:bits",
"//absl/strings:cord_test_helpers",
"//absl/strings:string_view",
"//absl/types:optional",
"//absl/types:variant",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -121,8 +118,8 @@
"//absl/container:flat_hash_set",
"//absl/container:node_hash_map",
"//absl/container:node_hash_set",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -142,7 +139,7 @@
"//absl/strings",
"//absl/strings:cord",
"//absl/strings:cord_test_helpers",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -155,6 +152,7 @@
visibility = ["//visibility:private"],
deps = [
":hash",
+ ":weakly_mixed_integer",
"//absl/strings",
"//absl/strings:str_format",
],
@@ -182,8 +180,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":city",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -196,12 +194,28 @@
visibility = ["//visibility:private"],
deps = [
"//absl/base:config",
+ "//absl/base:core_headers",
"//absl/base:endian",
"//absl/base:prefetch",
"//absl/numeric:int128",
],
)
+cc_library(
+ name = "weakly_mixed_integer",
+ hdrs = ["internal/weakly_mixed_integer.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/container:__pkg__",
+ "//absl/strings:__pkg__",
+ "//absl/types:__pkg__",
+ ],
+ deps = [
+ "//absl/base:config",
+ ],
+)
+
cc_test(
name = "low_level_hash_test",
srcs = ["internal/low_level_hash_test.cc"],
@@ -211,7 +225,7 @@
deps = [
":low_level_hash",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index 99d6fa1..6996d93 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -39,6 +39,7 @@
absl::variant
absl::utility
absl::low_level_hash
+ absl::weakly_mixed_integer
PUBLIC
)
@@ -68,18 +69,14 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
- absl::btree
+ absl::bits
absl::cord_test_helpers
- absl::core_headers
absl::flat_hash_map
absl::flat_hash_set
absl::hash
absl::hash_testing
- absl::int128
absl::memory
absl::meta
- absl::node_hash_map
- absl::node_hash_set
absl::optional
absl::spy_hash_state
absl::string_view
@@ -123,6 +120,7 @@
absl::hash
absl::strings
absl::str_format
+ absl::weakly_mixed_integer
TESTONLY
PUBLIC
)
@@ -167,11 +165,24 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
+ absl::core_headers
absl::endian
absl::int128
absl::prefetch
)
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ weakly_mixed_integer
+ HDRS
+ "internal/weakly_mixed_integer.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+)
+
absl_cc_test(
NAME
low_level_hash_test
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index 470cca4..23f4e9d 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -78,11 +78,17 @@
#ifndef ABSL_HASH_HASH_H_
#define ABSL_HASH_HASH_H_
+#include <cstddef>
+#include <cstdint>
#include <tuple>
+#include <type_traits>
#include <utility>
+#include "absl/base/config.h"
#include "absl/functional/function_ref.h"
#include "absl/hash/internal/hash.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
+#include "absl/meta/type_traits.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -319,8 +325,12 @@
// Create a new `HashState` instance that wraps `state`. All calls to
// `combine()` and `combine_contiguous()` on the new instance will be
// redirected to the original `state` object. The `state` object must outlive
- // the `HashState` instance.
- template <typename T>
+ // the `HashState` instance. `T` must be a subclass of `HashStateBase<T>` -
+ // users should not define their own HashState types.
+ template <
+ typename T,
+ absl::enable_if_t<
+ std::is_base_of<hash_internal::HashStateBase<T>, T>::value, int> = 0>
static HashState Create(T* state) {
HashState s;
s.Init(state);
@@ -347,12 +357,19 @@
hash_state.combine_contiguous_(hash_state.state_, first, size);
return hash_state;
}
+
+ static HashState combine_weakly_mixed_integer(
+ HashState hash_state, hash_internal::WeaklyMixedInteger value) {
+ hash_state.combine_weakly_mixed_integer_(hash_state.state_, value);
+ return hash_state;
+ }
using HashState::HashStateBase::combine_contiguous;
private:
HashState() = default;
friend class HashState::HashStateBase;
+ friend struct hash_internal::CombineRaw;
template <typename T>
static void CombineContiguousImpl(void* p, const unsigned char* first,
@@ -362,9 +379,29 @@
}
template <typename T>
+ static void CombineWeaklyMixedIntegerImpl(
+ void* p, hash_internal::WeaklyMixedInteger value) {
+ T& state = *static_cast<T*>(p);
+ state = T::combine_weakly_mixed_integer(std::move(state), value);
+ }
+
+ static HashState combine_raw(HashState hash_state, uint64_t value) {
+ hash_state.combine_raw_(hash_state.state_, value);
+ return hash_state;
+ }
+
+ template <typename T>
+ static void CombineRawImpl(void* p, uint64_t value) {
+ T& state = *static_cast<T*>(p);
+ state = hash_internal::CombineRaw()(std::move(state), value);
+ }
+
+ template <typename T>
void Init(T* state) {
state_ = state;
+ combine_weakly_mixed_integer_ = &CombineWeaklyMixedIntegerImpl<T>;
combine_contiguous_ = &CombineContiguousImpl<T>;
+ combine_raw_ = &CombineRawImpl<T>;
run_combine_unordered_ = &RunCombineUnorderedImpl<T>;
}
@@ -402,7 +439,9 @@
// Do not erase an already erased state.
void Init(HashState* state) {
state_ = state->state_;
+ combine_weakly_mixed_integer_ = state->combine_weakly_mixed_integer_;
combine_contiguous_ = state->combine_contiguous_;
+ combine_raw_ = state->combine_raw_;
run_combine_unordered_ = state->run_combine_unordered_;
}
@@ -412,7 +451,10 @@
}
void* state_;
+ void (*combine_weakly_mixed_integer_)(
+ void*, absl::hash_internal::WeaklyMixedInteger);
void (*combine_contiguous_)(void*, const unsigned char*, size_t);
+ void (*combine_raw_)(void*, uint64_t);
HashState (*run_combine_unordered_)(
HashState state,
absl::FunctionRef<void(HashState, absl::FunctionRef<void(HashState&)>)>);
diff --git a/absl/hash/hash_benchmark.cc b/absl/hash/hash_benchmark.cc
index 9b73f46..73b037d 100644
--- a/absl/hash/hash_benchmark.cc
+++ b/absl/hash/hash_benchmark.cc
@@ -146,6 +146,59 @@
return result;
}
+template <typename T>
+struct LongCombine {
+ T a[200]{};
+ template <typename H>
+ friend H AbslHashValue(H state, const LongCombine& v) {
+ // This is testing a single call to `combine` with a lot of arguments to
+ // test the performance of the folding logic.
+ return H::combine(
+ std::move(state), //
+ v.a[0], v.a[1], v.a[2], v.a[3], v.a[4], v.a[5], v.a[6], v.a[7], v.a[8],
+ v.a[9], v.a[10], v.a[11], v.a[12], v.a[13], v.a[14], v.a[15], v.a[16],
+ v.a[17], v.a[18], v.a[19], v.a[20], v.a[21], v.a[22], v.a[23], v.a[24],
+ v.a[25], v.a[26], v.a[27], v.a[28], v.a[29], v.a[30], v.a[31], v.a[32],
+ v.a[33], v.a[34], v.a[35], v.a[36], v.a[37], v.a[38], v.a[39], v.a[40],
+ v.a[41], v.a[42], v.a[43], v.a[44], v.a[45], v.a[46], v.a[47], v.a[48],
+ v.a[49], v.a[50], v.a[51], v.a[52], v.a[53], v.a[54], v.a[55], v.a[56],
+ v.a[57], v.a[58], v.a[59], v.a[60], v.a[61], v.a[62], v.a[63], v.a[64],
+ v.a[65], v.a[66], v.a[67], v.a[68], v.a[69], v.a[70], v.a[71], v.a[72],
+ v.a[73], v.a[74], v.a[75], v.a[76], v.a[77], v.a[78], v.a[79], v.a[80],
+ v.a[81], v.a[82], v.a[83], v.a[84], v.a[85], v.a[86], v.a[87], v.a[88],
+ v.a[89], v.a[90], v.a[91], v.a[92], v.a[93], v.a[94], v.a[95], v.a[96],
+ v.a[97], v.a[98], v.a[99], v.a[100], v.a[101], v.a[102], v.a[103],
+ v.a[104], v.a[105], v.a[106], v.a[107], v.a[108], v.a[109], v.a[110],
+ v.a[111], v.a[112], v.a[113], v.a[114], v.a[115], v.a[116], v.a[117],
+ v.a[118], v.a[119], v.a[120], v.a[121], v.a[122], v.a[123], v.a[124],
+ v.a[125], v.a[126], v.a[127], v.a[128], v.a[129], v.a[130], v.a[131],
+ v.a[132], v.a[133], v.a[134], v.a[135], v.a[136], v.a[137], v.a[138],
+ v.a[139], v.a[140], v.a[141], v.a[142], v.a[143], v.a[144], v.a[145],
+ v.a[146], v.a[147], v.a[148], v.a[149], v.a[150], v.a[151], v.a[152],
+ v.a[153], v.a[154], v.a[155], v.a[156], v.a[157], v.a[158], v.a[159],
+ v.a[160], v.a[161], v.a[162], v.a[163], v.a[164], v.a[165], v.a[166],
+ v.a[167], v.a[168], v.a[169], v.a[170], v.a[171], v.a[172], v.a[173],
+ v.a[174], v.a[175], v.a[176], v.a[177], v.a[178], v.a[179], v.a[180],
+ v.a[181], v.a[182], v.a[183], v.a[184], v.a[185], v.a[186], v.a[187],
+ v.a[188], v.a[189], v.a[190], v.a[191], v.a[192], v.a[193], v.a[194],
+ v.a[195], v.a[196], v.a[197], v.a[198], v.a[199]);
+ }
+};
+
+template <typename T>
+auto MakeLongTuple() {
+ auto t1 = std::tuple<T>();
+ auto t2 = std::tuple_cat(t1, t1);
+ auto t3 = std::tuple_cat(t2, t2);
+ auto t4 = std::tuple_cat(t3, t3);
+ auto t5 = std::tuple_cat(t4, t4);
+ auto t6 = std::tuple_cat(t5, t5);
+ // Ideally this would be much larger, but some configurations can't handle
+ // making tuples with that many elements. They break inside std::tuple itself.
+ static_assert(std::tuple_size<decltype(t6)>::value == 32, "");
+ return t6;
+}
+
// Generates a benchmark and a codegen method for the provided types. The
// codegen method provides a well known entrypoint for dumping assembly.
#define MAKE_BENCHMARK(hash, name, ...) \
@@ -171,6 +224,10 @@
MAKE_BENCHMARK(AbslHash, TupleInt32BoolInt64,
std::tuple<int32_t, bool, int64_t>{});
MAKE_BENCHMARK(AbslHash, String_0, std::string());
+MAKE_BENCHMARK(AbslHash, String_1, std::string(1, 'a'));
+MAKE_BENCHMARK(AbslHash, String_2, std::string(2, 'a'));
+MAKE_BENCHMARK(AbslHash, String_4, std::string(4, 'a'));
+MAKE_BENCHMARK(AbslHash, String_8, std::string(8, 'a'));
MAKE_BENCHMARK(AbslHash, String_10, std::string(10, 'a'));
MAKE_BENCHMARK(AbslHash, String_30, std::string(30, 'a'));
MAKE_BENCHMARK(AbslHash, String_90, std::string(90, 'a'));
@@ -212,6 +269,10 @@
std::make_pair(std::string(200, 'a'), std::string(200, 'b')));
MAKE_BENCHMARK(AbslHash, PairStringString_5000,
std::make_pair(std::string(5000, 'a'), std::string(5000, 'b')));
+MAKE_BENCHMARK(AbslHash, LongTupleInt32, MakeLongTuple<int>());
+MAKE_BENCHMARK(AbslHash, LongTupleString, MakeLongTuple<std::string>());
+MAKE_BENCHMARK(AbslHash, LongCombineInt32, LongCombine<int>());
+MAKE_BENCHMARK(AbslHash, LongCombineString, LongCombine<std::string>());
MAKE_BENCHMARK(TypeErasedAbslHash, Int32, int32_t{});
MAKE_BENCHMARK(TypeErasedAbslHash, Int64, int64_t{});
@@ -317,7 +378,10 @@
MAKE_LATENCY_BENCHMARK(AbslHash, Int32, PodRand<int32_t>)
MAKE_LATENCY_BENCHMARK(AbslHash, Int64, PodRand<int64_t>)
+MAKE_LATENCY_BENCHMARK(AbslHash, String3, StringRand<3>)
+MAKE_LATENCY_BENCHMARK(AbslHash, String5, StringRand<5>)
MAKE_LATENCY_BENCHMARK(AbslHash, String9, StringRand<9>)
+MAKE_LATENCY_BENCHMARK(AbslHash, String17, StringRand<17>)
MAKE_LATENCY_BENCHMARK(AbslHash, String33, StringRand<33>)
MAKE_LATENCY_BENCHMARK(AbslHash, String65, StringRand<65>)
MAKE_LATENCY_BENCHMARK(AbslHash, String257, StringRand<257>)
diff --git a/absl/hash/hash_instantiated_test.cc b/absl/hash/hash_instantiated_test.cc
index e65de9c..f0df86f 100644
--- a/absl/hash/hash_instantiated_test.cc
+++ b/absl/hash/hash_instantiated_test.cc
@@ -51,7 +51,7 @@
// Dummy type with unordered equality and hashing semantics. This preserves
// input order internally, and is used below to ensure we get test coverage
-// for equal sequences with different iteraton orders.
+// for equal sequences with different iteration orders.
template <typename T>
class UnorderedSequence {
public:
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 7fecf53..7582f54 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -29,20 +29,24 @@
#include <ostream>
#include <set>
#include <string>
+#include <string_view>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
+#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/hash/hash_testing.h"
#include "absl/hash/internal/hash_test.h"
#include "absl/hash/internal/spy_hash_state.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
+#include "absl/numeric/bits.h"
#include "absl/strings/cord_test_helpers.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@@ -52,15 +56,12 @@
#include <filesystem> // NOLINT
#endif
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
namespace {
using ::absl::hash_test_internal::is_hashable;
using ::absl::hash_test_internal::TypeErasedContainer;
using ::absl::hash_test_internal::TypeErasedValue;
+using ::testing::SizeIs;
template <typename T>
using TypeErasedVector = TypeErasedContainer<std::vector<T>>;
@@ -117,6 +118,15 @@
std::make_tuple(true, false)));
}
+TEST(HashValueTest, HashConsistentAcrossIntTypes){
+ std::vector<size_t> hashes = {
+ absl::Hash<int8_t>{}(1), absl::Hash<uint8_t>{}(1),
+ absl::Hash<int16_t>{}(1), absl::Hash<uint16_t>{}(1),
+ absl::Hash<int32_t>{}(1), absl::Hash<uint32_t>{}(1),
+ absl::Hash<int64_t>{}(1), absl::Hash<uint64_t>{}(1)};
+ EXPECT_THAT(hashes, testing::Each(absl::Hash<int>{}(1)));
+}
+
TEST(HashValueTest, FloatingPoint) {
EXPECT_TRUE((is_hashable<float>::value));
EXPECT_TRUE((is_hashable<double>::value));
@@ -153,8 +163,8 @@
}
TEST(HashValueTest, PointerAlignment) {
- // We want to make sure that pointer alignment will not cause bits to be
- // stuck.
+ // We want to make sure that pointer alignment will not cause too many bits to
+ // be stuck.
constexpr size_t kTotalSize = 1 << 20;
std::unique_ptr<char[]> data(new char[kTotalSize]);
@@ -178,7 +188,8 @@
// Limit the scope to the bits we would be using for Swisstable.
constexpr size_t kMask = (1 << (kLog2NumValues + 7)) - 1;
size_t stuck_bits = (~bits_or | bits_and) & kMask;
- EXPECT_EQ(stuck_bits, 0u) << "0x" << std::hex << stuck_bits;
+ // Test that there are at most 3 stuck bits.
+ EXPECT_LE(absl::popcount(stuck_bits), 3) << "0x" << std::hex << stuck_bits;
}
}
@@ -301,7 +312,7 @@
struct DummyDeleter {
template <typename T>
- void operator() (T* ptr) {}
+ void operator() (T*) {}
};
struct SmartPointerEq {
@@ -381,6 +392,37 @@
return absl::MakeFragmentedCord(parts);
}
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+TEST(HashValueTest, TestIntrinsicInt128) {
+ EXPECT_TRUE((is_hashable<__int128_t>::value));
+ EXPECT_TRUE((is_hashable<__uint128_t>::value));
+
+ absl::flat_hash_map<size_t, int> hash_to_index;
+ std::vector<__uint128_t> values;
+ for (int i = 0; i < 128; ++i) {
+ // Some arbitrary pattern to check if changing each bit changes the hash.
+ static constexpr __uint128_t kPattern =
+ __uint128_t{0x0123456789abcdef} |
+ (__uint128_t{0x0123456789abcdef} << 64);
+ const __uint128_t value = kPattern ^ (__uint128_t{1} << i);
+ const __int128_t as_signed = static_cast<__int128_t>(value);
+
+ values.push_back(value);
+ auto [it, inserted] =
+ hash_to_index.insert({absl::Hash<__uint128_t>{}(value), i});
+ ASSERT_TRUE(inserted) << "Duplicate hash: " << i << " vs " << it->second;
+
+ // Verify that the fast-path for MixingHashState does not break the hash.
+ EXPECT_EQ(absl::HashOf(value), absl::Hash<__uint128_t>{}(value));
+ EXPECT_EQ(absl::HashOf(as_signed), absl::Hash<__int128_t>{}(as_signed));
+ }
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(values));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::vector<__int128_t>(values.begin(), values.end())));
+}
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
TEST(HashValueTest, Strings) {
EXPECT_TRUE((is_hashable<std::string>::value));
@@ -389,33 +431,39 @@
const std::string large = std::string(2048, 'x'); // multiple of chunk size
const std::string huge = std::string(5000, 'a'); // not a multiple
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( //
- std::string(), absl::string_view(), absl::Cord(), //
- std::string(""), absl::string_view(""), absl::Cord(""), //
- std::string(small), absl::string_view(small), absl::Cord(small), //
- std::string(dup), absl::string_view(dup), absl::Cord(dup), //
- std::string(large), absl::string_view(large), absl::Cord(large), //
- std::string(huge), absl::string_view(huge), FlatCord(huge), //
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::string(), absl::string_view(), absl::Cord(), std::string(""),
+ absl::string_view(""), absl::Cord(""), std::string(small),
+ absl::string_view(small), absl::Cord(small), FragmentedCord(small),
+ std::string(dup), absl::string_view(dup), absl::Cord(dup),
+ std::string(large), absl::string_view(large), absl::Cord(large),
+ std::string(huge), absl::string_view(huge), FlatCord(huge),
FragmentedCord(huge))));
// Also check that nested types maintain the same hash.
const WrapInTuple t{};
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( //
- t(std::string()), t(absl::string_view()), t(absl::Cord()), //
- t(std::string("")), t(absl::string_view("")), t(absl::Cord("")), //
- t(std::string(small)), t(absl::string_view(small)), //
- t(absl::Cord(small)), //
- t(std::string(dup)), t(absl::string_view(dup)), t(absl::Cord(dup)), //
- t(std::string(large)), t(absl::string_view(large)), //
- t(absl::Cord(large)), //
- t(std::string(huge)), t(absl::string_view(huge)), //
- t(FlatCord(huge)), t(FragmentedCord(huge)))));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ t(std::string()), t(absl::string_view()), t(absl::Cord()),
+ t(std::string("")), t(absl::string_view("")), t(absl::Cord("")),
+ t(std::string(small)), t(absl::string_view(small)), t(absl::Cord(small)),
+ t(FragmentedCord(small)), t(std::string(dup)), t(absl::string_view(dup)),
+ t(absl::Cord(dup)), t(std::string(large)), t(absl::string_view(large)),
+ t(absl::Cord(large)), t(std::string(huge)), t(absl::string_view(huge)),
+ t(FlatCord(huge)), t(FragmentedCord(huge)))));
// Make sure that hashing a `const char*` does not use its string-value.
EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
SpyHash(absl::string_view("ABC")));
}
+TEST(HashValueTest, StringsVector) {
+ using Vec = std::vector<std::string>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ Vec{"abc", "def"}, Vec{"abcde", "f"},
+ Vec{"abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"},
+ Vec{"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY", "Z"})));
+}
+
TEST(HashValueTest, WString) {
EXPECT_TRUE((is_hashable<std::wstring>::value));
@@ -444,22 +492,15 @@
}
TEST(HashValueTest, WStringView) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
EXPECT_TRUE((is_hashable<std::wstring_view>::value));
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
std::wstring_view(), std::wstring_view(L"ABC"), std::wstring_view(L"ABC"),
std::wstring_view(L"Some other different string_view"),
std::wstring_view(L"Iñtërnâtiônàlizætiøn"))));
-#endif
}
TEST(HashValueTest, U16StringView) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
EXPECT_TRUE((is_hashable<std::u16string_view>::value));
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
@@ -467,13 +508,9 @@
std::u16string_view(u"ABC"),
std::u16string_view(u"Some other different string_view"),
std::u16string_view(u"Iñtërnâtiônàlizætiøn"))));
-#endif
}
TEST(HashValueTest, U32StringView) {
-#ifndef ABSL_HAVE_STD_STRING_VIEW
- GTEST_SKIP();
-#else
EXPECT_TRUE((is_hashable<std::u32string_view>::value));
EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
@@ -481,7 +518,6 @@
std::u32string_view(U"ABC"),
std::u32string_view(U"Some other different string_view"),
std::u32string_view(U"Iñtërnâtiônàlizætiøn"))));
-#endif
}
TEST(HashValueTest, StdFilesystemPath) {
@@ -656,7 +692,9 @@
//
// This test is run on a buffer that is a multiple of the stride size, and one
// that isn't.
- for (size_t big_buffer_size : {1024u * 2 + 512u, 1024u * 3}) {
+ const size_t kChunkSize = absl::hash_internal::PiecewiseChunkSize();
+ for (size_t big_buffer_size :
+ {2 * kChunkSize + kChunkSize / 2, 3 * kChunkSize}) {
SCOPED_TRACE(big_buffer_size);
std::string big_buffer;
for (size_t i = 0; i < big_buffer_size; ++i) {
@@ -666,8 +704,15 @@
auto big_buffer_hash = hash(PiecewiseHashTester(big_buffer));
const int possible_breaks = 9;
- size_t breaks[possible_breaks] = {1, 512, 1023, 1024, 1025,
- 1536, 2047, 2048, 2049};
+ size_t breaks[possible_breaks] = {1,
+ kChunkSize / 2,
+ kChunkSize - 1,
+ kChunkSize,
+ kChunkSize + 1,
+ kChunkSize + kChunkSize / 2,
+ 2 * kChunkSize - 1,
+ 2 * kChunkSize,
+ 2 * kChunkSize + 1};
for (unsigned test_mask = 0; test_mask < (1u << possible_breaks);
++test_mask) {
SCOPED_TRACE(test_mask);
@@ -677,7 +722,7 @@
break_locations.insert(breaks[j]);
}
}
- EXPECT_EQ(
+ ASSERT_EQ(
hash(PiecewiseHashTester(big_buffer, std::move(break_locations))),
big_buffer_hash);
}
@@ -1145,4 +1190,38 @@
EXPECT_FALSE(HashOfExplicitParameter<int>(0));
}
+struct TypeErasedHashStateUser {
+ int a;
+ std::string b;
+
+ template <typename H>
+ friend H AbslHashValue(H state, const TypeErasedHashStateUser& value) {
+ absl::HashState type_erased_state = absl::HashState::Create(&state);
+ absl::HashState::combine(std::move(type_erased_state), value.a, value.b);
+ return state;
+ }
+};
+
+TEST(HashOf, MatchesTypeErasedHashState) {
+ std::string s = "s";
+ EXPECT_EQ(absl::HashOf(1, s), absl::Hash<TypeErasedHashStateUser>{}(
+ TypeErasedHashStateUser{1, s}));
+}
+
+struct AutoReturnTypeUser {
+ int a;
+ std::string b;
+
+ template <typename H>
+ friend auto AbslHashValue(H state, const AutoReturnTypeUser& value) {
+ return H::combine(std::move(state), value.a, value.b);
+ }
+};
+
+TEST(HashOf, AutoReturnTypeUser) {
+ std::string s = "s";
+ EXPECT_EQ(absl::HashOf(1, s),
+ absl::Hash<AutoReturnTypeUser>{}(AutoReturnTypeUser{1, s}));
+}
+
} // namespace
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h
index 1e1c574..817a40d 100644
--- a/absl/hash/hash_testing.h
+++ b/absl/hash/hash_testing.h
@@ -15,7 +15,9 @@
#ifndef ABSL_HASH_HASH_TESTING_H_
#define ABSL_HASH_HASH_TESTING_H_
+#include <cstddef>
#include <initializer_list>
+#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
@@ -141,21 +143,20 @@
// }
//
template <int&... ExplicitBarrier, typename Container>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(const Container& values);
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ const Container& values);
template <int&... ExplicitBarrier, typename Container, typename Eq>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals);
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ const Container& values, Eq equals);
template <int&..., typename T>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values);
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ std::initializer_list<T> values);
template <int&..., typename T, typename Eq>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
- Eq equals);
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ std::initializer_list<T> values, Eq equals);
namespace hash_internal {
@@ -184,8 +185,8 @@
};
template <typename Container, typename Eq>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ const Container& values, Eq equals) {
using V = typename Container::value_type;
struct Info {
@@ -244,7 +245,8 @@
if (v.expand() != expected) {
return testing::AssertionFailure()
<< "Values " << c[0].ToString() << " and " << v.ToString()
- << " evaluate as equal but have an unequal hash expansion.";
+ << " evaluate as equal but have unequal hash expansions ("
+ << expected << " vs. " << v.expand() << ").";
}
}
@@ -256,17 +258,18 @@
case SpyHashState::CompareResult::kEqual:
return testing::AssertionFailure()
<< "Values " << c[0].ToString() << " and " << c2[0].ToString()
- << " evaluate as unequal but have an equal hash expansion.";
+ << " evaluate as unequal but have an equal hash expansion:"
+ << c2_hash << ".";
case SpyHashState::CompareResult::kBSuffixA:
return testing::AssertionFailure()
- << "Hash expansion of " << c2[0].ToString()
+ << "Hash expansion of " << c2[0].ToString() << ";" << c2_hash
<< " is a suffix of the hash expansion of " << c[0].ToString()
- << ".";
+ << ";" << expected << ".";
case SpyHashState::CompareResult::kASuffixB:
return testing::AssertionFailure()
- << "Hash expansion of " << c[0].ToString()
- << " is a suffix of the hash expansion of " << c2[0].ToString()
- << ".";
+ << "Hash expansion of " << c[0].ToString() << ";"
+ << expected << " is a suffix of the hash expansion of "
+ << c2[0].ToString() << ";" << c2_hash << ".";
case SpyHashState::CompareResult::kUnequal:
break;
}
@@ -341,32 +344,31 @@
} // namespace hash_internal
template <int&..., typename Container>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(const Container& values) {
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ const Container& values) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
hash_internal::ContainerAsVector<Container>::Do(values),
hash_internal::DefaultEquals{});
}
template <int&..., typename Container, typename Eq>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ const Container& values, Eq equals) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
hash_internal::ContainerAsVector<Container>::Do(values), equals);
}
template <int&..., typename T>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values) {
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ std::initializer_list<T> values) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
hash_internal::DefaultEquals{});
}
template <int&..., typename T, typename Eq>
-ABSL_MUST_USE_RESULT testing::AssertionResult
-VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
- Eq equals) {
+testing::AssertionResult VerifyTypeImplementsAbslHashCorrectly(
+ std::initializer_list<T> values, Eq equals) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
hash_internal::ContainerAsVector<std::initializer_list<T>>::Do(values),
equals);
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index 93906ef..9abace5 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -14,6 +14,14 @@
#include "absl/hash/internal/hash.h"
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/hash/internal/low_level_hash.h"
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace hash_internal {
@@ -21,9 +29,10 @@
uint64_t MixingHashState::CombineLargeContiguousImpl32(
uint64_t state, const unsigned char* first, size_t len) {
while (len >= PiecewiseChunkSize()) {
- state = Mix(state,
- hash_internal::CityHash32(reinterpret_cast<const char*>(first),
- PiecewiseChunkSize()));
+ state = Mix(
+ state ^ hash_internal::CityHash32(reinterpret_cast<const char*>(first),
+ PiecewiseChunkSize()),
+ kMul);
len -= PiecewiseChunkSize();
first += PiecewiseChunkSize();
}
@@ -35,7 +44,7 @@
uint64_t MixingHashState::CombineLargeContiguousImpl64(
uint64_t state, const unsigned char* first, size_t len) {
while (len >= PiecewiseChunkSize()) {
- state = Mix(state, Hash64(first, PiecewiseChunkSize()));
+ state = Mix(state ^ Hash64(first, PiecewiseChunkSize()), kMul);
len -= PiecewiseChunkSize();
first += PiecewiseChunkSize();
}
@@ -46,22 +55,9 @@
ABSL_CONST_INIT const void* const MixingHashState::kSeed = &kSeed;
-// The salt array used by LowLevelHash. This array is NOT the mechanism used to
-// make absl::Hash non-deterministic between program invocations. See `Seed()`
-// for that mechanism.
-//
-// Any random values are fine. These values are just digits from the decimal
-// part of pi.
-// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
-constexpr uint64_t kHashSalt[5] = {
- uint64_t{0x243F6A8885A308D3}, uint64_t{0x13198A2E03707344},
- uint64_t{0xA4093822299F31D0}, uint64_t{0x082EFA98EC4E6C89},
- uint64_t{0x452821E638D01377},
-};
-
uint64_t MixingHashState::LowLevelHashImpl(const unsigned char* data,
size_t len) {
- return LowLevelHashLenGt16(data, len, Seed(), kHashSalt);
+ return LowLevelHashLenGt32(data, len, Seed(), &kStaticRandomData[0]);
}
} // namespace hash_internal
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index 03bf183..eb53823 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -24,20 +24,36 @@
#include <TargetConditionals.h>
#endif
+// We include config.h here to make sure that ABSL_INTERNAL_CPLUSPLUS_LANG is
+// defined.
#include "absl/base/config.h"
+// GCC15 warns that <ciso646> is deprecated in C++17 and suggests using
+// <version> instead, even though <version> is not available in C++17 mode prior
+// to GCC9.
+#if defined(__has_include)
+#if __has_include(<version>)
+#define ABSL_INTERNAL_VERSION_HEADER_AVAILABLE 1
+#endif
+#endif
+
// For feature testing and determining which headers can be included.
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L || \
+ defined(ABSL_INTERNAL_VERSION_HEADER_AVAILABLE)
#include <version>
#else
#include <ciso646>
#endif
+#undef ABSL_INTERNAL_VERSION_HEADER_AVAILABLE
+
#include <algorithm>
#include <array>
#include <bitset>
+#include <cassert>
#include <cmath>
#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <deque>
#include <forward_list>
@@ -49,6 +65,7 @@
#include <memory>
#include <set>
#include <string>
+#include <string_view>
#include <tuple>
#include <type_traits>
#include <unordered_map>
@@ -56,11 +73,14 @@
#include <utility>
#include <vector>
+#include "absl/base/attributes.h"
+#include "absl/base/internal/endian.h"
#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
#include "absl/container/fixed_array.h"
#include "absl/hash/internal/city.h"
-#include "absl/hash/internal/low_level_hash.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/bits.h"
#include "absl/numeric/int128.h"
@@ -69,15 +89,10 @@
#include "absl/types/variant.h"
#include "absl/utility/utility.h"
-#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
- !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)
+#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
#include <filesystem> // NOLINT
#endif
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -340,16 +355,57 @@
template <>
struct is_uniquely_represented<bool> : std::false_type {};
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+// Specialize the trait for GNU extension types.
+template <>
+struct is_uniquely_represented<__int128> : std::true_type {};
+template <>
+struct is_uniquely_represented<unsigned __int128> : std::true_type {};
+#endif // ABSL_HAVE_INTRINSIC_INT128
+
+template <typename T>
+struct FitsIn64Bits : std::integral_constant<bool, sizeof(T) <= 8> {};
+
+struct CombineRaw {
+ template <typename H>
+ H operator()(H state, uint64_t value) const {
+ return H::combine_raw(std::move(state), value);
+ }
+};
+
// hash_bytes()
//
// Convenience function that combines `hash_state` with the byte representation
// of `value`.
-template <typename H, typename T>
+template <typename H, typename T,
+ absl::enable_if_t<FitsIn64Bits<T>::value, int> = 0>
+H hash_bytes(H hash_state, const T& value) {
+ const unsigned char* start = reinterpret_cast<const unsigned char*>(&value);
+ uint64_t v;
+ if constexpr (sizeof(T) == 1) {
+ v = *start;
+ } else if constexpr (sizeof(T) == 2) {
+ v = absl::base_internal::UnalignedLoad16(start);
+ } else if constexpr (sizeof(T) == 4) {
+ v = absl::base_internal::UnalignedLoad32(start);
+ } else {
+ static_assert(sizeof(T) == 8);
+ v = absl::base_internal::UnalignedLoad64(start);
+ }
+ return CombineRaw()(std::move(hash_state), v);
+}
+template <typename H, typename T,
+ absl::enable_if_t<!FitsIn64Bits<T>::value, int> = 0>
H hash_bytes(H hash_state, const T& value) {
const unsigned char* start = reinterpret_cast<const unsigned char*>(&value);
return H::combine_contiguous(std::move(hash_state), start, sizeof(value));
}
+template <typename H>
+H hash_weakly_mixed_integer(H hash_state, WeaklyMixedInteger value) {
+ return H::combine_weakly_mixed_integer(std::move(hash_state), value);
+}
+
// -----------------------------------------------------------------------------
// AbslHashValue for Basic Types
// -----------------------------------------------------------------------------
@@ -446,9 +502,9 @@
T ptr) {
auto v = reinterpret_cast<uintptr_t>(ptr);
// Due to alignment, pointers tend to have low bits as zero, and the next few
- // bits follow a pattern since they are also multiples of some base value.
- // Mixing the pointer twice helps prevent stuck low bits for certain alignment
- // values.
+ // bits follow a pattern since they are also multiples of some base value. The
+ // byte swap in WeakMix helps ensure we still have good entropy in low bits.
+ // Mix pointers twice to ensure we have good entropy in low bits.
return H::combine(std::move(hash_state), v, v);
}
@@ -468,7 +524,7 @@
// padding (namely when they have 1 or 3 ints). The value below is a lower
// bound on the number of salient, non-padding bytes that we use for
// hashing.
- if (alignof(T C::*) == alignof(int)) {
+ if constexpr (alignof(T C::*) == alignof(int)) {
// No padding when all subobjects have the same size as the total
// alignment. This happens in 32-bit mode.
return n;
@@ -565,7 +621,7 @@
H AbslHashValue(H hash_state, absl::string_view str) {
return H::combine(
H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
- str.size());
+ WeaklyMixedInteger{str.size()});
}
// Support std::wstring, std::u16string and std::u32string.
@@ -578,11 +634,9 @@
const std::basic_string<Char, std::char_traits<Char>, Alloc>& str) {
return H::combine(
H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
- str.size());
+ WeaklyMixedInteger{str.size()});
}
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-
// Support std::wstring_view, std::u16string_view and std::u32string_view.
template <typename Char, typename H,
typename = absl::enable_if_t<std::is_same<Char, wchar_t>::value ||
@@ -591,13 +645,10 @@
H AbslHashValue(H hash_state, std::basic_string_view<Char> str) {
return H::combine(
H::combine_contiguous(std::move(hash_state), str.data(), str.size()),
- str.size());
+ WeaklyMixedInteger{str.size()});
}
-#endif // ABSL_HAVE_STD_STRING_VIEW
-
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \
- !defined(_LIBCPP_HAS_NO_FILESYSTEM_LIBRARY) && \
(!defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 130000) && \
(!defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) || \
@@ -642,7 +693,7 @@
for (const auto& t : deque) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), deque.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{deque.size()});
}
// AbslHashValue for hashing std::forward_list
@@ -654,7 +705,7 @@
hash_state = H::combine(std::move(hash_state), t);
++size;
}
- return H::combine(std::move(hash_state), size);
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{size});
}
// AbslHashValue for hashing std::list
@@ -664,7 +715,7 @@
for (const auto& t : list) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), list.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{list.size()});
}
// AbslHashValue for hashing std::vector
@@ -678,7 +729,7 @@
AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) {
return H::combine(H::combine_contiguous(std::move(hash_state), vector.data(),
vector.size()),
- vector.size());
+ WeaklyMixedInteger{vector.size()});
}
// AbslHashValue special cases for hashing std::vector<bool>
@@ -699,7 +750,8 @@
unsigned char c = static_cast<unsigned char>(i);
hash_state = combiner.add_buffer(std::move(hash_state), &c, sizeof(c));
}
- return H::combine(combiner.finalize(std::move(hash_state)), vector.size());
+ return H::combine(combiner.finalize(std::move(hash_state)),
+ WeaklyMixedInteger{vector.size()});
}
#else
// When not working around the libstdc++ bug above, we still have to contend
@@ -715,7 +767,7 @@
AbslHashValue(H hash_state, const std::vector<T, Allocator>& vector) {
return H::combine(std::move(hash_state),
std::hash<std::vector<T, Allocator>>{}(vector),
- vector.size());
+ WeaklyMixedInteger{vector.size()});
}
#endif
@@ -732,7 +784,7 @@
for (const auto& t : map) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), map.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{map.size()});
}
// AbslHashValue for hashing std::multimap
@@ -745,7 +797,7 @@
for (const auto& t : map) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), map.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{map.size()});
}
// AbslHashValue for hashing std::set
@@ -755,7 +807,7 @@
for (const auto& t : set) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), set.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{set.size()});
}
// AbslHashValue for hashing std::multiset
@@ -765,7 +817,7 @@
for (const auto& t : set) {
hash_state = H::combine(std::move(hash_state), t);
}
- return H::combine(std::move(hash_state), set.size());
+ return H::combine(std::move(hash_state), WeaklyMixedInteger{set.size()});
}
// -----------------------------------------------------------------------------
@@ -779,7 +831,7 @@
H hash_state, const std::unordered_set<Key, Hash, KeyEqual, Alloc>& s) {
return H::combine(
H::combine_unordered(std::move(hash_state), s.begin(), s.end()),
- s.size());
+ WeaklyMixedInteger{s.size()});
}
// AbslHashValue for hashing std::unordered_multiset
@@ -790,7 +842,7 @@
const std::unordered_multiset<Key, Hash, KeyEqual, Alloc>& s) {
return H::combine(
H::combine_unordered(std::move(hash_state), s.begin(), s.end()),
- s.size());
+ WeaklyMixedInteger{s.size()});
}
// AbslHashValue for hashing std::unordered_set
@@ -802,7 +854,7 @@
const std::unordered_map<Key, T, Hash, KeyEqual, Alloc>& s) {
return H::combine(
H::combine_unordered(std::move(hash_state), s.begin(), s.end()),
- s.size());
+ WeaklyMixedInteger{s.size()});
}
// AbslHashValue for hashing std::unordered_multiset
@@ -814,7 +866,7 @@
const std::unordered_multimap<Key, T, Hash, KeyEqual, Alloc>& s) {
return H::combine(
H::combine_unordered(std::move(hash_state), s.begin(), s.end()),
- s.size());
+ WeaklyMixedInteger{s.size()});
}
// -----------------------------------------------------------------------------
@@ -925,10 +977,20 @@
// `false`.
struct HashSelect {
private:
+ struct WeaklyMixedIntegerProbe {
+ template <typename H>
+ static H Invoke(H state, WeaklyMixedInteger value) {
+ return hash_internal::hash_weakly_mixed_integer(std::move(state), value);
+ }
+ };
+
struct State : HashStateBase<State> {
static State combine_contiguous(State hash_state, const unsigned char*,
size_t);
using State::HashStateBase::combine_contiguous;
+ static State combine_raw(State state, uint64_t value);
+ static State combine_weakly_mixed_integer(State hash_state,
+ WeaklyMixedInteger value);
};
struct UniquelyRepresentedProbe {
@@ -990,6 +1052,7 @@
// disjunction provides short circuiting wrt instantiation.
template <typename T>
using Apply = absl::disjunction< //
+ Probe<WeaklyMixedIntegerProbe, T>, //
Probe<UniquelyRepresentedProbe, T>, //
Probe<HashValueProbe, T>, //
Probe<LegacyHashProbe, T>, //
@@ -1011,13 +1074,20 @@
using uint128 = absl::uint128;
#endif // ABSL_HAVE_INTRINSIC_INT128
+ // Random data taken from the hexadecimal digits of Pi's fractional component.
+ // https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
+ ABSL_CACHELINE_ALIGNED static constexpr uint64_t kStaticRandomData[] = {
+ 0x243f'6a88'85a3'08d3, 0x1319'8a2e'0370'7344, 0xa409'3822'299f'31d0,
+ 0x082e'fa98'ec4e'6c89, 0x4528'21e6'38d0'1377,
+ };
+
static constexpr uint64_t kMul =
- sizeof(size_t) == 4 ? uint64_t{0xcc9e2d51}
- : uint64_t{0x9ddfea08eb382d69};
+ uint64_t{0xdcb22ca68cb134ed};
template <typename T>
using IntegralFastPath =
- conjunction<std::is_integral<T>, is_uniquely_represented<T>>;
+ conjunction<std::is_integral<T>, is_uniquely_represented<T>,
+ FitsIn64Bits<T>>;
public:
// Move only
@@ -1047,7 +1117,7 @@
template <typename T, absl::enable_if_t<IntegralFastPath<T>::value, int> = 0>
static size_t hash(T value) {
return static_cast<size_t>(
- Mix(Seed(), static_cast<std::make_unsigned_t<T>>(value)));
+ WeakMix(Seed(), static_cast<std::make_unsigned_t<T>>(value)));
}
// Overload of MixingHashState::hash()
@@ -1062,6 +1132,18 @@
MixingHashState() : state_(Seed()) {}
friend class MixingHashState::HashStateBase;
+ template <typename H>
+ friend H absl::hash_internal::hash_weakly_mixed_integer(H,
+ WeaklyMixedInteger);
+
+ static MixingHashState combine_weakly_mixed_integer(
+ MixingHashState hash_state, WeaklyMixedInteger value) {
+ // Some transformation for the value is needed to make an empty
+ // string/container change the mixing hash state.
+ // We use constant smaller than 8 bits to make compiler use
+ // `add` with an immediate operand with 1 byte value.
+ return MixingHashState{hash_state.state_ + (0x57 + value.value)};
+ }
template <typename CombinerT>
static MixingHashState RunCombineUnordered(MixingHashState state,
@@ -1085,6 +1167,7 @@
// Allow the HashState type-erasure implementation to invoke
// RunCombinedUnordered() directly.
friend class absl::HashState;
+ friend struct CombineRaw;
// Workaround for MSVC bug.
// We make the type copyable to fix the calling convention, even though we
@@ -1094,6 +1177,14 @@
explicit MixingHashState(uint64_t state) : state_(state) {}
+ // Combines a raw value from e.g. integrals/floats/pointers/etc. This allows
+ // us to be consistent with IntegralFastPath when combining raw types, but
+ // optimize Read1To3 and Read4To8 differently for the string case.
+ static MixingHashState combine_raw(MixingHashState hash_state,
+ uint64_t value) {
+ return MixingHashState(WeakMix(hash_state.state_, value));
+ }
+
// Implementation of the base case for combine_contiguous where we actually
// mix the bytes into the state.
// Dispatch to different implementations of the combine_contiguous depending
@@ -1107,6 +1198,49 @@
std::integral_constant<int, 8>
/* sizeof_size_t */);
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineSmallContiguousImpl(
+ uint64_t state, const unsigned char* first, size_t len) {
+ ABSL_ASSUME(len <= 8);
+ uint64_t v;
+ if (len >= 4) {
+ v = Read4To8(first, len);
+ } else if (len > 0) {
+ v = Read1To3(first, len);
+ } else {
+ // Empty ranges have no effect.
+ return state;
+ }
+ return WeakMix(state, v);
+ }
+
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineContiguousImpl9to16(
+ uint64_t state, const unsigned char* first, size_t len) {
+ ABSL_ASSUME(len >= 9);
+ ABSL_ASSUME(len <= 16);
+ // Note: any time one half of the mix function becomes zero it will fail to
+ // incorporate any bits from the other half. However, there is exactly 1 in
+ // 2^64 values for each side that achieve this, and only when the size is
+ // exactly 16 -- for smaller sizes there is an overlapping byte that makes
+ // this impossible unless the seed is *also* incredibly unlucky.
+ auto p = Read9To16(first, len);
+ return Mix(state ^ p.first, kMul ^ p.second);
+ }
+
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t CombineContiguousImpl17to32(
+ uint64_t state, const unsigned char* first, size_t len) {
+ ABSL_ASSUME(len >= 17);
+ ABSL_ASSUME(len <= 32);
+ // Do two mixes of overlapping 16-byte ranges in parallel to minimize
+ // latency.
+ const uint64_t m0 =
+ Mix(Read8(first) ^ kStaticRandomData[1], Read8(first + 8) ^ state);
+
+ const unsigned char* tail_16b_ptr = first + (len - 16);
+ const uint64_t m1 = Mix(Read8(tail_16b_ptr) ^ kStaticRandomData[3],
+ Read8(tail_16b_ptr + 8) ^ state);
+ return m0 ^ m1;
+ }
+
// Slow dispatch path for calls to CombineContiguousImpl with a size argument
// larger than PiecewiseChunkSize(). Has the same effect as calling
// CombineContiguousImpl() repeatedly with the chunk stride size.
@@ -1118,12 +1252,12 @@
size_t len);
// Reads 9 to 16 bytes from p.
- // The least significant 8 bytes are in .first, the rest (zero padded) bytes
- // are in .second.
+ // The least significant 8 bytes are in .first, and the rest of the bytes are
+ // in .second along with duplicated bytes from .first if len<16.
static std::pair<uint64_t, uint64_t> Read9To16(const unsigned char* p,
size_t len) {
- uint64_t low_mem = absl::base_internal::UnalignedLoad64(p);
- uint64_t high_mem = absl::base_internal::UnalignedLoad64(p + len - 8);
+ uint64_t low_mem = Read8(p);
+ uint64_t high_mem = Read8(p + len - 8);
#ifdef ABSL_IS_LITTLE_ENDIAN
uint64_t most_significant = high_mem;
uint64_t least_significant = low_mem;
@@ -1134,53 +1268,74 @@
return {least_significant, most_significant};
}
- // Reads 4 to 8 bytes from p. Zero pads to fill uint64_t.
+ // Reads 8 bytes from p.
+ static uint64_t Read8(const unsigned char* p) {
+ // Suppress erroneous array bounds errors on GCC.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+ return absl::base_internal::UnalignedLoad64(p);
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+ }
+
+ // Reads 4 to 8 bytes from p. Some input bytes may be duplicated in output.
static uint64_t Read4To8(const unsigned char* p, size_t len) {
- uint32_t low_mem = absl::base_internal::UnalignedLoad32(p);
- uint32_t high_mem = absl::base_internal::UnalignedLoad32(p + len - 4);
-#ifdef ABSL_IS_LITTLE_ENDIAN
- uint32_t most_significant = high_mem;
- uint32_t least_significant = low_mem;
-#else
- uint32_t most_significant = low_mem;
- uint32_t least_significant = high_mem;
-#endif
- return (static_cast<uint64_t>(most_significant) << (len - 4) * 8) |
- least_significant;
+ // If `len < 8`, we duplicate bytes in the middle.
+ // E.g.:
+ // `ABCD` will be read as `ABCDABCD`.
+ // `ABCDE` will be read as `ABCDBCDE`.
+ // `ABCDEF` will be read as `ABCDCDEF`.
+ // `ABCDEFG` will be read as `ABCDDEFG`.
+ // We also do not care about endianness. On big-endian platforms, bytes will
+ // be shuffled (it's fine). We always shift low memory by 32, because that
+ // can be pipelined earlier. Reading high memory requires computing
+ // `p + len - 4`.
+ uint64_t most_significant =
+ static_cast<uint64_t>(absl::base_internal::UnalignedLoad32(p)) << 32;
+ uint64_t least_significant =
+ absl::base_internal::UnalignedLoad32(p + len - 4);
+ return most_significant | least_significant;
}
- // Reads 1 to 3 bytes from p. Zero pads to fill uint32_t.
+ // Reads 1 to 3 bytes from p. Some input bytes may be duplicated in output.
static uint32_t Read1To3(const unsigned char* p, size_t len) {
- // The trick used by this implementation is to avoid branches if possible.
- unsigned char mem0 = p[0];
- unsigned char mem1 = p[len / 2];
- unsigned char mem2 = p[len - 1];
-#ifdef ABSL_IS_LITTLE_ENDIAN
- unsigned char significant2 = mem2;
- unsigned char significant1 = mem1;
- unsigned char significant0 = mem0;
-#else
- unsigned char significant2 = mem0;
- unsigned char significant1 = len == 2 ? mem0 : mem1;
- unsigned char significant0 = mem2;
-#endif
- return static_cast<uint32_t>(significant0 | //
- (significant1 << (len / 2 * 8)) | //
- (significant2 << ((len - 1) * 8)));
+ // The trick used by this implementation is to avoid branches.
+ // We always read three bytes by duplicating.
+ // E.g.,
+ // `A` is read as `AAA`.
+ // `AB` is read as `ABB`.
+ // `ABC` is read as `ABC`.
+ // We always shift `p[0]` so that it can be pipelined better.
+ // Other bytes require extra computation to find indices.
+ uint32_t mem0 = (static_cast<uint32_t>(p[0]) << 16) | p[len - 1];
+ uint32_t mem1 = static_cast<uint32_t>(p[len / 2]) << 8;
+ return mem0 | mem1;
}
- ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t state, uint64_t v) {
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Mix(uint64_t lhs, uint64_t rhs) {
+ // For 32 bit platforms we are trying to use all 64 lower bits.
+ if constexpr (sizeof(size_t) < 8) {
+ uint64_t m = lhs * rhs;
+ return m ^ (m >> 32);
+ }
// Though the 128-bit product on AArch64 needs two instructions, it is
// still a good balance between speed and hash quality.
- using MultType =
- absl::conditional_t<sizeof(size_t) == 4, uint64_t, uint128>;
- // We do the addition in 64-bit space to make sure the 128-bit
- // multiplication is fast. If we were to do it as MultType the compiler has
- // to assume that the high word is non-zero and needs to perform 2
- // multiplications instead of one.
- MultType m = state + v;
- m *= kMul;
- return static_cast<uint64_t>(m ^ (m >> (sizeof(m) * 8 / 2)));
+ uint128 m = lhs;
+ m *= rhs;
+ return Uint128High64(m) ^ Uint128Low64(m);
+ }
+
+ // Slightly lower latency than Mix, but with lower quality. The byte swap
+ // helps ensure that low bits still have high quality.
+ ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t WeakMix(uint64_t lhs,
+ uint64_t rhs) {
+ const uint64_t n = lhs ^ rhs;
+ // WeakMix doesn't work well on 32-bit platforms so just use Mix.
+ if constexpr (sizeof(size_t) < 8) return Mix(n, kMul);
+ return absl::gbswap_64(n * kMul);
}
// An extern to avoid bloat on a direct call to LowLevelHash() with fixed
@@ -1234,21 +1389,15 @@
std::integral_constant<int, 4> /* sizeof_size_t */) {
// For large values we use CityHash, for small ones we just use a
// multiplicative hash.
- uint64_t v;
- if (len > 8) {
- if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
- return CombineLargeContiguousImpl32(state, first, len);
- }
- v = hash_internal::CityHash32(reinterpret_cast<const char*>(first), len);
- } else if (len >= 4) {
- v = Read4To8(first, len);
- } else if (len > 0) {
- v = Read1To3(first, len);
- } else {
- // Empty ranges have no effect.
- return state;
+ if (len <= 8) {
+ return CombineSmallContiguousImpl(state, first, len);
}
- return Mix(state, v);
+ if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
+ return Mix(state ^ hash_internal::CityHash32(
+ reinterpret_cast<const char*>(first), len),
+ kMul);
+ }
+ return CombineLargeContiguousImpl32(state, first, len);
}
// Overload of MixingHashState::CombineContiguousImpl()
@@ -1257,38 +1406,19 @@
std::integral_constant<int, 8> /* sizeof_size_t */) {
// For large values we use LowLevelHash or CityHash depending on the platform,
// for small ones we just use a multiplicative hash.
- uint64_t v;
- if (len > 16) {
- if (ABSL_PREDICT_FALSE(len > PiecewiseChunkSize())) {
- return CombineLargeContiguousImpl64(state, first, len);
- }
- v = Hash64(first, len);
- } else if (len > 8) {
- // This hash function was constructed by the ML-driven algorithm discovery
- // using reinforcement learning. We fed the agent lots of inputs from
- // microbenchmarks, SMHasher, low hamming distance from generated inputs and
- // picked up the one that was good on micro and macrobenchmarks.
- auto p = Read9To16(first, len);
- uint64_t lo = p.first;
- uint64_t hi = p.second;
- // Rotation by 53 was found to be most often useful when discovering these
- // hashing algorithms with ML techniques.
- lo = absl::rotr(lo, 53);
- state += kMul;
- lo += state;
- state ^= hi;
- uint128 m = state;
- m *= lo;
- return static_cast<uint64_t>(m ^ (m >> 64));
- } else if (len >= 4) {
- v = Read4To8(first, len);
- } else if (len > 0) {
- v = Read1To3(first, len);
- } else {
- // Empty ranges have no effect.
- return state;
+ if (len <= 8) {
+ return CombineSmallContiguousImpl(state, first, len);
}
- return Mix(state, v);
+ if (len <= 16) {
+ return CombineContiguousImpl9to16(state, first, len);
+ }
+ if (len <= 32) {
+ return CombineContiguousImpl17to32(state, first, len);
+ }
+ if (ABSL_PREDICT_TRUE(len <= PiecewiseChunkSize())) {
+ return Mix(state ^ Hash64(first, len), kMul);
+ }
+ return CombineLargeContiguousImpl64(state, first, len);
}
struct AggregateBarrier {};
diff --git a/absl/hash/internal/low_level_hash.cc b/absl/hash/internal/low_level_hash.cc
index 6dc71cf..1a107ec 100644
--- a/absl/hash/internal/low_level_hash.cc
+++ b/absl/hash/internal/low_level_hash.cc
@@ -14,36 +14,49 @@
#include "absl/hash/internal/low_level_hash.h"
+#include <cassert>
#include <cstddef>
#include <cstdint>
+#include "absl/base/config.h"
#include "absl/base/internal/unaligned_access.h"
+#include "absl/base/optimization.h"
#include "absl/base/prefetch.h"
#include "absl/numeric/int128.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace hash_internal {
-
-static uint64_t Mix(uint64_t v0, uint64_t v1) {
+namespace {
+uint64_t Mix(uint64_t v0, uint64_t v1) {
absl::uint128 p = v0;
p *= v1;
return absl::Uint128Low64(p) ^ absl::Uint128High64(p);
}
+uint64_t Mix32Bytes(const uint8_t* ptr, uint64_t current_state,
+ const uint64_t salt[5]) {
+ uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+ uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+ uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+ uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
-uint64_t LowLevelHashLenGt16(const void* data, size_t len, uint64_t seed,
+ uint64_t cs0 = Mix(a ^ salt[1], b ^ current_state);
+ uint64_t cs1 = Mix(c ^ salt[2], d ^ current_state);
+ return cs0 ^ cs1;
+}
+} // namespace
+
+uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
const uint64_t salt[5]) {
- // Prefetch the cacheline that data resides in.
- PrefetchToLocalCache(data);
+ assert(len > 32);
const uint8_t* ptr = static_cast<const uint8_t*>(data);
- uint64_t starting_length = static_cast<uint64_t>(len);
- const uint8_t* last_16_ptr = ptr + starting_length - 16;
- uint64_t current_state = seed ^ salt[0];
+ uint64_t current_state = seed ^ salt[0] ^ len;
+ const uint8_t* last_32_ptr = ptr + len - 32;
if (len > 64) {
// If we have more than 64 bytes, we're going to handle chunks of 64
- // bytes at a time. We're going to build up two separate hash states
- // which we will then hash together.
+ // bytes at a time. We're going to build up four separate hash states
+ // which we will then hash together. This avoids short dependency chains.
uint64_t duplicated_state0 = current_state;
uint64_t duplicated_state1 = current_state;
uint64_t duplicated_state2 = current_state;
@@ -78,71 +91,13 @@
// We now have a data `ptr` with at most 64 bytes and the current state
// of the hashing state machine stored in current_state.
if (len > 32) {
- uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
- uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
- uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
- uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
-
- uint64_t cs0 = Mix(a ^ salt[1], b ^ current_state);
- uint64_t cs1 = Mix(c ^ salt[2], d ^ current_state);
- current_state = cs0 ^ cs1;
-
- ptr += 32;
- len -= 32;
+ current_state = Mix32Bytes(ptr, current_state, salt);
}
// We now have a data `ptr` with at most 32 bytes and the current state
- // of the hashing state machine stored in current_state.
- if (len > 16) {
- uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
- uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
-
- current_state = Mix(a ^ salt[1], b ^ current_state);
- }
-
- // We now have a data `ptr` with at least 1 and at most 16 bytes. But we can
- // safely read from `ptr + len - 16`.
- uint64_t a = absl::base_internal::UnalignedLoad64(last_16_ptr);
- uint64_t b = absl::base_internal::UnalignedLoad64(last_16_ptr + 8);
-
- return Mix(a ^ salt[1] ^ starting_length, b ^ current_state);
-}
-
-uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed,
- const uint64_t salt[5]) {
- if (len > 16) return LowLevelHashLenGt16(data, len, seed, salt);
-
- // Prefetch the cacheline that data resides in.
- PrefetchToLocalCache(data);
- const uint8_t* ptr = static_cast<const uint8_t*>(data);
- uint64_t starting_length = static_cast<uint64_t>(len);
- uint64_t current_state = seed ^ salt[0];
- if (len == 0) return current_state;
-
- uint64_t a = 0;
- uint64_t b = 0;
-
- // We now have a data `ptr` with at least 1 and at most 16 bytes.
- if (len > 8) {
- // When we have at least 9 and at most 16 bytes, set A to the first 64
- // bits of the input and B to the last 64 bits of the input. Yes, they
- // will overlap in the middle if we are working with less than the full 16
- // bytes.
- a = absl::base_internal::UnalignedLoad64(ptr);
- b = absl::base_internal::UnalignedLoad64(ptr + len - 8);
- } else if (len > 3) {
- // If we have at least 4 and at most 8 bytes, set A to the first 32
- // bits and B to the last 32 bits.
- a = absl::base_internal::UnalignedLoad32(ptr);
- b = absl::base_internal::UnalignedLoad32(ptr + len - 4);
- } else {
- // If we have at least 1 and at most 3 bytes, read 2 bytes into A and the
- // other byte into B, with some adjustments.
- a = static_cast<uint64_t>((ptr[0] << 8) | ptr[len - 1]);
- b = static_cast<uint64_t>(ptr[len >> 1]);
- }
-
- return Mix(a ^ salt[1] ^ starting_length, b ^ current_state);
+ // of the hashing state machine stored in current_state. But we can
+ // safely read from `ptr + len - 32`.
+ return Mix32Bytes(last_32_ptr, current_state, salt);
}
} // namespace hash_internal
diff --git a/absl/hash/internal/low_level_hash.h b/absl/hash/internal/low_level_hash.h
index d460e35..49e9ec4 100644
--- a/absl/hash/internal/low_level_hash.h
+++ b/absl/hash/internal/low_level_hash.h
@@ -35,16 +35,12 @@
namespace hash_internal {
// Hash function for a byte array. A 64-bit seed and a set of five 64-bit
-// integers are hashed into the result.
+// integers are hashed into the result. The length must be greater than 32.
//
// To allow all hashable types (including string_view and Span) to depend on
// this algorithm, we keep the API low-level, with as few dependencies as
// possible.
-uint64_t LowLevelHash(const void* data, size_t len, uint64_t seed,
- const uint64_t salt[5]);
-
-// Same as above except the length must be greater than 16.
-uint64_t LowLevelHashLenGt16(const void* data, size_t len, uint64_t seed,
+uint64_t LowLevelHashLenGt32(const void* data, size_t len, uint64_t seed,
const uint64_t salt[5]);
} // namespace hash_internal
diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc
index ea781dd..d370dc7 100644
--- a/absl/hash/internal/low_level_hash_test.cc
+++ b/absl/hash/internal/low_level_hash_test.cc
@@ -15,6 +15,7 @@
#include "absl/hash/internal/low_level_hash.h"
#include <cinttypes>
+#include <cstdint>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -29,55 +30,11 @@
0x1d8e4e27c47d124f};
TEST(LowLevelHashTest, VerifyGolden) {
- constexpr size_t kNumGoldenOutputs = 134;
+ constexpr size_t kNumGoldenOutputs = 94;
static struct {
absl::string_view base64_data;
uint64_t seed;
} cases[] = {
- {"", uint64_t{0xec42b7ab404b8acb}},
- {"ICAg", uint64_t{0}},
- {"YWFhYQ==", uint64_t{0}},
- {"AQID", uint64_t{0}},
- {"AQIDBA==", uint64_t{0}},
- {"dGhpcmRfcGFydHl8d3loYXNofDY0", uint64_t{0}},
- {"Zw==", uint64_t{0xeeee074043a3ee0f}},
- {"xmk=", uint64_t{0x857902089c393de}},
- {"c1H/", uint64_t{0x993df040024ca3af}},
- {"SuwpzQ==", uint64_t{0xc4e4c2acea740e96}},
- {"uqvy++M=", uint64_t{0x6a214b3db872d0cf}},
- {"RnzCVPgb", uint64_t{0x44343db6a89dba4d}},
- {"6OeNdlouYw==", uint64_t{0x77b5d6d1ae1dd483}},
- {"M5/JmmYyDbc=", uint64_t{0x89ab8ecb44d221f1}},
- {"MVijWiVdBRdY", uint64_t{0x60244b17577ca81b}},
- {"6V7Uq7LNxpu0VA==", uint64_t{0x59a08dcee0717067}},
- {"EQ6CdEEhPdyHcOk=", uint64_t{0xf5f20db3ade57396}},
- {"PqFB4fxnPgF+l+rc", uint64_t{0xbf8dee0751ad3efb}},
- {"a5aPOFwq7LA7+zKvPA==", uint64_t{0x6b7a06b268d63e30}},
- {"VOwY21wCGv5D+/qqOvs=", uint64_t{0xb8c37f0ae0f54c82}},
- {"KdHmBTx8lHXYvmGJ+Vy7", uint64_t{0x9fcbed0c38e50eef}},
- {"qJkPlbHr8bMF7/cA6aE65Q==", uint64_t{0x2af4bade1d8e3a1d}},
- {"ygvL0EhHZL0fIx6oHHtkxRQ=", uint64_t{0x714e3aa912da2f2c}},
- {"c1rFXkt5YztwZCQRngncqtSs", uint64_t{0xf5ee75e3cbb82c1c}},
- {"8hsQrzszzeNQSEcVXLtvIhm6mw==", uint64_t{0x620e7007321b93b9}},
- {"ffUL4RocfyP4KfikGxO1yk7omDI=", uint64_t{0xc08528cac2e551fc}},
- {"OOB5TT00vF9Od/rLbAWshiErqhpV", uint64_t{0x6a1debf9cc3ad39}},
- {"or5wtXM7BFzTNpSzr+Lw5J5PMhVJ/Q==", uint64_t{0x7e0a3c88111fc226}},
- {"gk6pCHDUsoopVEiaCrzVDhioRKxb844=", uint64_t{0x1301fef15df39edb}},
- {"TNctmwlC5QbEM6/No4R/La3UdkfeMhzs", uint64_t{0x64e181f3d5817ab}},
- {"SsQw9iAjhWz7sgcE9OwLuSC6hsM+BfHs2Q==", uint64_t{0xafafc44961078ecb}},
- {"ZzO3mVCj4xTT2TT3XqDyEKj2BZQBvrS8RHg=", uint64_t{0x4f7bb45549250094}},
- {"+klp5iPQGtppan5MflEls0iEUzqU+zGZkDJX", uint64_t{0xa30061abaa2818c}},
- {"RO6bvOnlJc8I9eniXlNgqtKy0IX6VNg16NRmgg==",
- uint64_t{0xd902ee3e44a5705f}},
- {"ZJjZqId1ZXBaij9igClE3nyliU5XWdNRrayGlYA=", uint64_t{0x316d36da516f583}},
- {"7BfkhfGMDGbxfMB8uyL85GbaYQtjr2K8g7RpLzr/",
- uint64_t{0x402d83f9f834f616}},
- {"rycWk6wHH7htETQtje9PidS2YzXBx+Qkg2fY7ZYS7A==",
- uint64_t{0x9c604164c016b72c}},
- {"RTkC2OUK+J13CdGllsH0H5WqgspsSa6QzRZouqx6pvI=",
- uint64_t{0x3f4507e01f9e73ba}},
- {"tKjKmbLCNyrLCM9hycOAXm4DKNpM12oZ7dLTmUx5iwAi",
- uint64_t{0xc3fe0d5be8d2c7c7}},
{"VprUGNH+5NnNRaORxgH/ySrZFQFDL+4VAodhfBNinmn8cg==",
uint64_t{0x531858a40bfa7ea1}},
{"gc1xZaY+q0nPcUvOOnWnT3bqfmT/geth/f7Dm2e/DemMfk4=",
@@ -405,100 +362,42 @@
};
#if defined(ABSL_IS_BIG_ENDIAN)
- constexpr uint64_t kGolden[kNumGoldenOutputs] = {
- 0x4c34aacf38f6eee4, 0x88b1366815e50b88, 0x1a36bd0c6150fb9c,
- 0xa783aba8a67366c7, 0x5e4a92123ae874f2, 0x0cc9ecf27067ee9a,
- 0xbe77aa94940527f9, 0x7ea5c12f2669fe31, 0xa33eed8737d946b9,
- 0x310aec5b1340bb36, 0x354e400861c5d8ff, 0x15be98166adcf42f,
- 0xc51910b62a90ae51, 0x539d47fc7fdf6a1f, 0x3ebba9daa46eef93,
- 0xd96bcd3a9113c17f, 0xc78eaf6256ded15a, 0x98902ed321c2f0d9,
- 0x75a4ac96414b954a, 0x2cb90e00a39e307b, 0x46539574626c3637,
- 0x186ec89a2be3ff45, 0x972a3bf7531519d2, 0xa14df0d25922364b,
- 0xa351e19d22752109, 0x08bd311d8fed4f82, 0xea2b52ddc6af54f9,
- 0x5f20549941338336, 0xd43b07422dc2782e, 0x377c68e2acda4835,
- 0x1b31a0a663b1d7b3, 0x7388ba5d68058a1a, 0xe382794ea816f032,
- 0xd4c3fe7889276ee0, 0x2833030545582ea9, 0x554d32a55e55df32,
- 0x8d6d33d7e17b424d, 0xe51a193d03ae1e34, 0xabb6a80835bd66b3,
- 0x0e4ba5293f9ce9b7, 0x1ebd8642cb762cdf, 0xcb54b555850888ee,
- 0x1e4195e4717c701f, 0x6235a13937f6532a, 0xd460960741e845c0,
- 0x2a72168a2d6af7b1, 0x6be38fbbfc5b17de, 0x4ee97cffa0d0fb39,
- 0xfdf1119ad5e71a55, 0x0dff7f66b3070727, 0x812d791d6ed62744,
- 0x60962919074b70b8, 0x956fa5c7d6872547, 0xee892daa58aae597,
- 0xeeda546e998ee369, 0x454481f5eb9b1fa8, 0x1054394634c98b1b,
- 0x55bb425415f591fb, 0x9601fa97416232c4, 0xd7a18506519daad7,
- 0x90935cb5de039acf, 0xe64054c5146ed359, 0xe5b323fb1e866c09,
- 0x10a472555f5ba1bc, 0xe3c0cd57d26e0972, 0x7ca3db7c121da3e8,
- 0x7004a89c800bb466, 0x865f69c1a1ff7f39, 0xbe0edd48f0cf2b99,
- 0x10e5e4ba3cc400f5, 0xafc2b91a220eef50, 0x6f04a259289b24f1,
- 0x2179a8070e880ef0, 0xd6a9a3d023a740c2, 0x96e6d7954755d9b8,
- 0xc8e4bddecce5af9f, 0x93941f0fbc724c92, 0xbef5fb15bf76a479,
- 0x534dca8f5da86529, 0x70789790feec116b, 0x2a296e167eea1fe9,
- 0x54cb1efd2a3ec7ea, 0x357b43897dfeb9f7, 0xd1eda89bc7ff89d3,
- 0x434f2e10cbb83c98, 0xeec4cdac46ca69ce, 0xd46aafd52a303206,
- 0x4bf05968ff50a5c9, 0x71c533747a6292df, 0xa40bd0d16a36118c,
- 0x597b4ee310c395ab, 0xc5b3e3e386172583, 0x12ca0b32284e6c70,
- 0xb48995fadcf35630, 0x0646368454cd217d, 0xa21c168e40d765b5,
- 0x4260d3811337da30, 0xb72728a01cff78e4, 0x8586920947f4756f,
- 0xc21e5f853cae7dc1, 0xf08c9533be9de285, 0x72df06653b4256d6,
- 0xf7b7f937f8db1779, 0x976db27dd0418127, 0x9ce863b7bc3f9e00,
- 0xebb679854fcf3a0a, 0x2ccebabbcf1afa99, 0x44201d6be451dac5,
- 0xb4af71c0e9a537d1, 0xad8fe9bb33ed2681, 0xcb30128bb68df43b,
- 0x154d8328903e8d07, 0x5844276dabeabdff, 0xd99017d7d36d930b,
- 0xabb0b4774fb261ca, 0x0a43f075d62e67e0, 0x8df7b371355ada6b,
- 0xf4c7a40d06513dcf, 0x257a3615955a0372, 0x987ac410bba74c06,
- 0xa011a46f25a632a2, 0xa14384b963ddd995, 0xf51b6b8cf9d50ba7,
- 0x3acdb91ee3abf18d, 0x34e799be08920e8c, 0x8766748a31304b36,
- 0x0aa239d5d0092f2e, 0xadf473ed26628594, 0xc4094b798eb4b79b,
- 0xe04ee5f33cd130f4, 0x85045d098c341d46, 0xf936cdf115a890ec,
- 0x51d137b6d8d2eb4f, 0xd10738bb2fccc1ef,
- };
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {};
+ GTEST_SKIP() << "We only maintain golden data for little endian systems.";
#else
constexpr uint64_t kGolden[kNumGoldenOutputs] = {
- 0x4c34aacf38f6eee4, 0x88b1366815e50b88, 0x1a36bd0c6150fb9c,
- 0xa783aba8a67366c7, 0xbc89ebdc622314e4, 0x632bc3cfcc7544d8,
- 0xbe77aa94940527f9, 0x7ea5c12f2669fe31, 0xa33eed8737d946b9,
- 0x74d832ea11fd18ab, 0x49c0487486246cdc, 0x3fdd986c87ddb0a0,
- 0xac3fa52a64d7c09a, 0xbff0e330196e7ed2, 0x8c8138d3ad7d3cce,
- 0x968c7d4b48e93778, 0xa04c78d3a421f529, 0x8854bc9c3c3c0241,
- 0xcccfcdf5a41113fe, 0xe6fc63dc543d984d, 0x00a39ff89e903c05,
- 0xaf7e9da25f9a26f9, 0x6e269a13d01a43df, 0x846d2300ce2ecdf8,
- 0xe7ea8c8f08478260, 0x9a2db0d62f6232f3, 0x6f66c761d168c59f,
- 0x55f9feacaae82043, 0x518084043700f614, 0xb0c8cfc11bead99f,
- 0xe4a68fdab6359d80, 0x97b17caa8f92236e, 0x96edf5e8363643dc,
- 0x9b3fbcd8d5b254cd, 0x22a263621d9b3a8b, 0xde90bf6f81800a6d,
- 0x1b51cae38c2e9513, 0x689215b3c414ef21, 0x064dc85afae8f557,
- 0xa2f3a8b51f408378, 0x6907c197ec1f6a3b, 0xfe83a42ef5c1cf13,
- 0x9b8b1d8f7a20cc13, 0x1f1681d52ca895d0, 0xd7b1670bf28e0f96,
- 0xb32f20f82d8b038a, 0x6a61d030fb2f5253, 0x8eb2bb0bc29ebb39,
- 0x144f36f7a9eef95c, 0xe77aa47d29808d8c, 0xf14d34c1fc568bad,
- 0x9796dcd4383f3c73, 0xa2f685fc1be7225b, 0xf3791295b16068b1,
- 0xb6b8f63424618948, 0x8ac4fd587045db19, 0x7e2aec2c34feb72e,
- 0x72e135a6910ccbb1, 0x661ff16f3c904e6f, 0xdf92cf9d67ca092d,
- 0x98a9953d79722eef, 0xe0649ed2181d1707, 0xcd8b8478636a297b,
- 0x9516258709c8471b, 0xc703b675b51f4394, 0xdb740eae020139f3,
- 0x57d1499ac4212ff2, 0x355cc03713d43825, 0x0e71ac9b8b1e101e,
- 0x8029fa72258ff559, 0xa2159726b4c16a50, 0x04e61582fba43007,
- 0xdab25af835be8cce, 0x13510b1b184705ee, 0xabdbc9e53666fdeb,
- 0x94a788fcb8173cef, 0x750d5e031286e722, 0x02559e72f4f5b497,
- 0x7d6e0e5996a646fa, 0x66e871b73b014132, 0x2ec170083f8b784f,
- 0x34ac9540cfce3fd9, 0x75c5622c6aad1295, 0xf799a6bb2651acc1,
- 0x8f6bcd3145bdc452, 0xddd9d326eb584a04, 0x5411af1e3532f8dc,
- 0xeb34722f2ad0f509, 0x835bc952a82298cc, 0xeb3839ff60ea92ad,
- 0x70bddf1bcdc8a4bc, 0x4bfb3ee86fcde525, 0xc7b3b93b81dfa386,
- 0xe66db544d57997e8, 0xf68a1b83fd363187, 0xe9b99bec615b171b,
- 0x093fba04d04ad28a, 0xba6117ed4231a303, 0x594bef25f9d4e206,
- 0x0a8cba60578b8f67, 0x88f6c7ca10b06019, 0x32a74082aef17b08,
- 0xe758222f971e22df, 0x4af14ff4a593e51e, 0xdba651e16cb09044,
- 0x3f3ac837d181eaac, 0xa5589a3f89610c01, 0xd409a7c3a18d5643,
- 0x8a89444f82962f26, 0x22eb62a13b9771b9, 0xd3a617615256ddd8,
- 0x7089b990c4bba297, 0x7d752893783eac4f, 0x1f2fcbb79372c915,
- 0x67a4446b17eb9839, 0x70d11df5cae46788, 0x52621e1780b47d0f,
- 0xcf63b93a6e590ee6, 0xb6bc96b58ee064b8, 0x2587f8d635ca9c75,
- 0xc6bddd62ec5e5d01, 0x957398ad3009cdb7, 0x05b6890b20bcd0d3,
- 0xbe6e965ff837222e, 0x47383a87d2b04b1a, 0x7d42207e6d8d7950,
- 0x7e981ed12a7f4aa3, 0xdebb05b30769441a, 0xaac5d86f4ff76c49,
- 0x384f195ca3248331, 0xec4c4b855e909ca1, 0x6a7eeb5a657d73d5,
- 0x9efbebe2fa9c2791, 0x19e7fa0546900c4d,
+ 0x59b1542b0ff6b7b8, 0x3fb979d297096db9, 0xb391802c536343a9,
+ 0x94e0f7e4331081c4, 0x234d95e49e3ce30e, 0xca6351a3e568ed17,
+ 0xa62fcf7fa334293d, 0xb03111035f546067, 0x97b8c861e013d558,
+ 0xb6683803d9387949, 0xce5d907e0b3cb6a1, 0xab7466fae53ed201,
+ 0x8f13ca3f1cac3edd, 0xa2684a99cd909a2a, 0x03194f86b9440843,
+ 0xab3a745d96f75a66, 0xef2448606760ec3d, 0xd999e03247d5d5c5,
+ 0x4a25ab345d53f926, 0xa511b829ce9fc919, 0x4b76517f8e806cbf,
+ 0x006efd7ee09ff8d4, 0x790a4978bd0170a1, 0xc14f6e4b2dff057e,
+ 0xe0d2f4ae7c836d09, 0x4e2038a491ed939d, 0x23fd6f408e9598e0,
+ 0xa91cf8f1d92bcb08, 0x555cdec06df49d58, 0xe7d3e14bd6a8f3bd,
+ 0x4fdd25c1e75c009a, 0x3dffb8acf1ffbd17, 0x56946f33ed73a705,
+ 0x154c633d7690f3b0, 0x3e96f8e9a58a04e0, 0xb0279b244d3ccf9c,
+ 0x8571e87c882b2142, 0x9d9ada45132e7b41, 0xd5667655533f1dec,
+ 0x70607ace4ec36463, 0x691418d2eb63116c, 0xa70179d8e7142980,
+ 0xf8388d756bea25a7, 0xe5127c736d9826de, 0x7f1c95f9b6b656b6,
+ 0x66ab835b7bf4c7b3, 0xc03423b9a6db9728, 0xe88415a2b416b76d,
+ 0x8afd8c14d0b56c36, 0xe9a252b3ba217dad, 0x710150f5cd87a9ff,
+ 0xd66b147837fad9ae, 0x1af5f8ffbaa717a7, 0xe01f88d7a9a8ac17,
+ 0xd67870a7251fde72, 0xf32b837f845a676b, 0x0827717b1ffe59f7,
+ 0x80307212ca7645fb, 0xf0d22af71ea57c80, 0x459373765f2c114b,
+ 0x54d26109fab9cbaf, 0xc603da4e257b93db, 0x57fa334b5689d7d5,
+ 0x41cd1b2a8a91f620, 0xe1d6e7cd0fb015af, 0x8608e9035eb9d795,
+ 0x45c7b9fae739fee1, 0x9f5ae4f7a6b597ee, 0xfb771b6e0017757d,
+ 0x8dac6d29cfd8d027, 0x3c9ba4fb62ce6508, 0xa971fad8243844a7,
+ 0xd2126f49b2ea3b64, 0x5dd78fe7ac436861, 0xfe4004a6bb3494a8,
+ 0xe7c01cc63d770d7c, 0xa117075b8c801d37, 0xdf1dfe75f0e73069,
+ 0x7285b39700cefb98, 0x5e97ea1aa9a670eb, 0xe21872db2b9137a3,
+ 0x12630b02c6ca405e, 0xfe1f2d802151f97a, 0xb53b0ed3dea4fb02,
+ 0xc6d5ed56d1dbf9fd, 0xe5b92b558a5c70cb, 0xccd6eedf97277d08,
+ 0x08582fff2e1494ed, 0xa41f2b3d17f1c4c7, 0x29ec07e5ef950f3d,
+ 0x96aba32565a97084, 0xf26870eca10cebcd, 0xbe1432feb4d33361,
+ 0x21993a779845e6eb,
};
#endif
@@ -507,8 +406,9 @@
for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
std::string str;
ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
- uint64_t h = absl::hash_internal::LowLevelHash(str.data(), str.size(),
- cases[i].seed, kSalt);
+ ASSERT_GT(str.size(), 32);
+ uint64_t h = absl::hash_internal::LowLevelHashLenGt32(
+ str.data(), str.size(), cases[i].seed, kSalt);
printf("0x%016" PRIx64 ", ", h);
if (i % 3 == 2) {
printf("\n");
@@ -522,8 +422,9 @@
<< "i = " << i << "; input = " << cases[i].base64_data);
std::string str;
ASSERT_TRUE(absl::Base64Unescape(cases[i].base64_data, &str));
- EXPECT_EQ(absl::hash_internal::LowLevelHash(str.data(), str.size(),
- cases[i].seed, kSalt),
+ ASSERT_GT(str.size(), 32);
+ EXPECT_EQ(absl::hash_internal::LowLevelHashLenGt32(str.data(), str.size(),
+ cases[i].seed, kSalt),
kGolden[i]);
}
#endif
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h
index 357c301..e403113 100644
--- a/absl/hash/internal/spy_hash_state.h
+++ b/absl/hash/internal/spy_hash_state.h
@@ -16,11 +16,14 @@
#define ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
#include <algorithm>
+#include <cstddef>
+#include <cstdint>
#include <ostream>
#include <string>
#include <vector>
#include "absl/hash/hash.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/strings/match.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
@@ -166,6 +169,11 @@
return hash_state;
}
+ static SpyHashStateImpl combine_weakly_mixed_integer(
+ SpyHashStateImpl hash_state, WeaklyMixedInteger value) {
+ return combine(std::move(hash_state), value.value);
+ }
+
using SpyHashStateImpl::HashStateBase::combine_contiguous;
template <typename CombinerT>
@@ -196,6 +204,7 @@
private:
template <typename U>
friend class SpyHashStateImpl;
+ friend struct CombineRaw;
struct UnorderedCombinerCallback {
std::vector<std::string> element_hash_representations;
@@ -213,6 +222,12 @@
}
};
+ // Combines raw data from e.g. integrals/floats/pointers/etc.
+ static SpyHashStateImpl combine_raw(SpyHashStateImpl state, uint64_t value) {
+ const unsigned char* data = reinterpret_cast<const unsigned char*>(&value);
+ return SpyHashStateImpl::combine_contiguous(std::move(state), data, 8);
+ }
+
// This is true if SpyHashStateImpl<T> has been passed to a call of
// AbslHashValue with the wrong type. This detects that the user called
// AbslHashValue directly (because the hash state type does not match).
diff --git a/absl/hash/internal/weakly_mixed_integer.h b/absl/hash/internal/weakly_mixed_integer.h
new file mode 100644
index 0000000..5575436
--- /dev/null
+++ b/absl/hash/internal/weakly_mixed_integer.h
@@ -0,0 +1,38 @@
+// Copyright 2025 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_
+#define ABSL_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_
+
+#include <cstddef>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace hash_internal {
+
+// Contains an integer that will be mixed into a hash state more weakly than
+// regular integers. It is useful for cases in which an integer is a part of a
+// larger object and needs to be mixed as a supplement. E.g., absl::string_view
+// and absl::Span are mixing their size wrapped with WeaklyMixedInteger.
+struct WeaklyMixedInteger {
+ size_t value;
+};
+
+} // namespace hash_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_HASH_INTERNAL_WEAKLY_MIXED_INTEGER_H_
diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel
index b13cf4d..62ece45 100644
--- a/absl/log/BUILD.bazel
+++ b/absl/log/BUILD.bazel
@@ -152,7 +152,6 @@
cc_library(
name = "log_entry",
- srcs = ["log_entry.cc"],
hdrs = ["log_entry.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -187,6 +186,7 @@
deps = [
":log_sink",
"//absl/base:config",
+ "//absl/base:nullability",
"//absl/log/internal:log_sink_set",
],
)
@@ -222,7 +222,7 @@
"//absl/base:log_severity",
"//absl/base:raw_logging_internal",
"//absl/strings",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -233,6 +233,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
+ "//absl/base:core_headers",
"//absl/log/internal:structured",
"//absl/strings",
],
@@ -279,8 +280,8 @@
"//absl/base:log_severity",
"//absl/flags:flag",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -301,22 +302,23 @@
deps = [
":absl_check",
":check_test_impl",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
cc_test(
name = "absl_log_basic_test",
size = "small",
+ timeout = "moderate",
srcs = ["absl_log_basic_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":absl_log",
":log_basic_test_impl",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -335,8 +337,8 @@
deps = [
":check",
":check_test_impl",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -359,7 +361,7 @@
"//absl/status",
"//absl/strings",
"//absl/strings:string_view",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -373,8 +375,8 @@
":die_if_null",
"//absl/base:core_headers",
"//absl/log/internal:test_helpers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -397,8 +399,8 @@
"//absl/log/internal:test_helpers",
"//absl/log/internal:test_matchers",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -416,22 +418,23 @@
"//absl/base:log_severity",
"//absl/log/internal:globals",
"//absl/log/internal:test_helpers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
cc_test(
name = "log_basic_test",
size = "small",
+ timeout = "moderate",
srcs = ["log_basic_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":log",
":log_basic_test_impl",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -452,7 +455,7 @@
"//absl/log/internal:test_actions",
"//absl/log/internal:test_helpers",
"//absl/log/internal:test_matchers",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -473,8 +476,8 @@
"//absl/strings",
"//absl/time",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -488,12 +491,13 @@
":check",
":log",
":scoped_mock_log",
+ "//absl/base:config",
"//absl/log/internal:test_matchers",
"//absl/strings",
"//absl/strings:str_format",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -508,8 +512,8 @@
":scoped_mock_log",
"//absl/base:core_headers",
"//absl/base:log_severity",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -534,8 +538,8 @@
"//absl/log/internal:test_helpers",
"//absl/log/internal:test_matchers",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -556,8 +560,8 @@
"//absl/log/internal:test_helpers",
"//absl/log/internal:test_matchers",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -576,8 +580,8 @@
"//absl/log/internal:test_matchers",
"//absl/strings",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -604,8 +608,8 @@
"//absl/memory",
"//absl/strings",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -628,8 +632,8 @@
"//absl/status",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -646,8 +650,8 @@
"//absl/base:core_headers",
"//absl/log/internal:test_helpers",
"//absl/log/internal:test_matchers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -671,6 +675,6 @@
"//absl/base:log_severity",
"//absl/flags:flag",
"//absl/log/internal:flags",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt
index 4384465..130897f 100644
--- a/absl/log/CMakeLists.txt
+++ b/absl/log/CMakeLists.txt
@@ -44,11 +44,14 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::base
absl::config
absl::core_headers
+ absl::leak_check
absl::log_internal_nullguard
absl::log_internal_nullstream
absl::log_internal_strip
+ absl::nullability
absl::strings
)
@@ -195,25 +198,28 @@
absl::config
absl::core_headers
absl::errno_saver
- absl::inlined_vector
absl::examine_stack
+ absl::inlined_vector
absl::log_internal_append_truncated
absl::log_internal_format
absl::log_internal_globals
absl::log_internal_proto
absl::log_internal_log_sink_set
absl::log_internal_nullguard
+ absl::log_internal_structured_proto
absl::log_globals
absl::log_entry
absl::log_severity
absl::log_sink
absl::log_sink_registry
absl::memory
+ absl::nullability
absl::raw_logging_internal
- absl::strings
- absl::strerror
- absl::time
absl::span
+ absl::strerror
+ absl::strings
+ absl::strings_internal
+ absl::time
)
absl_cc_library(
@@ -374,6 +380,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
+ absl::core_headers
)
absl_cc_library(
@@ -389,6 +396,7 @@
DEPS
absl::config
absl::strings
+ absl::strings_internal
absl::span
)
@@ -552,8 +560,6 @@
absl_cc_library(
NAME
log_entry
- SRCS
- "log_entry.cc"
HDRS
"log_entry.h"
COPTS
@@ -602,6 +608,7 @@
absl::config
absl::log_sink
absl::log_internal_log_sink_set
+ absl::nullability
PUBLIC
)
@@ -661,13 +668,54 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::any_invocable
absl::config
+ absl::core_headers
absl::log_internal_message
+ absl::log_internal_structured_proto
absl::strings
)
absl_cc_library(
NAME
+ log_internal_structured_proto
+ SRCS
+ "internal/structured_proto.cc"
+ HDRS
+ "internal/structured_proto.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::log_internal_proto
+ absl::config
+ absl::span
+ absl::strings
+ absl::variant
+ PUBLIC
+)
+
+absl_cc_test(
+ NAME
+ log_internal_structured_proto_test
+ SRCS
+ "internal/structured_proto_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+ absl::log_internal_structured_proto
+ absl::span
+ absl::string_view
+ absl::utility
+ GTest::gmock_main
+)
+
+absl_cc_library(
+ NAME
log_structured
HDRS
"structured.h"
@@ -677,6 +725,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
+ absl::core_headers
absl::log_internal_structured
absl::strings
PUBLIC
@@ -700,6 +749,7 @@
absl::log_internal_fnmatch
absl::memory
absl::no_destructor
+ absl::nullability
absl::strings
absl::synchronization
absl::optional
@@ -958,6 +1008,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::check
+ absl::config
absl::log
absl::log_internal_test_matchers
absl::optional
diff --git a/absl/log/absl_vlog_is_on.h b/absl/log/absl_vlog_is_on.h
index 6bf6c41..e4ec86d 100644
--- a/absl/log/absl_vlog_is_on.h
+++ b/absl/log/absl_vlog_is_on.h
@@ -40,6 +40,8 @@
// last . and everything after it) is stripped from each filename prior to
// matching, as is the special suffix "-inl".
//
+// Example: --vmodule=module_a=1,module_b=2
+//
// Files are matched against globs in `--vmodule` in order, and the first match
// determines the verbosity level.
//
diff --git a/absl/log/check.h b/absl/log/check.h
index 50f633d..9e2219b 100644
--- a/absl/log/check.h
+++ b/absl/log/check.h
@@ -42,7 +42,8 @@
// CHECK()
//
-// `CHECK` terminates the program with a fatal error if `condition` is not true.
+// `CHECK` enforces that the `condition` is true. If the condition is false,
+// the program is terminated with a fatal error.
//
// The message may include additional information such as stack traces, when
// available.
diff --git a/absl/log/check_test_impl.inc b/absl/log/check_test_impl.inc
index 6431810..7a0000e 100644
--- a/absl/log/check_test_impl.inc
+++ b/absl/log/check_test_impl.inc
@@ -39,6 +39,7 @@
namespace absl_log_internal {
using ::testing::AllOf;
+using ::testing::AnyOf;
using ::testing::HasSubstr;
using ::testing::Not;
@@ -64,7 +65,6 @@
ABSL_TEST_CHECK(i < 0 || i > 3);
}
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
ABSL_CONST_INIT const auto global_var_check = [](int i) {
ABSL_TEST_CHECK(i > 0); // NOLINT
return i + 1;
@@ -74,7 +74,6 @@
ABSL_TEST_CHECK_GE(i, 0); // NOLINT
return i + 1;
}(global_var_check);
-#endif // ABSL_INTERNAL_CPLUSPLUS_LANG
TEST(CHECKTest, TestPlacementsInCompoundStatements) {
// check placement inside if/else clauses
@@ -89,13 +88,11 @@
case 0:
ABSL_TEST_CHECK(true); // NOLINT
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
constexpr auto var = [](int i) {
ABSL_TEST_CHECK(i > 0); // NOLINT
return i + 1;
}(global_var);
(void)var;
-#endif // ABSL_INTERNAL_CPLUSPLUS_LANG
}
TEST(CHECKTest, TestBoolConvertible) {
@@ -354,7 +351,6 @@
case 0:
ABSL_TEST_CHECK_STRCASEEQ("A", "a");
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
constexpr auto var = [](int i) {
ABSL_TEST_CHECK_GT(i, 0);
return i + 1;
@@ -374,7 +370,6 @@
int var4 = (({ ABSL_TEST_CHECK_STREQ("a", "a"); }), global_var < 10) ? 1 : 0;
(void)var4;
#endif // __GNUC__
-#endif // ABSL_INTERNAL_CPLUSPLUS_LANG
}
TEST(CHECKTest, TestDCHECK) {
@@ -441,7 +436,6 @@
case 0:
ABSL_TEST_QCHECK(true);
-#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
constexpr auto var = [](int i) {
ABSL_TEST_QCHECK(i > 0); // NOLINT
return i + 1;
@@ -452,7 +446,6 @@
int var2 = (({ ABSL_TEST_CHECK_LE(1, 2); }), global_var < 10) ? 1 : 0;
(void)var2;
#endif // __GNUC__
-#endif // ABSL_INTERNAL_CPLUSPLUS_LANG
}
class ComparableType {
@@ -642,14 +635,12 @@
TEST(CHECKDeathTest, TestPointerPrintedAsNumberDespiteAbslStringify) {
const auto* p = reinterpret_cast<const PointerIsStringifiable*>(0x1234);
-#ifdef _MSC_VER
EXPECT_DEATH(
ABSL_TEST_CHECK_EQ(p, nullptr),
- HasSubstr("Check failed: p == nullptr (0000000000001234 vs. (null))"));
-#else // _MSC_VER
- EXPECT_DEATH(ABSL_TEST_CHECK_EQ(p, nullptr),
- HasSubstr("Check failed: p == nullptr (0x1234 vs. (null))"));
-#endif // _MSC_VER
+ AnyOf(
+ HasSubstr("Check failed: p == nullptr (0000000000001234 vs. (null))"),
+ HasSubstr("Check failed: p == nullptr (0x1234 vs. (null))")
+ ));
}
// An uncopyable object with operator<<.
diff --git a/absl/log/die_if_null.h b/absl/log/die_if_null.h
index f773aa8..8597976 100644
--- a/absl/log/die_if_null.h
+++ b/absl/log/die_if_null.h
@@ -60,8 +60,8 @@
// Helper for `ABSL_DIE_IF_NULL`.
template <typename T>
-ABSL_MUST_USE_RESULT T DieIfNull(const char* file, int line,
- const char* exprtext, T&& t) {
+[[nodiscard]] T DieIfNull(const char* file, int line, const char* exprtext,
+ T&& t) {
if (ABSL_PREDICT_FALSE(t == nullptr)) {
// Call a non-inline helper function for a small code size improvement.
DieBecauseNull(file, line, exprtext);
diff --git a/absl/log/globals.h b/absl/log/globals.h
index 4feec40..9718967 100644
--- a/absl/log/globals.h
+++ b/absl/log/globals.h
@@ -43,7 +43,7 @@
//
// Returns the value of the Minimum Log Level parameter.
// This function is async-signal-safe.
-ABSL_MUST_USE_RESULT absl::LogSeverityAtLeast MinLogLevel();
+[[nodiscard]] absl::LogSeverityAtLeast MinLogLevel();
// SetMinLogLevel()
//
@@ -82,7 +82,7 @@
//
// Returns the value of the Stderr Threshold parameter.
// This function is async-signal-safe.
-ABSL_MUST_USE_RESULT absl::LogSeverityAtLeast StderrThreshold();
+[[nodiscard]] absl::LogSeverityAtLeast StderrThreshold();
// SetStderrThreshold()
//
@@ -118,8 +118,7 @@
//
// Returns true if we should log a backtrace at the specified location.
namespace log_internal {
-ABSL_MUST_USE_RESULT bool ShouldLogBacktraceAt(absl::string_view file,
- int line);
+[[nodiscard]] bool ShouldLogBacktraceAt(absl::string_view file, int line);
} // namespace log_internal
// SetLogBacktraceLocation()
@@ -145,7 +144,7 @@
//
// Returns the value of the Prepend Log Prefix option.
// This function is async-signal-safe.
-ABSL_MUST_USE_RESULT bool ShouldPrependLogPrefix();
+[[nodiscard]] bool ShouldPrependLogPrefix();
// EnableLogPrefix()
//
diff --git a/absl/log/globals_test.cc b/absl/log/globals_test.cc
index 0dc54d5..78430d4 100644
--- a/absl/log/globals_test.cc
+++ b/absl/log/globals_test.cc
@@ -100,6 +100,15 @@
EXPECT_EQ(absl::SetVLogLevel("setvloglevel", 42), 0);
EXPECT_EQ(absl::SetVLogLevel("setvloglevel", 1337), 42);
EXPECT_EQ(absl::SetVLogLevel("othersetvloglevel", 50), 0);
+
+ EXPECT_EQ(absl::SetVLogLevel("*pattern*", 1), 0);
+ EXPECT_EQ(absl::SetVLogLevel("*less_generic_pattern*", 2), 1);
+ // "pattern_match" matches the pattern "*pattern*". Therefore, the previous
+ // level must be 1.
+ EXPECT_EQ(absl::SetVLogLevel("pattern_match", 3), 1);
+ // "less_generic_pattern_match" matches the pattern "*pattern*". Therefore,
+ // the previous level must be 2.
+ EXPECT_EQ(absl::SetVLogLevel("less_generic_pattern_match", 4), 2);
}
TEST(TestGlobals, AndroidLogTag) {
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel
index 2dbf337..953b690 100644
--- a/absl/log/internal/BUILD.bazel
+++ b/absl/log/internal/BUILD.bazel
@@ -23,7 +23,7 @@
package(
default_visibility = [
- "//absl/log:__pkg__",
+ ":internal_users",
],
features = [
"header_modules",
@@ -34,6 +34,20 @@
licenses(["notice"])
+package_group(
+ name = "internal_users",
+ packages = [
+ "//absl/log",
+ ],
+)
+
+package_group(
+ name = "structured_proto_users",
+ packages = [
+ "//absl/log/...",
+ ],
+)
+
cc_library(
name = "check_impl",
hdrs = ["check_impl.h"],
@@ -54,15 +68,16 @@
hdrs = ["check_op.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl/log:__pkg__",
- ],
+ visibility = ["//absl/log:__pkg__"],
deps = [
":nullguard",
":nullstream",
":strip",
+ "//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:nullability",
+ "//absl/debugging:leak_check",
"//absl/strings",
],
)
@@ -173,11 +188,13 @@
":log_sink_set",
":nullguard",
":proto",
+ ":structured_proto",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:errno_saver",
"//absl/base:log_severity",
+ "//absl/base:nullability",
"//absl/base:raw_logging_internal",
"//absl/base:strerror",
"//absl/container:inlined_vector",
@@ -188,6 +205,7 @@
"//absl/log:log_sink_registry",
"//absl/memory",
"//absl/strings",
+ "//absl/strings:internal",
"//absl/time",
"//absl/types:span",
],
@@ -201,6 +219,7 @@
deps = [
"//absl/base:config",
"//absl/strings",
+ "//absl/strings:internal",
"//absl/types:span",
],
)
@@ -276,10 +295,49 @@
hdrs = ["structured.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ ":internal_users",
+ ":structured_proto_users",
+ ],
deps = [
":log_message",
+ ":structured_proto",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/functional:any_invocable",
+ "//absl/strings",
+ ],
+)
+
+cc_library(
+ name = "structured_proto",
+ srcs = ["structured_proto.cc"],
+ hdrs = ["structured_proto.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ ":structured_proto_users",
+ ],
+ deps = [
+ ":proto",
"//absl/base:config",
"//absl/strings",
+ "//absl/types:span",
+ "//absl/types:variant",
+ ],
+)
+
+cc_test(
+ name = "structured_proto_test",
+ srcs = ["structured_proto_test.cc"],
+ deps = [
+ ":structured_proto",
+ "//absl/base:config",
+ "//absl/strings:string_view",
+ "//absl/types:span",
+ "//absl/utility",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -298,7 +356,7 @@
"//absl/strings",
"//absl/time",
] + select({
- "//absl:msvc_compiler": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
"//conditions:default": [
],
}),
@@ -311,13 +369,17 @@
hdrs = ["test_helpers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ ":internal_users",
+ ":structured_proto_users",
+ ],
deps = [
":globals",
"//absl/base:config",
"//absl/base:log_severity",
"//absl/log:globals",
"//absl/log:initialize",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -328,6 +390,10 @@
hdrs = ["test_matchers.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ ":internal_users",
+ ":structured_proto_users",
+ ],
deps = [
":test_helpers",
"//absl/base:config",
@@ -336,9 +402,9 @@
"//absl/log:log_entry",
"//absl/strings",
"//absl/time",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
] + select({
- "//absl:msvc_compiler": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
"//conditions:default": [
],
}),
@@ -349,7 +415,10 @@
hdrs = ["voidify.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = ["//absl/base:config"],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ ],
)
cc_library(
@@ -389,11 +458,12 @@
"//absl/log:__subpackages__",
],
deps = [
+ ":fnmatch",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:no_destructor",
- "//absl/log/internal:fnmatch",
+ "//absl/base:nullability",
"//absl/memory",
"//absl/strings",
"//absl/synchronization",
@@ -419,7 +489,7 @@
"//absl/memory",
"//absl/random:distributions",
"//absl/strings",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -427,6 +497,7 @@
cc_test(
name = "stderr_log_sink_test",
size = "small",
+ timeout = "moderate",
srcs = ["stderr_log_sink_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -434,7 +505,9 @@
"no_test:os:android",
"no_test:os:ios",
"no_test_android",
+ "no_test_darwin_arm64",
"no_test_darwin_x86_64",
+ "no_test_fuchsia_x64",
"no_test_ios",
"no_test_wasm",
],
@@ -444,8 +517,8 @@
"//absl/base:log_severity",
"//absl/log",
"//absl/log:globals",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -456,8 +529,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fnmatch",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -469,6 +542,6 @@
tags = ["benchmark"],
deps = [
":fnmatch",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/log/internal/append_truncated.h b/absl/log/internal/append_truncated.h
index f0e7912..d420a8b 100644
--- a/absl/log/internal/append_truncated.h
+++ b/absl/log/internal/append_truncated.h
@@ -17,8 +17,10 @@
#include <cstddef>
#include <cstring>
+#include <string_view>
#include "absl/base/config.h"
+#include "absl/strings/internal/utf8.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
@@ -33,6 +35,32 @@
dst.remove_prefix(src.size());
return src.size();
}
+// Likewise, but it also takes a wide character string and transforms it into a
+// UTF-8 encoded byte string regardless of the current locale.
+// - On platforms where `wchar_t` is 2 bytes (e.g., Windows), the input is
+// treated as UTF-16.
+// - On platforms where `wchar_t` is 4 bytes (e.g., Linux, macOS), the input
+// is treated as UTF-32.
+inline size_t AppendTruncated(std::wstring_view src, absl::Span<char> &dst) {
+ absl::strings_internal::ShiftState state;
+ size_t total_bytes_written = 0;
+ for (const wchar_t wc : src) {
+ // If the destination buffer might not be large enough to write the next
+ // character, stop.
+ if (dst.size() < absl::strings_internal::kMaxEncodedUTF8Size) break;
+ size_t bytes_written =
+ absl::strings_internal::WideToUtf8(wc, dst.data(), state);
+ if (bytes_written == static_cast<size_t>(-1)) {
+ // Invalid character. Encode REPLACEMENT CHARACTER (U+FFFD) instead.
+ constexpr wchar_t kReplacementCharacter = L'\uFFFD';
+ bytes_written = absl::strings_internal::WideToUtf8(kReplacementCharacter,
+ dst.data(), state);
+ }
+ dst.remove_prefix(bytes_written);
+ total_bytes_written += bytes_written;
+ }
+ return total_bytes_written;
+}
// Likewise, but `n` copies of `c`.
inline size_t AppendTruncated(char c, size_t n, absl::Span<char> &dst) {
if (n > dst.size()) n = dst.size();
diff --git a/absl/log/internal/check_op.cc b/absl/log/internal/check_op.cc
index 23c4a3b..23db63b 100644
--- a/absl/log/internal/check_op.cc
+++ b/absl/log/internal/check_op.cc
@@ -14,10 +14,15 @@
#include "absl/log/internal/check_op.h"
-#include <string.h>
-
+#include <cstring>
#include <ostream>
+#include <string>
+#include <utility>
+#include "absl/base/config.h"
+#include "absl/base/nullability.h"
+#include "absl/debugging/leak_check.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#ifdef _MSC_VER
@@ -26,34 +31,30 @@
#include <strings.h> // for strcasecmp, but msvc does not have this header
#endif
-#include <sstream>
-#include <string>
-
-#include "absl/base/config.h"
-#include "absl/strings/str_cat.h"
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
-#define ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(x) \
- template std::string* MakeCheckOpString(x, x, const char*)
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(bool);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(int64_t);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(uint64_t);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(float);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(double);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(char);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(unsigned char);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const std::string&);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const absl::string_view&);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const char*);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const signed char*);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const unsigned char*);
-ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const void*);
-#undef ABSL_LOGGING_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING
+#define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(x) \
+ template const char* absl_nonnull MakeCheckOpString( \
+ x, x, const char* absl_nonnull)
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(bool);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(int64_t);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(uint64_t);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(float);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(double);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(char);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(unsigned char);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const std::string&);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const absl::string_view&);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const char*);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const signed char*);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const unsigned char*);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING(const void*);
+#undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING
-CheckOpMessageBuilder::CheckOpMessageBuilder(const char* exprtext) {
+CheckOpMessageBuilder::CheckOpMessageBuilder(
+ const char* absl_nonnull exprtext) {
stream_ << exprtext << " (";
}
@@ -62,9 +63,10 @@
return stream_;
}
-std::string* CheckOpMessageBuilder::NewString() {
+const char* absl_nonnull CheckOpMessageBuilder::NewString() {
stream_ << ")";
- return new std::string(stream_.str());
+ // There's no need to free this string since the process is crashing.
+ return absl::IgnoreLeak(new std::string(std::move(stream_).str()))->c_str();
}
void MakeCheckOpValueString(std::ostream& os, const char v) {
@@ -100,16 +102,19 @@
}
// Helper functions for string comparisons.
-#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
- std::string* Check##func##expected##Impl(const char* s1, const char* s2, \
- const char* exprtext) { \
- bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
- if (equal == expected) { \
- return nullptr; \
- } else { \
- return new std::string( \
- absl::StrCat(exprtext, " (", s1, " vs. ", s2, ")")); \
- } \
+#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
+ const char* absl_nullable Check##func##expected##Impl( \
+ const char* absl_nullable s1, const char* absl_nullable s2, \
+ const char* absl_nonnull exprtext) { \
+ bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
+ if (equal == expected) { \
+ return nullptr; \
+ } else { \
+ /* There's no need to free this string since the process is crashing. */ \
+ return absl::IgnoreLeak(new std::string(absl::StrCat(exprtext, " (", s1, \
+ " vs. ", s2, ")"))) \
+ ->c_str(); \
+ } \
}
DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
diff --git a/absl/log/internal/check_op.h b/absl/log/internal/check_op.h
index 2159220..7253402 100644
--- a/absl/log/internal/check_op.h
+++ b/absl/log/internal/check_op.h
@@ -32,7 +32,9 @@
#include <utility>
#include "absl/base/attributes.h"
+#include "absl/base/casts.h"
#include "absl/base/config.h"
+#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/log/internal/nullguard.h"
#include "absl/log/internal/nullstream.h"
@@ -62,45 +64,51 @@
#endif
#define ABSL_LOG_INTERNAL_CHECK_OP(name, op, val1, val1_text, val2, val2_text) \
- while (::std::string* absl_log_internal_check_op_result \
- ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG = \
- ::absl::log_internal::name##Impl( \
- ::absl::log_internal::GetReferenceableValue(val1), \
- ::absl::log_internal::GetReferenceableValue(val2), \
- ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \
- val1_text " " #op " " val2_text))) \
+ while (const char* absl_nullable absl_log_internal_check_op_result \
+ [[maybe_unused]] = ::absl::log_internal::name##Impl( \
+ ::absl::log_internal::GetReferenceableValue(val1), \
+ ::absl::log_internal::GetReferenceableValue(val2), \
+ ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val1_text " " #op \
+ " " val2_text))) \
ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_op_result).InternalStream()
-#define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \
- val2_text) \
- while (::std::string* absl_log_internal_qcheck_op_result = \
- ::absl::log_internal::name##Impl( \
- ::absl::log_internal::GetReferenceableValue(val1), \
- ::absl::log_internal::GetReferenceableValue(val2), \
- ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \
- val1_text " " #op " " val2_text))) \
- ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_op_result).InternalStream()
+ ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_check_op_result)) \
+ .InternalStream()
+#define ABSL_LOG_INTERNAL_QCHECK_OP(name, op, val1, val1_text, val2, \
+ val2_text) \
+ while (const char* absl_nullable absl_log_internal_qcheck_op_result = \
+ ::absl::log_internal::name##Impl( \
+ ::absl::log_internal::GetReferenceableValue(val1), \
+ ::absl::log_internal::GetReferenceableValue(val2), \
+ ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL( \
+ val1_text " " #op " " val2_text))) \
+ ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \
+ ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_qcheck_op_result)) \
+ .InternalStream()
#define ABSL_LOG_INTERNAL_CHECK_STROP(func, op, expected, s1, s1_text, s2, \
s2_text) \
- while (::std::string* absl_log_internal_check_strop_result = \
+ while (const char* absl_nullable absl_log_internal_check_strop_result = \
::absl::log_internal::Check##func##expected##Impl( \
(s1), (s2), \
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \
" " s2_text))) \
ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_strop_result) \
+ ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_check_strop_result)) \
.InternalStream()
#define ABSL_LOG_INTERNAL_QCHECK_STROP(func, op, expected, s1, s1_text, s2, \
s2_text) \
- while (::std::string* absl_log_internal_qcheck_strop_result = \
+ while (const char* absl_nullable absl_log_internal_qcheck_strop_result = \
::absl::log_internal::Check##func##expected##Impl( \
(s1), (s2), \
ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(s1_text " " #op \
" " s2_text))) \
ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_strop_result) \
+ ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_qcheck_strop_result)) \
.InternalStream()
+
// This one is tricky:
// * We must evaluate `val` exactly once, yet we need to do two things with it:
// evaluate `.ok()` and (sometimes) `.ToString()`.
@@ -125,37 +133,41 @@
// string literal and abort without doing any streaming. We don't need to
// strip the call to stringify the non-ok `Status` as long as we don't log it;
// dropping the `Status`'s message text is out of scope.
-#define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \
- for (::std::pair<const ::absl::Status*, ::std::string*> \
- absl_log_internal_check_ok_goo; \
- absl_log_internal_check_ok_goo.first = \
- ::absl::log_internal::AsStatus(val), \
- absl_log_internal_check_ok_goo.second = \
- ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \
- ? nullptr \
- : ::absl::status_internal::MakeCheckFailString( \
- absl_log_internal_check_ok_goo.first, \
- ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \
- " is OK")), \
- !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \
- ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_CHECK(*absl_log_internal_check_ok_goo.second) \
+#define ABSL_LOG_INTERNAL_CHECK_OK(val, val_text) \
+ for (::std::pair<const ::absl::Status* absl_nonnull, \
+ const char* absl_nullable> \
+ absl_log_internal_check_ok_goo; \
+ absl_log_internal_check_ok_goo.first = \
+ ::absl::log_internal::AsStatus(val), \
+ absl_log_internal_check_ok_goo.second = \
+ ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok()) \
+ ? nullptr \
+ : ::absl::status_internal::MakeCheckFailString( \
+ absl_log_internal_check_ok_goo.first, \
+ ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \
+ " is OK")), \
+ !ABSL_PREDICT_TRUE(absl_log_internal_check_ok_goo.first->ok());) \
+ ABSL_LOG_INTERNAL_CONDITION_FATAL(STATELESS, true) \
+ ABSL_LOG_INTERNAL_CHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_check_ok_goo.second)) \
.InternalStream()
-#define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \
- for (::std::pair<const ::absl::Status*, ::std::string*> \
- absl_log_internal_qcheck_ok_goo; \
- absl_log_internal_qcheck_ok_goo.first = \
- ::absl::log_internal::AsStatus(val), \
- absl_log_internal_qcheck_ok_goo.second = \
- ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \
- ? nullptr \
- : ::absl::status_internal::MakeCheckFailString( \
- absl_log_internal_qcheck_ok_goo.first, \
- ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \
- " is OK")), \
- !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());) \
- ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \
- ABSL_LOG_INTERNAL_QCHECK(*absl_log_internal_qcheck_ok_goo.second) \
+#define ABSL_LOG_INTERNAL_QCHECK_OK(val, val_text) \
+ for (::std::pair<const ::absl::Status* absl_nonnull, \
+ const char* absl_nullable> \
+ absl_log_internal_qcheck_ok_goo; \
+ absl_log_internal_qcheck_ok_goo.first = \
+ ::absl::log_internal::AsStatus(val), \
+ absl_log_internal_qcheck_ok_goo.second = \
+ ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok()) \
+ ? nullptr \
+ : ::absl::status_internal::MakeCheckFailString( \
+ absl_log_internal_qcheck_ok_goo.first, \
+ ABSL_LOG_INTERNAL_STRIP_STRING_LITERAL(val_text \
+ " is OK")), \
+ !ABSL_PREDICT_TRUE(absl_log_internal_qcheck_ok_goo.first->ok());) \
+ ABSL_LOG_INTERNAL_CONDITION_QFATAL(STATELESS, true) \
+ ABSL_LOG_INTERNAL_QCHECK(::absl::implicit_cast<const char* absl_nonnull>( \
+ absl_log_internal_qcheck_ok_goo.second)) \
.InternalStream()
namespace absl {
@@ -166,8 +178,8 @@
class StatusOr;
namespace status_internal {
-ABSL_ATTRIBUTE_PURE_FUNCTION std::string* MakeCheckFailString(
- const absl::Status* status, const char* prefix);
+ABSL_ATTRIBUTE_PURE_FUNCTION const char* absl_nonnull MakeCheckFailString(
+ const absl::Status* absl_nonnull status, const char* absl_nonnull prefix);
} // namespace status_internal
namespace log_internal {
@@ -175,9 +187,11 @@
// Convert a Status or a StatusOr to its underlying status value.
//
// (This implementation does not require a dep on absl::Status to work.)
-inline const absl::Status* AsStatus(const absl::Status& s) { return &s; }
+inline const absl::Status* absl_nonnull AsStatus(const absl::Status& s) {
+ return &s;
+}
template <typename T>
-const absl::Status* AsStatus(const absl::StatusOr<T>& s) {
+const absl::Status* absl_nonnull AsStatus(const absl::StatusOr<T>& s) {
return &s.status();
}
@@ -186,14 +200,14 @@
class CheckOpMessageBuilder final {
public:
// Inserts `exprtext` and ` (` to the stream.
- explicit CheckOpMessageBuilder(const char* exprtext);
+ explicit CheckOpMessageBuilder(const char* absl_nonnull exprtext);
~CheckOpMessageBuilder() = default;
// For inserting the first variable.
std::ostream& ForVar1() { return stream_; }
// For inserting the second variable (adds an intermediate ` vs. `).
std::ostream& ForVar2();
// Get the result (inserts the closing `)`).
- std::string* NewString();
+ const char* absl_nonnull NewString();
private:
std::ostringstream stream_;
@@ -210,7 +224,7 @@
void MakeCheckOpValueString(std::ostream& os, char v);
void MakeCheckOpValueString(std::ostream& os, signed char v);
void MakeCheckOpValueString(std::ostream& os, unsigned char v);
-void MakeCheckOpValueString(std::ostream& os, const void* p);
+void MakeCheckOpValueString(std::ostream& os, const void* absl_nullable p);
namespace detect_specialization {
@@ -252,8 +266,9 @@
double operator<<(std::ostream&, double value);
long double operator<<(std::ostream&, long double value);
bool operator<<(std::ostream&, bool value);
-const void* operator<<(std::ostream&, const void* value);
-const void* operator<<(std::ostream&, std::nullptr_t);
+const void* absl_nullable operator<<(std::ostream&,
+ const void* absl_nullable value);
+const void* absl_nullable operator<<(std::ostream&, std::nullptr_t);
// These `char` overloads are specified like this in the standard, so we have to
// write them exactly the same to ensure the call is ambiguous.
@@ -267,13 +282,14 @@
template <typename Traits>
unsigned char operator<<(std::basic_ostream<char, Traits>&, unsigned char);
template <typename Traits>
-const char* operator<<(std::basic_ostream<char, Traits>&, const char*);
+const char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&,
+ const char* absl_nonnull);
template <typename Traits>
-const signed char* operator<<(std::basic_ostream<char, Traits>&,
- const signed char*);
+const signed char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&,
+ const signed char* absl_nonnull);
template <typename Traits>
-const unsigned char* operator<<(std::basic_ostream<char, Traits>&,
- const unsigned char*);
+const unsigned char* absl_nonnull operator<<(std::basic_ostream<char, Traits>&,
+ const unsigned char* absl_nonnull);
// This overload triggers when the call is not ambiguous.
// It means that T is being printed with some overload not on this list.
@@ -298,7 +314,8 @@
void Append(absl::string_view text);
void Append(size_t length, char ch);
- friend void AbslFormatFlush(StringifySink* sink, absl::string_view text);
+ friend void AbslFormatFlush(StringifySink* absl_nonnull sink,
+ absl::string_view text);
private:
std::ostream& os_;
@@ -336,11 +353,12 @@
// Build the error message string. Specify no inlining for code size.
template <typename T1, typename T2>
-ABSL_ATTRIBUTE_RETURNS_NONNULL std::string* MakeCheckOpString(
- T1 v1, T2 v2, const char* exprtext) ABSL_ATTRIBUTE_NOINLINE;
+ABSL_ATTRIBUTE_RETURNS_NONNULL const char* absl_nonnull MakeCheckOpString(
+ T1 v1, T2 v2, const char* absl_nonnull exprtext) ABSL_ATTRIBUTE_NOINLINE;
template <typename T1, typename T2>
-std::string* MakeCheckOpString(T1 v1, T2 v2, const char* exprtext) {
+const char* absl_nonnull MakeCheckOpString(T1 v1, T2 v2,
+ const char* absl_nonnull exprtext) {
CheckOpMessageBuilder comb(exprtext);
MakeCheckOpValueString(comb.ForVar1(), v1);
MakeCheckOpValueString(comb.ForVar2(), v2);
@@ -350,7 +368,8 @@
// Add a few commonly used instantiations as extern to reduce size of objects
// files.
#define ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(x) \
- extern template std::string* MakeCheckOpString(x, x, const char*)
+ extern template const char* absl_nonnull MakeCheckOpString( \
+ x, x, const char* absl_nonnull)
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(bool);
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(int64_t);
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(uint64_t);
@@ -360,10 +379,12 @@
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(unsigned char);
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const std::string&);
ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const absl::string_view&);
-ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char*);
-ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const signed char*);
-ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const unsigned char*);
-ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void*);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const char* absl_nonnull);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(
+ const signed char* absl_nonnull);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(
+ const unsigned char* absl_nonnull);
+ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN(const void* absl_nonnull);
#undef ABSL_LOG_INTERNAL_DEFINE_MAKE_CHECK_OP_STRING_EXTERN
// `ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT` skips formatting the Check_OP result
@@ -374,7 +395,7 @@
((::absl::LogSeverity::kFatal >= \
static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL)) \
? MakeCheckOpString<U1, U2>(v1, v2, exprtext) \
- : new std::string())
+ : "")
#else
#define ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, v1, v2, exprtext) \
MakeCheckOpString<U1, U2>(v1, v2, exprtext)
@@ -386,8 +407,8 @@
// type.
#define ABSL_LOG_INTERNAL_CHECK_OP_IMPL(name, op) \
template <typename T1, typename T2> \
- inline constexpr ::std::string* name##Impl(const T1& v1, const T2& v2, \
- const char* exprtext) { \
+ inline constexpr const char* absl_nullable name##Impl( \
+ const T1& v1, const T2& v2, const char* absl_nonnull exprtext) { \
using U1 = CheckOpStreamType<T1>; \
using U2 = CheckOpStreamType<T2>; \
return ABSL_PREDICT_TRUE(v1 op v2) \
@@ -395,8 +416,8 @@
: ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT(U1, U2, U1(v1), \
U2(v2), exprtext); \
} \
- inline constexpr ::std::string* name##Impl(int v1, int v2, \
- const char* exprtext) { \
+ inline constexpr const char* absl_nullable name##Impl( \
+ int v1, int v2, const char* absl_nonnull exprtext) { \
return name##Impl<int, int>(v1, v2, exprtext); \
}
@@ -409,14 +430,18 @@
#undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL_RESULT
#undef ABSL_LOG_INTERNAL_CHECK_OP_IMPL
-std::string* CheckstrcmptrueImpl(const char* s1, const char* s2,
- const char* exprtext);
-std::string* CheckstrcmpfalseImpl(const char* s1, const char* s2,
- const char* exprtext);
-std::string* CheckstrcasecmptrueImpl(const char* s1, const char* s2,
- const char* exprtext);
-std::string* CheckstrcasecmpfalseImpl(const char* s1, const char* s2,
- const char* exprtext);
+const char* absl_nullable CheckstrcmptrueImpl(
+ const char* absl_nullable s1, const char* absl_nullable s2,
+ const char* absl_nonnull exprtext);
+const char* absl_nullable CheckstrcmpfalseImpl(
+ const char* absl_nullable s1, const char* absl_nullable s2,
+ const char* absl_nonnull exprtext);
+const char* absl_nullable CheckstrcasecmptrueImpl(
+ const char* absl_nullable s1, const char* absl_nullable s2,
+ const char* absl_nonnull exprtext);
+const char* absl_nullable CheckstrcasecmpfalseImpl(
+ const char* absl_nullable s1, const char* absl_nullable s2,
+ const char* absl_nonnull exprtext);
// `CHECK_EQ` and friends want to pass their arguments by reference, however
// this winds up exposing lots of cases where people have defined and
@@ -424,6 +449,8 @@
// file), meaning they are not referenceable. This function avoids that problem
// for integers (the most common cases) by overloading for every primitive
// integer type, even the ones we discourage, and returning them by value.
+// NOLINTBEGIN(runtime/int)
+// NOLINTBEGIN(google-runtime-int)
template <typename T>
inline constexpr const T& GetReferenceableValue(const T& t) {
return t;
@@ -433,27 +460,25 @@
return t;
}
inline constexpr signed char GetReferenceableValue(signed char t) { return t; }
-inline constexpr short GetReferenceableValue(short t) { return t; } // NOLINT
-inline constexpr unsigned short GetReferenceableValue( // NOLINT
- unsigned short t) { // NOLINT
+inline constexpr short GetReferenceableValue(short t) { return t; }
+inline constexpr unsigned short GetReferenceableValue(unsigned short t) {
return t;
}
inline constexpr int GetReferenceableValue(int t) { return t; }
inline constexpr unsigned int GetReferenceableValue(unsigned int t) {
return t;
}
-inline constexpr long GetReferenceableValue(long t) { return t; } // NOLINT
-inline constexpr unsigned long GetReferenceableValue( // NOLINT
- unsigned long t) { // NOLINT
+inline constexpr long GetReferenceableValue(long t) { return t; }
+inline constexpr unsigned long GetReferenceableValue(unsigned long t) {
return t;
}
-inline constexpr long long GetReferenceableValue(long long t) { // NOLINT
+inline constexpr long long GetReferenceableValue(long long t) { return t; }
+inline constexpr unsigned long long GetReferenceableValue(
+ unsigned long long t) {
return t;
}
-inline constexpr unsigned long long GetReferenceableValue( // NOLINT
- unsigned long long t) { // NOLINT
- return t;
-}
+// NOLINTEND(google-runtime-int)
+// NOLINTEND(runtime/int)
} // namespace log_internal
ABSL_NAMESPACE_END
diff --git a/absl/log/internal/conditions.cc b/absl/log/internal/conditions.cc
index a9f4966..a418c88 100644
--- a/absl/log/internal/conditions.cc
+++ b/absl/log/internal/conditions.cc
@@ -63,8 +63,9 @@
// myriad2 does not have 8-byte compare and exchange. Use a racy version that
// is "good enough" but will over-log in the face of concurrent logging.
if (now_cycles > next_cycles) {
- next_log_time_cycles_.store(now_cycles + seconds * CycleClock::Frequency(),
- std::memory_order_relaxed);
+ next_log_time_cycles_.store(
+ static_cast<int64_t>(now_cycles + seconds * CycleClock::Frequency()),
+ std::memory_order_relaxed);
return true;
}
return false;
@@ -72,7 +73,8 @@
do {
if (now_cycles <= next_cycles) return false;
} while (!next_log_time_cycles_.compare_exchange_weak(
- next_cycles, now_cycles + seconds * CycleClock::Frequency(),
+ next_cycles,
+ static_cast<int64_t>(now_cycles + seconds * CycleClock::Frequency()),
std::memory_order_relaxed, std::memory_order_relaxed));
return true;
#endif
diff --git a/absl/log/internal/conditions.h b/absl/log/internal/conditions.h
index 9dc15db..6fb74b1 100644
--- a/absl/log/internal/conditions.h
+++ b/absl/log/internal/conditions.h
@@ -65,7 +65,7 @@
switch (0) \
case 0: \
default: \
- !(condition) ? (void)0 : ::absl::log_internal::Voidify()&&
+ !(condition) ? (void)0 : ::absl::log_internal::Voidify() &&
// `ABSL_LOG_INTERNAL_STATEFUL_CONDITION` applies a condition like
// `ABSL_LOG_INTERNAL_STATELESS_CONDITION` but adds to that a series of variable
@@ -96,7 +96,8 @@
for (const uint32_t COUNTER ABSL_ATTRIBUTE_UNUSED = \
absl_log_internal_stateful_condition_state.counter(); \
absl_log_internal_stateful_condition_do_log; \
- absl_log_internal_stateful_condition_do_log = false)
+ absl_log_internal_stateful_condition_do_log = false) \
+ ::absl::log_internal::Voidify() &&
// `ABSL_LOG_INTERNAL_CONDITION_*` serve to combine any conditions from the
// macro (e.g. `LOG_IF` or `VLOG`) with inherent conditions (e.g.
@@ -117,6 +118,8 @@
ABSL_LOG_INTERNAL_##type##_CONDITION( \
(condition) && ::absl::LogSeverity::kError >= \
static_cast<::absl::LogSeverity>(ABSL_MIN_LOG_LEVEL))
+#define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \
+ ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition)
// NOTE: Use ternary operators instead of short-circuiting to mitigate
// https://bugs.llvm.org/show_bug.cgi?id=51928.
#define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \
@@ -168,6 +171,8 @@
ABSL_LOG_INTERNAL_##type##_CONDITION(condition)
#define ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition) \
ABSL_LOG_INTERNAL_##type##_CONDITION(condition)
+#define ABSL_LOG_INTERNAL_CONDITION_DO_NOT_SUBMIT(type, condition) \
+ ABSL_LOG_INTERNAL_CONDITION_ERROR(type, condition)
#define ABSL_LOG_INTERNAL_CONDITION_FATAL(type, condition) \
ABSL_LOG_INTERNAL_##type##_CONDITION(condition)
#define ABSL_LOG_INTERNAL_CONDITION_QFATAL(type, condition) \
diff --git a/absl/log/internal/fnmatch_test.cc b/absl/log/internal/fnmatch_test.cc
index e16a64e..614c7d3 100644
--- a/absl/log/internal/fnmatch_test.cc
+++ b/absl/log/internal/fnmatch_test.cc
@@ -27,6 +27,7 @@
EXPECT_THAT(FNMatch("foo", "bar"), IsFalse());
EXPECT_THAT(FNMatch("foo", "fo"), IsFalse());
EXPECT_THAT(FNMatch("foo", "foo2"), IsFalse());
+ EXPECT_THAT(FNMatch("foo/*", "foo/1/2/3/4"), IsTrue());
EXPECT_THAT(FNMatch("bar/foo.ext", "bar/foo.ext"), IsTrue());
EXPECT_THAT(FNMatch("*ba*r/fo*o.ext*", "bar/foo.ext"), IsTrue());
EXPECT_THAT(FNMatch("bar/foo.ext", "bar/baz.ext"), IsFalse());
diff --git a/absl/log/internal/log_message.cc b/absl/log/internal/log_message.cc
index 4e9b08a..3aed3a2 100644
--- a/absl/log/internal/log_message.cc
+++ b/absl/log/internal/log_message.cc
@@ -31,6 +31,7 @@
#include <memory>
#include <ostream>
#include <string>
+#include <string_view>
#include <tuple>
#include "absl/base/attributes.h"
@@ -39,6 +40,7 @@
#include "absl/base/internal/strerror.h"
#include "absl/base/internal/sysinfo.h"
#include "absl/base/log_severity.h"
+#include "absl/base/nullability.h"
#include "absl/container/inlined_vector.h"
#include "absl/debugging/internal/examine_stack.h"
#include "absl/log/globals.h"
@@ -46,11 +48,14 @@
#include "absl/log/internal/globals.h"
#include "absl/log/internal/log_format.h"
#include "absl/log/internal/log_sink_set.h"
+#include "absl/log/internal/nullguard.h"
#include "absl/log/internal/proto.h"
+#include "absl/log/internal/structured_proto.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/log/log_sink_registry.h"
#include "absl/memory/memory.h"
+#include "absl/strings/internal/utf8.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
@@ -145,8 +150,8 @@
} // namespace
struct LogMessage::LogMessageData final {
- LogMessageData(const char* file, int line, absl::LogSeverity severity,
- absl::Time timestamp);
+ LogMessageData(const char* absl_nonnull file, int line,
+ absl::LogSeverity severity, absl::Time timestamp);
LogMessageData(const LogMessageData&) = delete;
LogMessageData& operator=(const LogMessageData&) = delete;
@@ -161,7 +166,7 @@
bool is_perror;
// Extra `LogSink`s to log to, in addition to `global_sinks`.
- absl::InlinedVector<absl::LogSink*, 16> extra_sinks;
+ absl::InlinedVector<absl::LogSink* absl_nonnull, 16> extra_sinks;
// If true, log to `extra_sinks` but not to `global_sinks` or hardcoded
// non-sink targets (e.g. stderr, log files).
bool extra_sinks_only;
@@ -197,8 +202,8 @@
void FinalizeEncodingAndFormat();
};
-LogMessage::LogMessageData::LogMessageData(const char* file, int line,
- absl::LogSeverity severity,
+LogMessage::LogMessageData::LogMessageData(const char* absl_nonnull file,
+ int line, absl::LogSeverity severity,
absl::Time timestamp)
: extra_sinks_only(false), manipulated(nullptr) {
// Legacy defaults for LOG's ostream:
@@ -268,7 +273,8 @@
absl::MakeSpan(string_buf).subspan(0, chars_written);
}
-LogMessage::LogMessage(const char* file, int line, absl::LogSeverity severity)
+LogMessage::LogMessage(const char* absl_nonnull file, int line,
+ absl::LogSeverity severity)
: data_(absl::make_unique<LogMessageData>(file, line, severity,
absl::Now())) {
data_->first_fatal = false;
@@ -281,23 +287,15 @@
LogBacktraceIfNeeded();
}
-LogMessage::LogMessage(const char* file, int line, InfoTag)
+LogMessage::LogMessage(const char* absl_nonnull file, int line, InfoTag)
: LogMessage(file, line, absl::LogSeverity::kInfo) {}
-LogMessage::LogMessage(const char* file, int line, WarningTag)
+LogMessage::LogMessage(const char* absl_nonnull file, int line, WarningTag)
: LogMessage(file, line, absl::LogSeverity::kWarning) {}
-LogMessage::LogMessage(const char* file, int line, ErrorTag)
+LogMessage::LogMessage(const char* absl_nonnull file, int line, ErrorTag)
: LogMessage(file, line, absl::LogSeverity::kError) {}
-LogMessage::~LogMessage() {
-#ifdef ABSL_MIN_LOG_LEVEL
- if (data_->entry.log_severity() <
- static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
- data_->entry.log_severity() < absl::LogSeverity::kFatal) {
- return;
- }
-#endif
- Flush();
-}
+// This cannot go in the header since LogMessageData is defined in this file.
+LogMessage::~LogMessage() = default;
LogMessage& LogMessage::AtLocation(absl::string_view file, int line) {
data_->entry.full_filename_ = file;
@@ -348,13 +346,13 @@
return *this;
}
-LogMessage& LogMessage::ToSinkAlso(absl::LogSink* sink) {
+LogMessage& LogMessage::ToSinkAlso(absl::LogSink* absl_nonnull sink) {
ABSL_INTERNAL_CHECK(sink, "null LogSink*");
data_->extra_sinks.push_back(sink);
return *this;
}
-LogMessage& LogMessage::ToSinkOnly(absl::LogSink* sink) {
+LogMessage& LogMessage::ToSinkOnly(absl::LogSink* absl_nonnull sink) {
ABSL_INTERNAL_CHECK(sink, "null LogSink*");
data_->extra_sinks.clear();
data_->extra_sinks.push_back(sink);
@@ -408,6 +406,34 @@
CopyToEncodedBuffer<StringType::kNotLiteral>(v);
return *this;
}
+
+LogMessage& LogMessage::operator<<(const std::wstring& v) {
+ CopyToEncodedBuffer<StringType::kNotLiteral>(v);
+ return *this;
+}
+
+LogMessage& LogMessage::operator<<(std::wstring_view v) {
+ CopyToEncodedBuffer<StringType::kNotLiteral>(v);
+ return *this;
+}
+
+template <>
+LogMessage& LogMessage::operator<< <const wchar_t*>(
+ const wchar_t* absl_nullable const& v) {
+ if (v == nullptr) {
+ CopyToEncodedBuffer<StringType::kNotLiteral>(
+ absl::string_view(kCharNull.data(), kCharNull.size() - 1));
+ } else {
+ CopyToEncodedBuffer<StringType::kNotLiteral>(v);
+ }
+ return *this;
+}
+
+LogMessage& LogMessage::operator<<(wchar_t v) {
+ CopyToEncodedBuffer<StringType::kNotLiteral>(std::wstring_view(&v, 1));
+ return *this;
+}
+
LogMessage& LogMessage::operator<<(std::ostream& (*m)(std::ostream& os)) {
OstreamView view(*data_);
data_->manipulated << m;
@@ -418,23 +444,26 @@
data_->manipulated << m;
return *this;
}
+// NOLINTBEGIN(runtime/int)
+// NOLINTBEGIN(google-runtime-int)
template LogMessage& LogMessage::operator<<(const char& v);
template LogMessage& LogMessage::operator<<(const signed char& v);
template LogMessage& LogMessage::operator<<(const unsigned char& v);
-template LogMessage& LogMessage::operator<<(const short& v); // NOLINT
-template LogMessage& LogMessage::operator<<(const unsigned short& v); // NOLINT
+template LogMessage& LogMessage::operator<<(const short& v);
+template LogMessage& LogMessage::operator<<(const unsigned short& v);
template LogMessage& LogMessage::operator<<(const int& v);
template LogMessage& LogMessage::operator<<(const unsigned int& v);
-template LogMessage& LogMessage::operator<<(const long& v); // NOLINT
-template LogMessage& LogMessage::operator<<(const unsigned long& v); // NOLINT
-template LogMessage& LogMessage::operator<<(const long long& v); // NOLINT
-template LogMessage& LogMessage::operator<<(
- const unsigned long long& v); // NOLINT
+template LogMessage& LogMessage::operator<<(const long& v);
+template LogMessage& LogMessage::operator<<(const unsigned long& v);
+template LogMessage& LogMessage::operator<<(const long long& v);
+template LogMessage& LogMessage::operator<<(const unsigned long long& v);
template LogMessage& LogMessage::operator<<(void* const& v);
template LogMessage& LogMessage::operator<<(const void* const& v);
template LogMessage& LogMessage::operator<<(const float& v);
template LogMessage& LogMessage::operator<<(const double& v);
template LogMessage& LogMessage::operator<<(const bool& v);
+// NOLINTEND(google-runtime-int)
+// NOLINTEND(runtime/int)
void LogMessage::Flush() {
if (data_->entry.log_severity() < absl::MinLogLevel()) return;
@@ -575,16 +604,17 @@
template <LogMessage::StringType str_type>
void LogMessage::CopyToEncodedBuffer(absl::string_view str) {
auto encoded_remaining_copy = data_->encoded_remaining();
+ constexpr uint8_t tag_value = str_type == StringType::kLiteral
+ ? ValueTag::kStringLiteral
+ : ValueTag::kString;
auto start = EncodeMessageStart(
- EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + str.size(),
+ EventTag::kValue,
+ BufferSizeFor(tag_value, WireType::kLengthDelimited) + str.size(),
&encoded_remaining_copy);
// If the `logging.proto.Event.value` field header did not fit,
// `EncodeMessageStart` will have zeroed `encoded_remaining_copy`'s size and
// `EncodeStringTruncate` will fail too.
- if (EncodeStringTruncate(str_type == StringType::kLiteral
- ? ValueTag::kStringLiteral
- : ValueTag::kString,
- str, &encoded_remaining_copy)) {
+ if (EncodeStringTruncate(tag_value, str, &encoded_remaining_copy)) {
// The string may have been truncated, but the field header fit.
EncodeMessageLength(start, &encoded_remaining_copy);
data_->encoded_remaining() = encoded_remaining_copy;
@@ -601,13 +631,14 @@
template <LogMessage::StringType str_type>
void LogMessage::CopyToEncodedBuffer(char ch, size_t num) {
auto encoded_remaining_copy = data_->encoded_remaining();
+ constexpr uint8_t tag_value = str_type == StringType::kLiteral
+ ? ValueTag::kStringLiteral
+ : ValueTag::kString;
auto value_start = EncodeMessageStart(
- EventTag::kValue, BufferSizeFor(WireType::kLengthDelimited) + num,
+ EventTag::kValue,
+ BufferSizeFor(tag_value, WireType::kLengthDelimited) + num,
&encoded_remaining_copy);
- auto str_start = EncodeMessageStart(str_type == StringType::kLiteral
- ? ValueTag::kStringLiteral
- : ValueTag::kString,
- num, &encoded_remaining_copy);
+ auto str_start = EncodeMessageStart(tag_value, num, &encoded_remaining_copy);
if (str_start.data()) {
// The field headers fit.
log_internal::AppendTruncated(ch, num, encoded_remaining_copy);
@@ -625,6 +656,78 @@
template void LogMessage::CopyToEncodedBuffer<
LogMessage::StringType::kNotLiteral>(char ch, size_t num);
+template <LogMessage::StringType str_type>
+void LogMessage::CopyToEncodedBuffer(std::wstring_view str) {
+ auto encoded_remaining_copy = data_->encoded_remaining();
+ constexpr uint8_t tag_value = str_type == StringType::kLiteral
+ ? ValueTag::kStringLiteral
+ : ValueTag::kString;
+ size_t max_str_byte_length =
+ absl::strings_internal::kMaxEncodedUTF8Size * str.length();
+ auto value_start =
+ EncodeMessageStart(EventTag::kValue,
+ BufferSizeFor(tag_value, WireType::kLengthDelimited) +
+ max_str_byte_length,
+ &encoded_remaining_copy);
+ auto str_start = EncodeMessageStart(tag_value, max_str_byte_length,
+ &encoded_remaining_copy);
+ if (str_start.data()) {
+ log_internal::AppendTruncated(str, encoded_remaining_copy);
+ EncodeMessageLength(str_start, &encoded_remaining_copy);
+ EncodeMessageLength(value_start, &encoded_remaining_copy);
+ data_->encoded_remaining() = encoded_remaining_copy;
+ } else {
+ // The field header(s) did not fit; zero `encoded_remaining()` so we don't
+ // write anything else later.
+ data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
+ }
+}
+template void LogMessage::CopyToEncodedBuffer<LogMessage::StringType::kLiteral>(
+ std::wstring_view str);
+template void LogMessage::CopyToEncodedBuffer<
+ LogMessage::StringType::kNotLiteral>(std::wstring_view str);
+
+template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
+ LogMessage::StringType::kLiteral>(StructuredProtoField field,
+ absl::string_view str);
+template void LogMessage::CopyToEncodedBufferWithStructuredProtoField<
+ LogMessage::StringType::kNotLiteral>(StructuredProtoField field,
+ absl::string_view str);
+
+template <LogMessage::StringType str_type>
+void LogMessage::CopyToEncodedBufferWithStructuredProtoField(
+ StructuredProtoField field, absl::string_view str) {
+ auto encoded_remaining_copy = data_->encoded_remaining();
+ size_t encoded_field_size = BufferSizeForStructuredProtoField(field);
+ constexpr uint8_t tag_value = str_type == StringType::kLiteral
+ ? ValueTag::kStringLiteral
+ : ValueTag::kString;
+ auto start = EncodeMessageStart(
+ EventTag::kValue,
+ encoded_field_size +
+ BufferSizeFor(tag_value, WireType::kLengthDelimited) + str.size(),
+ &encoded_remaining_copy);
+
+ // Write the encoded proto field.
+ if (!EncodeStructuredProtoField(field, encoded_remaining_copy)) {
+ // The header / field will not fit; zero `encoded_remaining()` so we
+ // don't write anything else later.
+ data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
+ return;
+ }
+
+ // Write the string, truncating if necessary.
+ if (!EncodeStringTruncate(ValueTag::kString, str, &encoded_remaining_copy)) {
+ // The length of the string itself did not fit; zero `encoded_remaining()`
+ // so the value is not encoded at all.
+ data_->encoded_remaining().remove_suffix(data_->encoded_remaining().size());
+ return;
+ }
+
+ EncodeMessageLength(start, &encoded_remaining_copy);
+ data_->encoded_remaining() = encoded_remaining_copy;
+}
+
// We intentionally don't return from these destructors. Disable MSVC's warning
// about the destructor never returning as we do so intentionally here.
#if defined(_MSC_VER) && !defined(__clang__)
@@ -632,54 +735,45 @@
#pragma warning(disable : 4722)
#endif
-LogMessageFatal::LogMessageFatal(const char* file, int line)
+LogMessageFatal::LogMessageFatal(const char* absl_nonnull file, int line)
: LogMessage(file, line, absl::LogSeverity::kFatal) {}
-LogMessageFatal::LogMessageFatal(const char* file, int line,
- absl::string_view failure_msg)
+LogMessageFatal::LogMessageFatal(const char* absl_nonnull file, int line,
+ const char* absl_nonnull failure_msg)
: LogMessage(file, line, absl::LogSeverity::kFatal) {
*this << "Check failed: " << failure_msg << " ";
}
-LogMessageFatal::~LogMessageFatal() {
- Flush();
- FailWithoutStackTrace();
-}
+LogMessageFatal::~LogMessageFatal() { FailWithoutStackTrace(); }
-LogMessageDebugFatal::LogMessageDebugFatal(const char* file, int line)
+LogMessageDebugFatal::LogMessageDebugFatal(const char* absl_nonnull file,
+ int line)
: LogMessage(file, line, absl::LogSeverity::kFatal) {}
-LogMessageDebugFatal::~LogMessageDebugFatal() {
- Flush();
- FailWithoutStackTrace();
-}
+LogMessageDebugFatal::~LogMessageDebugFatal() { FailWithoutStackTrace(); }
-LogMessageQuietlyDebugFatal::LogMessageQuietlyDebugFatal(const char* file,
- int line)
+LogMessageQuietlyDebugFatal::LogMessageQuietlyDebugFatal(
+ const char* absl_nonnull file, int line)
: LogMessage(file, line, absl::LogSeverity::kFatal) {
SetFailQuietly();
}
-LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() {
- Flush();
- FailQuietly();
-}
+LogMessageQuietlyDebugFatal::~LogMessageQuietlyDebugFatal() { FailQuietly(); }
-LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line)
+LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* absl_nonnull file,
+ int line)
: LogMessage(file, line, absl::LogSeverity::kFatal) {
SetFailQuietly();
}
-LogMessageQuietlyFatal::LogMessageQuietlyFatal(const char* file, int line,
- absl::string_view failure_msg)
+LogMessageQuietlyFatal::LogMessageQuietlyFatal(
+ const char* absl_nonnull file, int line,
+ const char* absl_nonnull failure_msg)
: LogMessageQuietlyFatal(file, line) {
- *this << "Check failed: " << failure_msg << " ";
+ *this << "Check failed: " << failure_msg << " ";
}
-LogMessageQuietlyFatal::~LogMessageQuietlyFatal() {
- Flush();
- FailQuietly();
-}
+LogMessageQuietlyFatal::~LogMessageQuietlyFatal() { FailQuietly(); }
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
#endif
diff --git a/absl/log/internal/log_message.h b/absl/log/internal/log_message.h
index 0c067da..1aaf05e 100644
--- a/absl/log/internal/log_message.h
+++ b/absl/log/internal/log_message.h
@@ -17,27 +17,34 @@
// -----------------------------------------------------------------------------
//
// This file declares `class absl::log_internal::LogMessage`. This class more or
-// less represents a particular log message. LOG/CHECK macros create a
-// temporary instance of `LogMessage` and then stream values to it. At the end
-// of the LOG/CHECK statement, LogMessage instance goes out of scope and
-// `~LogMessage` directs the message to the registered log sinks.
-// Heap-allocation of `LogMessage` is unsupported. Construction outside of a
-// `LOG` macro is unsupported.
+// less represents a particular log message. LOG/CHECK macros create a temporary
+// instance of `LogMessage` and then stream values to it. At the end of the
+// LOG/CHECK statement, the LogMessage is voidified by operator&&, and `Flush()`
+// directs the message to the registered log sinks. Heap-allocation of
+// `LogMessage` is unsupported. Construction outside of a `LOG` macro is
+// unsupported.
#ifndef ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
#define ABSL_LOG_INTERNAL_LOG_MESSAGE_H_
+#include <wchar.h>
+
+#include <cstddef>
#include <ios>
#include <memory>
#include <ostream>
#include <streambuf>
#include <string>
+#include <string_view>
+#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/errno_saver.h"
#include "absl/base/log_severity.h"
+#include "absl/base/nullability.h"
#include "absl/log/internal/nullguard.h"
+#include "absl/log/internal/structured_proto.h"
#include "absl/log/log_entry.h"
#include "absl/log/log_sink.h"
#include "absl/strings/has_absl_stringify.h"
@@ -49,6 +56,8 @@
namespace log_internal {
constexpr int kLogMessageBufferSize = 15000;
+enum class StructuredStringType;
+
class LogMessage {
public:
struct InfoTag {};
@@ -56,15 +65,15 @@
struct ErrorTag {};
// Used for `LOG`.
- LogMessage(const char* file, int line,
+ LogMessage(const char* absl_nonnull file, int line,
absl::LogSeverity severity) ABSL_ATTRIBUTE_COLD;
// These constructors are slightly smaller/faster to call; the severity is
// curried into the function pointer.
- LogMessage(const char* file, int line,
+ LogMessage(const char* absl_nonnull file, int line,
InfoTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE;
- LogMessage(const char* file, int line,
+ LogMessage(const char* absl_nonnull file, int line,
WarningTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE;
- LogMessage(const char* file, int line,
+ LogMessage(const char* absl_nonnull file, int line,
ErrorTag) ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE;
LogMessage(const LogMessage&) = delete;
LogMessage& operator=(const LogMessage&) = delete;
@@ -95,59 +104,73 @@
// of `errno`.
LogMessage& WithPerror();
// Sends this message to `*sink` in addition to whatever other sinks it would
- // otherwise have been sent to. `sink` must not be null.
- LogMessage& ToSinkAlso(absl::LogSink* sink);
- // Sends this message to `*sink` and no others. `sink` must not be null.
- LogMessage& ToSinkOnly(absl::LogSink* sink);
+ // otherwise have been sent to.
+ LogMessage& ToSinkAlso(absl::LogSink* absl_nonnull sink);
+ // Sends this message to `*sink` and no others.
+ LogMessage& ToSinkOnly(absl::LogSink* absl_nonnull sink);
// Don't call this method from outside this library.
LogMessage& InternalStream() { return *this; }
// By-value overloads for small, common types let us overlook common failures
// to define globals and static data members (i.e. in a .cc file).
- // clang-format off
- // The CUDA toolchain cannot handle these <<<'s:
+ // NOLINTBEGIN(runtime/int)
+ // NOLINTBEGIN(google-runtime-int)
+ // clang-format off: The CUDA toolchain cannot handle these <<<'s
LogMessage& operator<<(char v) { return operator<< <char>(v); }
LogMessage& operator<<(signed char v) { return operator<< <signed char>(v); }
LogMessage& operator<<(unsigned char v) {
return operator<< <unsigned char>(v);
}
- LogMessage& operator<<(signed short v) { // NOLINT
- return operator<< <signed short>(v); // NOLINT
+ LogMessage& operator<<(signed short v) {
+ return operator<< <signed short>(v);
}
LogMessage& operator<<(signed int v) { return operator<< <signed int>(v); }
- LogMessage& operator<<(signed long v) { // NOLINT
- return operator<< <signed long>(v); // NOLINT
+ LogMessage& operator<<(signed long v) {
+ return operator<< <signed long>(v);
}
- LogMessage& operator<<(signed long long v) { // NOLINT
- return operator<< <signed long long>(v); // NOLINT
+ LogMessage& operator<<(signed long long v) {
+ return operator<< <signed long long>(v);
}
- LogMessage& operator<<(unsigned short v) { // NOLINT
- return operator<< <unsigned short>(v); // NOLINT
+ LogMessage& operator<<(unsigned short v) {
+ return operator<< <unsigned short>(v);
}
LogMessage& operator<<(unsigned int v) {
return operator<< <unsigned int>(v);
}
- LogMessage& operator<<(unsigned long v) { // NOLINT
- return operator<< <unsigned long>(v); // NOLINT
+ LogMessage& operator<<(unsigned long v) {
+ return operator<< <unsigned long>(v);
}
- LogMessage& operator<<(unsigned long long v) { // NOLINT
- return operator<< <unsigned long long>(v); // NOLINT
+ LogMessage& operator<<(unsigned long long v) {
+ return operator<< <unsigned long long>(v);
}
- LogMessage& operator<<(void* v) { return operator<< <void*>(v); }
- LogMessage& operator<<(const void* v) { return operator<< <const void*>(v); }
+ LogMessage& operator<<(void* absl_nullable v) {
+ return operator<< <void*>(v);
+ }
+ LogMessage& operator<<(const void* absl_nullable v) {
+ return operator<< <const void*>(v);
+ }
LogMessage& operator<<(float v) { return operator<< <float>(v); }
LogMessage& operator<<(double v) { return operator<< <double>(v); }
LogMessage& operator<<(bool v) { return operator<< <bool>(v); }
// clang-format on
+ // NOLINTEND(google-runtime-int)
+ // NOLINTEND(runtime/int)
// These overloads are more efficient since no `ostream` is involved.
LogMessage& operator<<(const std::string& v);
LogMessage& operator<<(absl::string_view v);
+ // Wide string overloads (since std::ostream does not provide them).
+ LogMessage& operator<<(const std::wstring& v);
+ LogMessage& operator<<(std::wstring_view v);
+ // `const wchar_t*` is handled by `operator<< <const wchar_t*>`.
+ LogMessage& operator<<(wchar_t* absl_nullable v);
+ LogMessage& operator<<(wchar_t v);
+
// Handle stream manipulators e.g. std::endl.
- LogMessage& operator<<(std::ostream& (*m)(std::ostream& os));
- LogMessage& operator<<(std::ios_base& (*m)(std::ios_base& os));
+ LogMessage& operator<<(std::ostream& (*absl_nonnull m)(std::ostream& os));
+ LogMessage& operator<<(std::ios_base& (*absl_nonnull m)(std::ios_base& os));
// Literal strings. This allows us to record C string literals as literals in
// the logging.proto.Value.
@@ -156,31 +179,30 @@
// this template for every value of `SIZE` encountered in each source code
// file. That significantly increases linker input sizes. Inlining is cheap
// because the argument to this overload is almost always a string literal so
- // the call to `strlen` can be replaced at compile time. The overload for
- // `char[]` below should not be inlined. The compiler typically does not have
- // the string at compile time and cannot replace the call to `strlen` so
- // inlining it increases the binary size. See the discussion on
+ // the call to `strlen` can be replaced at compile time. The overloads for
+ // `char[]`/`wchar_t[]` below should not be inlined. The compiler typically
+ // does not have the string at compile time and cannot replace the call to
+ // `strlen` so inlining it increases the binary size. See the discussion on
// cl/107527369.
template <int SIZE>
LogMessage& operator<<(const char (&buf)[SIZE]);
+ template <int SIZE>
+ LogMessage& operator<<(const wchar_t (&buf)[SIZE]);
// This prevents non-const `char[]` arrays from looking like literals.
template <int SIZE>
LogMessage& operator<<(char (&buf)[SIZE]) ABSL_ATTRIBUTE_NOINLINE;
+ // `wchar_t[SIZE]` is handled by `operator<< <const wchar_t*>`.
// Types that support `AbslStringify()` are serialized that way.
- template <typename T,
- typename std::enable_if<absl::HasAbslStringify<T>::value,
- int>::type = 0>
- LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
-
// Types that don't support `AbslStringify()` but do support streaming into a
// `std::ostream&` are serialized that way.
- template <typename T,
- typename std::enable_if<!absl::HasAbslStringify<T>::value,
- int>::type = 0>
+ template <typename T>
LogMessage& operator<<(const T& v) ABSL_ATTRIBUTE_NOINLINE;
+ // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
+ void Flush();
+
// Note: We explicitly do not support `operator<<` for non-const references
// because it breaks logging of non-integer bitfield types (i.e., enums).
@@ -193,11 +215,6 @@
// the process with an error exit code.
[[noreturn]] static void FailQuietly();
- // Dispatches the completed `absl::LogEntry` to applicable `absl::LogSink`s.
- // This might as well be inlined into `~LogMessage` except that
- // `~LogMessageFatal` needs to call it early.
- void Flush();
-
// After this is called, failures are done as quiet as possible for this log
// message.
void SetFailQuietly();
@@ -206,6 +223,10 @@
struct LogMessageData; // Opaque type containing message state
friend class AsLiteralImpl;
friend class StringifySink;
+ template <StructuredStringType str_type>
+ friend class AsStructuredStringTypeImpl;
+ template <typename T>
+ friend class AsStructuredValueImpl;
// This streambuf writes directly into the structured logging buffer so that
// arbitrary types can be encoded as string data (using
@@ -235,6 +256,15 @@
void CopyToEncodedBuffer(absl::string_view str) ABSL_ATTRIBUTE_NOINLINE;
template <StringType str_type>
void CopyToEncodedBuffer(char ch, size_t num) ABSL_ATTRIBUTE_NOINLINE;
+ template <StringType str_type>
+ void CopyToEncodedBuffer(std::wstring_view str) ABSL_ATTRIBUTE_NOINLINE;
+
+ // Copies `field` to the encoded buffer, then appends `str` after it
+ // (truncating `str` if necessary to fit).
+ template <StringType str_type>
+ void CopyToEncodedBufferWithStructuredProtoField(StructuredProtoField field,
+ absl::string_view str)
+ ABSL_ATTRIBUTE_NOINLINE;
// Returns `true` if the message is fatal or enabled debug-fatal.
bool IsFatal() const;
@@ -255,9 +285,25 @@
// We keep the data in a separate struct so that each instance of `LogMessage`
// uses less stack space.
- std::unique_ptr<LogMessageData> data_;
+ absl_nonnull std::unique_ptr<LogMessageData> data_;
};
+// Explicitly specializes the generic operator<< for `const wchar_t*`
+// arguments.
+//
+// This method is used instead of a non-template `const wchar_t*` overload,
+// as the latter was found to take precedence over the array template
+// (`operator<<(const wchar_t(&)[SIZE])`) when handling string literals.
+// This specialization ensures the array template now correctly processes
+// literals.
+template <>
+LogMessage& LogMessage::operator<< <const wchar_t*>(
+ const wchar_t* absl_nullable const& v);
+
+inline LogMessage& LogMessage::operator<<(wchar_t* absl_nullable v) {
+ return operator<<(const_cast<const wchar_t*>(v));
+}
+
// Helper class so that `AbslStringify()` can modify the LogMessage.
class StringifySink final {
public:
@@ -273,7 +319,8 @@
}
// For types that implement `AbslStringify` using `absl::Format()`.
- friend void AbslFormatFlush(StringifySink* sink, absl::string_view v) {
+ friend void AbslFormatFlush(StringifySink* absl_nonnull sink,
+ absl::string_view v) {
sink->Append(v);
}
@@ -282,21 +329,16 @@
};
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
-template <typename T,
- typename std::enable_if<absl::HasAbslStringify<T>::value, int>::type>
+template <typename T>
LogMessage& LogMessage::operator<<(const T& v) {
- StringifySink sink(*this);
- // Replace with public API.
- AbslStringify(sink, v);
- return *this;
-}
-
-// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
-template <typename T,
- typename std::enable_if<!absl::HasAbslStringify<T>::value, int>::type>
-LogMessage& LogMessage::operator<<(const T& v) {
- OstreamView view(*data_);
- view.stream() << log_internal::NullGuard<T>().Guard(v);
+ if constexpr (absl::HasAbslStringify<T>::value) {
+ StringifySink sink(*this);
+ // Replace with public API.
+ AbslStringify(sink, v);
+ } else {
+ OstreamView view(*data_);
+ view.stream() << log_internal::NullGuard<T>().Guard(v);
+ }
return *this;
}
@@ -306,6 +348,12 @@
return *this;
}
+template <int SIZE>
+LogMessage& LogMessage::operator<<(const wchar_t (&buf)[SIZE]) {
+ CopyToEncodedBuffer<StringType::kLiteral>(buf);
+ return *this;
+}
+
// Note: the following is declared `ABSL_ATTRIBUTE_NOINLINE`
template <int SIZE>
LogMessage& LogMessage::operator<<(char (&buf)[SIZE]) {
@@ -315,27 +363,28 @@
// We instantiate these specializations in the library's TU to save space in
// other TUs. Since the template is marked `ABSL_ATTRIBUTE_NOINLINE` we will be
// emitting a function call either way.
+// NOLINTBEGIN(runtime/int)
+// NOLINTBEGIN(google-runtime-int)
extern template LogMessage& LogMessage::operator<<(const char& v);
extern template LogMessage& LogMessage::operator<<(const signed char& v);
extern template LogMessage& LogMessage::operator<<(const unsigned char& v);
-extern template LogMessage& LogMessage::operator<<(const short& v); // NOLINT
-extern template LogMessage& LogMessage::operator<<(
- const unsigned short& v); // NOLINT
+extern template LogMessage& LogMessage::operator<<(const short& v);
+extern template LogMessage& LogMessage::operator<<(const unsigned short& v);
extern template LogMessage& LogMessage::operator<<(const int& v);
+extern template LogMessage& LogMessage::operator<<(const unsigned int& v);
+extern template LogMessage& LogMessage::operator<<(const long& v);
+extern template LogMessage& LogMessage::operator<<(const unsigned long& v);
+extern template LogMessage& LogMessage::operator<<(const long long& v);
+extern template LogMessage& LogMessage::operator<<(const unsigned long long& v);
extern template LogMessage& LogMessage::operator<<(
- const unsigned int& v); // NOLINT
-extern template LogMessage& LogMessage::operator<<(const long& v); // NOLINT
+ void* absl_nullable const& v);
extern template LogMessage& LogMessage::operator<<(
- const unsigned long& v); // NOLINT
-extern template LogMessage& LogMessage::operator<<(
- const long long& v); // NOLINT
-extern template LogMessage& LogMessage::operator<<(
- const unsigned long long& v); // NOLINT
-extern template LogMessage& LogMessage::operator<<(void* const& v);
-extern template LogMessage& LogMessage::operator<<(const void* const& v);
+ const void* absl_nullable const& v);
extern template LogMessage& LogMessage::operator<<(const float& v);
extern template LogMessage& LogMessage::operator<<(const double& v);
extern template LogMessage& LogMessage::operator<<(const bool& v);
+// NOLINTEND(google-runtime-int)
+// NOLINTEND(runtime/int)
extern template void LogMessage::CopyToEncodedBuffer<
LogMessage::StringType::kLiteral>(absl::string_view str);
@@ -346,14 +395,18 @@
size_t num);
extern template void LogMessage::CopyToEncodedBuffer<
LogMessage::StringType::kNotLiteral>(char ch, size_t num);
+extern template void LogMessage::CopyToEncodedBuffer<
+ LogMessage::StringType::kLiteral>(std::wstring_view str);
+extern template void LogMessage::CopyToEncodedBuffer<
+ LogMessage::StringType::kNotLiteral>(std::wstring_view str);
// `LogMessageFatal` ensures the process will exit in failure after logging this
// message.
class LogMessageFatal final : public LogMessage {
public:
- LogMessageFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
- LogMessageFatal(const char* file, int line,
- absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD;
+ LogMessageFatal(const char* absl_nonnull file, int line) ABSL_ATTRIBUTE_COLD;
+ LogMessageFatal(const char* absl_nonnull file, int line,
+ const char* absl_nonnull failure_msg) ABSL_ATTRIBUTE_COLD;
[[noreturn]] ~LogMessageFatal();
};
@@ -362,7 +415,8 @@
// for DLOG(FATAL) variants.
class LogMessageDebugFatal final : public LogMessage {
public:
- LogMessageDebugFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
+ LogMessageDebugFatal(const char* absl_nonnull file,
+ int line) ABSL_ATTRIBUTE_COLD;
~LogMessageDebugFatal();
};
@@ -371,16 +425,19 @@
// DLOG(QFATAL) calls this instead of LogMessageQuietlyFatal to make sure the
// destructor is not [[noreturn]] even if this is always FATAL as this is only
// invoked when DLOG() is enabled.
- LogMessageQuietlyDebugFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
+ LogMessageQuietlyDebugFatal(const char* absl_nonnull file,
+ int line) ABSL_ATTRIBUTE_COLD;
~LogMessageQuietlyDebugFatal();
};
// Used for LOG(QFATAL) to make sure it's properly understood as [[noreturn]].
class LogMessageQuietlyFatal final : public LogMessage {
public:
- LogMessageQuietlyFatal(const char* file, int line) ABSL_ATTRIBUTE_COLD;
- LogMessageQuietlyFatal(const char* file, int line,
- absl::string_view failure_msg) ABSL_ATTRIBUTE_COLD;
+ LogMessageQuietlyFatal(const char* absl_nonnull file,
+ int line) ABSL_ATTRIBUTE_COLD;
+ LogMessageQuietlyFatal(const char* absl_nonnull file, int line,
+ const char* absl_nonnull failure_msg)
+ ABSL_ATTRIBUTE_COLD;
[[noreturn]] ~LogMessageQuietlyFatal();
};
diff --git a/absl/log/internal/nullstream.h b/absl/log/internal/nullstream.h
index 973e91a..c87f9aa 100644
--- a/absl/log/internal/nullstream.h
+++ b/absl/log/internal/nullstream.h
@@ -79,6 +79,7 @@
return *this;
}
NullStream& InternalStream() { return *this; }
+ void Flush() {}
};
template <typename T>
inline NullStream& operator<<(NullStream& str, const T&) {
diff --git a/absl/log/internal/proto.cc b/absl/log/internal/proto.cc
index eb699ae..821be2b 100644
--- a/absl/log/internal/proto.cc
+++ b/absl/log/internal/proto.cc
@@ -35,9 +35,6 @@
}
buf->remove_prefix(size);
}
-constexpr uint64_t MakeTagType(uint64_t tag, WireType type) {
- return tag << 3 | static_cast<uint64_t>(type);
-}
} // namespace
bool EncodeVarint(uint64_t tag, uint64_t value, absl::Span<char> *buf) {
@@ -126,8 +123,9 @@
return true;
}
-ABSL_MUST_USE_RESULT absl::Span<char> EncodeMessageStart(
- uint64_t tag, uint64_t max_size, absl::Span<char> *buf) {
+[[nodiscard]] absl::Span<char> EncodeMessageStart(uint64_t tag,
+ uint64_t max_size,
+ absl::Span<char> *buf) {
const uint64_t tag_type = MakeTagType(tag, WireType::kLengthDelimited);
const size_t tag_type_size = VarintSize(tag_type);
max_size = std::min<uint64_t>(max_size, buf->size());
diff --git a/absl/log/internal/proto.h b/absl/log/internal/proto.h
index c8d14ac..23f7954 100644
--- a/absl/log/internal/proto.h
+++ b/absl/log/internal/proto.h
@@ -169,9 +169,9 @@
// safe to pass to `EncodeMessageLength` but need not be.
// Used for string, bytes, message, and packed-repeated field type.
// Consumes up to kMaxVarintSize * 2 bytes (20).
-ABSL_MUST_USE_RESULT absl::Span<char> EncodeMessageStart(uint64_t tag,
- uint64_t max_size,
- absl::Span<char> *buf);
+[[nodiscard]] absl::Span<char> EncodeMessageStart(uint64_t tag,
+ uint64_t max_size,
+ absl::Span<char> *buf);
// Finalizes the length field in `msg` so that it encompasses all data encoded
// since the call to `EncodeMessageStart` which returned `msg`. Does nothing if
@@ -199,23 +199,33 @@
return size >= 10 ? (std::numeric_limits<uint64_t>::max)()
: (static_cast<uint64_t>(1) << size * 7) - 1;
}
+constexpr uint64_t MakeTagType(uint64_t tag, WireType type) {
+ return tag << 3 | static_cast<uint64_t>(type);
+}
// `BufferSizeFor` returns a number of bytes guaranteed to be sufficient to
-// store encoded fields of the specified WireTypes regardless of tag numbers and
-// data values. This only makes sense for `WireType::kLengthDelimited` if you
-// add in the length of the contents yourself, e.g. for string and bytes fields
-// by adding the lengths of any encoded strings to the return value or for
-// submessage fields by enumerating the fields you may encode into their
-// contents.
-constexpr size_t BufferSizeFor() { return 0; }
-template <typename... T>
-constexpr size_t BufferSizeFor(WireType type, T... tail) {
- // tag_type + data + ...
- return MaxVarintSize() +
- (type == WireType::kVarint ? MaxVarintSize() : //
- type == WireType::k64Bit ? 8 : //
- type == WireType::k32Bit ? 4 : MaxVarintSize()) + //
- BufferSizeFor(tail...);
+// store encoded fields as `(tag, WireType)`, regardless of data values. This
+// only makes sense for `WireType::kLengthDelimited` if you add in the length of
+// the contents yourself, e.g. for string and bytes fields by adding the lengths
+// of any encoded strings to the return value or for submessage fields by
+// enumerating the fields you may encode into their contents.
+constexpr size_t BufferSizeFor(uint64_t tag, WireType type) {
+ size_t buffer_size = VarintSize(MakeTagType(tag, type));
+ switch (type) {
+ case WireType::kVarint:
+ buffer_size += MaxVarintSize();
+ break;
+ case WireType::k64Bit:
+ buffer_size += size_t{8};
+ break;
+ case WireType::kLengthDelimited:
+ buffer_size += MaxVarintSize();
+ break;
+ case WireType::k32Bit:
+ buffer_size += size_t{4};
+ break;
+ }
+ return buffer_size;
}
// absl::Span<const char> represents a view into the un-processed space in a
diff --git a/absl/log/internal/strip.h b/absl/log/internal/strip.h
index 3e55010..60ef878 100644
--- a/absl/log/internal/strip.h
+++ b/absl/log/internal/strip.h
@@ -15,7 +15,8 @@
// -----------------------------------------------------------------------------
// File: log/internal/strip.h
// -----------------------------------------------------------------------------
-//
+
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
#ifndef ABSL_LOG_INTERNAL_STRIP_H_
#define ABSL_LOG_INTERNAL_STRIP_H_
@@ -31,15 +32,6 @@
// logging in subtly different ways for subtly different reasons (see below).
#if defined(STRIP_LOG) && STRIP_LOG
-// Attribute for marking variables used in implementation details of logging
-// macros as unused, but only when `STRIP_LOG` is defined.
-// With `STRIP_LOG` on, not marking them triggers `-Wunused-but-set-variable`,
-// With `STRIP_LOG` off, marking them triggers `-Wused-but-marked-unused`.
-//
-// TODO(b/290784225): Replace this macro with attribute [[maybe_unused]] when
-// Abseil stops supporting C++14.
-#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG ABSL_ATTRIBUTE_UNUSED
-
#define ABSL_LOGGING_INTERNAL_LOG_INFO ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_WARNING ::absl::log_internal::NullStream()
#define ABSL_LOGGING_INTERNAL_LOG_ERROR ::absl::log_internal::NullStream()
@@ -62,8 +54,6 @@
#else // !defined(STRIP_LOG) || !STRIP_LOG
-#define ABSL_LOG_INTERNAL_ATTRIBUTE_UNUSED_IF_STRIP_LOG
-
#define ABSL_LOGGING_INTERNAL_LOG_INFO \
::absl::log_internal::LogMessage( \
__FILE__, __LINE__, ::absl::log_internal::LogMessage::InfoTag{})
@@ -105,4 +95,6 @@
#define ABSL_LOGGING_INTERNAL_DLOG_DFATAL ABSL_LOGGING_INTERNAL_LOG_DFATAL
#define ABSL_LOGGING_INTERNAL_DLOG_LEVEL ABSL_LOGGING_INTERNAL_LOG_LEVEL
+#define ABSL_LOGGING_INTERNAL_LOG_DO_NOT_SUBMIT ABSL_LOGGING_INTERNAL_LOG_ERROR
+
#endif // ABSL_LOG_INTERNAL_STRIP_H_
diff --git a/absl/log/internal/structured.h b/absl/log/internal/structured.h
index 5223dbc..70b50e2 100644
--- a/absl/log/internal/structured.h
+++ b/absl/log/internal/structured.h
@@ -20,25 +20,32 @@
#define ABSL_LOG_INTERNAL_STRUCTURED_H_
#include <ostream>
+#include <string>
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
+#include "absl/functional/any_invocable.h"
#include "absl/log/internal/log_message.h"
+#include "absl/log/internal/structured_proto.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace log_internal {
-class ABSL_MUST_USE_RESULT AsLiteralImpl final {
+class [[nodiscard]] AsLiteralImpl final {
public:
- explicit AsLiteralImpl(absl::string_view str) : str_(str) {}
+ explicit AsLiteralImpl(absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND)
+ : str_(str) {}
AsLiteralImpl(const AsLiteralImpl&) = default;
AsLiteralImpl& operator=(const AsLiteralImpl&) = default;
private:
absl::string_view str_;
- friend std::ostream& operator<<(std::ostream& os, AsLiteralImpl as_literal) {
+ friend std::ostream& operator<<(std::ostream& os,
+ AsLiteralImpl&& as_literal) {
return os << as_literal.str_;
}
void AddToMessage(log_internal::LogMessage& m) {
@@ -51,6 +58,101 @@
}
};
+enum class StructuredStringType {
+ kLiteral,
+ kNotLiteral,
+};
+
+// Structured log data for a string and associated structured proto field,
+// both of which must outlive this object.
+template <StructuredStringType str_type>
+class [[nodiscard]] AsStructuredStringTypeImpl final {
+ public:
+ constexpr AsStructuredStringTypeImpl(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND)
+ : str_(str), field_(field) {}
+
+ private:
+ absl::string_view str_;
+ StructuredProtoField field_;
+
+ friend std::ostream& operator<<(std::ostream& os,
+ const AsStructuredStringTypeImpl& impl) {
+ return os << impl.str_;
+ }
+ void AddToMessage(LogMessage& m) const {
+ if (str_type == StructuredStringType::kLiteral) {
+ return m.CopyToEncodedBufferWithStructuredProtoField<
+ log_internal::LogMessage::StringType::kLiteral>(field_, str_);
+ } else {
+ return m.CopyToEncodedBufferWithStructuredProtoField<
+ log_internal::LogMessage::StringType::kNotLiteral>(field_, str_);
+ }
+ }
+ friend LogMessage& operator<<(LogMessage& m,
+ const AsStructuredStringTypeImpl& impl) {
+ impl.AddToMessage(m);
+ return m;
+ }
+};
+
+using AsStructuredLiteralImpl =
+ AsStructuredStringTypeImpl<StructuredStringType::kLiteral>;
+using AsStructuredNotLiteralImpl =
+ AsStructuredStringTypeImpl<StructuredStringType::kNotLiteral>;
+
+// Structured log data for a stringifyable type T and associated structured
+// proto field, both of which must outlive this object.
+template <typename T>
+class [[nodiscard]] AsStructuredValueImpl final {
+ public:
+ using ValueFormatter = absl::AnyInvocable<std::string(T) const>;
+
+ constexpr AsStructuredValueImpl(
+ T value ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ StructuredProtoField field ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ ValueFormatter value_formatter =
+ [](T value) { return absl::StrCat(value); })
+ : value_(value),
+ field_(field),
+ value_formatter_(std::move(value_formatter)) {}
+
+ private:
+ T value_;
+ StructuredProtoField field_;
+ ValueFormatter value_formatter_;
+
+ friend std::ostream& operator<<(std::ostream& os,
+ const AsStructuredValueImpl& impl) {
+ return os << impl.value_formatter_(impl.value_);
+ }
+ void AddToMessage(LogMessage& m) const {
+ m.CopyToEncodedBufferWithStructuredProtoField<
+ log_internal::LogMessage::StringType::kNotLiteral>(
+ field_, value_formatter_(value_));
+ }
+ friend LogMessage& operator<<(LogMessage& m,
+ const AsStructuredValueImpl& impl) {
+ impl.AddToMessage(m);
+ return m;
+ }
+};
+
+// Template deduction guide so `AsStructuredValueImpl(42, data)` works
+// without specifying the template type.
+template <typename T>
+AsStructuredValueImpl(T value, StructuredProtoField field)
+ -> AsStructuredValueImpl<T>;
+
+// Template deduction guide so `AsStructuredValueImpl(42, data, formatter)`
+// works without specifying the template type.
+template <typename T>
+AsStructuredValueImpl(
+ T value, StructuredProtoField field,
+ typename AsStructuredValueImpl<T>::ValueFormatter value_formatter)
+ -> AsStructuredValueImpl<T>;
+
} // namespace log_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/log/internal/structured_proto.cc b/absl/log/internal/structured_proto.cc
new file mode 100644
index 0000000..e3829e4
--- /dev/null
+++ b/absl/log/internal/structured_proto.cc
@@ -0,0 +1,115 @@
+//
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/log/internal/structured_proto.h"
+
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/log/internal/proto.h"
+#include "absl/types/span.h"
+#include "absl/types/variant.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+
+namespace {
+
+// Handles protobuf-encoding a type contained inside
+// `StructuredProtoField::Varint`.
+struct VarintEncoderVisitor final {
+ template <typename T>
+ bool operator()(T value) const {
+ return EncodeVarint(field_number, value, &buf);
+ }
+
+ uint64_t field_number;
+ absl::Span<char>& buf;
+};
+
+// Handles protobuf-encoding a type contained inside
+// `StructuredProtoField::I64`.
+struct I64EncoderVisitor final {
+ bool operator()(uint64_t value) const {
+ return Encode64Bit(field_number, value, &buf);
+ }
+
+ bool operator()(int64_t value) const {
+ return Encode64Bit(field_number, value, &buf);
+ }
+
+ bool operator()(double value) const {
+ return EncodeDouble(field_number, value, &buf);
+ }
+
+ uint64_t field_number;
+ absl::Span<char>& buf;
+};
+
+// Handles protobuf-encoding a type contained inside
+// `StructuredProtoField::I32`.
+struct I32EncoderVisitor final {
+ bool operator()(uint32_t value) const {
+ return Encode32Bit(field_number, value, &buf);
+ }
+
+ bool operator()(int32_t value) const {
+ return Encode32Bit(field_number, value, &buf);
+ }
+
+ bool operator()(float value) const {
+ return EncodeFloat(field_number, value, &buf);
+ }
+
+ uint64_t field_number;
+ absl::Span<char>& buf;
+};
+
+// Handles protobuf-encoding a type contained inside `StructuredProtoField`.
+struct EncoderVisitor final {
+ bool operator()(StructuredProtoField::Varint varint) {
+ return absl::visit(VarintEncoderVisitor{field_number, buf}, varint);
+ }
+
+ bool operator()(StructuredProtoField::I64 i64) {
+ return absl::visit(I64EncoderVisitor{field_number, buf}, i64);
+ }
+
+ bool operator()(StructuredProtoField::LengthDelimited length_delimited) {
+ // No need for a visitor, since `StructuredProtoField::LengthDelimited` is
+ // just `absl::Span<const char>`.
+ return EncodeBytes(field_number, length_delimited, &buf);
+ }
+
+ bool operator()(StructuredProtoField::I32 i32) {
+ return absl::visit(I32EncoderVisitor{field_number, buf}, i32);
+ }
+
+ uint64_t field_number;
+ absl::Span<char>& buf;
+};
+
+} // namespace
+
+bool EncodeStructuredProtoField(StructuredProtoField field,
+ absl::Span<char>& buf) {
+ return absl::visit(EncoderVisitor{field.field_number, buf}, field.value);
+}
+
+} // namespace log_internal
+
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/log/internal/structured_proto.h b/absl/log/internal/structured_proto.h
new file mode 100644
index 0000000..3ebc4be
--- /dev/null
+++ b/absl/log/internal/structured_proto.h
@@ -0,0 +1,107 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: log/internal/structured_proto.h
+// -----------------------------------------------------------------------------
+
+#ifndef ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
+#define ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
+
+#include <cstddef>
+#include <cstdint>
+
+#include "absl/base/config.h"
+#include "absl/log/internal/proto.h"
+#include "absl/types/span.h"
+#include "absl/types/variant.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+
+// Sum type holding a single valid protobuf field suitable for encoding.
+struct StructuredProtoField final {
+ // Numeric type encoded with varint encoding:
+ // https://protobuf.dev/programming-guides/encoding/#varints
+ using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>;
+
+ // Fixed-length 64-bit integer encoding:
+ // https://protobuf.dev/programming-guides/encoding/#non-varints
+ using I64 = absl::variant<uint64_t, int64_t, double>;
+
+ // Length-delimited record type (string, sub-message):
+ // https://protobuf.dev/programming-guides/encoding/#length-types
+ using LengthDelimited = absl::Span<const char>;
+
+ // Fixed-length 32-bit integer encoding:
+ // https://protobuf.dev/programming-guides/encoding/#non-varints
+ using I32 = absl::variant<uint32_t, int32_t, float>;
+
+ // Valid record type:
+ // https://protobuf.dev/programming-guides/encoding/#structure
+ using Value = absl::variant<Varint, I64, LengthDelimited, I32>;
+
+ // Field number for the protobuf value.
+ uint64_t field_number;
+
+ // Value to encode.
+ Value value;
+};
+
+// Estimates the number of bytes needed to encode `field` using
+// protobuf encoding.
+//
+// The returned value might be larger than the actual number of bytes needed.
+inline size_t BufferSizeForStructuredProtoField(StructuredProtoField field) {
+ // Visitor to estimate the number of bytes of one of the types contained
+ // inside `StructuredProtoField`.
+ struct BufferSizeVisitor final {
+ size_t operator()(StructuredProtoField::Varint /*unused*/) {
+ return BufferSizeFor(field_number, WireType::kVarint);
+ }
+
+ size_t operator()(StructuredProtoField::I64 /*unused*/) {
+ return BufferSizeFor(field_number, WireType::k64Bit);
+ }
+
+ size_t operator()(StructuredProtoField::LengthDelimited length_delimited) {
+ return BufferSizeFor(field_number, WireType::kLengthDelimited) +
+ length_delimited.size();
+ }
+
+ size_t operator()(StructuredProtoField::I32 /*unused*/) {
+ return BufferSizeFor(field_number, WireType::k32Bit);
+ }
+
+ uint64_t field_number;
+ };
+
+ return absl::visit(BufferSizeVisitor{field.field_number}, field.value);
+}
+
+// Encodes `field` into `buf` using protobuf encoding.
+//
+// On success, returns `true` and advances `buf` to the end of
+// the bytes consumed.
+//
+// On failure (if `buf` was too small), returns `false`.
+bool EncodeStructuredProtoField(StructuredProtoField field,
+ absl::Span<char>& buf);
+
+} // namespace log_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
diff --git a/absl/log/internal/structured_proto_test.cc b/absl/log/internal/structured_proto_test.cc
new file mode 100644
index 0000000..a4deebc
--- /dev/null
+++ b/absl/log/internal/structured_proto_test.cc
@@ -0,0 +1,120 @@
+//
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/log/internal/structured_proto.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/config.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace log_internal {
+namespace {
+
+using ::testing::TestWithParam;
+
+struct StructuredProtoTestCase {
+ std::string test_name;
+ StructuredProtoField field;
+ std::vector<char> expected_encoded_field;
+};
+
+using StructuredProtoTest = TestWithParam<StructuredProtoTestCase>;
+
+TEST_P(StructuredProtoTest, Encoding) {
+ const StructuredProtoTestCase& test_case = GetParam();
+
+ // Greater than or equal to since BufferSizeForStructuredProtoField() is just
+ // an estimate of the data size and not an exact measurement.
+ ASSERT_GE(BufferSizeForStructuredProtoField(test_case.field),
+ test_case.expected_encoded_field.size());
+
+ std::vector<char> buf;
+ buf.resize(1024);
+
+ absl::Span<char> buf_span(buf);
+ EXPECT_TRUE(EncodeStructuredProtoField(test_case.field, buf_span));
+ size_t encoded_field_size = buf.size() - buf_span.size();
+
+ ASSERT_EQ(encoded_field_size, test_case.expected_encoded_field.size());
+ buf.resize(encoded_field_size);
+ EXPECT_EQ(buf, test_case.expected_encoded_field);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ StructuredProtoTestSuiteInstantiation,
+ StructuredProtoTest, // This is the name of your parameterized test
+ testing::ValuesIn<StructuredProtoTestCase>({
+ {
+ "Varint",
+ {
+ 42,
+ StructuredProtoField::Value{
+ absl::in_place_type<StructuredProtoField::Varint>,
+ int32_t{23},
+ },
+ },
+ {'\xD0', '\x02', '\x17'},
+ },
+ {
+ "I64",
+ {
+ 42,
+ StructuredProtoField::Value{
+ absl::in_place_type<StructuredProtoField::I64>,
+ int64_t{23},
+ },
+ },
+ {'\xD1', '\x02', '\x17', '\x00', '\x00', '\x00', '\x00', '\x00',
+ '\x00', '\x00'},
+ },
+ {
+ "LengthDelimited",
+ {
+ 42,
+ // Use a string_view so the terminating NUL is excluded.
+ absl::string_view("Hello"),
+ },
+ {'\xD2', '\x02', '\x05', 'H', 'e', 'l', 'l', 'o'},
+ },
+ {
+ "I32",
+ {
+ 42,
+ StructuredProtoField::Value{
+ absl::in_place_type<StructuredProtoField::I32>,
+ int32_t{23},
+ },
+ },
+ {'\xD5', '\x02', '\x17', '\x00', '\x00', '\x00'},
+ },
+ }),
+ [](const testing::TestParamInfo<StructuredProtoTest::ParamType>& info) {
+ return info.param.test_name;
+ });
+
+} // namespace
+} // namespace log_internal
+ABSL_NAMESPACE_END
+} // namespace absl
diff --git a/absl/log/internal/vlog_config.cc b/absl/log/internal/vlog_config.cc
index b578850..f7c61be 100644
--- a/absl/log/internal/vlog_config.cc
+++ b/absl/log/internal/vlog_config.cc
@@ -207,7 +207,14 @@
get_vmodule_info().erase(
std::remove_if(++iter, get_vmodule_info().end(),
[module_pattern](const VModuleInfo& info) {
- return FNMatch(info.module_pattern, module_pattern);
+ // Remove the previous pattern if it is less generic than
+ // the new one. For example, if the new pattern
+ // `module_pattern` is "foo*" and the previous pattern
+ // `info.module_pattern` is "foo", we should remove the
+ // previous pattern. Because the new pattern "foo*" will
+ // match all the files that the previous pattern "foo"
+ // matches.
+ return FNMatch(module_pattern, info.module_pattern);
}),
get_vmodule_info().cend());
return old_log_level.value_or(global_v);
diff --git a/absl/log/internal/vlog_config.h b/absl/log/internal/vlog_config.h
index b6e322c..84e817a 100644
--- a/absl/log/internal/vlog_config.h
+++ b/absl/log/internal/vlog_config.h
@@ -34,6 +34,7 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
+#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/base/thread_annotations.h"
#include "absl/strings/string_view.h"
@@ -45,7 +46,7 @@
class SyntheticBinary;
class VLogSite;
-int RegisterAndInitialize(VLogSite* v);
+int RegisterAndInitialize(VLogSite* absl_nonnull v);
void UpdateVLogSites();
constexpr int kUseFlag = (std::numeric_limits<int16_t>::min)();
@@ -60,7 +61,7 @@
class VLogSite final {
public:
// `f` must not be destroyed until the program exits.
- explicit constexpr VLogSite(const char* f)
+ explicit constexpr VLogSite(const char* absl_nonnull f)
: file_(f), v_(kUninitialized), next_(nullptr) {}
VLogSite(const VLogSite&) = delete;
VLogSite& operator=(const VLogSite&) = delete;
@@ -93,7 +94,7 @@
}
private:
- friend int log_internal::RegisterAndInitialize(VLogSite* v);
+ friend int log_internal::RegisterAndInitialize(VLogSite* absl_nonnull v);
friend void log_internal::UpdateVLogSites();
friend class log_internal::SyntheticBinary;
static constexpr int kUninitialized = (std::numeric_limits<int>::max)();
@@ -116,7 +117,7 @@
ABSL_ATTRIBUTE_NOINLINE bool SlowIsEnabled5(int stale_v);
// This object is too size-sensitive to use absl::string_view.
- const char* const file_;
+ const char* absl_nonnull const file_;
std::atomic<int> v_;
std::atomic<VLogSite*> next_;
};
@@ -130,7 +131,7 @@
// Registers a site `v` to get updated as `vmodule` and `v` change. Also
// initializes the site based on their current values, and returns that result.
// Does not allocate memory.
-int RegisterAndInitialize(VLogSite* v);
+int RegisterAndInitialize(VLogSite* absl_nonnull v);
// Allocates memory.
void UpdateVLogSites();
@@ -154,7 +155,8 @@
void OnVLogVerbosityUpdate(std::function<void()> cb);
// Does not allocate memory.
-VLogSite* SetVModuleListHeadForTestOnly(VLogSite* v);
+VLogSite* absl_nullable SetVModuleListHeadForTestOnly(
+ VLogSite* absl_nullable v);
} // namespace log_internal
ABSL_NAMESPACE_END
diff --git a/absl/log/internal/voidify.h b/absl/log/internal/voidify.h
index 8f62da2..f42859e 100644
--- a/absl/log/internal/voidify.h
+++ b/absl/log/internal/voidify.h
@@ -16,13 +16,15 @@
// File: log/internal/voidify.h
// -----------------------------------------------------------------------------
//
-// This class is used to explicitly ignore values in the conditional logging
-// macros. This avoids compiler warnings like "value computed is not used" and
-// "statement has no effect".
+// This class does the dispatching of the completed `absl::LogEntry` to
+// applicable `absl::LogSink`s, and is used to explicitly ignore values in the
+// conditional logging macros. This avoids compiler warnings like "value
+// computed is not used" and "statement has no effect".
#ifndef ABSL_LOG_INTERNAL_VOIDIFY_H_
#define ABSL_LOG_INTERNAL_VOIDIFY_H_
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
namespace absl {
@@ -34,7 +36,11 @@
// This has to be an operator with a precedence lower than << but higher than
// ?:
template <typename T>
- void operator&&(const T&) const&& {}
+ ABSL_ATTRIBUTE_COLD void operator&&(T&& message) const&& {
+ // The dispatching of the completed `absl::LogEntry` to applicable
+ // `absl::LogSink`s happens here.
+ message.Flush();
+ }
};
} // namespace log_internal
diff --git a/absl/log/log.h b/absl/log/log.h
index a4e1d1f..f1cab9d 100644
--- a/absl/log/log.h
+++ b/absl/log/log.h
@@ -34,6 +34,13 @@
// running registered error handlers.
// * The `DFATAL` pseudo-severity level is defined as `FATAL` in debug mode and
// as `ERROR` otherwise.
+// * The `DO_NOT_SUBMIT` pseudo-severity level is an alias for `ERROR`, and is
+// intended for debugging statements that won't be submitted. The name is
+// chosen to be easy to spot in review and with tools in order to ensure that
+// such statements aren't inadvertently checked in.
+// The contract is that **it may not be checked in**, meaning that no
+// in-contract uses will be affected if we decide in the future to remove it
+// or change what it does.
// Some preprocessor shenanigans are used to ensure that e.g. `LOG(INFO)` has
// the same meaning even if a local symbol or preprocessor macro named `INFO` is
// defined. To specify a severity level using an expression instead of a
@@ -194,6 +201,8 @@
// LOG(INFO) << std::hex << 0xdeadbeef; // logs "0xdeadbeef"
// LOG(INFO) << 0xdeadbeef; // logs "3735928559"
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_LOG_LOG_H_
#define ABSL_LOG_LOG_H_
@@ -260,44 +269,55 @@
ABSL_LOG_INTERNAL_DLOG_IF_IMPL(_##severity, condition)
// LOG_EVERY_N
+// LOG_FIRST_N
+// LOG_EVERY_POW_2
+// LOG_EVERY_N_SEC
//
-// An instance of `LOG_EVERY_N` increments a hidden zero-initialized counter
-// every time execution passes through it and logs the specified message when
-// the counter's value is a multiple of `n`, doing nothing otherwise. Each
-// instance has its own counter. The counter's value can be logged by streaming
-// the symbol `COUNTER`. `LOG_EVERY_N` is thread-safe.
-// Example:
+// These "stateful" macros log conditionally based on a hidden counter or timer.
+// When the condition is false and no logging is done, streamed operands aren't
+// evaluated either. Each instance has its own state (i.e. counter, timer)
+// that's independent of other instances of the macros. The macros in this
+// family are thread-safe in the sense that they are meant to be called
+// concurrently and will not invoke undefined behavior, however their
+// implementation prioritizes efficiency over exactness and may occasionally log
+// more or less often than specified.
+//
+// * `LOG_EVERY_N` logs the first time and once every `n` times thereafter.
+// * `LOG_FIRST_N` logs the first `n` times and then stops.
+// * `LOG_EVERY_POW_2` logs the first, second, fourth, eighth, etc. times.
+// * `LOG_EVERY_N_SEC` logs the first time and no more than once every `n`
+// seconds thereafter. `n` is passed as a floating point value.
+//
+// The `LOG_IF`... variations with an extra condition evaluate the specified
+// condition first and short-circuit if it is false. For example, an evaluation
+// of `LOG_IF_FIRST_N` does not count against the first `n` if the specified
+// condition is false. Stateful `VLOG`... variations likewise short-circuit
+// if `VLOG` is disabled.
+//
+// An approximate count of the number of times a particular instance's stateful
+// condition has been evaluated (i.e. excluding those where a specified `LOG_IF`
+// condition was false) can be included in the logged message by streaming the
+// symbol `COUNTER`.
+//
+// The `n` parameter need not be a constant. Conditional logging following a
+// change to `n` isn't fully specified, but it should converge on the new value
+// within roughly `max(old_n, new_n)` evaluations or seconds.
+//
+// Examples:
//
// LOG_EVERY_N(WARNING, 1000) << "Got a packet with a bad CRC (" << COUNTER
// << " total)";
-#define LOG_EVERY_N(severity, n) \
- ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(_##severity, n)
-
-// LOG_FIRST_N
-//
-// `LOG_FIRST_N` behaves like `LOG_EVERY_N` except that the specified message is
-// logged when the counter's value is less than `n`. `LOG_FIRST_N` is
-// thread-safe.
-#define LOG_FIRST_N(severity, n) \
- ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(_##severity, n)
-
-// LOG_EVERY_POW_2
-//
-// `LOG_EVERY_POW_2` behaves like `LOG_EVERY_N` except that the specified
-// message is logged when the counter's value is a power of 2.
-// `LOG_EVERY_POW_2` is thread-safe.
-#define LOG_EVERY_POW_2(severity) \
- ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(_##severity)
-
-// LOG_EVERY_N_SEC
-//
-// An instance of `LOG_EVERY_N_SEC` uses a hidden state variable to log the
-// specified message at most once every `n_seconds`. A hidden counter of
-// executions (whether a message is logged or not) is also maintained and can be
-// logged by streaming the symbol `COUNTER`. `LOG_EVERY_N_SEC` is thread-safe.
-// Example:
//
// LOG_EVERY_N_SEC(INFO, 2.5) << "Got " << COUNTER << " cookies so far";
+//
+// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER
+// << "th big cookie";
+#define LOG_EVERY_N(severity, n) \
+ ABSL_LOG_INTERNAL_LOG_EVERY_N_IMPL(_##severity, n)
+#define LOG_FIRST_N(severity, n) \
+ ABSL_LOG_INTERNAL_LOG_FIRST_N_IMPL(_##severity, n)
+#define LOG_EVERY_POW_2(severity) \
+ ABSL_LOG_INTERNAL_LOG_EVERY_POW_2_IMPL(_##severity)
#define LOG_EVERY_N_SEC(severity, n_seconds) \
ABSL_LOG_INTERNAL_LOG_EVERY_N_SEC_IMPL(_##severity, n_seconds)
@@ -328,13 +348,6 @@
#define VLOG_EVERY_N_SEC(severity, n_seconds) \
ABSL_LOG_INTERNAL_VLOG_EVERY_N_SEC_IMPL(severity, n_seconds)
-// `LOG_IF_EVERY_N` and friends behave as the corresponding `LOG_EVERY_N`
-// but neither increment a counter nor log a message if condition is false (as
-// `LOG_IF`).
-// Example:
-//
-// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << COUNTER
-// << "th big cookie";
#define LOG_IF_EVERY_N(severity, condition, n) \
ABSL_LOG_INTERNAL_LOG_IF_EVERY_N_IMPL(_##severity, condition, n)
#define LOG_IF_FIRST_N(severity, condition, n) \
diff --git a/absl/log/log_basic_test_impl.inc b/absl/log/log_basic_test_impl.inc
index 7baf5e7..c4b4e24 100644
--- a/absl/log/log_basic_test_impl.inc
+++ b/absl/log/log_basic_test_impl.inc
@@ -13,6 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
// The testcases in this file are expected to pass or be skipped with any value
// of ABSL_MIN_LOG_LEVEL
@@ -111,7 +113,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::INFO), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))));
}
@@ -142,7 +144,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::WARNING), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))));
}
@@ -173,7 +175,38 @@
ENCODED_MESSAGE(MatchesEvent(
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
+ Stacktrace(IsEmpty()))));
+ }
+
+ test_sink.StartCapturingLogs();
+ do_log();
+}
+
+TEST_P(BasicLogTest, DoNotSubmit) {
+ absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam());
+
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ const int log_line = __LINE__ + 1;
+ auto do_log = [] { ABSL_TEST_LOG(DO_NOT_SUBMIT) << "hello world"; };
+
+ if (LoggingEnabledAt(absl::LogSeverity::kError)) {
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ SourceFilename(Eq(__FILE__)),
+ SourceBasename(Eq("log_basic_test_impl.inc")),
+ SourceLine(Eq(log_line)), Prefix(IsTrue()),
+ LogSeverity(Eq(absl::LogSeverity::kError)),
+ Timestamp(InMatchWindow()),
+ ThreadID(Eq(absl::base_internal::GetTID())),
+ TextMessage(Eq("hello world")),
+ Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq(__FILE__), Eq(log_line), InMatchWindow(),
+ Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))));
}
@@ -226,8 +259,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))))
.WillOnce(DeathTestExpectedLogging());
@@ -246,8 +278,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(Not(IsEmpty())))))
.WillOnce(DeathTestExpectedLogging());
}
@@ -288,8 +319,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))))
.WillOnce(DeathTestExpectedLogging());
}
@@ -325,7 +355,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))));
}
@@ -368,8 +398,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))))
.WillOnce(DeathTestExpectedLogging());
@@ -388,8 +417,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(Not(IsEmpty())))))
.WillOnce(DeathTestExpectedLogging());
}
@@ -454,7 +482,7 @@
? logging::proto::ERROR
: 0),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))));
}
test_sink.StartCapturingLogs();
@@ -500,8 +528,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(IsEmpty()))))
.WillOnce(DeathTestExpectedLogging());
@@ -519,8 +546,7 @@
Eq(__FILE__), Eq(log_line), InMatchWindow(),
Eq(logging::proto::FATAL),
Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(literal: "hello world")pb")))),
+ ElementsAre(ValueWithLiteral(Eq("hello world"))))),
Stacktrace(Not(IsEmpty())))))
.WillOnce(DeathTestExpectedLogging());
}
diff --git a/absl/log/log_entry.cc b/absl/log/log_entry.cc
deleted file mode 100644
index fe58a57..0000000
--- a/absl/log/log_entry.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright 2022 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/log/log_entry.h"
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr int LogEntry::kNoVerbosityLevel;
-constexpr int LogEntry::kNoVerboseLevel;
-#endif
-
-// https://github.com/abseil/abseil-cpp/issues/1465
-// CMake builds on Apple platforms error when libraries are empty.
-// Our CMake configuration can avoid this error on header-only libraries,
-// but since this library is conditionally empty, including a single
-// variable is an easy workaround.
-#ifdef __APPLE__
-namespace log_internal {
-extern const char kAvoidEmptyLogEntryLibraryWarning;
-const char kAvoidEmptyLogEntryLibraryWarning = 0;
-} // namespace log_internal
-#endif // __APPLE__
-
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc
index beee966..6b7d1e5 100644
--- a/absl/log/log_format_test.cc
+++ b/absl/log/log_format_test.cc
@@ -15,12 +15,14 @@
#include <math.h>
+#include <cstring>
#include <iomanip>
#include <ios>
#include <limits>
#include <ostream>
#include <sstream>
#include <string>
+#include <string_view>
#include <type_traits>
#ifdef __ANDROID__
@@ -28,6 +30,7 @@
#endif
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/log/check.h"
#include "absl/log/internal/test_matchers.h"
#include "absl/log/log.h"
@@ -44,6 +47,7 @@
using ::absl::log_internal::RawEncodedMessage;
using ::absl::log_internal::TextMessage;
using ::absl::log_internal::TextPrefix;
+using ::testing::_;
using ::testing::AllOf;
using ::testing::AnyOf;
using ::testing::Each;
@@ -96,11 +100,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("x")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "x")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("x")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("x"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -113,16 +117,44 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("\xee")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "\xee")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("\xee")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("\xee"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
}
+TEST(WideCharLogFormatTest, Printable) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("€")),
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("€"))))))));
+
+ test_sink.StartCapturingLogs();
+ const wchar_t value = L'\u20AC';
+ LOG(INFO) << value;
+}
+
+TEST(WideCharLogFormatTest, Unprintable) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ // Using NEL (Next Line) Unicode character (U+0085).
+ // It is encoded as "\xC2\x85" in UTF-8.
+ constexpr wchar_t wide_value = L'\u0085';
+ constexpr char value[] = "\xC2\x85";
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << wide_value;
+}
+
template <typename T>
class UnsignedIntLogFormatTest : public testing::Test {};
using UnsignedIntTypes = Types<unsigned short, unsigned int, // NOLINT
@@ -136,11 +168,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("224")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "224")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("224")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("224"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -155,11 +188,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("42")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "42")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("42")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("42"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -178,11 +211,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("224")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "224")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("224")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("224"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -195,11 +229,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("-112")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-112")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("-112")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("-112"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -214,11 +249,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("21")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "21")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("21")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("21"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -233,11 +268,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("-21")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "-21")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("-21")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("-21"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -274,11 +310,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("224")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "224")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("224")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("224"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -293,11 +330,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("42")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "42")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("42")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("42"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -333,11 +370,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("224")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "224")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("224")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("224"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -350,11 +388,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("-112")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-112")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("-112")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("-112"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -369,11 +408,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("21")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "21")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("21")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("21"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -388,11 +427,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value.bits;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("-21")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "-21")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("-21")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("-21"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value.bits;
@@ -409,8 +449,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("6.02e+23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "6.02e+23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("6.02e+23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -426,8 +466,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("-6.02e+23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-6.02e+23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("-6.02e+23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -443,8 +483,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("6.02e-23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "6.02e-23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("6.02e-23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -460,8 +500,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("6.02e+23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "6.02e+23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("6.02e+23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -477,8 +517,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("-6.02e+23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-6.02e+23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("-6.02e+23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -494,8 +534,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("6.02e-23")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "6.02e-23")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("6.02e-23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -513,11 +553,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("0")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "0")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("0")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("0"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -530,11 +570,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("1")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "1")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("1")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("1"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -547,11 +587,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(AnyOf(Eq("inf"), Eq("Inf"))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "inf")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("inf"), Eq("Inf"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("inf"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -564,11 +605,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(AnyOf(Eq("-inf"), Eq("-Inf"))),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-inf")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("-inf"), Eq("-Inf"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("-inf"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -581,11 +623,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(AnyOf(Eq("nan"), Eq("NaN"))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "nan")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("nan"), Eq("NaN"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("nan"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
}
@@ -602,24 +645,20 @@
// streaming it. #ifdefing out just the relevant line breaks the MSVC build,
// so duplicate the entire EXPECT_CALL.
#ifdef __riscv
- EXPECT_CALL(
- test_sink,
- Send(AllOf(
- TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"), Eq("-nan(ind)"))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(AnyOf(EqualsProto(R"pb(str: "-nan")pb"),
- EqualsProto(R"pb(str: "nan")pb"),
- EqualsProto(R"pb(str: "-nan(ind)")pb"))))))));
+ EXPECT_CALL(test_sink,
+ Send(AllOf(TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"),
+ Eq("-nan(ind)"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf(
+ ValueWithStr(Eq("-nan")), ValueWithStr(Eq("nan")),
+ ValueWithStr(Eq("-nan(ind)")))))))));
#else
- EXPECT_CALL(
- test_sink,
- Send(AllOf(
- TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"), Eq("-nan(ind)"))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(AnyOf(EqualsProto(R"pb(str: "-nan")pb"),
- EqualsProto(R"pb(str: "nan")pb"),
- EqualsProto(R"pb(str: "-nan(ind)")pb"))))))));
+ EXPECT_CALL(test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("-nan"), Eq("nan"), Eq("NaN"),
+ Eq("-nan(ind)"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf(
+ ValueWithStr(Eq("-nan")), ValueWithStr(Eq("nan")),
+ ValueWithStr(Eq("-nan(ind)")))))))));
#endif
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -627,7 +666,7 @@
template <typename T>
class VoidPtrLogFormatTest : public testing::Test {};
-using VoidPtrTypes = Types<void *, const void *>;
+using VoidPtrTypes = Types<void*, const void*>;
TYPED_TEST_SUITE(VoidPtrLogFormatTest, VoidPtrTypes);
TYPED_TEST(VoidPtrLogFormatTest, Null) {
@@ -654,14 +693,13 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(
- test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(AnyOf(Eq("0xdeadbeef"), Eq("DEADBEEF"),
- Eq("00000000DEADBEEF"))),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- AnyOf(EqualsProto(R"pb(str: "0xdeadbeef")pb"),
- EqualsProto(R"pb(str: "00000000DEADBEEF")pb"))))))));
+ EXPECT_CALL(test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("0xdeadbeef"), Eq("DEADBEEF"),
+ Eq("00000000DEADBEEF"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ AnyOf(ValueWithStr(Eq("0xdeadbeef")),
+ ValueWithStr(Eq("00000000DEADBEEF")))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -669,11 +707,10 @@
template <typename T>
class VolatilePtrLogFormatTest : public testing::Test {};
-using VolatilePtrTypes =
- Types<volatile void*, const volatile void*, volatile char*,
- const volatile char*, volatile signed char*,
- const volatile signed char*, volatile unsigned char*,
- const volatile unsigned char*>;
+using VolatilePtrTypes = Types<
+ volatile void*, const volatile void*, volatile char*, const volatile char*,
+ volatile signed char*, const volatile signed char*, volatile unsigned char*,
+ const volatile unsigned char*, volatile wchar_t*, const volatile wchar_t*>;
TYPED_TEST_SUITE(VolatilePtrLogFormatTest, VolatilePtrTypes);
TYPED_TEST(VolatilePtrLogFormatTest, Null) {
@@ -683,11 +720,21 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("false")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "false")pb")))))));
+ // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1147r1.html
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202302L
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(AnyOf(Eq("(nil)"), Eq("0"), Eq("0x0"),
+ Eq("00000000"), Eq("0000000000000000"))))));
+#else
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("false")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("false"))))))));
+#endif
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -700,11 +747,23 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
+ // https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1147r1.html
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202302L
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("true")),
+ TextMessage(AnyOf(Eq("0xdeadbeef"), Eq("DEADBEEF"),
+ Eq("00000000DEADBEEF"))),
ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "true")pb")))))));
+ AnyOf(ValueWithStr(Eq("0xdeadbeef")),
+ ValueWithStr(Eq("00000000DEADBEEF")))))))));
+#else
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("true")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("true"))))))));
+#endif
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -729,9 +788,8 @@
test_sink,
Send(AllOf(
// `MatchesOstream` deliberately omitted since we deliberately differ.
- TextMessage(Eq("(null)")),
- ENCODED_MESSAGE(
- HasValues(ElementsAre(EqualsProto(R"pb(str: "(null)")pb")))))));
+ TextMessage(Eq("(null)")), ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("(null)"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -745,11 +803,44 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("value")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "value")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("value")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("value"))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+template <typename T>
+class WideCharPtrLogFormatTest : public testing::Test {};
+using WideCharPtrTypes = Types<wchar_t, const wchar_t>;
+TYPED_TEST_SUITE(WideCharPtrLogFormatTest, WideCharPtrTypes);
+
+TYPED_TEST(WideCharPtrLogFormatTest, Null) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam* const value = nullptr;
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("(null)")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("(null)"))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideCharPtrLogFormatTest, NonNull) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam data[] = {'v', 'a', 'l', 'u', 'e', '\0'};
+ TypeParam* const value = data;
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("value"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -762,11 +853,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("true")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "true")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("true")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("true"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -779,11 +871,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("false")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "false")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("false")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("false"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -798,13 +891,24 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("value")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(literal: "value")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithLiteral(Eq("value"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << "value";
}
+TEST(LogFormatTest, WideStringLiteral) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithLiteral(Eq("value"))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << L"value";
+}
+
TEST(LogFormatTest, CharArray) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
@@ -812,16 +916,204 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("value")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "value")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("value")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("value"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
}
+TEST(LogFormatTest, WideCharArray) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ wchar_t value[] = L"value";
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("value")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("value"))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+// Comprehensive test string for validating wchar_t to UTF-8 conversion.
+// See details in absl/strings/internal/utf8_test.cc.
+//
+// clang-format off
+#define ABSL_LOG_INTERNAL_WIDE_LITERAL L"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
+#define ABSL_LOG_INTERNAL_UTF8_LITERAL u8"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
+// clang-format on
+
+absl::string_view GetUtf8TestString() {
+ // `u8""` forces UTF-8 encoding; MSVC will default to e.g. CP1252 (and warn)
+ // without it. However, the resulting character type differs between pre-C++20
+ // (`char`) and C++20 (`char8_t`). So we reinterpret_cast to `char*` and wrap
+ // it in a `string_view`.
+ static const absl::string_view kUtf8TestString(
+ reinterpret_cast<const char*>(ABSL_LOG_INTERNAL_UTF8_LITERAL),
+ sizeof(ABSL_LOG_INTERNAL_UTF8_LITERAL) - 1);
+ return kUtf8TestString;
+}
+
+template <typename T>
+class WideStringLogFormatTest : public testing::Test {};
+using StringTypes =
+ Types<std::wstring, const std::wstring, wchar_t[], const wchar_t*>;
+TYPED_TEST_SUITE(WideStringLogFormatTest, StringTypes);
+
+TYPED_TEST(WideStringLogFormatTest, NonLiterals) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
+ absl::string_view utf8_value = GetUtf8TestString();
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TEST(WideStringLogFormatTest, StringView) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ std::wstring_view value = ABSL_LOG_INTERNAL_WIDE_LITERAL;
+ absl::string_view utf8_value = GetUtf8TestString();
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TEST(WideStringLogFormatTest, Literal) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ absl::string_view utf8_value = GetUtf8TestString();
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithLiteral(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << ABSL_LOG_INTERNAL_WIDE_LITERAL;
+}
+
+#undef ABSL_LOG_INTERNAL_WIDE_LITERAL
+#undef ABSL_LOG_INTERNAL_UTF8_LITERAL
+
+TYPED_TEST(WideStringLogFormatTest, IsolatedLowSurrogatesAreReplaced) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"AAA \xDC00 BBB";
+ // NOLINTNEXTLINE(readability/utf8)
+ absl::string_view utf8_value = "AAA � BBB";
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideStringLogFormatTest,
+ DISABLED_IsolatedHighSurrogatesAreReplaced) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"AAA \xD800 BBB";
+ // NOLINTNEXTLINE(readability/utf8)
+ absl::string_view utf8_value = "AAA � BBB";
+ // Currently, this is "AAA \xF0\x90 BBB".
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideStringLogFormatTest,
+ DISABLED_ConsecutiveHighSurrogatesAreReplaced) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"AAA \xD800\xD800 BBB";
+ // NOLINTNEXTLINE(readability/utf8)
+ absl::string_view utf8_value = "AAA �� BBB";
+ // Currently, this is "AAA \xF0\x90\xF0\x90 BBB".
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideStringLogFormatTest,
+ DISABLED_HighHighLowSurrogateSequencesAreReplaced) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"AAA \xD800\xD800\xDC00 BBB";
+ // NOLINTNEXTLINE(readability/utf8)
+ absl::string_view utf8_value = "AAA �𐀀 BBB";
+ // Currently, this is "AAA \xF0\x90𐀀 BBB".
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideStringLogFormatTest,
+ DISABLED_TrailingHighSurrogatesAreReplaced) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"AAA \xD800";
+ // NOLINTNEXTLINE(readability/utf8)
+ absl::string_view utf8_value = "AAA �";
+ // Currently, this is "AAA \xF0\x90".
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq(utf8_value)),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(utf8_value))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TYPED_TEST(WideStringLogFormatTest, EmptyWideString) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ TypeParam value = L"";
+
+ EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("")),
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq(""))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << value;
+}
+
+TEST(WideStringLogFormatTest, MixedNarrowAndWideStrings) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ EXPECT_CALL(test_sink, Log(_, _, "1234"));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << "1" << L"2" << "3" << L"4";
+}
+
class CustomClass {};
std::ostream& operator<<(std::ostream& os, const CustomClass&) {
return os << "CustomClass{}";
@@ -838,7 +1130,7 @@
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("CustomClass{}")),
ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "CustomClass{}")pb")))))));
+ ValueWithStr(Eq("CustomClass{}"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
}
@@ -863,8 +1155,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("CustomClassNonCopyable{}")),
- ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto(
- R"pb(str: "CustomClassNonCopyable{}")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("CustomClassNonCopyable{}"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value;
@@ -888,8 +1180,8 @@
EXPECT_CALL(
test_sink,
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "(10, 20)")pb")))))));
+ ENCODED_MESSAGE(
+ HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << p;
@@ -919,8 +1211,8 @@
EXPECT_CALL(
test_sink,
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "(10, 20)")pb")))))));
+ ENCODED_MESSAGE(
+ HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << p;
@@ -939,10 +1231,11 @@
PointStreamsNothing p;
- EXPECT_CALL(test_sink, Send(AllOf(TextMessage(Eq("77")),
- TextMessage(Eq(absl::StrCat(p, 77))),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(Eq("77")), TextMessage(Eq(absl::StrCat(p, 77))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << p << 77;
@@ -967,9 +1260,8 @@
EXPECT_CALL(
test_sink,
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "(")pb"),
- EqualsProto(R"pb(str: "10, 20)")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("(")), ValueWithStr(Eq("10, 20)"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << p;
@@ -984,15 +1276,14 @@
<< std::boolalpha << value << " " //
<< std::noboolalpha << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("1 true 1")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "1")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "true")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "1")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("1 true 1")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("1")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("true")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("1"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::noboolalpha << value << " " //
@@ -1009,15 +1300,14 @@
<< std::boolalpha << value << " " //
<< std::noboolalpha << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("0 false 0")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "0")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "false")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "0")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("0 false 0")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("0")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("false")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("0"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::noboolalpha << value << " " //
@@ -1034,15 +1324,14 @@
<< std::showpoint << value << " " //
<< std::noshowpoint << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("77 77.0000 77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "77.0000")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("77 77.0000 77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("77.0000")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::noshowpoint << value << " " //
@@ -1062,12 +1351,10 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("77 +77 77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "+77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "77")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("+77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::noshowpos << value << " " //
@@ -1084,15 +1371,14 @@
<< std::uppercase << value << " " //
<< std::nouppercase << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("7.7e+07 7.7E+07 7.7e+07")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "7.7e+07")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "7.7E+07")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "7.7e+07")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("7.7e+07 7.7E+07 7.7e+07")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("7.7e+07")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("7.7E+07")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("7.7e+07"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::nouppercase << value << " " //
@@ -1107,11 +1393,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << std::hex << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("0x77")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "0x77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("0x77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("0x77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hex << value;
}
@@ -1123,11 +1410,12 @@
auto comparison_stream = ComparisonStream();
comparison_stream << std::oct << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("077")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "077")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("077")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("077"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::oct << value;
@@ -1140,11 +1428,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << std::hex << std::dec << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hex << std::dec << value;
@@ -1160,15 +1448,14 @@
<< std::showbase << value << " " //
<< std::noshowbase << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("77 0x77 77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "0x77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("77 0x77 77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("0x77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hex //
@@ -1190,12 +1477,10 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("77 077 77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "077")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "77")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("077")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::oct //
@@ -1215,15 +1500,14 @@
<< std::uppercase << value << " " //
<< std::nouppercase << value;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("0xbeef 0XBEEF 0xbeef")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "0xbeef")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "0XBEEF")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "0xbeef")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("0xbeef 0XBEEF 0xbeef")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("0xbeef")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("0XBEEF")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("0xbeef"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hex //
@@ -1243,7 +1527,7 @@
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("77000000.000000")),
ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "77000000.000000")pb")))))));
+ ValueWithStr(Eq("77000000.000000"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::fixed << value;
@@ -1259,8 +1543,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("7.700000e+07")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "7.700000e+07")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("7.700000e+07"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::scientific << value;
@@ -1286,9 +1570,9 @@
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(AnyOf(Eq("0x1.25bb50p+26"), Eq("0x1.25bb5p+26"),
Eq("0x1.25bb500000000p+26"))),
- ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf(
- EqualsProto(R"pb(str: "0x1.25bb5p+26")pb"),
- EqualsProto(R"pb(str: "0x1.25bb500000000p+26")pb"))))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ AnyOf(ValueWithStr(Eq("0x1.25bb5p+26")),
+ ValueWithStr(Eq("0x1.25bb500000000p+26")))))))));
test_sink.StartCapturingLogs();
@@ -1317,9 +1601,9 @@
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(AnyOf(Eq("0x1.25bb50p+26"), Eq("0x1.25bb5p+26"),
Eq("0x1.25bb500000000p+26"))),
- ENCODED_MESSAGE(HasValues(ElementsAre(AnyOf(
- EqualsProto(R"pb(str: "0x1.25bb5p+26")pb"),
- EqualsProto(R"pb(str: "0x1.25bb500000000p+26")pb"))))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ AnyOf(ValueWithStr(Eq("0x1.25bb5p+26")),
+ ValueWithStr(Eq("0x1.25bb500000000p+26")))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hexfloat << value;
@@ -1336,8 +1620,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("7.7e+07")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "7.7e+07")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("7.7e+07"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hexfloat << std::defaultfloat << value;
@@ -1352,8 +1636,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq(absl::string_view("\0", 1))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "\0")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq(absl::string_view("\0", 1)))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::ends;
@@ -1370,8 +1654,7 @@
Send(AllOf(
TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("\n")),
- ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto(R"pb(str:
- "\n")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("\n"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::endl;
@@ -1395,10 +1678,9 @@
// `std::setiosflags` and `std::resetiosflags` aren't manipulators.
// We're unable to distinguish their return type(s) from arbitrary
// user-defined types and thus don't suppress the empty str value.
- ENCODED_MESSAGE(
- HasValues(ElementsAre(EqualsProto(R"pb(str: "0x77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "119")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("0x77")),
+ ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("119"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::resetiosflags(std::ios_base::basefield)
@@ -1422,10 +1704,9 @@
// `std::setbase` isn't a manipulator. We're unable to
// distinguish its return type from arbitrary user-defined
// types and thus don't suppress the empty str value.
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "0x77")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "119")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("0x77")), ValueWithLiteral(Eq(" ")),
+ ValueWithStr(Eq("119"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::setbase(16) << value << " " //
@@ -1446,8 +1727,8 @@
// `std::setprecision` isn't a manipulator. We're unable to
// distinguish its return type from arbitrary user-defined
// types and thus don't suppress the empty str value.
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "6.022e+23")pb")))))));
+ ENCODED_MESSAGE(
+ HasValues(ElementsAre(ValueWithStr(Eq("6.022e+23"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::setprecision(4) << value;
@@ -1463,8 +1744,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("602214085700000015187968")),
- ENCODED_MESSAGE(HasValues(ElementsAre(EqualsProto(
- R"pb(str: "602214085700000015187968")pb")))))));
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("602214085700000015187968"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::setprecision(200) << value;
@@ -1484,8 +1765,8 @@
// `std::setw` isn't a manipulator. We're unable to
// distinguish its return type from arbitrary user-defined
// types and thus don't suppress the empty str value.
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: " 77")pb")))))));
+ ENCODED_MESSAGE(
+ HasValues(ElementsAre(ValueWithStr(Eq(" 77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::setw(8) << value;
@@ -1501,8 +1782,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("-77 ")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "-77 ")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("-77 "))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::left << std::setw(8) << value;
@@ -1518,8 +1799,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq(" -77")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: " -77")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq(" -77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::right << std::setw(8) << value;
@@ -1535,8 +1816,8 @@
EXPECT_CALL(test_sink,
Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
TextMessage(Eq("- 77")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "- 77")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("- 77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::internal << std::setw(8) << value;
@@ -1556,8 +1837,8 @@
// unable to distinguish its return
// type from arbitrary user-defined types and
// thus don't suppress the empty str value.
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "00000077")pb")))))));
+ ENCODED_MESSAGE(HasValues(
+ ElementsAre(ValueWithStr(Eq("00000077"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::setfill('0') << std::setw(8) << value;
@@ -1575,13 +1856,13 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value << " " << 0x77;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("FromCustomClass{} 0x77")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(str: "FromCustomClass{}")pb"),
- EqualsProto(R"pb(literal: " ")pb"),
- EqualsProto(R"pb(str: "0x77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
+ TextMessage(Eq("FromCustomClass{} 0x77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithStr(Eq("FromCustomClass{}")),
+ ValueWithLiteral(Eq(" ")), ValueWithStr(Eq("0x77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value << " " << 0x77;
@@ -1597,11 +1878,11 @@
auto comparison_stream = ComparisonStream();
comparison_stream << value << 77;
- EXPECT_CALL(test_sink,
- Send(AllOf(TextMessage(MatchesOstream(comparison_stream)),
- TextMessage(Eq("77")),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "77")pb")))))));
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(MatchesOstream(comparison_stream)), TextMessage(Eq("77")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(ValueWithStr(Eq("77"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << value << 77;
@@ -1625,8 +1906,8 @@
EXPECT_CALL(
test_sink,
Send(AllOf(TextMessage(Eq("(10, 20)")), TextMessage(Eq(absl::StrCat(p))),
- ENCODED_MESSAGE(HasValues(
- ElementsAre(EqualsProto(R"pb(str: "(10, 20)")pb")))))));
+ ENCODED_MESSAGE(
+ HasValues(ElementsAre(ValueWithStr(Eq("(10, 20)"))))))));
test_sink.StartCapturingLogs();
LOG(INFO) << std::hex << p;
@@ -1654,6 +1935,29 @@
LOG(INFO) << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x');
}
+TEST(StructuredLoggingOverflowTest, TruncatesWideStrings) {
+ absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
+
+ // This message is too long and should be truncated to some unspecified size
+ // no greater than the buffer size but not too much less either. It should be
+ // truncated rather than discarded.
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ TextMessage(AllOf(
+ SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256),
+ Le(absl::log_internal::kLogMessageBufferSize))),
+ Each(Eq('x')))),
+ ENCODED_MESSAGE(HasOneStrThat(AllOf(
+ SizeIs(AllOf(Ge(absl::log_internal::kLogMessageBufferSize - 256),
+ Le(absl::log_internal::kLogMessageBufferSize))),
+ Each(Eq('x'))))))));
+
+ test_sink.StartCapturingLogs();
+ LOG(INFO) << std::wstring(2 * absl::log_internal::kLogMessageBufferSize,
+ L'x');
+}
+
struct StringLike {
absl::string_view data;
};
diff --git a/absl/log/log_modifier_methods_test.cc b/absl/log/log_modifier_methods_test.cc
index 4ccde40..4cee0c0 100644
--- a/absl/log/log_modifier_methods_test.cc
+++ b/absl/log/log_modifier_methods_test.cc
@@ -15,6 +15,8 @@
#include <errno.h>
+#include <string>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/log/internal/test_actions.h"
@@ -77,6 +79,14 @@
<< "hello world";
}
+TEST(TailCallsModifiesTest, AtLocationFileLineLifetime) {
+ // The macro takes care to not use this temporary after its lifetime.
+ // The only salient expectation is "no sanitizer diagnostics".
+ LOG(INFO).AtLocation(std::string("/my/very/very/very_long_source_file.cc"),
+ 777)
+ << "hello world";
+}
+
TEST(TailCallsModifiesTest, NoPrefix) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
@@ -159,8 +169,8 @@
ENCODED_MESSAGE(MatchesEvent(
Eq("fake/file"), Eq(123), Eq(absl::UnixEpoch()),
Eq(logging::proto::WARNING), Eq(456),
- ElementsAre(EqualsProto(R"pb(literal: "forwarded: ")pb"),
- EqualsProto(R"pb(str: "hello world")pb")))))));
+ ElementsAre(ValueWithLiteral(Eq("forwarded: ")),
+ ValueWithStr(Eq("hello world"))))))));
test_sink.StartCapturingLogs();
LOG(WARNING)
@@ -178,18 +188,17 @@
EXPECT_CALL(
test_sink,
- Send(AllOf(TextMessage(AnyOf(Eq("hello world: Bad file number [9]"),
- Eq("hello world: Bad file descriptor [9]"),
- Eq("hello world: Bad file descriptor [8]"))),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(literal: "hello world")pb"),
- EqualsProto(R"pb(literal: ": ")pb"),
- AnyOf(EqualsProto(R"pb(str: "Bad file number")pb"),
- EqualsProto(R"pb(str: "Bad file descriptor")pb")),
- EqualsProto(R"pb(literal: " [")pb"),
- AnyOf(EqualsProto(R"pb(str: "8")pb"),
- EqualsProto(R"pb(str: "9")pb")),
- EqualsProto(R"pb(literal: "]")pb")))))));
+ Send(AllOf(
+ TextMessage(AnyOf(Eq("hello world: Bad file number [9]"),
+ Eq("hello world: Bad file descriptor [9]"),
+ Eq("hello world: Bad file descriptor [8]"))),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithLiteral(Eq("hello world")), ValueWithLiteral(Eq(": ")),
+ AnyOf(ValueWithStr(Eq("Bad file number")),
+ ValueWithStr(Eq("Bad file descriptor"))),
+ ValueWithLiteral(Eq(" [")),
+ AnyOf(ValueWithStr(Eq("8")), ValueWithStr(Eq("9"))),
+ ValueWithLiteral(Eq("]"))))))));
test_sink.StartCapturingLogs();
errno = EBADF;
diff --git a/absl/log/log_sink_registry.h b/absl/log/log_sink_registry.h
index bf76cce..a3fa9a3 100644
--- a/absl/log/log_sink_registry.h
+++ b/absl/log/log_sink_registry.h
@@ -22,6 +22,7 @@
#define ABSL_LOG_LOG_SINK_REGISTRY_H_
#include "absl/base/config.h"
+#include "absl/base/nullability.h"
#include "absl/log/internal/log_sink_set.h"
#include "absl/log/log_sink.h"
@@ -43,8 +44,10 @@
// sink instead which writes them to `stderr`.
//
// Do not call these inside `absl::LogSink::Send`.
-inline void AddLogSink(absl::LogSink* sink) { log_internal::AddLogSink(sink); }
-inline void RemoveLogSink(absl::LogSink* sink) {
+inline void AddLogSink(absl::LogSink* absl_nonnull sink) {
+ log_internal::AddLogSink(sink);
+}
+inline void RemoveLogSink(absl::LogSink* absl_nonnull sink) {
log_internal::RemoveLogSink(sink);
}
diff --git a/absl/log/log_streamer_test.cc b/absl/log/log_streamer_test.cc
index b9b9428..4fe88e9 100644
--- a/absl/log/log_streamer_test.cc
+++ b/absl/log/log_streamer_test.cc
@@ -69,17 +69,17 @@
EXPECT_CALL(
test_sink,
- Send(AllOf(
- SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
- Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kInfo)),
- Timestamp(InMatchWindow()),
- ThreadID(Eq(absl::base_internal::GetTID())),
- TextMessage(Eq("WriteToStream: foo")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), InMatchWindow(),
- Eq(logging::proto::INFO), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(str: "WriteToStream: foo")pb")))),
- Stacktrace(IsEmpty()))));
+ Send(
+ AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kInfo)),
+ Timestamp(InMatchWindow()),
+ ThreadID(Eq(absl::base_internal::GetTID())),
+ TextMessage(Eq("WriteToStream: foo")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), InMatchWindow(),
+ Eq(logging::proto::INFO), Eq(absl::base_internal::GetTID()),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
WriteToStream("foo", &absl::LogInfoStreamer("path/file.cc", 1234).stream());
@@ -99,7 +99,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq("path/file.cc"), Eq(1234), InMatchWindow(),
Eq(logging::proto::WARNING), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(str: "WriteToStream: foo")pb")))),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))),
Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
@@ -121,7 +121,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq("path/file.cc"), Eq(1234), InMatchWindow(),
Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(str: "WriteToStream: foo")pb")))),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))),
Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
@@ -138,19 +138,19 @@
.Times(AnyNumber())
.WillRepeatedly(DeathTestUnexpectedLogging());
- EXPECT_CALL(test_sink,
- Send(AllOf(SourceFilename(Eq("path/file.cc")),
- SourceLine(Eq(1234)), Prefix(IsTrue()),
- LogSeverity(Eq(absl::LogSeverity::kFatal)),
- Timestamp(InMatchWindow()),
- ThreadID(Eq(absl::base_internal::GetTID())),
- TextMessage(Eq("WriteToStream: foo")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234),
- InMatchWindow(), Eq(logging::proto::FATAL),
- Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(str: "WriteToStream: foo")pb")))))))
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
+ Timestamp(InMatchWindow()),
+ ThreadID(Eq(absl::base_internal::GetTID())),
+ TextMessage(Eq("WriteToStream: foo")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), InMatchWindow(),
+ Eq(logging::proto::FATAL),
+ Eq(absl::base_internal::GetTID()),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))))))
.WillOnce(DeathTestExpectedLogging());
test_sink.StartCapturingLogs();
@@ -176,7 +176,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq("path/file.cc"), Eq(1234), InMatchWindow(),
Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(str: "WriteToStream: foo")pb")))),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))),
Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
@@ -193,19 +193,19 @@
.Times(AnyNumber())
.WillRepeatedly(DeathTestUnexpectedLogging());
- EXPECT_CALL(test_sink,
- Send(AllOf(SourceFilename(Eq("path/file.cc")),
- SourceLine(Eq(1234)), Prefix(IsTrue()),
- LogSeverity(Eq(absl::LogSeverity::kFatal)),
- Timestamp(InMatchWindow()),
- ThreadID(Eq(absl::base_internal::GetTID())),
- TextMessage(Eq("WriteToStream: foo")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234),
- InMatchWindow(), Eq(logging::proto::FATAL),
- Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(str: "WriteToStream: foo")pb")))))))
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
+ Timestamp(InMatchWindow()),
+ ThreadID(Eq(absl::base_internal::GetTID())),
+ TextMessage(Eq("WriteToStream: foo")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), InMatchWindow(),
+ Eq(logging::proto::FATAL),
+ Eq(absl::base_internal::GetTID()),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))))))
.WillOnce(DeathTestExpectedLogging());
test_sink.StartCapturingLogs();
@@ -230,7 +230,7 @@
ENCODED_MESSAGE(MatchesEvent(
Eq("path/file.cc"), Eq(1234), InMatchWindow(),
Eq(logging::proto::ERROR), Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(R"pb(str: "WriteToStream: foo")pb")))),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))),
Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
@@ -249,19 +249,19 @@
.Times(AnyNumber())
.WillRepeatedly(DeathTestUnexpectedLogging());
- EXPECT_CALL(test_sink,
- Send(AllOf(SourceFilename(Eq("path/file.cc")),
- SourceLine(Eq(1234)), Prefix(IsTrue()),
- LogSeverity(Eq(absl::LogSeverity::kFatal)),
- Timestamp(InMatchWindow()),
- ThreadID(Eq(absl::base_internal::GetTID())),
- TextMessage(Eq("WriteToStream: foo")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234),
- InMatchWindow(), Eq(logging::proto::FATAL),
- Eq(absl::base_internal::GetTID()),
- ElementsAre(EqualsProto(
- R"pb(str: "WriteToStream: foo")pb")))))))
+ EXPECT_CALL(
+ test_sink,
+ Send(AllOf(
+ SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ Prefix(IsTrue()), LogSeverity(Eq(absl::LogSeverity::kFatal)),
+ Timestamp(InMatchWindow()),
+ ThreadID(Eq(absl::base_internal::GetTID())),
+ TextMessage(Eq("WriteToStream: foo")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), InMatchWindow(),
+ Eq(logging::proto::FATAL),
+ Eq(absl::base_internal::GetTID()),
+ ElementsAre(ValueWithStr(Eq("WriteToStream: foo"))))))))
.WillOnce(DeathTestExpectedLogging());
test_sink.StartCapturingLogs();
@@ -278,13 +278,12 @@
EXPECT_CALL(
test_sink,
- Send(AllOf(
- SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
- TextMessage(Eq("WriteToStreamRef: foo")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), _, _, _,
- ElementsAre(EqualsProto(R"pb(str: "WriteToStreamRef: foo")pb")))),
- Stacktrace(IsEmpty()))));
+ Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ TextMessage(Eq("WriteToStreamRef: foo")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), _, _, _,
+ ElementsAre(ValueWithStr(Eq("WriteToStreamRef: foo"))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
WriteToStreamRef("foo", absl::LogInfoStreamer("path/file.cc", 1234).stream());
@@ -303,14 +302,13 @@
// test would fail.
EXPECT_CALL(
test_sink,
- Send(AllOf(
- SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
- TextMessage(Eq("WriteToStream: foo WriteToStreamRef: bar")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), _, _, _,
- ElementsAre(EqualsProto(
- R"pb(str: "WriteToStream: foo WriteToStreamRef: bar")pb")))),
- Stacktrace(IsEmpty()))));
+ Send(AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ TextMessage(Eq("WriteToStream: foo WriteToStreamRef: bar")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), _, _, _,
+ ElementsAre(ValueWithStr(
+ Eq("WriteToStream: foo WriteToStreamRef: bar"))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
}
@@ -331,13 +329,12 @@
TEST(LogStreamerTest, LogsEmptyLine) {
absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected);
- EXPECT_CALL(test_sink,
- Send(AllOf(SourceFilename(Eq("path/file.cc")),
- SourceLine(Eq(1234)), TextMessage(Eq("")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), _, _, _,
- ElementsAre(EqualsProto(R"pb(str: "")pb")))),
- Stacktrace(IsEmpty()))));
+ EXPECT_CALL(test_sink, Send(AllOf(SourceFilename(Eq("path/file.cc")),
+ SourceLine(Eq(1234)), TextMessage(Eq("")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), _, _, _,
+ ElementsAre(ValueWithStr(Eq(""))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
absl::LogInfoStreamer("path/file.cc", 1234);
@@ -356,9 +353,9 @@
EXPECT_CALL(
test_sink,
Send(AllOf(SourceFilename(Eq("path/file.cc")), TextMessage(Eq("")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), _, _, _, _,
- ElementsAre(EqualsProto(R"pb(str: "")pb")))))))
+ ENCODED_MESSAGE(
+ MatchesEvent(Eq("path/file.cc"), _, _, _, _,
+ ElementsAre(ValueWithStr(Eq(""))))))))
.WillOnce(DeathTestExpectedLogging());
test_sink.StartCapturingLogs();
@@ -374,14 +371,14 @@
EXPECT_CALL(
test_sink,
- Send(AllOf(
- SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
- LogSeverity(Eq(absl::LogSeverity::kInfo)),
- TextMessage(Eq("hello 0x10 world 0x10")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), _, Eq(logging::proto::INFO), _,
- ElementsAre(EqualsProto(R"pb(str: "hello 0x10 world 0x10")pb")))),
- Stacktrace(IsEmpty()))));
+ Send(
+ AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ LogSeverity(Eq(absl::LogSeverity::kInfo)),
+ TextMessage(Eq("hello 0x10 world 0x10")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), _, Eq(logging::proto::INFO),
+ _, ElementsAre(ValueWithStr(Eq("hello 0x10 world 0x10"))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
@@ -402,18 +399,18 @@
TextMessage(Eq("something else")),
ENCODED_MESSAGE(MatchesEvent(
Eq("path/file2.cc"), Eq(5678), _, Eq(logging::proto::WARNING), _,
- ElementsAre(EqualsProto(R"pb(str: "something else")pb")))),
+ ElementsAre(ValueWithStr(Eq("something else"))))),
Stacktrace(IsEmpty()))));
EXPECT_CALL(
test_sink,
- Send(AllOf(
- SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
- LogSeverity(Eq(absl::LogSeverity::kInfo)),
- TextMessage(Eq("hello 0x10 world 0x10")),
- ENCODED_MESSAGE(MatchesEvent(
- Eq("path/file.cc"), Eq(1234), _, Eq(logging::proto::INFO), _,
- ElementsAre(EqualsProto(R"pb(str: "hello 0x10 world 0x10")pb")))),
- Stacktrace(IsEmpty()))));
+ Send(
+ AllOf(SourceFilename(Eq("path/file.cc")), SourceLine(Eq(1234)),
+ LogSeverity(Eq(absl::LogSeverity::kInfo)),
+ TextMessage(Eq("hello 0x10 world 0x10")),
+ ENCODED_MESSAGE(MatchesEvent(
+ Eq("path/file.cc"), Eq(1234), _, Eq(logging::proto::INFO),
+ _, ElementsAre(ValueWithStr(Eq("hello 0x10 world 0x10"))))),
+ Stacktrace(IsEmpty()))));
test_sink.StartCapturingLogs();
auto streamer1 = absl::LogInfoStreamer("path/file.cc", 1234);
diff --git a/absl/log/scoped_mock_log.h b/absl/log/scoped_mock_log.h
index 399e604..a383066 100644
--- a/absl/log/scoped_mock_log.h
+++ b/absl/log/scoped_mock_log.h
@@ -40,8 +40,8 @@
// ScopedMockLog
//
-// ScopedMockLog is a LogSink that intercepts LOG() messages issued during its
-// lifespan.
+// ScopedMockLog is a LogSink that intercepts LOG() messages issued by all
+// threads when active.
//
// Using this together with GoogleTest, it's easy to test how a piece of code
// calls LOG(). The typical usage, noting the distinction between
diff --git a/absl/log/structured.h b/absl/log/structured.h
index 9ad69fb..89d241e 100644
--- a/absl/log/structured.h
+++ b/absl/log/structured.h
@@ -32,6 +32,7 @@
#include <ostream>
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/log/internal/structured.h"
#include "absl/strings/string_view.h"
@@ -60,7 +61,11 @@
// int line) {
// LOG(LEVEL(severity)).AtLocation(file, line) << absl::LogAsLiteral(str);
// }
-inline log_internal::AsLiteralImpl LogAsLiteral(absl::string_view s) {
+//
+// `LogAsLiteral` should only be used as a streaming operand and not, for
+// example, as a local variable initializer.
+inline log_internal::AsLiteralImpl LogAsLiteral(
+ absl::string_view s ABSL_ATTRIBUTE_LIFETIME_BOUND) {
return log_internal::AsLiteralImpl(s);
}
diff --git a/absl/log/structured_test.cc b/absl/log/structured_test.cc
index 6f1df18..9fe0756 100644
--- a/absl/log/structured_test.cc
+++ b/absl/log/structured_test.cc
@@ -51,11 +51,10 @@
absl::ScopedMockLog sink;
- EXPECT_CALL(sink,
- Send(AllOf(TextMessage(MatchesOstream(stream)),
- TextMessage(Eq("hello world")),
- ENCODED_MESSAGE(HasValues(ElementsAre(
- EqualsProto(R"pb(literal: "hello world")pb")))))));
+ EXPECT_CALL(sink, Send(AllOf(TextMessage(MatchesOstream(stream)),
+ TextMessage(Eq("hello world")),
+ ENCODED_MESSAGE(HasValues(ElementsAre(
+ ValueWithLiteral(Eq("hello world"))))))));
sink.StartCapturingLogs();
LOG(INFO) << absl::LogAsLiteral(not_a_literal);
diff --git a/absl/log/vlog_is_on.h b/absl/log/vlog_is_on.h
index f7539df..c33fcc1 100644
--- a/absl/log/vlog_is_on.h
+++ b/absl/log/vlog_is_on.h
@@ -40,6 +40,8 @@
// last . and everything after it) is stripped from each filename prior to
// matching, as is the special suffix "-inl".
//
+// Example: --vmodule=module_a=1,module_b=2
+//
// Files are matched against globs in `--vmodule` in order, and the first match
// determines the verbosity level.
//
diff --git a/absl/log/vlog_is_on_test.cc b/absl/log/vlog_is_on_test.cc
index 883d798..f612283 100644
--- a/absl/log/vlog_is_on_test.cc
+++ b/absl/log/vlog_is_on_test.cc
@@ -44,7 +44,23 @@
#endif
}
-TEST(VLogIsOn, GlobalWorksWithoutMaxVerbosityAndMinLogLevel) {
+// This fixture is used to reset the VLOG levels to their default values before
+// each test.
+class VLogIsOnTest : public ::testing::Test {
+ protected:
+ void SetUp() override { ResetVLogLevels(); }
+
+ private:
+ // Resets the VLOG levels to their default values.
+ // It is supposed to be called in the SetUp() method of the test fixture to
+ // eliminate any side effects from other tests.
+ static void ResetVLogLevels() {
+ absl::log_internal::UpdateVModule("");
+ absl::SetGlobalVLogLevel(0);
+ }
+};
+
+TEST_F(VLogIsOnTest, GlobalWorksWithoutMaxVerbosityAndMinLogLevel) {
if (MaxLogVerbosity().has_value() || MinLogLevel().has_value()) {
GTEST_SKIP();
}
@@ -59,7 +75,7 @@
VLOG(4) << "spam";
}
-TEST(VLogIsOn, FileWorksWithoutMaxVerbosityAndMinLogLevel) {
+TEST_F(VLogIsOnTest, FileWorksWithoutMaxVerbosityAndMinLogLevel) {
if (MaxLogVerbosity().has_value() || MinLogLevel().has_value()) {
GTEST_SKIP();
}
@@ -74,7 +90,7 @@
VLOG(4) << "spam";
}
-TEST(VLogIsOn, PatternWorksWithoutMaxVerbosityAndMinLogLevel) {
+TEST_F(VLogIsOnTest, PatternWorksWithoutMaxVerbosityAndMinLogLevel) {
if (MaxLogVerbosity().has_value() || MinLogLevel().has_value()) {
GTEST_SKIP();
}
@@ -89,7 +105,48 @@
VLOG(4) << "spam";
}
-TEST(VLogIsOn, GlobalDoesNotFilterBelowMaxVerbosity) {
+TEST_F(VLogIsOnTest,
+ PatternOverridesLessGenericOneWithoutMaxVerbosityAndMinLogLevel) {
+ if (MaxLogVerbosity().has_value() || MinLogLevel().has_value()) {
+ GTEST_SKIP();
+ }
+
+ // This should disable logging in this file
+ absl::SetVLogLevel("vlog_is_on*", -1);
+ // This overrides the previous setting, because "vlog*" is more generic than
+ // "vlog_is_on*". This should enable VLOG level 3 in this file.
+ absl::SetVLogLevel("vlog*", 3);
+ absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected);
+
+ EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "important"));
+
+ log.StartCapturingLogs();
+ VLOG(3) << "important";
+ VLOG(4) << "spam";
+}
+
+TEST_F(VLogIsOnTest,
+ PatternDoesNotOverridesMoreGenericOneWithoutMaxVerbosityAndMinLogLevel) {
+ if (MaxLogVerbosity().has_value() || MinLogLevel().has_value()) {
+ GTEST_SKIP();
+ }
+
+ // This should enable VLOG level 3 in this file.
+ absl::SetVLogLevel("vlog*", 3);
+ // This should not change the VLOG level in this file. The pattern does not
+ // match this file and it is less generic than the previous patter "vlog*".
+ // Therefore, it does not disable VLOG level 3 in this file.
+ absl::SetVLogLevel("vlog_is_on_some_other_test*", -1);
+ absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected);
+
+ EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "important"));
+
+ log.StartCapturingLogs();
+ VLOG(3) << "important";
+ VLOG(5) << "spam";
+}
+
+TEST_F(VLogIsOnTest, GlobalDoesNotFilterBelowMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() < 2) {
GTEST_SKIP();
}
@@ -104,7 +161,7 @@
VLOG(2) << "asdf";
}
-TEST(VLogIsOn, FileDoesNotFilterBelowMaxVerbosity) {
+TEST_F(VLogIsOnTest, FileDoesNotFilterBelowMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() < 2) {
GTEST_SKIP();
}
@@ -119,7 +176,7 @@
VLOG(2) << "asdf";
}
-TEST(VLogIsOn, PatternDoesNotFilterBelowMaxVerbosity) {
+TEST_F(VLogIsOnTest, PatternDoesNotFilterBelowMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() < 2) {
GTEST_SKIP();
}
@@ -134,7 +191,7 @@
VLOG(2) << "asdf";
}
-TEST(VLogIsOn, GlobalFiltersAboveMaxVerbosity) {
+TEST_F(VLogIsOnTest, GlobalFiltersAboveMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() >= 4) {
GTEST_SKIP();
}
@@ -147,7 +204,7 @@
VLOG(4) << "dfgh";
}
-TEST(VLogIsOn, FileFiltersAboveMaxVerbosity) {
+TEST_F(VLogIsOnTest, FileFiltersAboveMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() >= 4) {
GTEST_SKIP();
}
@@ -160,7 +217,7 @@
VLOG(4) << "dfgh";
}
-TEST(VLogIsOn, PatternFiltersAboveMaxVerbosity) {
+TEST_F(VLogIsOnTest, PatternFiltersAboveMaxVerbosity) {
if (!MaxLogVerbosity().has_value() || *MaxLogVerbosity() >= 4) {
GTEST_SKIP();
}
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
index 4573f17..d50a502 100644
--- a/absl/memory/BUILD.bazel
+++ b/absl/memory/BUILD.bazel
@@ -54,7 +54,7 @@
deps = [
":memory",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index cf5df9b..d01cb8a 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -53,7 +53,7 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index ded5582..02c1e63 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -38,6 +38,7 @@
#include <cstddef>
#include <functional>
#include <string>
+#include <string_view>
#include <type_traits>
#include <vector>
@@ -48,10 +49,6 @@
#include <span> // NOLINT(build/c++20)
#endif
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
// Defines the default alignment. `__STDCPP_DEFAULT_NEW_ALIGNMENT__` is a C++17
// feature.
#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__)
@@ -97,22 +94,6 @@
template <template <class...> class Op, class... Args>
struct is_detected : is_detected_impl<void, Op, Args...>::type {};
-template <class Enabler, class To, template <class...> class Op, class... Args>
-struct is_detected_convertible_impl {
- using type = std::false_type;
-};
-
-template <class To, template <class...> class Op, class... Args>
-struct is_detected_convertible_impl<
- typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
- To, Op, Args...> {
- using type = std::true_type;
-};
-
-template <class To, template <class...> class Op, class... Args>
-struct is_detected_convertible
- : is_detected_convertible_impl<void, To, Op, Args...>::type {};
-
} // namespace type_traits_internal
// void_t()
@@ -121,96 +102,32 @@
// metafunction allows you to create a general case that maps to `void` while
// allowing specializations that map to specific types.
//
-// This metafunction is designed to be a drop-in replacement for the C++17
-// `std::void_t` metafunction.
-//
-// NOTE: `absl::void_t` does not use the standard-specified implementation so
-// that it can remain compatible with gcc < 5.1. This can introduce slightly
-// different behavior, such as when ordering partial specializations.
+// This metafunction is not 100% compatible with the C++17 `std::void_t`
+// metafunction. It has slightly different behavior, such as when ordering
+// partial specializations. It is recommended to use `std::void_t` instead.
template <typename... Ts>
using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
-// conjunction
-//
-// Performs a compile-time logical AND operation on the passed types (which
-// must have `::value` members convertible to `bool`. Short-circuits if it
-// encounters any `false` members (and does not compare the `::value` members
-// of any remaining arguments).
-//
-// This metafunction is designed to be a drop-in replacement for the C++17
-// `std::conjunction` metafunction.
-template <typename... Ts>
-struct conjunction : std::true_type {};
-
-template <typename T, typename... Ts>
-struct conjunction<T, Ts...>
- : std::conditional<T::value, conjunction<Ts...>, T>::type {};
-
-template <typename T>
-struct conjunction<T> : T {};
-
-// disjunction
-//
-// Performs a compile-time logical OR operation on the passed types (which
-// must have `::value` members convertible to `bool`. Short-circuits if it
-// encounters any `true` members (and does not compare the `::value` members
-// of any remaining arguments).
-//
-// This metafunction is designed to be a drop-in replacement for the C++17
-// `std::disjunction` metafunction.
-template <typename... Ts>
-struct disjunction : std::false_type {};
-
-template <typename T, typename... Ts>
-struct disjunction<T, Ts...>
- : std::conditional<T::value, T, disjunction<Ts...>>::type {};
-
-template <typename T>
-struct disjunction<T> : T {};
-
-// negation
-//
-// Performs a compile-time logical NOT operation on the passed type (which
-// must have `::value` members convertible to `bool`.
-//
-// This metafunction is designed to be a drop-in replacement for the C++17
-// `std::negation` metafunction.
-template <typename T>
-struct negation : std::integral_constant<bool, !T::value> {};
-
-// is_function()
-//
-// Determines whether the passed type `T` is a function type.
-//
-// This metafunction is designed to be a drop-in replacement for the C++11
-// `std::is_function()` metafunction for platforms that have incomplete C++11
-// support (such as libstdc++ 4.x).
-//
-// This metafunction works because appending `const` to a type does nothing to
-// function types and reference types (and forms a const-qualified type
-// otherwise).
-template <typename T>
-struct is_function
- : std::integral_constant<
- bool, !(std::is_reference<T>::value ||
- std::is_const<typename std::add_const<T>::type>::value)> {};
-
-// is_copy_assignable()
-// is_move_assignable()
-// is_trivially_destructible()
-// is_trivially_default_constructible()
-// is_trivially_move_constructible()
-// is_trivially_copy_constructible()
-// is_trivially_move_assignable()
-// is_trivially_copy_assignable()
-//
// Historical note: Abseil once provided implementations of these type traits
// for platforms that lacked full support. New code should prefer to use the
// std variants.
//
// See the documentation for the STL <type_traits> header for more information:
// https://en.cppreference.com/w/cpp/header/type_traits
+using std::add_const_t;
+using std::add_cv_t;
+using std::add_lvalue_reference_t;
+using std::add_pointer_t;
+using std::add_rvalue_reference_t;
+using std::add_volatile_t;
+using std::common_type_t;
+using std::conditional_t;
+using std::conjunction;
+using std::decay_t;
+using std::enable_if_t;
+using std::disjunction;
using std::is_copy_assignable;
+using std::is_function;
using std::is_move_assignable;
using std::is_trivially_copy_assignable;
using std::is_trivially_copy_constructible;
@@ -218,6 +135,17 @@
using std::is_trivially_destructible;
using std::is_trivially_move_assignable;
using std::is_trivially_move_constructible;
+using std::make_signed_t;
+using std::make_unsigned_t;
+using std::negation;
+using std::remove_all_extents_t;
+using std::remove_const_t;
+using std::remove_cv_t;
+using std::remove_extent_t;
+using std::remove_pointer_t;
+using std::remove_reference_t;
+using std::remove_volatile_t;
+using std::underlying_type_t;
#if defined(__cpp_lib_remove_cvref) && __cpp_lib_remove_cvref >= 201711L
template <typename T>
@@ -240,70 +168,6 @@
using remove_cvref_t = typename remove_cvref<T>::type;
#endif
-// -----------------------------------------------------------------------------
-// C++14 "_t" trait aliases
-// -----------------------------------------------------------------------------
-
-template <typename T>
-using remove_cv_t = typename std::remove_cv<T>::type;
-
-template <typename T>
-using remove_const_t = typename std::remove_const<T>::type;
-
-template <typename T>
-using remove_volatile_t = typename std::remove_volatile<T>::type;
-
-template <typename T>
-using add_cv_t = typename std::add_cv<T>::type;
-
-template <typename T>
-using add_const_t = typename std::add_const<T>::type;
-
-template <typename T>
-using add_volatile_t = typename std::add_volatile<T>::type;
-
-template <typename T>
-using remove_reference_t = typename std::remove_reference<T>::type;
-
-template <typename T>
-using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
-
-template <typename T>
-using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
-
-template <typename T>
-using remove_pointer_t = typename std::remove_pointer<T>::type;
-
-template <typename T>
-using add_pointer_t = typename std::add_pointer<T>::type;
-
-template <typename T>
-using make_signed_t = typename std::make_signed<T>::type;
-
-template <typename T>
-using make_unsigned_t = typename std::make_unsigned<T>::type;
-
-template <typename T>
-using remove_extent_t = typename std::remove_extent<T>::type;
-
-template <typename T>
-using remove_all_extents_t = typename std::remove_all_extents<T>::type;
-
-template <typename T>
-using decay_t = typename std::decay<T>::type;
-
-template <bool B, typename T = void>
-using enable_if_t = typename std::enable_if<B, T>::type;
-
-template <bool B, typename T, typename F>
-using conditional_t = typename std::conditional<B, T, F>::type;
-
-template <typename... T>
-using common_type_t = typename std::common_type<T...>::type;
-
-template <typename T>
-using underlying_type_t = typename std::underlying_type<T>::type;
-
namespace type_traits_internal {
#if (defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703L) || \
@@ -460,11 +324,17 @@
// absl::is_trivially_relocatable<T>
//
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2786r11.html
+//
// Detects whether a type is known to be "trivially relocatable" -- meaning it
// can be relocated from one place to another as if by memcpy/memmove.
// This implies that its object representation doesn't depend on its address,
// and also none of its special member functions do anything strange.
//
+// Note that when relocating the caller code should ensure that if the object is
+// polymorphic, the dynamic type is of the most derived type. Padding bytes
+// should not be copied.
+//
// This trait is conservative. If it's true then the type is definitely
// trivially relocatable, but if it's false then the type may or may not be. For
// example, std::vector<int> is trivially relocatable on every known STL
@@ -482,11 +352,7 @@
//
// Upstream documentation:
//
-// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__is_trivially_relocatable
-
-// If the compiler offers a builtin that tells us the answer, we can use that.
-// This covers all of the cases in the fallback below, plus types that opt in
-// using e.g. [[clang::trivial_abi]].
+// https://clang.llvm.org/docs/LanguageExtensions.html#:~:text=__builtin_is_cpp_trivially_relocatable
//
// Clang on Windows has the builtin, but it falsely claims types with a
// user-provided destructor are trivial (http://b/275003464). So we opt out
@@ -503,19 +369,36 @@
// remove the condition.
//
// Clang on all platforms fails to detect that a type with a user-provided
-// move-assignment operator is not trivially relocatable. So in fact we
-// opt out of Clang altogether, for now.
+// move-assignment operator is not trivially relocatable so we also check for
+// is_trivially_move_assignable for Clang.
//
-// TODO(b/325479096): Remove the opt-out once Clang's behavior is fixed.
+// TODO(b/325479096): Remove the Clang is_trivially_move_assignable version once
+// Clang's behavior is fixed.
//
// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not
// work with NVCC either.
-#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
- (defined(__cpp_impl_trivially_relocatable) || \
- (!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__)))
+#if ABSL_HAVE_BUILTIN(__builtin_is_cpp_trivially_relocatable)
+// https://github.com/llvm/llvm-project/pull/127636#pullrequestreview-2637005293
+// In the current implementation, __builtin_is_cpp_trivially_relocatable will
+// only return true for types that are trivially relocatable according to the
+// standard. Notably, this means that marking a type [[clang::trivial_abi]] aka
+// ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI will have no effect on this trait.
template <class T>
struct is_trivially_relocatable
- : std::integral_constant<bool, __is_trivially_relocatable(T)> {};
+ : std::integral_constant<bool, __builtin_is_cpp_trivially_relocatable(T)> {
+};
+#elif ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && defined(__clang__) && \
+ !(defined(_WIN32) || defined(_WIN64)) && !defined(__APPLE__) && \
+ !defined(__NVCC__)
+// https://github.com/llvm/llvm-project/pull/139061
+// __is_trivially_relocatable is deprecated.
+// TODO(b/325479096): Remove this case.
+template <class T>
+struct is_trivially_relocatable
+ : std::integral_constant<
+ bool, std::is_trivially_copyable<T>::value ||
+ (__is_trivially_relocatable(T) &&
+ std::is_trivially_move_assignable<T>::value)> {};
#else
// Otherwise we use a fallback that detects only those types we can feasibly
// detect. Any type that is trivially copyable is by definition trivially
@@ -630,10 +513,8 @@
struct IsView : std::integral_constant<bool, std::is_pointer<T>::value ||
IsViewImpl<T>::value> {};
-#ifdef ABSL_HAVE_STD_STRING_VIEW
template <typename Char, typename Traits>
struct IsView<std::basic_string_view<Char, Traits>> : std::true_type {};
-#endif
#ifdef __cpp_lib_span
template <typename T>
@@ -648,9 +529,9 @@
// Until then, we consider an assignment from an "owner" (such as std::string)
// to a "view" (such as std::string_view) to be a lifetime-bound assignment.
template <typename T, typename U>
-using IsLifetimeBoundAssignment =
- std::integral_constant<bool, IsView<absl::remove_cvref_t<T>>::value &&
- IsOwner<absl::remove_cvref_t<U>>::value>;
+using IsLifetimeBoundAssignment = absl::conjunction<
+ std::integral_constant<bool, !std::is_lvalue_reference<U>::value>,
+ IsOwner<absl::remove_cvref_t<U>>, IsView<absl::remove_cvref_t<T>>>;
} // namespace type_traits_internal
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index 1e056bb..3d55a00 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -16,6 +16,7 @@
#include <cstdint>
#include <string>
+#include <string_view>
#include <type_traits>
#include <utility>
#include <vector>
@@ -26,10 +27,6 @@
#include "absl/time/clock.h"
#include "absl/time/time.h"
-#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
-#endif
-
namespace {
using ::testing::StaticAssertTypeEq;
@@ -45,12 +42,10 @@
"string is an owner, not a view");
static_assert(IsOwnerAndNotView<std::wstring>::value,
"wstring is an owner, not a view");
-#ifdef ABSL_HAVE_STD_STRING_VIEW
static_assert(!IsOwnerAndNotView<std::string_view>::value,
"string_view is a view, not an owner");
static_assert(!IsOwnerAndNotView<std::wstring_view>::value,
"wstring_view is a view, not an owner");
-#endif
template <class T, class U>
struct simple_pair {
@@ -90,10 +85,6 @@
using BarIsCallable =
absl::type_traits_internal::is_detected<BarIsCallableImpl, Class, T...>;
-template <class Class, class... T>
-using BarIsCallableConv = absl::type_traits_internal::is_detected_convertible<
- ReturnType, BarIsCallableImpl, Class, T...>;
-
// NOTE: Test of detail type_traits_internal::is_detected.
TEST(IsDetectedTest, BasicUsage) {
EXPECT_TRUE((BarIsCallable<TypeWithBarFunction, StructA&, const StructB&,
@@ -110,286 +101,11 @@
StructC>::value));
}
-// NOTE: Test of detail type_traits_internal::is_detected_convertible.
-TEST(IsDetectedConvertibleTest, BasicUsage) {
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, const StructB&,
- StructC>::value));
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB&,
- StructC>::value));
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB,
- StructC>::value));
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
- StructA&, const StructB&, StructC>::value));
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
- StructA&, StructB&, StructC>::value));
- EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
- StructA&, StructB, StructC>::value));
-
- EXPECT_FALSE(
- (BarIsCallableConv<int, StructA&, const StructB&, StructC>::value));
- EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction&, StructA&,
- const StructB&, StructC>::value));
- EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction, StructA, const StructB&,
- StructC>::value));
- EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType&,
- StructA&, const StructB&, StructC>::value));
- EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType,
- StructA, const StructB&, StructC>::value));
-}
-
TEST(VoidTTest, BasicUsage) {
StaticAssertTypeEq<void, absl::void_t<Dummy>>();
StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>();
}
-TEST(ConjunctionTest, BasicBooleanLogic) {
- EXPECT_TRUE(absl::conjunction<>::value);
- EXPECT_TRUE(absl::conjunction<std::true_type>::value);
- EXPECT_TRUE((absl::conjunction<std::true_type, std::true_type>::value));
- EXPECT_FALSE((absl::conjunction<std::true_type, std::false_type>::value));
- EXPECT_FALSE((absl::conjunction<std::false_type, std::true_type>::value));
- EXPECT_FALSE((absl::conjunction<std::false_type, std::false_type>::value));
-}
-
-struct MyTrueType {
- static constexpr bool value = true;
-};
-
-struct MyFalseType {
- static constexpr bool value = false;
-};
-
-TEST(ConjunctionTest, ShortCircuiting) {
- EXPECT_FALSE(
- (absl::conjunction<std::true_type, std::false_type, Dummy>::value));
- EXPECT_TRUE((std::is_base_of<MyFalseType,
- absl::conjunction<std::true_type, MyFalseType,
- std::false_type>>::value));
- EXPECT_TRUE(
- (std::is_base_of<MyTrueType,
- absl::conjunction<std::true_type, MyTrueType>>::value));
-}
-
-TEST(DisjunctionTest, BasicBooleanLogic) {
- EXPECT_FALSE(absl::disjunction<>::value);
- EXPECT_FALSE(absl::disjunction<std::false_type>::value);
- EXPECT_TRUE((absl::disjunction<std::true_type, std::true_type>::value));
- EXPECT_TRUE((absl::disjunction<std::true_type, std::false_type>::value));
- EXPECT_TRUE((absl::disjunction<std::false_type, std::true_type>::value));
- EXPECT_FALSE((absl::disjunction<std::false_type, std::false_type>::value));
-}
-
-TEST(DisjunctionTest, ShortCircuiting) {
- EXPECT_TRUE(
- (absl::disjunction<std::false_type, std::true_type, Dummy>::value));
- EXPECT_TRUE((
- std::is_base_of<MyTrueType, absl::disjunction<std::false_type, MyTrueType,
- std::true_type>>::value));
- EXPECT_TRUE((
- std::is_base_of<MyFalseType,
- absl::disjunction<std::false_type, MyFalseType>>::value));
-}
-
-TEST(NegationTest, BasicBooleanLogic) {
- EXPECT_FALSE(absl::negation<std::true_type>::value);
- EXPECT_FALSE(absl::negation<MyTrueType>::value);
- EXPECT_TRUE(absl::negation<std::false_type>::value);
- EXPECT_TRUE(absl::negation<MyFalseType>::value);
-}
-
-// all member functions are trivial
-class Trivial {
- int n_;
-};
-
-struct TrivialDestructor {
- ~TrivialDestructor() = default;
-};
-
-struct NontrivialDestructor {
- ~NontrivialDestructor() {}
-};
-
-struct DeletedDestructor {
- ~DeletedDestructor() = delete;
-};
-
-class TrivialDefaultCtor {
- public:
- TrivialDefaultCtor() = default;
- explicit TrivialDefaultCtor(int n) : n_(n) {}
-
- private:
- int n_;
-};
-
-class NontrivialDefaultCtor {
- public:
- NontrivialDefaultCtor() : n_(1) {}
-
- private:
- int n_;
-};
-
-class DeletedDefaultCtor {
- public:
- DeletedDefaultCtor() = delete;
- explicit DeletedDefaultCtor(int n) : n_(n) {}
-
- private:
- int n_;
-};
-
-class TrivialMoveCtor {
- public:
- explicit TrivialMoveCtor(int n) : n_(n) {}
- TrivialMoveCtor(TrivialMoveCtor&&) = default;
- TrivialMoveCtor& operator=(const TrivialMoveCtor& t) {
- n_ = t.n_;
- return *this;
- }
-
- private:
- int n_;
-};
-
-class NontrivialMoveCtor {
- public:
- explicit NontrivialMoveCtor(int n) : n_(n) {}
- NontrivialMoveCtor(NontrivialMoveCtor&& t) noexcept : n_(t.n_) {}
- NontrivialMoveCtor& operator=(const NontrivialMoveCtor&) = default;
-
- private:
- int n_;
-};
-
-class TrivialCopyCtor {
- public:
- explicit TrivialCopyCtor(int n) : n_(n) {}
- TrivialCopyCtor(const TrivialCopyCtor&) = default;
- TrivialCopyCtor& operator=(const TrivialCopyCtor& t) {
- n_ = t.n_;
- return *this;
- }
-
- private:
- int n_;
-};
-
-class NontrivialCopyCtor {
- public:
- explicit NontrivialCopyCtor(int n) : n_(n) {}
- NontrivialCopyCtor(const NontrivialCopyCtor& t) : n_(t.n_) {}
- NontrivialCopyCtor& operator=(const NontrivialCopyCtor&) = default;
-
- private:
- int n_;
-};
-
-class DeletedCopyCtor {
- public:
- explicit DeletedCopyCtor(int n) : n_(n) {}
- DeletedCopyCtor(const DeletedCopyCtor&) = delete;
- DeletedCopyCtor& operator=(const DeletedCopyCtor&) = default;
-
- private:
- int n_;
-};
-
-class TrivialMoveAssign {
- public:
- explicit TrivialMoveAssign(int n) : n_(n) {}
- TrivialMoveAssign(const TrivialMoveAssign& t) : n_(t.n_) {}
- TrivialMoveAssign& operator=(TrivialMoveAssign&&) = default;
- ~TrivialMoveAssign() {} // can have nontrivial destructor
- private:
- int n_;
-};
-
-class NontrivialMoveAssign {
- public:
- explicit NontrivialMoveAssign(int n) : n_(n) {}
- NontrivialMoveAssign(const NontrivialMoveAssign&) = default;
- NontrivialMoveAssign& operator=(NontrivialMoveAssign&& t) noexcept {
- n_ = t.n_;
- return *this;
- }
-
- private:
- int n_;
-};
-
-class TrivialCopyAssign {
- public:
- explicit TrivialCopyAssign(int n) : n_(n) {}
- TrivialCopyAssign(const TrivialCopyAssign& t) : n_(t.n_) {}
- TrivialCopyAssign& operator=(const TrivialCopyAssign& t) = default;
- ~TrivialCopyAssign() {} // can have nontrivial destructor
- private:
- int n_;
-};
-
-class NontrivialCopyAssign {
- public:
- explicit NontrivialCopyAssign(int n) : n_(n) {}
- NontrivialCopyAssign(const NontrivialCopyAssign&) = default;
- NontrivialCopyAssign& operator=(const NontrivialCopyAssign& t) {
- n_ = t.n_;
- return *this;
- }
-
- private:
- int n_;
-};
-
-class DeletedCopyAssign {
- public:
- explicit DeletedCopyAssign(int n) : n_(n) {}
- DeletedCopyAssign(const DeletedCopyAssign&) = default;
- DeletedCopyAssign& operator=(const DeletedCopyAssign&) = delete;
-
- private:
- int n_;
-};
-
-struct MovableNonCopyable {
- MovableNonCopyable() = default;
- MovableNonCopyable(const MovableNonCopyable&) = delete;
- MovableNonCopyable(MovableNonCopyable&&) = default;
- MovableNonCopyable& operator=(const MovableNonCopyable&) = delete;
- MovableNonCopyable& operator=(MovableNonCopyable&&) = default;
-};
-
-struct NonCopyableOrMovable {
- NonCopyableOrMovable() = default;
- virtual ~NonCopyableOrMovable() = default;
- NonCopyableOrMovable(const NonCopyableOrMovable&) = delete;
- NonCopyableOrMovable(NonCopyableOrMovable&&) = delete;
- NonCopyableOrMovable& operator=(const NonCopyableOrMovable&) = delete;
- NonCopyableOrMovable& operator=(NonCopyableOrMovable&&) = delete;
-};
-
-class Base {
- public:
- virtual ~Base() {}
-};
-
-TEST(TypeTraitsTest, TestIsFunction) {
- struct Callable {
- void operator()() {}
- };
- EXPECT_TRUE(absl::is_function<void()>::value);
- EXPECT_TRUE(absl::is_function<void()&>::value);
- EXPECT_TRUE(absl::is_function<void() const>::value);
- EXPECT_TRUE(absl::is_function<void() noexcept>::value);
- EXPECT_TRUE(absl::is_function<void(...) noexcept>::value);
-
- EXPECT_FALSE(absl::is_function<void (*)()>::value);
- EXPECT_FALSE(absl::is_function<void (&)()>::value);
- EXPECT_FALSE(absl::is_function<int>::value);
- EXPECT_FALSE(absl::is_function<Callable>::value);
-}
-
TEST(TypeTraitsTest, TestRemoveCVRef) {
EXPECT_TRUE(
(std::is_same<typename absl::remove_cvref<int>::type, int>::value));
@@ -418,124 +134,6 @@
int[2]>::value));
}
-#define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \
- EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \
- absl::trait_name##_t<__VA_ARGS__>>::value))
-
-TEST(TypeTraitsTest, TestRemoveCVAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const volatile int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const volatile int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const volatile int);
-}
-
-TEST(TypeTraitsTest, TestAddCVAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const volatile int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const volatile int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const volatile int);
-}
-
-TEST(TypeTraitsTest, TestReferenceAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&&);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&&);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&&);
-}
-
-TEST(TypeTraitsTest, TestPointerAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, int*);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, volatile int*);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, volatile int);
-}
-
-TEST(TypeTraitsTest, TestSignednessAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, unsigned);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile unsigned);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, unsigned);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile unsigned);
-}
-
-TEST(TypeTraitsTest, TestExtentAliases) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1][1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[][1]);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1][1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]);
-}
-
-TEST(TypeTraitsTest, TestDecay) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1][1]);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int());
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float)); // NOLINT
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...)); // NOLINT
-}
-
struct TypeA {};
struct TypeB {};
struct TypeC {};
@@ -568,36 +166,6 @@
// NOTE: TypeD is intentionally not handled
} constexpr GetType = {};
-TEST(TypeTraitsTest, TestEnableIf) {
- EXPECT_EQ(TypeEnum::A, GetType(Wrap<TypeA>()));
- EXPECT_EQ(TypeEnum::B, GetType(Wrap<TypeB>()));
- EXPECT_EQ(TypeEnum::C, GetType(Wrap<TypeC>()));
-}
-
-TEST(TypeTraitsTest, TestConditional) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, true, int, char);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, false, int, char);
-}
-
-// TODO(calabrese) Check with specialized std::common_type
-TEST(TypeTraitsTest, TestCommonType) {
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int);
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char&);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int&);
-}
-
-TEST(TypeTraitsTest, TestUnderlyingType) {
- enum class enum_char : char {};
- enum class enum_long_long : long long {}; // NOLINT(runtime/int)
-
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_char);
- ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_long_long);
-}
-
struct GetTypeExtT {
template <typename T>
absl::result_of_t<const GetTypeT&(T)> operator()(T&& arg) const {
@@ -765,29 +333,6 @@
static_assert(!absl::is_trivially_relocatable<S>::value, "");
}
-// TODO(b/275003464): remove the opt-out for Clang on Windows once
-// __is_trivially_relocatable is used there again.
-// TODO(b/324278148): remove the opt-out for Apple once
-// __is_trivially_relocatable is fixed there.
-#if defined(ABSL_HAVE_ATTRIBUTE_TRIVIAL_ABI) && \
- ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
- (defined(__cpp_impl_trivially_relocatable) || \
- (!defined(__clang__) && !defined(__APPLE__) && !defined(__NVCC__)))
-// A type marked with the "trivial ABI" attribute is trivially relocatable even
-// if it has user-provided special members.
-TEST(TriviallyRelocatable, TrivialAbi) {
- struct ABSL_ATTRIBUTE_TRIVIAL_ABI S {
- S(S&&) {} // NOLINT(modernize-use-equals-default)
- S(const S&) {} // NOLINT(modernize-use-equals-default)
- void operator=(S&&) {}
- void operator=(const S&) {}
- ~S() {} // NOLINT(modernize-use-equals-default)
- };
-
- static_assert(absl::is_trivially_relocatable<S>::value, "");
-}
-#endif
-
#ifdef ABSL_HAVE_CONSTANT_EVALUATED
constexpr int64_t NegateIfConstantEvaluated(int64_t i) {
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index f202c6e..f455d1e 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -41,6 +41,7 @@
deps = [
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/base:endian",
],
)
@@ -54,8 +55,7 @@
":bits",
"//absl/base:core_headers",
"//absl/random",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -70,8 +70,8 @@
deps = [
":bits",
"//absl/random",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -109,13 +109,14 @@
"//absl/meta:type_traits",
"//absl/strings",
"//absl/types:compare",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "int128_benchmark",
+ testonly = True,
srcs = ["int128_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -123,8 +124,8 @@
deps = [
":int128",
"//absl/base:config",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "//absl/random",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index da3b6ef..68446b0 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -23,7 +23,9 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::config
absl::core_headers
+ absl::endian
PUBLIC
)
diff --git a/absl/numeric/bits.h b/absl/numeric/bits.h
index c76454c..9a0c229 100644
--- a/absl/numeric/bits.h
+++ b/absl/numeric/bits.h
@@ -27,6 +27,10 @@
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1355r2.html
// P1956R1:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1956r1.pdf
+// P0463R1
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0463r1.html
+// P1272R4
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1272r4.html
//
// When using a standard library that implements these functions, we use the
// standard library's implementation.
@@ -45,6 +49,7 @@
#endif
#include "absl/base/attributes.h"
+#include "absl/base/internal/endian.h"
#include "absl/numeric/internal/bits.h"
namespace absl {
@@ -63,14 +68,14 @@
// Rotating functions
template <class T>
-ABSL_MUST_USE_RESULT constexpr
+[[nodiscard]] constexpr
typename std::enable_if<std::is_unsigned<T>::value, T>::type
rotl(T x, int s) noexcept {
return numeric_internal::RotateLeft(x, s);
}
template <class T>
-ABSL_MUST_USE_RESULT constexpr
+[[nodiscard]] constexpr
typename std::enable_if<std::is_unsigned<T>::value, T>::type
rotr(T x, int s) noexcept {
return numeric_internal::RotateRight(x, s);
@@ -190,6 +195,67 @@
#endif
+#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L
+
+// https://en.cppreference.com/w/cpp/types/endian
+//
+// Indicates the endianness of all scalar types:
+// * If all scalar types are little-endian, `absl::endian::native` equals
+// absl::endian::little.
+// * If all scalar types are big-endian, `absl::endian::native` equals
+// `absl::endian::big`.
+// * Platforms that use anything else are unsupported.
+using std::endian;
+
+#else
+
+enum class endian {
+ little,
+ big,
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+ native = little
+#elif defined(ABSL_IS_BIG_ENDIAN)
+ native = big
+#else
+#error "Endian detection needs to be set up for this platform"
+#endif
+};
+
+#endif // defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L
+
+#if defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L
+
+// https://en.cppreference.com/w/cpp/numeric/byteswap
+//
+// Reverses the bytes in the given integer value `x`.
+//
+// `absl::byteswap` participates in overload resolution only if `T` satisfies
+// integral, i.e., `T` is an integer type. The program is ill-formed if `T` has
+// padding bits.
+using std::byteswap;
+
+#else
+
+template <class T>
+[[nodiscard]] constexpr T byteswap(T x) noexcept {
+ static_assert(std::is_integral_v<T>,
+ "byteswap requires an integral argument");
+ static_assert(
+ sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
+ "byteswap works only with 8, 16, 32, or 64-bit integers");
+ if constexpr (sizeof(T) == 1) {
+ return x;
+ } else if constexpr (sizeof(T) == 2) {
+ return static_cast<T>(gbswap_16(static_cast<uint16_t>(x)));
+ } else if constexpr (sizeof(T) == 4) {
+ return static_cast<T>(gbswap_32(static_cast<uint32_t>(x)));
+ } else if constexpr (sizeof(T) == 8) {
+ return static_cast<T>(gbswap_64(static_cast<uint64_t>(x)));
+ }
+}
+
+#endif // defined(__cpp_lib_byteswap) && __cpp_lib_byteswap >= 202110L
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/numeric/bits_benchmark.cc b/absl/numeric/bits_benchmark.cc
index 2c89afd..429b4ca 100644
--- a/absl/numeric/bits_benchmark.cc
+++ b/absl/numeric/bits_benchmark.cc
@@ -15,10 +15,10 @@
#include <cstdint>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/optimization.h"
#include "absl/numeric/bits.h"
#include "absl/random/random.h"
+#include "benchmark/benchmark.h"
namespace absl {
namespace {
diff --git a/absl/numeric/bits_test.cc b/absl/numeric/bits_test.cc
index 14955eb..3b71ccc 100644
--- a/absl/numeric/bits_test.cc
+++ b/absl/numeric/bits_test.cc
@@ -14,6 +14,7 @@
#include "absl/numeric/bits.h"
+#include <cstdint>
#include <limits>
#include <type_traits>
@@ -636,6 +637,61 @@
static_assert(ABSL_INTERNAL_HAS_CONSTEXPR_CTZ, "ctz should be constexpr");
#endif
+TEST(Endian, Comparison) {
+#if defined(ABSL_IS_LITTLE_ENDIAN)
+ static_assert(absl::endian::native == absl::endian::little);
+ static_assert(absl::endian::native != absl::endian::big);
+#endif
+#if defined(ABSL_IS_BIG_ENDIAN)
+ static_assert(absl::endian::native != absl::endian::little);
+ static_assert(absl::endian::native == absl::endian::big);
+#endif
+}
+
+TEST(Byteswap, Constexpr) {
+ static_assert(absl::byteswap<int8_t>(0x12) == 0x12);
+ static_assert(absl::byteswap<int16_t>(0x1234) == 0x3412);
+ static_assert(absl::byteswap<int32_t>(0x12345678) == 0x78563412);
+ static_assert(absl::byteswap<int64_t>(0x123456789abcdef0) ==
+ static_cast<int64_t>(0xf0debc9a78563412));
+ static_assert(absl::byteswap<uint8_t>(0x21) == 0x21);
+ static_assert(absl::byteswap<uint16_t>(0x4321) == 0x2143);
+ static_assert(absl::byteswap<uint32_t>(0x87654321) == 0x21436587);
+ static_assert(absl::byteswap<uint64_t>(0xfedcba9876543210) ==
+ static_cast<uint64_t>(0x1032547698badcfe));
+ static_assert(absl::byteswap<int32_t>(static_cast<int32_t>(0xdeadbeef)) ==
+ static_cast<int32_t>(0xefbeadde));
+}
+
+TEST(Byteswap, NotConstexpr) {
+ int8_t a = 0x12;
+ int16_t b = 0x1234;
+ int32_t c = 0x12345678;
+ int64_t d = 0x123456789abcdef0;
+ uint8_t e = 0x21;
+ uint16_t f = 0x4321;
+ uint32_t g = 0x87654321;
+ uint64_t h = 0xfedcba9876543210;
+ EXPECT_EQ(absl::byteswap<int8_t>(a), 0x12);
+ EXPECT_EQ(absl::byteswap<int16_t>(b), 0x3412);
+ EXPECT_EQ(absl::byteswap(c), 0x78563412);
+ EXPECT_EQ(absl::byteswap(d), 0xf0debc9a78563412);
+ EXPECT_EQ(absl::byteswap<uint8_t>(e), 0x21);
+ EXPECT_EQ(absl::byteswap<uint16_t>(f), 0x2143);
+ EXPECT_EQ(absl::byteswap(g), 0x21436587);
+ EXPECT_EQ(absl::byteswap(h), 0x1032547698badcfe);
+ EXPECT_EQ(absl::byteswap(absl::byteswap<int8_t>(a)), a);
+ EXPECT_EQ(absl::byteswap(absl::byteswap<int16_t>(b)), b);
+ EXPECT_EQ(absl::byteswap(absl::byteswap(c)), c);
+ EXPECT_EQ(absl::byteswap(absl::byteswap(d)), d);
+ EXPECT_EQ(absl::byteswap(absl::byteswap<uint8_t>(e)), e);
+ EXPECT_EQ(absl::byteswap(absl::byteswap<uint16_t>(f)), f);
+ EXPECT_EQ(absl::byteswap(absl::byteswap(g)), g);
+ EXPECT_EQ(absl::byteswap(absl::byteswap(h)), h);
+ EXPECT_EQ(absl::byteswap<uint32_t>(0xdeadbeef), 0xefbeadde);
+ EXPECT_EQ(absl::byteswap<const uint32_t>(0xdeadbeef), 0xefbeadde);
+}
+
} // namespace
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
index 5d6c68d..281bf12 100644
--- a/absl/numeric/int128.cc
+++ b/absl/numeric/int128.cc
@@ -342,55 +342,3 @@
ABSL_NAMESPACE_END
} // namespace absl
-
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-namespace std {
-constexpr bool numeric_limits<absl::uint128>::is_specialized;
-constexpr bool numeric_limits<absl::uint128>::is_signed;
-constexpr bool numeric_limits<absl::uint128>::is_integer;
-constexpr bool numeric_limits<absl::uint128>::is_exact;
-constexpr bool numeric_limits<absl::uint128>::has_infinity;
-constexpr bool numeric_limits<absl::uint128>::has_quiet_NaN;
-constexpr bool numeric_limits<absl::uint128>::has_signaling_NaN;
-constexpr float_denorm_style numeric_limits<absl::uint128>::has_denorm;
-constexpr bool numeric_limits<absl::uint128>::has_denorm_loss;
-constexpr float_round_style numeric_limits<absl::uint128>::round_style;
-constexpr bool numeric_limits<absl::uint128>::is_iec559;
-constexpr bool numeric_limits<absl::uint128>::is_bounded;
-constexpr bool numeric_limits<absl::uint128>::is_modulo;
-constexpr int numeric_limits<absl::uint128>::digits;
-constexpr int numeric_limits<absl::uint128>::digits10;
-constexpr int numeric_limits<absl::uint128>::max_digits10;
-constexpr int numeric_limits<absl::uint128>::radix;
-constexpr int numeric_limits<absl::uint128>::min_exponent;
-constexpr int numeric_limits<absl::uint128>::min_exponent10;
-constexpr int numeric_limits<absl::uint128>::max_exponent;
-constexpr int numeric_limits<absl::uint128>::max_exponent10;
-constexpr bool numeric_limits<absl::uint128>::traps;
-constexpr bool numeric_limits<absl::uint128>::tinyness_before;
-
-constexpr bool numeric_limits<absl::int128>::is_specialized;
-constexpr bool numeric_limits<absl::int128>::is_signed;
-constexpr bool numeric_limits<absl::int128>::is_integer;
-constexpr bool numeric_limits<absl::int128>::is_exact;
-constexpr bool numeric_limits<absl::int128>::has_infinity;
-constexpr bool numeric_limits<absl::int128>::has_quiet_NaN;
-constexpr bool numeric_limits<absl::int128>::has_signaling_NaN;
-constexpr float_denorm_style numeric_limits<absl::int128>::has_denorm;
-constexpr bool numeric_limits<absl::int128>::has_denorm_loss;
-constexpr float_round_style numeric_limits<absl::int128>::round_style;
-constexpr bool numeric_limits<absl::int128>::is_iec559;
-constexpr bool numeric_limits<absl::int128>::is_bounded;
-constexpr bool numeric_limits<absl::int128>::is_modulo;
-constexpr int numeric_limits<absl::int128>::digits;
-constexpr int numeric_limits<absl::int128>::digits10;
-constexpr int numeric_limits<absl::int128>::max_digits10;
-constexpr int numeric_limits<absl::int128>::radix;
-constexpr int numeric_limits<absl::int128>::min_exponent;
-constexpr int numeric_limits<absl::int128>::min_exponent10;
-constexpr int numeric_limits<absl::int128>::max_exponent;
-constexpr int numeric_limits<absl::int128>::max_exponent10;
-constexpr bool numeric_limits<absl::int128>::traps;
-constexpr bool numeric_limits<absl::int128>::tinyness_before;
-} // namespace std
-#endif
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index 5a067d1..ae736b2 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -216,7 +216,11 @@
// Support for absl::Hash.
template <typename H>
friend H AbslHashValue(H h, uint128 v) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ return H::combine(std::move(h), static_cast<unsigned __int128>(v));
+#else
return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v));
+#endif
}
// Support for absl::StrCat() etc.
@@ -458,7 +462,11 @@
// Support for absl::Hash.
template <typename H>
friend H AbslHashValue(H h, int128 v) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ return H::combine(std::move(h), v.v_);
+#else
return H::combine(std::move(h), Int128High64(v), Int128Low64(v));
+#endif
}
// Support for absl::StrCat() etc.
@@ -781,16 +789,20 @@
// Conversion operators to floating point types.
inline uint128::operator float() const {
- return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64);
+ // Note: This method might return Inf.
+ constexpr float pow_2_64 = 18446744073709551616.0f;
+ return static_cast<float>(lo_) + static_cast<float>(hi_) * pow_2_64;
}
inline uint128::operator double() const {
- return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64);
+ constexpr double pow_2_64 = 18446744073709551616.0;
+ return static_cast<double>(lo_) + static_cast<double>(hi_) * pow_2_64;
}
inline uint128::operator long double() const {
+ constexpr long double pow_2_64 = 18446744073709551616.0L;
return static_cast<long double>(lo_) +
- std::ldexp(static_cast<long double>(hi_), 64);
+ static_cast<long double>(hi_) * pow_2_64;
}
// Comparison operators.
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
index eab1515..c37abec 100644
--- a/absl/numeric/int128_benchmark.cc
+++ b/absl/numeric/int128_benchmark.cc
@@ -13,31 +13,29 @@
// limitations under the License.
#include <algorithm>
+#include <cstddef>
#include <cstdint>
#include <limits>
#include <random>
+#include <type_traits>
+#include <utility>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/config.h"
#include "absl/numeric/int128.h"
+#include "absl/random/random.h"
+#include "benchmark/benchmark.h"
namespace {
constexpr size_t kSampleSize = 1000000;
-std::mt19937 MakeRandomEngine() {
- std::random_device r;
- std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
- return std::mt19937(seed);
-}
-
template <typename T,
typename H = typename std::conditional<
std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
std::vector<std::pair<T, T>> GetRandomClass128SampleUniformDivisor() {
std::vector<std::pair<T, T>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
std::uniform_int_distribution<H> uniform_h;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
@@ -77,7 +75,7 @@
std::numeric_limits<T>::is_signed, int64_t, uint64_t>::type>
std::vector<std::pair<T, H>> GetRandomClass128SampleSmallDivisor() {
std::vector<std::pair<T, H>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
std::uniform_int_distribution<H> uniform_h;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
@@ -114,7 +112,7 @@
std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
std::vector<std::pair<absl::uint128, absl::uint128>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
std::uniform_int_distribution<uint64_t> uniform_uint64;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
@@ -155,7 +153,8 @@
class UniformIntDistribution128 {
public:
// NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
- T operator()(std::mt19937& generator) {
+ template <class URBG>
+ T operator()(URBG& generator) {
return (static_cast<T>(dist64_(generator)) << 64) | dist64_(generator);
}
@@ -168,7 +167,7 @@
std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
std::vector<std::pair<T, T>> GetRandomIntrinsic128SampleUniformDivisor() {
std::vector<std::pair<T, T>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
UniformIntDistribution128<T> uniform_128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
@@ -209,7 +208,7 @@
std::is_same<T, __int128>::value, int64_t, uint64_t>::type>
std::vector<std::pair<T, H>> GetRandomIntrinsic128SampleSmallDivisor() {
std::vector<std::pair<T, H>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
UniformIntDistribution128<T> uniform_int128;
std::uniform_int_distribution<H> uniform_int64;
values.reserve(kSampleSize);
@@ -246,9 +245,9 @@
BENCHMARK_TEMPLATE(BM_RemainderIntrinsic128SmallDivisor, __int128);
std::vector<std::pair<unsigned __int128, unsigned __int128>>
- GetRandomIntrinsic128Sample() {
+GetRandomIntrinsic128Sample() {
std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
- std::mt19937 random = MakeRandomEngine();
+ absl::InsecureBitGen random;
UniformIntDistribution128<unsigned __int128> uniform_uint128;
values.reserve(kSampleSize);
for (size_t i = 0; i < kSampleSize; ++i) {
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index 51e4b9d..216115a 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -170,27 +170,29 @@
// complement overwhelms the precision of the mantissa.
//
// Also check to make sure we don't negate Int128Min()
+ constexpr float pow_2_64 = 18446744073709551616.0f;
return v_ < 0 && *this != Int128Min()
? -static_cast<float>(-*this)
: static_cast<float>(Int128Low64(*this)) +
- std::ldexp(static_cast<float>(Int128High64(*this)), 64);
+ static_cast<float>(Int128High64(*this)) * pow_2_64;
}
inline int128::operator double() const {
// See comment in int128::operator float() above.
+ constexpr double pow_2_64 = 18446744073709551616.0;
return v_ < 0 && *this != Int128Min()
? -static_cast<double>(-*this)
: static_cast<double>(Int128Low64(*this)) +
- std::ldexp(static_cast<double>(Int128High64(*this)), 64);
+ static_cast<double>(Int128High64(*this)) * pow_2_64;
}
inline int128::operator long double() const {
// See comment in int128::operator float() above.
+ constexpr long double pow_2_64 = 18446744073709551616.0L;
return v_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this)
: static_cast<long double>(Int128Low64(*this)) +
- std::ldexp(static_cast<long double>(Int128High64(*this)),
- 64);
+ static_cast<long double>(Int128High64(*this)) * pow_2_64;
}
#endif // Clang on PowerPC
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 195b745..a7cdcea 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -139,26 +139,29 @@
// complement overwhelms the precision of the mantissa.
//
// Also check to make sure we don't negate Int128Min()
+ constexpr float pow_2_64 = 18446744073709551616.0f;
return hi_ < 0 && *this != Int128Min()
? -static_cast<float>(-*this)
: static_cast<float>(lo_) +
- std::ldexp(static_cast<float>(hi_), 64);
+ static_cast<float>(hi_) * pow_2_64;
}
inline int128::operator double() const {
// See comment in int128::operator float() above.
+ constexpr double pow_2_64 = 18446744073709551616.0;
return hi_ < 0 && *this != Int128Min()
? -static_cast<double>(-*this)
: static_cast<double>(lo_) +
- std::ldexp(static_cast<double>(hi_), 64);
+ static_cast<double>(hi_) * pow_2_64;
}
inline int128::operator long double() const {
// See comment in int128::operator float() above.
+ constexpr long double pow_2_64 = 18446744073709551616.0L;
return hi_ < 0 && *this != Int128Min()
? -static_cast<long double>(-*this)
: static_cast<long double>(lo_) +
- std::ldexp(static_cast<long double>(hi_), 64);
+ static_cast<long double>(hi_) * pow_2_64;
}
// Comparison operators.
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
index 3f16e05..13a0e7f 100644
--- a/absl/numeric/int128_test.cc
+++ b/absl/numeric/int128_test.cc
@@ -17,11 +17,13 @@
#include <algorithm>
#include <limits>
#include <random>
+#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/casts.h"
#include "absl/base/internal/cycleclock.h"
#include "absl/hash/hash_testing.h"
#include "absl/meta/type_traits.h"
@@ -473,29 +475,51 @@
EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
}
+// Some arbitrary constant to test hashing. The first hex digits of pi.
+constexpr absl::uint128 kPi = (absl::uint128(0x3243f6a8885a308d) << 64) |
+ absl::uint128(0x313198a2e0370734);
+
TEST(Uint128, Hash) {
- EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ using Ext128 = unsigned __int128;
+#endif
+ // Make the tuple outside the EXPECT_TRUE because putting the #if inside the
+ // macro argument is not ok.
+ const auto values = std::make_tuple(
// Some simple values
- absl::uint128{0},
- absl::uint128{1},
- ~absl::uint128{},
+ absl::uint128{0}, absl::uint128{1}, ~absl::uint128{},
// 64 bit limits
absl::uint128{std::numeric_limits<int64_t>::max()},
absl::uint128{std::numeric_limits<uint64_t>::max()} + 0,
absl::uint128{std::numeric_limits<uint64_t>::max()} + 1,
absl::uint128{std::numeric_limits<uint64_t>::max()} + 2,
// Keeping high same
- absl::uint128{1} << 62,
- absl::uint128{1} << 63,
+ absl::uint128{1} << 62, absl::uint128{1} << 63,
// Keeping low same
- absl::uint128{1} << 64,
- absl::uint128{1} << 65,
+ absl::uint128{1} << 64, absl::uint128{1} << 65,
// 128 bit limits
std::numeric_limits<absl::uint128>::max(),
std::numeric_limits<absl::uint128>::max() - 1,
std::numeric_limits<absl::uint128>::min() + 1,
std::numeric_limits<absl::uint128>::min(),
- }));
+ // arbitrary constant
+ kPi
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ // Same but with the intrinsic to verify that they match
+ ,
+ Ext128{0}, Ext128{1}, ~Ext128{},
+ Ext128{std::numeric_limits<int64_t>::max()},
+ Ext128{std::numeric_limits<uint64_t>::max()} + 0,
+ Ext128{std::numeric_limits<uint64_t>::max()} + 1,
+ Ext128{std::numeric_limits<uint64_t>::max()} + 2, Ext128{1} << 62,
+ Ext128{1} << 63, Ext128{1} << 64, Ext128{1} << 65,
+ std::numeric_limits<Ext128>::max(),
+ std::numeric_limits<Ext128>::max() - 1,
+ std::numeric_limits<Ext128>::min() + 1,
+ std::numeric_limits<Ext128>::min(), static_cast<Ext128>(kPi)
+#endif
+ );
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(values));
}
@@ -1249,19 +1273,24 @@
}
}
+ // Signed integer overflow is undefined behavior, so in these cases enough
+ // high bits must be zero to avoid over-shifting.
+ EXPECT_EQ(MAKE_INT128(0x0, 0x123456789abcdef0) << 63,
+ MAKE_INT128(0x91a2b3c4d5e6f78, 0x0));
+ EXPECT_EQ(MAKE_INT128(0x0, 0x123456789abcdef0) << 64,
+ MAKE_INT128(0x123456789abcdef0, 0x0));
+ EXPECT_EQ(MAKE_INT128(0x1, 0xfedcba0987654321) << 63,
+ MAKE_INT128(0xff6e5d04c3b2a190, 0x8000000000000000));
+ EXPECT_EQ(MAKE_INT128(0x0, 0xfedcba0987654321) << 64,
+ MAKE_INT128(0xfedcba0987654321, 0x0));
+ EXPECT_EQ(MAKE_INT128(0x0, 0x0) << 126, MAKE_INT128(0x0, 0x0));
+ EXPECT_EQ(MAKE_INT128(0x0, 0x1) << 126, MAKE_INT128(0x4000000000000000, 0x0));
+
// Manually calculated cases with shift count for positive (val1) and negative
// (val2) values
absl::int128 val1 = MAKE_INT128(0x123456789abcdef0, 0x123456789abcdef0);
absl::int128 val2 = MAKE_INT128(0xfedcba0987654321, 0xfedcba0987654321);
- EXPECT_EQ(val1 << 63, MAKE_INT128(0x91a2b3c4d5e6f78, 0x0));
- EXPECT_EQ(val1 << 64, MAKE_INT128(0x123456789abcdef0, 0x0));
- EXPECT_EQ(val2 << 63, MAKE_INT128(0xff6e5d04c3b2a190, 0x8000000000000000));
- EXPECT_EQ(val2 << 64, MAKE_INT128(0xfedcba0987654321, 0x0));
-
- EXPECT_EQ(val1 << 126, MAKE_INT128(0x0, 0x0));
- EXPECT_EQ(val2 << 126, MAKE_INT128(0x4000000000000000, 0x0));
-
EXPECT_EQ(val1 >> 63, MAKE_INT128(0x0, 0x2468acf13579bde0));
EXPECT_EQ(val1 >> 64, MAKE_INT128(0x0, 0x123456789abcdef0));
EXPECT_EQ(val2 >> 63, MAKE_INT128(0xffffffffffffffff, 0xfdb974130eca8643));
@@ -1282,4 +1311,50 @@
EXPECT_EQ(absl::Int128Max(), std::numeric_limits<absl::int128>::max());
}
+TEST(Int128, BitCastable) {
+ // NOTE: This test is not intended to be an example that demonstrate usages of
+ // `static_cast` and `std::bit_cast`, rather it is here simply to verify
+ // behavior. When deciding whether you should use `static_cast` or
+ // `std::bit_cast` when converting between `absl::int128` and `absl::uint128`,
+ // use your best judgement. As a rule of thumb, use the same cast that you
+ // would use when converting between the signed and unsigned counterparts of a
+ // builtin integral type.
+
+ // Verify bit casting between signed and unsigned works with regards to two's
+ // complement. This verifies we exhibit the same behavior as a theoretical
+ // builtin int128_t and uint128_t in C++20 onwards.
+ EXPECT_EQ(absl::bit_cast<absl::uint128>(absl::int128(-1)),
+ std::numeric_limits<absl::uint128>::max());
+ EXPECT_EQ(
+ absl::bit_cast<absl::int128>(std::numeric_limits<absl::uint128>::max()),
+ absl::int128(-1));
+ EXPECT_EQ(
+ absl::bit_cast<absl::uint128>(std::numeric_limits<absl::int128>::min()),
+ absl::uint128(1) << 127);
+ EXPECT_EQ(absl::bit_cast<absl::int128>(absl::uint128(1) << 127),
+ std::numeric_limits<absl::int128>::min());
+ EXPECT_EQ(
+ absl::bit_cast<absl::uint128>(std::numeric_limits<absl::int128>::max()),
+ (absl::uint128(1) << 127) - 1);
+ EXPECT_EQ(absl::bit_cast<absl::int128>((absl::uint128(1) << 127) - 1),
+ std::numeric_limits<absl::int128>::max());
+
+ // Also verify static casting has the same behavior as bit casting.
+ EXPECT_EQ(static_cast<absl::uint128>(absl::int128(-1)),
+ std::numeric_limits<absl::uint128>::max());
+ EXPECT_EQ(
+ static_cast<absl::int128>(std::numeric_limits<absl::uint128>::max()),
+ absl::int128(-1));
+ EXPECT_EQ(
+ static_cast<absl::uint128>(std::numeric_limits<absl::int128>::min()),
+ absl::uint128(1) << 127);
+ EXPECT_EQ(static_cast<absl::int128>(absl::uint128(1) << 127),
+ std::numeric_limits<absl::int128>::min());
+ EXPECT_EQ(
+ static_cast<absl::uint128>(std::numeric_limits<absl::int128>::max()),
+ (absl::uint128(1) << 127) - 1);
+ EXPECT_EQ(static_cast<absl::int128>((absl::uint128(1) << 127) - 1),
+ std::numeric_limits<absl::int128>::max());
+}
+
} // namespace
diff --git a/absl/numeric/internal/bits.h b/absl/numeric/internal/bits.h
index 0917464..e1d18b8 100644
--- a/absl/numeric/internal/bits.h
+++ b/absl/numeric/internal/bits.h
@@ -71,7 +71,7 @@
}
template <class T>
-ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
+[[nodiscard]] ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateRight(
T x, int s) noexcept {
static_assert(std::is_unsigned<T>::value, "T must be unsigned");
static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
@@ -82,7 +82,7 @@
}
template <class T>
-ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
+[[nodiscard]] ABSL_ATTRIBUTE_ALWAYS_INLINE constexpr T RotateLeft(
T x, int s) noexcept {
static_assert(std::is_unsigned<T>::value, "T must be unsigned");
static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
@@ -126,7 +126,11 @@
static_assert(IsPowerOf2(std::numeric_limits<T>::digits),
"T must have a power-of-2 size");
static_assert(sizeof(x) <= sizeof(uint64_t), "T is too large");
- return sizeof(x) <= sizeof(uint32_t) ? Popcount32(x) : Popcount64(x);
+ if constexpr (sizeof(x) <= sizeof(uint32_t)) {
+ return Popcount32(x);
+ } else {
+ return Popcount64(x);
+ }
}
ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_INTERNAL_CONSTEXPR_CLZ inline int
diff --git a/absl/profiling/BUILD.bazel b/absl/profiling/BUILD.bazel
index abe127e..ee4800d 100644
--- a/absl/profiling/BUILD.bazel
+++ b/absl/profiling/BUILD.bazel
@@ -56,11 +56,12 @@
deps = [
":sample_recorder",
"//absl/base:core_headers",
+ "//absl/random",
"//absl/synchronization",
"//absl/synchronization:thread_pool",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -88,8 +89,8 @@
deps = [
":exponential_biased",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -119,8 +120,8 @@
deps = [
":periodic_sampler",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -135,6 +136,6 @@
deps = [
":periodic_sampler",
"//absl/base:core_headers",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/profiling/CMakeLists.txt b/absl/profiling/CMakeLists.txt
index 9b3a710..84b8b3b 100644
--- a/absl/profiling/CMakeLists.txt
+++ b/absl/profiling/CMakeLists.txt
@@ -32,6 +32,7 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::random_random
absl::sample_recorder
absl::time
GTest::gmock_main
diff --git a/absl/profiling/internal/exponential_biased.cc b/absl/profiling/internal/exponential_biased.cc
index 81d9a75..918d063 100644
--- a/absl/profiling/internal/exponential_biased.cc
+++ b/absl/profiling/internal/exponential_biased.cc
@@ -66,7 +66,7 @@
}
double value = std::rint(interval);
bias_ = interval - value;
- return value;
+ return static_cast<int64_t>(value);
}
int64_t ExponentialBiased::GetStride(int64_t mean) {
diff --git a/absl/profiling/internal/sample_recorder_test.cc b/absl/profiling/internal/sample_recorder_test.cc
index 3373329..a037f9d 100644
--- a/absl/profiling/internal/sample_recorder_test.cc
+++ b/absl/profiling/internal/sample_recorder_test.cc
@@ -15,14 +15,20 @@
#include "absl/profiling/internal/sample_recorder.h"
#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
#include <random>
#include <vector>
#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "absl/base/thread_annotations.h"
+#include "absl/random/random.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
+#include "absl/time/clock.h"
#include "absl/time/time.h"
namespace absl {
@@ -112,9 +118,7 @@
for (int i = 0; i < 10; ++i) {
pool.Schedule([&sampler, &stop, i]() {
- std::random_device rd;
- std::mt19937 gen(rd());
-
+ absl::InsecureBitGen gen;
std::vector<Info*> infoz;
while (!stop.HasBeenNotified()) {
if (infoz.empty()) {
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index f276cc0..887ab0f 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -42,9 +42,9 @@
deps = [
":distributions",
":seed_sequences",
+ "//absl/base:config",
"//absl/random/internal:nonsecure_base",
"//absl/random/internal:pcg_engine",
- "//absl/random/internal:pool_urbg",
"//absl/random/internal:randen_engine",
],
)
@@ -75,7 +75,6 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/meta:type_traits",
- "//absl/numeric:bits",
"//absl/random/internal:distribution_caller",
"//absl/random/internal:fast_uniform_bits",
"//absl/random/internal:fastmath",
@@ -94,7 +93,10 @@
hdrs = ["seed_gen_exception.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = ["//absl/base:config"],
+ deps = [
+ "//absl/base:config",
+ "//absl/base:raw_logging_internal",
+ ],
)
cc_library(
@@ -109,7 +111,7 @@
":seed_gen_exception",
"//absl/base:config",
"//absl/base:nullability",
- "//absl/random/internal:pool_urbg",
+ "//absl/random/internal:entropy_pool",
"//absl/random/internal:salted_seed_seq",
"//absl/random/internal:seed_material",
"//absl/strings:string_view",
@@ -124,6 +126,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":random",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:fast_type_id",
"//absl/meta:type_traits",
@@ -156,13 +159,12 @@
deps = [
":random",
"//absl/base:config",
- "//absl/base:core_headers",
"//absl/base:fast_type_id",
"//absl/container:flat_hash_map",
"//absl/meta:type_traits",
"//absl/random/internal:mock_helpers",
"//absl/utility",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -178,8 +180,8 @@
":random",
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -204,8 +206,8 @@
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -224,8 +226,8 @@
"//absl/meta:type_traits",
"//absl/numeric:int128",
"//absl/random/internal:distribution_test_util",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -238,8 +240,8 @@
deps = [
":distributions",
":random",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -263,8 +265,8 @@
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -284,8 +286,8 @@
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -314,8 +316,8 @@
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -337,8 +339,8 @@
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -361,8 +363,8 @@
"//absl/random/internal:sequence_urbg",
"//absl/strings",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -383,8 +385,8 @@
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -410,8 +412,8 @@
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -431,8 +433,8 @@
"//absl/random/internal:pcg_engine",
"//absl/random/internal:sequence_urbg",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -445,10 +447,11 @@
deps = [
":bit_gen_ref",
":random",
+ "//absl/base:config",
"//absl/base:fast_type_id",
"//absl/random/internal:sequence_urbg",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -466,14 +469,15 @@
":mock_distributions",
":mocking_bit_gen",
":random",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
cc_test(
name = "mock_distributions_test",
size = "small",
+ timeout = "moderate",
srcs = ["mock_distributions_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -486,8 +490,8 @@
":mocking_bit_gen",
":random",
"//absl/numeric:int128",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -502,8 +506,8 @@
],
deps = [
":random",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -517,8 +521,8 @@
":random",
":seed_sequences",
"//absl/random/internal:nonsecure_base",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -535,11 +539,9 @@
deps = [
":distributions",
":random",
- ":seed_sequences",
"//absl/base:core_headers",
- "//absl/meta:type_traits",
"//absl/random/internal:fast_uniform_bits",
"//absl/random/internal:randen_engine",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index ad5477e..e0294a1 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -24,10 +24,10 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::random_distributions
absl::random_internal_nonsecure_base
absl::random_internal_pcg_engine
- absl::random_internal_pool_urbg
absl::random_internal_randen_engine
absl::random_seed_sequences
)
@@ -42,6 +42,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::core_headers
absl::random_internal_distribution_caller
absl::random_internal_fast_uniform_bits
@@ -58,6 +59,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::random_bit_gen_ref
absl::random_random
absl::random_internal_sequence_urbg
@@ -210,6 +212,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
+ absl::raw_logging_internal
)
absl_cc_library(
@@ -227,7 +230,7 @@
absl::config
absl::inlined_vector
absl::nullability
- absl::random_internal_pool_urbg
+ absl::random_internal_entropy_pool
absl::random_internal_salted_seed_seq
absl::random_internal_seed_material
absl::random_seed_gen_exception
@@ -549,6 +552,7 @@
absl::config
absl::utility
absl::fast_type_id
+ absl::type_traits
)
# Internal-only target, do not depend on directly.
@@ -579,7 +583,7 @@
${ABSL_DEFAULT_LINKOPTS}
$<$<BOOL:${MINGW}>:-lbcrypt>
DEPS
- absl::core_headers
+ absl::config
absl::optional
absl::random_internal_fast_uniform_bits
absl::raw_logging_internal
@@ -590,11 +594,11 @@
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
- random_internal_pool_urbg
+ random_internal_entropy_pool
SRCS
- "internal/pool_urbg.cc"
+ "internal/entropy_pool.cc"
HDRS
- "internal/pool_urbg.h"
+ "internal/entropy_pool.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
@@ -603,13 +607,12 @@
absl::base
absl::config
absl::core_headers
- absl::endian
+ absl::random_internal_platform
absl::random_internal_randen
absl::random_internal_seed_material
- absl::random_internal_traits
absl::random_seed_gen_exception
- absl::raw_logging_internal
absl::span
+ absl::synchronization
)
# Internal-only target, do not depend on directly.
@@ -672,6 +675,7 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::config
absl::int128
absl::type_traits
)
@@ -734,12 +738,11 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::core_headers
+ absl::config
absl::inlined_vector
- absl::random_internal_pool_urbg
+ absl::random_internal_entropy_pool
absl::random_internal_salted_seed_seq
absl::random_internal_seed_material
- absl::span
absl::type_traits
)
@@ -849,6 +852,7 @@
absl::random_internal_platform
absl::random_internal_randen_hwaes_impl
absl::config
+ absl::optional
)
# Internal-only target, do not depend on directly.
@@ -1028,11 +1032,12 @@
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
+ absl::flat_hash_map
+ absl::random_distributions
absl::random_internal_nonsecure_base
absl::random_random
- absl::random_distributions
- absl::random_seed_sequences
- absl::strings
+ absl::synchronization
+ absl::type_traits
GTest::gtest_main
)
@@ -1048,6 +1053,7 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_internal_seed_material
+ absl::span
GTest::gmock
GTest::gtest_main
)
@@ -1055,17 +1061,17 @@
# Internal-only target, do not depend on directly.
absl_cc_test(
NAME
- random_internal_pool_urbg_test
+ random_internal_entropy_pool_test
SRCS
- "internal/pool_urbg_test.cc"
+ "internal/entropy_pool_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
- absl::random_internal_pool_urbg
- absl::span
- absl::type_traits
+ absl::flat_hash_map
+ absl::random_internal_entropy_pool
+ absl::synchronization
GTest::gtest_main
)
@@ -1238,7 +1244,6 @@
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_internal_wide_multiply
- absl::bits
absl::int128
GTest::gmock
GTest::gtest_main
diff --git a/absl/random/benchmarks.cc b/absl/random/benchmarks.cc
index 26bc95e..958dfe4 100644
--- a/absl/random/benchmarks.cc
+++ b/absl/random/benchmarks.cc
@@ -26,7 +26,6 @@
#include <vector>
#include "absl/base/macros.h"
-#include "absl/meta/type_traits.h"
#include "absl/random/bernoulli_distribution.h"
#include "absl/random/beta_distribution.h"
#include "absl/random/exponential_distribution.h"
@@ -65,10 +64,10 @@
PrecompiledSeedSeq() = default;
template <typename Iterator>
- PrecompiledSeedSeq(Iterator begin, Iterator end) {}
+ PrecompiledSeedSeq(Iterator, Iterator) {}
template <typename T>
- PrecompiledSeedSeq(std::initializer_list<T> il) {}
+ PrecompiledSeedSeq(std::initializer_list<T>) {}
template <typename OutIterator>
void generate(OutIterator begin, OutIterator end) {
@@ -89,30 +88,23 @@
}
};
-// use_default_initialization<T> indicates whether the random engine
-// T must be default initialized, or whether we may initialize it using
-// a seed sequence. This is used because some engines do not accept seed
-// sequence-based initialization.
-template <typename E>
-using use_default_initialization = std::false_type;
+// Triggers default constructor initialization.
+class DefaultConstructorSeedSeq {};
// make_engine<T, SSeq> returns a random_engine which is initialized,
// either via the default constructor, when use_default_initialization<T>
// is true, or via the indicated seed sequence, SSeq.
-template <typename Engine, typename SSeq = PrecompiledSeedSeq>
-typename absl::enable_if_t<!use_default_initialization<Engine>::value, Engine>
-make_engine() {
- // Initialize the random engine using the seed sequence SSeq, which
- // is constructed from the precompiled seed data.
- SSeq seq(std::begin(kSeedData), std::end(kSeedData));
- return Engine(seq);
-}
-
-template <typename Engine, typename SSeq = PrecompiledSeedSeq>
-typename absl::enable_if_t<use_default_initialization<Engine>::value, Engine>
-make_engine() {
- // Initialize the random engine using the default constructor.
- return Engine();
+template <typename Engine, typename SSeq = DefaultConstructorSeedSeq>
+Engine make_engine() {
+ constexpr bool use_default_initialization =
+ std::is_same_v<SSeq, DefaultConstructorSeedSeq>;
+ if constexpr (use_default_initialization) {
+ return Engine();
+ } else {
+ // Otherwise, use the provided seed sequence.
+ SSeq seq(std::begin(kSeedData), std::end(kSeedData));
+ return Engine(seq);
+ }
}
template <typename Engine, typename SSeq>
@@ -248,6 +240,7 @@
// Normal benchmark suite
#define BM_BASIC(Engine) \
+ BENCHMARK_TEMPLATE(BM_Construct, Engine, DefaultConstructorSeedSeq); \
BENCHMARK_TEMPLATE(BM_Construct, Engine, PrecompiledSeedSeq); \
BENCHMARK_TEMPLATE(BM_Construct, Engine, std::seed_seq); \
BENCHMARK_TEMPLATE(BM_Direct, Engine); \
@@ -359,7 +352,7 @@
// ABSL Recommended interfaces.
BM_BASIC(absl::InsecureBitGen); // === pcg64_2018_engine
-BM_BASIC(absl::BitGen); // === randen_engine<uint64_t>.
+BM_BASIC(absl::BitGen); // === randen_engine<uint64_t>.
BM_THREAD(absl::BitGen);
BM_EXTENDED(absl::BitGen);
diff --git a/absl/random/bernoulli_distribution.h b/absl/random/bernoulli_distribution.h
index d81b6ae..10c24e6 100644
--- a/absl/random/bernoulli_distribution.h
+++ b/absl/random/bernoulli_distribution.h
@@ -15,10 +15,12 @@
#ifndef ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_
#define ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_
+#include <cassert>
#include <cstdint>
#include <istream>
-#include <limits>
+#include <ostream>
+#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/iostream_state_saver.h"
diff --git a/absl/random/beta_distribution.h b/absl/random/beta_distribution.h
index 432c516..a362345 100644
--- a/absl/random/beta_distribution.h
+++ b/absl/random/beta_distribution.h
@@ -17,14 +17,16 @@
#include <cassert>
#include <cmath>
+#include <cstdint>
#include <istream>
#include <limits>
#include <ostream>
#include <type_traits>
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
-#include "absl/random/internal/fastmath.h"
#include "absl/random/internal/generate_real.h"
#include "absl/random/internal/iostream_state_saver.h"
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
index ac26d9d..dfce2c4 100644
--- a/absl/random/bit_gen_ref.h
+++ b/absl/random/bit_gen_ref.h
@@ -24,13 +24,14 @@
#ifndef ABSL_RANDOM_BIT_GEN_REF_H_
#define ABSL_RANDOM_BIT_GEN_REF_H_
+#include <cstdint>
#include <limits>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
-#include "absl/base/internal/fast_type_id.h"
-#include "absl/base/macros.h"
+#include "absl/base/config.h"
+#include "absl/base/fast_type_id.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/distribution_caller.h"
#include "absl/random/internal/fast_uniform_bits.h"
@@ -87,7 +88,7 @@
//
class BitGenRef {
// SFINAE to detect whether the URBG type includes a member matching
- // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+ // bool InvokeMock(key_id, args_tuple*, result*).
//
// These live inside BitGenRef so that they have friend access
// to MockingBitGen. (see similar methods in DistributionCaller).
@@ -99,7 +100,7 @@
template <class T>
using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
- std::declval<base_internal::FastTypeIdType>(), std::declval<void*>(),
+ std::declval<FastTypeIdType>(), std::declval<void*>(),
std::declval<void*>()));
template <typename T>
@@ -144,8 +145,7 @@
private:
using impl_fn = result_type (*)(uintptr_t);
- using mock_call_fn = bool (*)(uintptr_t, base_internal::FastTypeIdType, void*,
- void*);
+ using mock_call_fn = bool (*)(uintptr_t, FastTypeIdType, void*, void*);
template <typename URBG>
static result_type ImplFn(uintptr_t ptr) {
@@ -157,19 +157,19 @@
// Get a type-erased InvokeMock pointer.
template <typename URBG>
- static bool MockCall(uintptr_t gen_ptr, base_internal::FastTypeIdType type,
- void* result, void* arg_tuple) {
- return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(type, result,
+ static bool MockCall(uintptr_t gen_ptr, FastTypeIdType key_id, void* result,
+ void* arg_tuple) {
+ return reinterpret_cast<URBG*>(gen_ptr)->InvokeMock(key_id, result,
arg_tuple);
}
- static bool NotAMock(uintptr_t, base_internal::FastTypeIdType, void*, void*) {
+ static bool NotAMock(uintptr_t, FastTypeIdType, void*, void*) {
return false;
}
- inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ inline bool InvokeMock(FastTypeIdType key_id, void* args_tuple,
void* result) {
if (mock_call_ == NotAMock) return false; // avoids an indirect call.
- return mock_call_(t_erased_gen_ptr_, type, args_tuple, result);
+ return mock_call_(t_erased_gen_ptr_, key_id, args_tuple, result);
}
uintptr_t t_erased_gen_ptr_;
diff --git a/absl/random/bit_gen_ref_test.cc b/absl/random/bit_gen_ref_test.cc
index 1135cf2..d581352 100644
--- a/absl/random/bit_gen_ref_test.cc
+++ b/absl/random/bit_gen_ref_test.cc
@@ -15,9 +15,14 @@
//
#include "absl/random/bit_gen_ref.h"
+#include <cstdint>
+#include <random>
+#include <vector>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/config.h"
+#include "absl/base/fast_type_id.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
@@ -34,7 +39,7 @@
result_type operator()() { return 1; }
// InvokeMock method
- bool InvokeMock(base_internal::FastTypeIdType index, void*, void* result) {
+ bool InvokeMock(FastTypeIdType, void*, void* result) {
*static_cast<int*>(result) = 42;
return true;
}
diff --git a/absl/random/discrete_distribution.cc b/absl/random/discrete_distribution.cc
index 081acce..247faa8 100644
--- a/absl/random/discrete_distribution.cc
+++ b/absl/random/discrete_distribution.cc
@@ -14,6 +14,16 @@
#include "absl/random/discrete_distribution.h"
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <iterator>
+#include <numeric>
+#include <utility>
+#include <vector>
+
+#include "absl/base/config.h"
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace random_internal {
diff --git a/absl/random/discrete_distribution.h b/absl/random/discrete_distribution.h
index 171aa11..f579a64 100644
--- a/absl/random/discrete_distribution.h
+++ b/absl/random/discrete_distribution.h
@@ -16,14 +16,16 @@
#define ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_
#include <cassert>
-#include <cmath>
+#include <cstddef>
+#include <initializer_list>
#include <istream>
#include <limits>
-#include <numeric>
+#include <ostream>
#include <type_traits>
#include <utility>
#include <vector>
+#include "absl/base/config.h"
#include "absl/random/bernoulli_distribution.h"
#include "absl/random/internal/iostream_state_saver.h"
#include "absl/random/uniform_int_distribution.h"
diff --git a/absl/random/distributions.h b/absl/random/distributions.h
index b6ade68..dced895 100644
--- a/absl/random/distributions.h
+++ b/absl/random/distributions.h
@@ -50,7 +50,6 @@
#include <type_traits>
#include "absl/base/config.h"
-#include "absl/base/internal/inline_variable.h"
#include "absl/meta/type_traits.h"
#include "absl/random/bernoulli_distribution.h"
#include "absl/random/beta_distribution.h"
@@ -68,13 +67,12 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosedClosed,
- {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedClosedTag, IntervalClosed, {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalClosedOpenTag, IntervalClosedOpen, {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpenOpen, {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenOpenTag, IntervalOpen, {});
-ABSL_INTERNAL_INLINE_CONSTEXPR(IntervalOpenClosedTag, IntervalOpenClosed, {});
+inline constexpr IntervalClosedClosedTag IntervalClosedClosed = {};
+inline constexpr IntervalClosedClosedTag IntervalClosed = {};
+inline constexpr IntervalClosedOpenTag IntervalClosedOpen = {};
+inline constexpr IntervalOpenOpenTag IntervalOpenOpen = {};
+inline constexpr IntervalOpenOpenTag IntervalOpen = {};
+inline constexpr IntervalOpenClosedTag IntervalOpenClosed = {};
// -----------------------------------------------------------------------------
// absl::Uniform<T>(tag, bitgen, lo, hi)
diff --git a/absl/random/distributions_test.cc b/absl/random/distributions_test.cc
index ea32183..4340aeb 100644
--- a/absl/random/distributions_test.cc
+++ b/absl/random/distributions_test.cc
@@ -97,17 +97,16 @@
template <typename A, typename B, typename ExplicitRet>
auto ExplicitUniformReturnT(int) -> decltype(absl::Uniform<ExplicitRet>(
- std::declval<absl::InsecureBitGen&>(),
- std::declval<A>(), std::declval<B>()));
+ std::declval<absl::InsecureBitGen&>(), std::declval<A>(),
+ std::declval<B>()));
template <typename, typename, typename ExplicitRet>
Invalid ExplicitUniformReturnT(...);
template <typename TagType, typename A, typename B, typename ExplicitRet>
-auto ExplicitTaggedUniformReturnT(int)
- -> decltype(absl::Uniform<ExplicitRet>(
- std::declval<TagType>(), std::declval<absl::InsecureBitGen&>(),
- std::declval<A>(), std::declval<B>()));
+auto ExplicitTaggedUniformReturnT(int) -> decltype(absl::Uniform<ExplicitRet>(
+ std::declval<TagType>(), std::declval<absl::InsecureBitGen&>(),
+ std::declval<A>(), std::declval<B>()));
template <typename, typename, typename, typename ExplicitRet>
Invalid ExplicitTaggedUniformReturnT(...);
@@ -471,6 +470,13 @@
EXPECT_NEAR(6.5944, moments.mean, 2000) << moments;
}
+TEST_F(RandomDistributionsTest, ZipfWithZeroMax) {
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(0, absl::Zipf(gen, 0));
+ }
+}
+
TEST_F(RandomDistributionsTest, Gaussian) {
std::vector<double> values(kSize);
diff --git a/absl/random/examples_test.cc b/absl/random/examples_test.cc
index 1dcb514..29c27f1 100644
--- a/absl/random/examples_test.cc
+++ b/absl/random/examples_test.cc
@@ -96,4 +96,3 @@
EXPECT_EQ(absl::Uniform<uint32_t>(gen_1), absl::Uniform<uint32_t>(gen_2));
}
}
-
diff --git a/absl/random/exponential_distribution.h b/absl/random/exponential_distribution.h
index b5caf8a..4af2fb4 100644
--- a/absl/random/exponential_distribution.h
+++ b/absl/random/exponential_distribution.h
@@ -21,6 +21,7 @@
#include <limits>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/generate_real.h"
diff --git a/absl/random/gaussian_distribution.h b/absl/random/gaussian_distribution.h
index 4b07a5c..eb75bfe 100644
--- a/absl/random/gaussian_distribution.h
+++ b/absl/random/gaussian_distribution.h
@@ -26,6 +26,7 @@
#include <cstdint>
#include <istream>
#include <limits>
+#include <ostream>
#include <type_traits>
#include "absl/base/config.h"
@@ -57,7 +58,7 @@
bool neg);
// Constants used for the gaussian distribution.
- static constexpr double kR = 3.442619855899; // Start of the tail.
+ static constexpr double kR = 3.442619855899; // Start of the tail.
static constexpr double kRInv = 0.29047645161474317; // ~= (1.0 / kR) .
static constexpr double kV = 9.91256303526217e-3;
static constexpr uint64_t kMask = 0x07f;
@@ -243,7 +244,7 @@
bits); // U(-1, 1)
const double x = j * zg_.x[i];
- // Retangular box. Handles >97% of all cases.
+ // Rectangular box. Handles >97% of all cases.
// For any given box, this handles between 75% and 99% of values.
// Equivalent to U(01) < (x[i+1] / x[i]), and when i == 0, ~93.5%
if (std::abs(x) < zg_.x[i + 1]) {
diff --git a/absl/random/generators_test.cc b/absl/random/generators_test.cc
index 2009130..c367567 100644
--- a/absl/random/generators_test.cc
+++ b/absl/random/generators_test.cc
@@ -117,7 +117,6 @@
absl::Bernoulli(*gen, 0.5);
}
-
template <typename URBG>
void TestZipf(URBG* gen) {
absl::Zipf<int>(*gen, 100);
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index 5e05130..994fb5c 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -14,14 +14,14 @@
# limitations under the License.
#
+load("@bazel_skylib//lib:selects.bzl", "selects")
+
# Internal-only implementation classes for Abseil Random
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_DEFAULT_LINKOPTS",
- "ABSL_RANDOM_RANDEN_COPTS",
"ABSL_TEST_COPTS",
- "absl_random_randen_copts_init",
)
default_package_visibility = [
@@ -39,6 +39,72 @@
licenses(["notice"])
+# Used to select on compilers that support GCC-compatible options
+# (e.g. "-maes").
+selects.config_setting_group(
+ name = "gcc_compatible",
+ match_any = [
+ "@rules_cc//cc/compiler:clang",
+ "@rules_cc//cc/compiler:gcc",
+ ],
+)
+
+selects.config_setting_group(
+ name = "gcc_compatible-aarch32",
+ match_all = [
+ ":gcc_compatible",
+ "@platforms//cpu:aarch32",
+ ],
+)
+
+selects.config_setting_group(
+ name = "gcc_compatible-aarch64",
+ match_all = [
+ ":gcc_compatible",
+ "@platforms//cpu:aarch64",
+ ],
+)
+
+selects.config_setting_group(
+ name = "ppc_crypto",
+ match_any = [
+ "@platforms//cpu:ppc",
+ "@platforms//cpu:ppc32",
+ "@platforms//cpu:ppc64le",
+ ],
+)
+
+selects.config_setting_group(
+ name = "gcc_compatible-ppc_crypto",
+ match_all = [
+ ":gcc_compatible",
+ ":ppc_crypto",
+ ],
+)
+
+selects.config_setting_group(
+ name = "gcc_compatible-x86_64",
+ match_all = [
+ ":gcc_compatible",
+ "@platforms//cpu:x86_64",
+ ],
+)
+
+# Some libraries are compiled with options to generate AES-NI
+# instructions, and runtime dispatch is used to determine if the host
+# microarchitecture supports AES-NI or if a portable fallback library
+# should be called.
+ABSL_RANDOM_RANDEN_COPTS = select({
+ ":gcc_compatible-aarch32": ["-mfpu=neon"],
+ ":gcc_compatible-aarch64": ["-march=armv8-a+crypto"],
+ ":gcc_compatible-ppc_crypto": ["-mcrypto"],
+ ":gcc_compatible-x86_64": [
+ "-maes",
+ "-msse4.1",
+ ],
+ "//conditions:default": [],
+})
+
cc_library(
name = "traits",
hdrs = ["traits.h"],
@@ -59,6 +125,7 @@
deps = [
"//absl/base:config",
"//absl/base:fast_type_id",
+ "//absl/meta:type_traits",
"//absl/utility",
],
)
@@ -87,8 +154,8 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS + select({
- "//absl:msvc_compiler": ["-DEFAULTLIB:bcrypt.lib"],
- "//absl:clang-cl_compiler": ["-DEFAULTLIB:bcrypt.lib"],
+ "@rules_cc//cc/compiler:msvc-cl": ["-DEFAULTLIB:bcrypt.lib"],
+ "@rules_cc//cc/compiler:clang-cl": ["-DEFAULTLIB:bcrypt.lib"],
"//absl:mingw_compiler": [
"-DEFAULTLIB:bcrypt.lib",
"-lbcrypt",
@@ -97,7 +164,7 @@
}),
deps = [
":fast_uniform_bits",
- "//absl/base:core_headers",
+ "//absl/base:config",
"//absl/base:dynamic_annotations",
"//absl/base:raw_logging_internal",
"//absl/strings",
@@ -107,29 +174,23 @@
)
cc_library(
- name = "pool_urbg",
- srcs = [
- "pool_urbg.cc",
- ],
- hdrs = [
- "pool_urbg.h",
- ],
+ name = "entropy_pool",
+ srcs = ["entropy_pool.cc"],
+ hdrs = ["entropy_pool.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = select({
- "//absl:msvc_compiler": [],
- "//absl:clang-cl_compiler": [],
- "//absl:wasm": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
+ "@rules_cc//cc/compiler:clang-cl": [],
+ "@rules_cc//cc/compiler:emscripten": [],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":platform",
":randen",
":seed_material",
- ":traits",
"//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
- "//absl/base:endian",
- "//absl/base:raw_logging_internal",
"//absl/random:seed_gen_exception",
"//absl/types:span",
],
@@ -182,6 +243,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ "//absl/base:config",
"//absl/meta:type_traits",
"//absl/numeric:int128",
],
@@ -231,13 +293,12 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":pool_urbg",
+ ":entropy_pool",
":salted_seed_seq",
":seed_material",
- "//absl/base:core_headers",
+ "//absl/base:config",
"//absl/container:inlined_vector",
"//absl/meta:type_traits",
- "//absl/types:span",
],
)
@@ -320,8 +381,6 @@
],
)
-absl_random_randen_copts_init()
-
cc_library(
name = "randen_hwaes",
srcs = [
@@ -337,6 +396,7 @@
":platform",
":randen_hwaes_impl",
"//absl/base:config",
+ "//absl/types:optional",
],
)
@@ -348,8 +408,8 @@
"randen_hwaes.h",
],
copts = ABSL_DEFAULT_COPTS + ABSL_RANDOM_RANDEN_COPTS + select({
- "//absl:msvc_compiler": [],
- "//absl:clang-cl_compiler": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
+ "@rules_cc//cc/compiler:clang-cl": [],
"//conditions:default": ["-Wno-pass-failed"],
}),
linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -416,8 +476,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -433,8 +493,8 @@
":generate_real",
"//absl/flags:flag",
"//absl/numeric:bits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -446,8 +506,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":distribution_test_util",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -459,8 +519,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fastmath",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -473,8 +533,8 @@
deps = [
":explicit_seed_seq",
"//absl/random:seed_sequences",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -486,8 +546,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":salted_seed_seq",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -502,8 +562,8 @@
deps = [
":distribution_test_util",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -517,8 +577,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fast_uniform_bits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -542,7 +602,7 @@
":mock_helpers",
"//absl/base:config",
"//absl/random:mocking_bit_gen",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -556,12 +616,13 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":nonsecure_base",
+ "//absl/container:flat_hash_set",
+ "//absl/meta:type_traits",
"//absl/random",
"//absl/random:distributions",
- "//absl/random:seed_sequences",
- "//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/synchronization",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -573,25 +634,26 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":seed_material",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/types:span",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
cc_test(
- name = "pool_urbg_test",
+ name = "entropy_pool_test",
size = "small",
srcs = [
- "pool_urbg_test.cc",
+ "entropy_pool_test.cc",
],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":pool_urbg",
- "//absl/meta:type_traits",
- "//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ ":entropy_pool",
+ "//absl/container:flat_hash_set",
+ "//absl/synchronization",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -606,8 +668,8 @@
":explicit_seed_seq",
":pcg_engine",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -625,8 +687,8 @@
"//absl/log",
"//absl/strings",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -639,8 +701,8 @@
deps = [
":randen",
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -654,8 +716,8 @@
":platform",
":randen_slow",
"//absl/base:endian",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -672,7 +734,7 @@
":randen_hwaes_impl", # build_cleaner: keep
"//absl/log",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -684,10 +746,9 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":wide_multiply",
- "//absl/numeric:bits",
"//absl/numeric:int128",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -779,8 +840,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":iostream_state_saver",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -792,7 +853,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":uniform_helper",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/random/internal/chi_square.cc b/absl/random/internal/chi_square.cc
index fbe0173..4cfc4d7 100644
--- a/absl/random/internal/chi_square.cc
+++ b/absl/random/internal/chi_square.cc
@@ -25,9 +25,7 @@
#if defined(__EMSCRIPTEN__)
// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found.
-inline double fma(double x, double y, double z) {
- return (x * y) + z;
-}
+inline double fma(double x, double y, double z) { return (x * y) + z; }
#endif
// Use Horner's method to evaluate a polynomial.
@@ -105,9 +103,8 @@
// p-value, usually using bisection. Also known by the name CRITCHI.
double ChiSquareValue(int dof, double p) {
static constexpr double kChiEpsilon =
- 0.000001; // Accuracy of the approximation.
- static constexpr double kChiMax =
- 99999.0; // Maximum chi-squared value.
+ 0.000001; // Accuracy of the approximation.
+ static constexpr double kChiMax = 99999.0; // Maximum chi-squared value.
const double p_value = 1.0 - p;
if (dof < 1 || p_value > 1.0) {
diff --git a/absl/random/internal/chi_square_test.cc b/absl/random/internal/chi_square_test.cc
index 5025def..29fd988 100644
--- a/absl/random/internal/chi_square_test.cc
+++ b/absl/random/internal/chi_square_test.cc
@@ -291,8 +291,7 @@
/*97*/ {115.223, 120.990, 126.141, 132.309, 145.789},
/*98*/ {116.315, 122.108, 127.282, 133.476, 147.010},
/*99*/ {117.407, 123.225, 128.422, 134.642, 148.230},
- /*100*/ {118.498, 124.342, 129.561, 135.807, 149.449}
- /**/};
+ /*100*/ {118.498, 124.342, 129.561, 135.807, 149.449} /**/};
// 0.90 0.95 0.975 0.99 0.999
for (int i = 0; i < ABSL_ARRAYSIZE(data); i++) {
diff --git a/absl/random/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
index 0f162a4..e84ec8c 100644
--- a/absl/random/internal/distribution_caller.h
+++ b/absl/random/internal/distribution_caller.h
@@ -17,11 +17,13 @@
#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
-#include <utility>
+#include <tuple>
#include <type_traits>
+#include <utility>
#include "absl/base/config.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/fast_type_id.h"
+#include "absl/meta/type_traits.h"
#include "absl/utility/utility.h"
namespace absl {
@@ -36,7 +38,7 @@
static_assert(!std::is_pointer<URBG>::value,
"You must pass a reference, not a pointer.");
// SFINAE to detect whether the URBG type includes a member matching
- // bool InvokeMock(base_internal::FastTypeIdType, void*, void*).
+ // bool InvokeMock(key_id, args_tuple*, result*).
//
// These live inside BitGenRef so that they have friend access
// to MockingBitGen. (see similar methods in DistributionCaller).
@@ -48,8 +50,8 @@
template <class T>
using invoke_mock_t = decltype(std::declval<T*>()->InvokeMock(
- std::declval<::absl::base_internal::FastTypeIdType>(),
- std::declval<void*>(), std::declval<void*>()));
+ std::declval<FastTypeIdType>(), std::declval<void*>(),
+ std::declval<void*>()));
using HasInvokeMock = typename detector<invoke_mock_t, void, URBG>::type;
@@ -72,8 +74,7 @@
ArgTupleT arg_tuple(std::forward<Args>(args)...);
ResultT result;
- if (!urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
- &result)) {
+ if (!urbg->InvokeMock(FastTypeId<KeyT>(), &arg_tuple, &result)) {
auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
result = dist(*urbg);
}
diff --git a/absl/random/internal/distribution_test_util.h b/absl/random/internal/distribution_test_util.h
index 6d94cf6..1189340 100644
--- a/absl/random/internal/distribution_test_util.h
+++ b/absl/random/internal/distribution_test_util.h
@@ -16,9 +16,9 @@
#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_
#include <cstddef>
-#include <iostream>
-#include <vector>
+#include <ostream>
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
@@ -96,7 +96,7 @@
// https://www.jstor.org/stable/2346798
// https://www.jstor.org/stable/2346887
//
-// BetaIncompleteInv(p, q, beta, alhpa)
+// BetaIncompleteInv(p, q, beta, alpha)
// `p` is beta parameter p, `q` is beta parameter q.
// `alpha` is the value of the lower tail area.
//
diff --git a/absl/random/internal/pool_urbg.cc b/absl/random/internal/entropy_pool.cc
similarity index 63%
rename from absl/random/internal/pool_urbg.cc
rename to absl/random/internal/entropy_pool.cc
index 5aefa7d..fa47d0d 100644
--- a/absl/random/internal/pool_urbg.cc
+++ b/absl/random/internal/entropy_pool.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/random/internal/pool_urbg.h"
+#include "absl/random/internal/entropy_pool.h"
#include <algorithm>
#include <atomic>
@@ -23,15 +23,14 @@
#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
#include "absl/base/config.h"
-#include "absl/base/internal/endian.h"
-#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h"
-#include "absl/base/internal/sysinfo.h"
-#include "absl/base/internal/unaligned_access.h"
#include "absl/base/optimization.h"
+#include "absl/base/thread_annotations.h"
#include "absl/random/internal/randen.h"
+#include "absl/random/internal/randen_traits.h"
#include "absl/random/internal/seed_material.h"
#include "absl/random/seed_gen_exception.h"
+#include "absl/types/span.h"
using absl::base_internal::SpinLock;
using absl::base_internal::SpinLockHolder;
@@ -45,9 +44,11 @@
// single generator within a RandenPool<T>. It is an internal implementation
// detail, and does not aim to conform to [rand.req.urng].
//
-// NOTE: There are alignment issues when used on ARM, for instance.
-// See the allocation code in PoolAlignedAlloc().
-class RandenPoolEntry {
+// At least 32-byte alignment is required for the state_ array on some ARM
+// platforms. We also want this aligned to a cacheline to eliminate false
+// sharing.
+class alignas(std::max(size_t{ABSL_CACHELINE_SIZE}, size_t{32}))
+ RandenPoolEntry {
public:
static constexpr size_t kState = RandenTraits::kStateBytes / sizeof(uint32_t);
static constexpr size_t kCapacity =
@@ -62,10 +63,6 @@
// Copy bytes into out.
void Fill(uint8_t* out, size_t bytes) ABSL_LOCKS_EXCLUDED(mu_);
- // Returns random bits from the buffer in units of T.
- template <typename T>
- inline T Generate() ABSL_LOCKS_EXCLUDED(mu_);
-
inline void MaybeRefill() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
if (next_ >= kState) {
next_ = kCapacity;
@@ -73,55 +70,24 @@
}
}
+ inline size_t available() const ABSL_SHARED_LOCKS_REQUIRED(mu_) {
+ return kState - next_;
+ }
+
private:
// Randen URBG state.
- uint32_t state_[kState] ABSL_GUARDED_BY(mu_); // First to satisfy alignment.
+ // At least 32-byte alignment is required by ARM platform code.
+ alignas(32) uint32_t state_[kState] ABSL_GUARDED_BY(mu_);
SpinLock mu_;
const Randen impl_;
size_t next_ ABSL_GUARDED_BY(mu_);
};
-template <>
-inline uint8_t RandenPoolEntry::Generate<uint8_t>() {
- SpinLockHolder l(&mu_);
- MaybeRefill();
- return static_cast<uint8_t>(state_[next_++]);
-}
-
-template <>
-inline uint16_t RandenPoolEntry::Generate<uint16_t>() {
- SpinLockHolder l(&mu_);
- MaybeRefill();
- return static_cast<uint16_t>(state_[next_++]);
-}
-
-template <>
-inline uint32_t RandenPoolEntry::Generate<uint32_t>() {
- SpinLockHolder l(&mu_);
- MaybeRefill();
- return state_[next_++];
-}
-
-template <>
-inline uint64_t RandenPoolEntry::Generate<uint64_t>() {
- SpinLockHolder l(&mu_);
- if (next_ >= kState - 1) {
- next_ = kCapacity;
- impl_.Generate(state_);
- }
- auto p = state_ + next_;
- next_ += 2;
-
- uint64_t result;
- std::memcpy(&result, p, sizeof(result));
- return result;
-}
-
void RandenPoolEntry::Fill(uint8_t* out, size_t bytes) {
SpinLockHolder l(&mu_);
while (bytes > 0) {
MaybeRefill();
- size_t remaining = (kState - next_) * sizeof(state_[0]);
+ size_t remaining = available() * sizeof(state_[0]);
size_t to_copy = std::min(bytes, remaining);
std::memcpy(out, &state_[next_], to_copy);
out += to_copy;
@@ -185,38 +151,17 @@
#endif
}
-// Allocate a RandenPoolEntry with at least 32-byte alignment, which is required
-// by ARM platform code.
-RandenPoolEntry* PoolAlignedAlloc() {
- constexpr size_t kAlignment =
- ABSL_CACHELINE_SIZE > 32 ? ABSL_CACHELINE_SIZE : 32;
-
- // Not all the platforms that we build for have std::aligned_alloc, however
- // since we never free these objects, we can over allocate and munge the
- // pointers to the correct alignment.
- uintptr_t x = reinterpret_cast<uintptr_t>(
- new char[sizeof(RandenPoolEntry) + kAlignment]);
- auto y = x % kAlignment;
- void* aligned = reinterpret_cast<void*>(y == 0 ? x : (x + kAlignment - y));
- return new (aligned) RandenPoolEntry();
-}
-
// Allocate and initialize kPoolSize objects of type RandenPoolEntry.
-//
-// The initialization strategy is to initialize one object directly from
-// OS entropy, then to use that object to seed all of the individual
-// pool instances.
void InitPoolURBG() {
static constexpr size_t kSeedSize =
RandenTraits::kStateBytes / sizeof(uint32_t);
- // Read the seed data from OS entropy once.
+ // Read OS entropy once, and use it to initialize each pool entry.
uint32_t seed_material[kPoolSize * kSeedSize];
- if (!random_internal::ReadSeedMaterialFromOSEntropy(
- absl::MakeSpan(seed_material))) {
- random_internal::ThrowSeedGenException();
+ if (!ReadSeedMaterialFromOSEntropy(absl::MakeSpan(seed_material))) {
+ ThrowSeedGenException();
}
for (size_t i = 0; i < kPoolSize; i++) {
- shared_pools[i] = PoolAlignedAlloc();
+ shared_pools[i] = new RandenPoolEntry();
shared_pools[i]->Init(
absl::MakeSpan(&seed_material[i * kSeedSize], kSeedSize));
}
@@ -230,24 +175,11 @@
} // namespace
-template <typename T>
-typename RandenPool<T>::result_type RandenPool<T>::Generate() {
+void GetEntropyFromRandenPool(void* dest, size_t bytes) {
auto* pool = GetPoolForCurrentThread();
- return pool->Generate<T>();
+ pool->Fill(reinterpret_cast<uint8_t*>(dest), bytes);
}
-template <typename T>
-void RandenPool<T>::Fill(absl::Span<result_type> data) {
- auto* pool = GetPoolForCurrentThread();
- pool->Fill(reinterpret_cast<uint8_t*>(data.data()),
- data.size() * sizeof(result_type));
-}
-
-template class RandenPool<uint8_t>;
-template class RandenPool<uint16_t>;
-template class RandenPool<uint32_t>;
-template class RandenPool<uint64_t>;
-
} // namespace random_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/random/internal/entropy_pool.h b/absl/random/internal/entropy_pool.h
new file mode 100644
index 0000000..970ef87
--- /dev/null
+++ b/absl/random/internal/entropy_pool.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_ENTROPY_POOL_H_
+#define ABSL_RANDOM_INTERNAL_ENTROPY_POOL_H_
+
+#include <cstddef>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace random_internal {
+
+// GetEntropyFromRandenPool() is a helper function that fills a memory region
+// with random bytes from the RandenPool. This is used by the absl::BitGen
+// implementation to fill the internal buffer.
+void GetEntropyFromRandenPool(void* dest, size_t bytes);
+
+} // namespace random_internal
+ABSL_NAMESPACE_END
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_ENTROPY_POOL_H_
diff --git a/absl/random/internal/entropy_pool_test.cc b/absl/random/internal/entropy_pool_test.cc
new file mode 100644
index 0000000..89ea72f
--- /dev/null
+++ b/absl/random/internal/entropy_pool_test.cc
@@ -0,0 +1,119 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/entropy_pool.h"
+
+#include <bitset>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <thread> // NOLINT
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/synchronization/mutex.h"
+
+namespace {
+
+using ::absl::random_internal::GetEntropyFromRandenPool;
+
+TEST(EntropyPoolTest, DistinctSequencesPerThread) {
+ using result_type = uint32_t;
+ constexpr int kNumThreads = 12;
+ constexpr size_t kValuesPerThread = 32;
+
+ // Acquire entropy from multiple threads.
+ std::vector<std::vector<result_type>> data;
+ {
+ absl::Mutex mu;
+ std::vector<std::thread> threads;
+ for (int i = 0; i < kNumThreads; i++) {
+ threads.emplace_back([&]() {
+ std::vector<result_type> v(kValuesPerThread);
+ GetEntropyFromRandenPool(v.data(), sizeof(result_type) * v.size());
+ absl::MutexLock l(&mu);
+ data.push_back(std::move(v));
+ });
+ }
+ for (auto& t : threads) t.join();
+ }
+
+ EXPECT_EQ(data.size(), kNumThreads);
+
+ // There should be essentially no duplicates in the sequences.
+ size_t expected_size = 0;
+ absl::flat_hash_set<result_type> seen;
+ for (const auto& v : data) {
+ expected_size += v.size();
+ for (result_type x : v) seen.insert(x);
+ }
+ EXPECT_GE(seen.size(), expected_size - 1);
+}
+
+// This validates that sequences are independent.
+TEST(EntropyPoolTest, ValidateDistribution) {
+ using result_type = uint32_t;
+ constexpr int kNumOutputs = 16;
+ std::vector<result_type> a(kNumOutputs);
+ std::vector<result_type> b(kNumOutputs);
+
+ GetEntropyFromRandenPool(a.data(), sizeof(a[0]) * a.size());
+ GetEntropyFromRandenPool(b.data(), sizeof(b[0]) * b.size());
+
+ // Compare the two sequences, counting the number of bits that are different,
+ // then verify using a normal-approximation of the binomial distribution.
+ size_t changed_bits = 0;
+ size_t total_set = 0;
+ size_t equal_count = 0;
+ size_t zero_count = 0;
+ for (size_t i = 0; i < a.size(); ++i) {
+ std::bitset<sizeof(result_type) * 8> changed_set(a[i] ^ b[i]);
+ changed_bits += changed_set.count();
+
+ std::bitset<sizeof(result_type) * 8> a_set(a[i]);
+ std::bitset<sizeof(result_type) * 8> b_set(b[i]);
+ total_set += a_set.count() + b_set.count();
+
+ equal_count += (a[i] == b[i]) ? 1 : 0;
+
+ zero_count += (a[i] == 0) ? 1 : 0;
+ zero_count += (b[i] == 0) ? 1 : 0;
+ }
+
+ constexpr size_t kNBits = kNumOutputs * sizeof(result_type) * 8;
+
+ // This should be a binomial distribution with:
+ // p = 0.5
+ // n = kNBits
+ // sigma =~ 11.3 (sqrt(n * 0.5 * 0.5))
+ // So we expect the number of changed bits to be within 5 standard deviations
+ // of the mean; this should fail less than one in 3 million times.
+ EXPECT_NEAR(changed_bits, kNBits * 0.5, 5 * std::sqrt(kNBits))
+ << "@" << changed_bits / static_cast<double>(kNBits);
+
+ // Verify that the number of set bits is also within the expected range;
+ // Note that this is summed over the two sequences, so the number of trials
+ // is twice the number of bits.
+ EXPECT_NEAR(total_set, kNBits, 5 * std::sqrt(2 * kNBits))
+ << "@" << total_set / static_cast<double>(2 * kNBits);
+
+ // A[i] == B[i] with probability ~= 16 * 1/2^32; certainly less than 1.
+ EXPECT_LE(equal_count, 1);
+
+ // Zeros values must be rare; 32 / 2^32 is certainly less than 1.
+ EXPECT_LE(zero_count, 1);
+}
+} // namespace
diff --git a/absl/random/internal/explicit_seed_seq_test.cc b/absl/random/internal/explicit_seed_seq_test.cc
index e36d5fa..68c9ab2 100644
--- a/absl/random/internal/explicit_seed_seq_test.cc
+++ b/absl/random/internal/explicit_seed_seq_test.cc
@@ -29,14 +29,18 @@
template <typename Sseq>
bool ConformsToInterface() {
// Check that the SeedSequence can be default-constructed.
- { Sseq default_constructed_seq; }
+ {
+ Sseq default_constructed_seq;
+ }
// Check that the SeedSequence can be constructed with two iterators.
{
uint32_t init_array[] = {1, 3, 5, 7, 9};
Sseq iterator_constructed_seq(init_array, &init_array[5]);
}
// Check that the SeedSequence can be std::initializer_list-constructed.
- { Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13}; }
+ {
+ Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13};
+ }
// Check that param() and size() return state provided to constructor.
{
uint32_t init_array[] = {1, 2, 3, 4, 5};
diff --git a/absl/random/internal/gaussian_distribution_gentables.cc b/absl/random/internal/gaussian_distribution_gentables.cc
index a95333d..3561251 100644
--- a/absl/random/internal/gaussian_distribution_gentables.cc
+++ b/absl/random/internal/gaussian_distribution_gentables.cc
@@ -16,8 +16,6 @@
//
// $ blaze run :gaussian_distribution_gentables > gaussian_distribution.cc
//
-#include "absl/random/gaussian_distribution.h"
-
#include <cmath>
#include <cstddef>
#include <iostream>
@@ -25,6 +23,7 @@
#include <string>
#include "absl/base/macros.h"
+#include "absl/random/gaussian_distribution.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/random/internal/iostream_state_saver.h b/absl/random/internal/iostream_state_saver.h
index e6e242e..0f56bcb 100644
--- a/absl/random/internal/iostream_state_saver.h
+++ b/absl/random/internal/iostream_state_saver.h
@@ -16,10 +16,14 @@
#define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
#include <cmath>
-#include <iostream>
+#include <cstdint>
+#include <ios>
+#include <istream>
#include <limits>
+#include <ostream>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/numeric/int128.h"
@@ -95,7 +99,6 @@
null_state_saver<T>>
make_ostream_state_saver(T& is, // NOLINT(runtime/references)
std::ios_base::fmtflags flags = std::ios_base::dec) {
- std::cerr << "null_state_saver";
using result_type = null_state_saver<T>;
return result_type(is, flags);
}
diff --git a/absl/random/internal/mock_helpers.h b/absl/random/internal/mock_helpers.h
index 19d0561..85f7387 100644
--- a/absl/random/internal/mock_helpers.h
+++ b/absl/random/internal/mock_helpers.h
@@ -19,7 +19,7 @@
#include <utility>
#include "absl/base/config.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/fast_type_id.h"
#include "absl/types/optional.h"
namespace absl {
@@ -48,7 +48,7 @@
// result_type(args...)
//
class MockHelpers {
- using IdType = ::absl::base_internal::FastTypeIdType;
+ using IdType = ::absl::FastTypeIdType;
// Given a key signature type used to index the mock, extract the components.
// KeyT is expected to have the form:
@@ -82,8 +82,7 @@
Args&&... args) {
ArgTupleT arg_tuple(std::forward<Args>(args)...);
ReturnT result;
- if (urbg->InvokeMock(::absl::base_internal::FastTypeId<KeyT>(), &arg_tuple,
- &result)) {
+ if (urbg->InvokeMock(FastTypeId<KeyT>(), &arg_tuple, &result)) {
return result;
}
return absl::nullopt;
@@ -92,9 +91,9 @@
public:
// InvokeMock is private; this provides access for some specialized use cases.
template <typename URBG>
- static inline bool PrivateInvokeMock(URBG* urbg, IdType type,
+ static inline bool PrivateInvokeMock(URBG* urbg, IdType key_id,
void* args_tuple, void* result) {
- return urbg->InvokeMock(type, args_tuple, result);
+ return urbg->InvokeMock(key_id, args_tuple, result);
}
// Invoke a mock for the KeyT (may or may not be a signature).
@@ -138,7 +137,7 @@
m, std::declval<IdType>(), ValidatorT())) {
return m.template RegisterMock<typename KeySignature<KeyT>::result_type,
typename KeySignature<KeyT>::arg_tuple_type>(
- m, ::absl::base_internal::FastTypeId<KeyT>(), ValidatorT());
+ m, ::absl::FastTypeId<KeyT>(), ValidatorT());
}
// Acquire a mock for the KeyT (may or may not be a signature).
diff --git a/absl/random/internal/mock_overload_set.h b/absl/random/internal/mock_overload_set.h
index cfaeeee..a09f035 100644
--- a/absl/random/internal/mock_overload_set.h
+++ b/absl/random/internal/mock_overload_set.h
@@ -51,10 +51,8 @@
auto gmock_Call(MockURBG& gen, const ::testing::Matcher<Args>&... matchers)
-> decltype(MockHelpers::MockFor<KeyT>(gen, ValidatorT())
.gmock_Call(matchers...)) {
- static_assert(
- std::is_base_of<MockingBitGenImpl<true>, MockURBG>::value ||
- std::is_base_of<MockingBitGenImpl<false>, MockURBG>::value,
- "Mocking requires an absl::MockingBitGen");
+ static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+ "Mocking requires an absl::MockingBitGen");
return MockHelpers::MockFor<KeyT>(gen, ValidatorT())
.gmock_Call(matchers...);
}
@@ -74,10 +72,8 @@
const ::testing::Matcher<Args>&... matchers)
-> decltype(MockHelpers::MockFor<KeyT>(gen, ValidatorT())
.gmock_Call(matcher, matchers...)) {
- static_assert(
- std::is_base_of<MockingBitGenImpl<true>, MockURBG>::value ||
- std::is_base_of<MockingBitGenImpl<false>, MockURBG>::value,
- "Mocking requires an absl::MockingBitGen");
+ static_assert(std::is_base_of<MockingBitGen, MockURBG>::value,
+ "Mocking requires an absl::MockingBitGen");
return MockHelpers::MockFor<KeyT>(gen, ValidatorT())
.gmock_Call(matcher, matchers...);
}
diff --git a/absl/random/internal/nonsecure_base.h b/absl/random/internal/nonsecure_base.h
index c3b8033..e8c2bb9 100644
--- a/absl/random/internal/nonsecure_base.h
+++ b/absl/random/internal/nonsecure_base.h
@@ -16,19 +16,19 @@
#define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
#include <algorithm>
+#include <cstddef>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
-#include "absl/base/macros.h"
+#include "absl/base/config.h"
#include "absl/container/inlined_vector.h"
#include "absl/meta/type_traits.h"
-#include "absl/random/internal/pool_urbg.h"
+#include "absl/random/internal/entropy_pool.h"
#include "absl/random/internal/salted_seed_seq.h"
#include "absl/random/internal/seed_material.h"
-#include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -46,8 +46,7 @@
void generate_impl(ContiguousTag, Contiguous begin, Contiguous end) {
const size_t n = static_cast<size_t>(std::distance(begin, end));
auto* a = &(*begin);
- RandenPool<uint8_t>::Fill(
- absl::MakeSpan(reinterpret_cast<uint8_t*>(a), sizeof(*a) * n));
+ GetEntropyFromRandenPool(a, sizeof(*a) * n);
}
// Construct a buffer of size n and fill it with values, then copy
@@ -57,7 +56,7 @@
RandomAccessIterator end) {
const size_t n = std::distance(begin, end);
absl::InlinedVector<uint32_t, 8> data(n, 0);
- RandenPool<uint32_t>::Fill(absl::MakeSpan(data.begin(), data.end()));
+ GetEntropyFromRandenPool(data.begin(), sizeof(data[0]) * n);
std::copy(std::begin(data), std::end(data), begin);
}
diff --git a/absl/random/internal/nonsecure_base_test.cc b/absl/random/internal/nonsecure_base_test.cc
index 3502243..6b6f2d5 100644
--- a/absl/random/internal/nonsecure_base_test.cc
+++ b/absl/random/internal/nonsecure_base_test.cc
@@ -15,16 +15,21 @@
#include "absl/random/internal/nonsecure_base.h"
#include <algorithm>
+#include <cstddef>
#include <cstdint>
-#include <iostream>
-#include <memory>
+#include <iterator>
#include <random>
-#include <sstream>
+#include <thread> // NOLINT
+#include <type_traits>
+#include <utility>
+#include <vector>
#include "gtest/gtest.h"
+#include "absl/container/flat_hash_set.h"
+#include "absl/meta/type_traits.h"
#include "absl/random/distributions.h"
#include "absl/random/random.h"
-#include "absl/strings/str_cat.h"
+#include "absl/synchronization/mutex.h"
namespace {
@@ -193,6 +198,41 @@
}
}
+TEST(NonsecureURBGBase, DistinctSequencesPerThread) {
+ constexpr int kNumThreads = 12;
+ constexpr size_t kValuesPerThread = 32;
+ using result_type = absl::BitGen::result_type;
+
+ // Acquire initial sequences from multiple threads.
+ std::vector<std::vector<result_type>> data;
+ {
+ absl::Mutex mu;
+ std::vector<std::thread> threads;
+ for (int i = 0; i < kNumThreads; i++) {
+ threads.emplace_back([&]() {
+ absl::BitGen gen;
+
+ std::vector<result_type> v(kValuesPerThread);
+ std::generate(v.begin(), v.end(), [&]() { return gen(); });
+ absl::MutexLock l(&mu);
+ data.push_back(std::move(v));
+ });
+ }
+ for (auto& t : threads) t.join();
+ }
+
+ EXPECT_EQ(data.size(), kNumThreads);
+
+ // There should be essentially no duplicates in the sequences.
+ size_t expected_size = 0;
+ absl::flat_hash_set<result_type> seen;
+ for (const auto& v : data) {
+ expected_size += v.size();
+ for (result_type x : v) seen.insert(x);
+ }
+ EXPECT_GE(seen.size(), expected_size - 1);
+}
+
TEST(RandenPoolSeedSeqTest, SeederWorksForU32) {
absl::random_internal::RandenPoolSeedSeq seeder;
diff --git a/absl/random/internal/platform.h b/absl/random/internal/platform.h
index d779f48..bd2993e 100644
--- a/absl/random/internal/platform.h
+++ b/absl/random/internal/platform.h
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// SKIP_ABSL_INLINE_NAMESPACE_CHECK
+
#ifndef ABSL_RANDOM_INTERNAL_PLATFORM_H_
#define ABSL_RANDOM_INTERNAL_PLATFORM_H_
@@ -134,7 +136,14 @@
// accelerated Randen implementation.
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
-#if defined(ABSL_ARCH_X86_64)
+// iOS does not support dispatch, even on x86, since applications
+// should be bundled as fat binaries, with a different build tailored for
+// each specific supported platform/architecture.
+#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
+ (defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR)
+#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
+#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
+#elif defined(ABSL_ARCH_X86_64)
// Dispatch is available on x86_64
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
@@ -142,8 +151,8 @@
// Or when running linux PPC
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
-#elif defined(__linux__) && defined(ABSL_ARCH_AARCH64)
-// Or when running linux AArch64
+#elif (defined(__linux__) || defined(__APPLE__)) && defined(ABSL_ARCH_AARCH64)
+// Or when running linux or macOS AArch64
#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
#elif defined(__linux__) && defined(ABSL_ARCH_ARM) && (__ARM_ARCH >= 8)
@@ -159,13 +168,4 @@
#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
#endif
-// iOS does not support dispatch, even on x86, since applications
-// should be bundled as fat binaries, with a different build tailored for
-// each specific supported platform/architecture.
-#if (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
- (defined(TARGET_OS_IPHONE_SIMULATOR) && TARGET_OS_IPHONE_SIMULATOR)
-#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
-#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
-#endif
-
#endif // ABSL_RANDOM_INTERNAL_PLATFORM_H_
diff --git a/absl/random/internal/pool_urbg.h b/absl/random/internal/pool_urbg.h
deleted file mode 100644
index 0572192..0000000
--- a/absl/random/internal/pool_urbg.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_RANDOM_INTERNAL_POOL_URBG_H_
-#define ABSL_RANDOM_INTERNAL_POOL_URBG_H_
-
-#include <cinttypes>
-#include <limits>
-
-#include "absl/random/internal/traits.h"
-#include "absl/types/span.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace random_internal {
-
-// RandenPool is a thread-safe random number generator [random.req.urbg] that
-// uses an underlying pool of Randen generators to generate values. Each thread
-// has affinity to one instance of the underlying pool generators. Concurrent
-// access is guarded by a spin-lock.
-template <typename T>
-class RandenPool {
- public:
- using result_type = T;
- static_assert(std::is_unsigned<result_type>::value,
- "RandenPool template argument must be a built-in unsigned "
- "integer type");
-
- static constexpr result_type(min)() {
- return (std::numeric_limits<result_type>::min)();
- }
-
- static constexpr result_type(max)() {
- return (std::numeric_limits<result_type>::max)();
- }
-
- RandenPool() {}
-
- // Returns a single value.
- inline result_type operator()() { return Generate(); }
-
- // Fill data with random values.
- static void Fill(absl::Span<result_type> data);
-
- protected:
- // Generate returns a single value.
- static result_type Generate();
-};
-
-extern template class RandenPool<uint8_t>;
-extern template class RandenPool<uint16_t>;
-extern template class RandenPool<uint32_t>;
-extern template class RandenPool<uint64_t>;
-
-// PoolURBG uses an underlying pool of random generators to implement a
-// thread-compatible [random.req.urbg] interface with an internal cache of
-// values.
-template <typename T, size_t kBufferSize>
-class PoolURBG {
- // Inheritance to access the protected static members of RandenPool.
- using unsigned_type = typename make_unsigned_bits<T>::type;
- using PoolType = RandenPool<unsigned_type>;
- using SpanType = absl::Span<unsigned_type>;
-
- static constexpr size_t kInitialBuffer = kBufferSize + 1;
- static constexpr size_t kHalfBuffer = kBufferSize / 2;
-
- public:
- using result_type = T;
-
- static_assert(std::is_unsigned<result_type>::value,
- "PoolURBG must be parameterized by an unsigned integer type");
-
- static_assert(kBufferSize > 1,
- "PoolURBG must be parameterized by a buffer-size > 1");
-
- static_assert(kBufferSize <= 256,
- "PoolURBG must be parameterized by a buffer-size <= 256");
-
- static constexpr result_type(min)() {
- return (std::numeric_limits<result_type>::min)();
- }
-
- static constexpr result_type(max)() {
- return (std::numeric_limits<result_type>::max)();
- }
-
- PoolURBG() : next_(kInitialBuffer) {}
-
- // copy-constructor does not copy cache.
- PoolURBG(const PoolURBG&) : next_(kInitialBuffer) {}
- const PoolURBG& operator=(const PoolURBG&) {
- next_ = kInitialBuffer;
- return *this;
- }
-
- // move-constructor does move cache.
- PoolURBG(PoolURBG&&) = default;
- PoolURBG& operator=(PoolURBG&&) = default;
-
- inline result_type operator()() {
- if (next_ >= kBufferSize) {
- next_ = (kBufferSize > 2 && next_ > kBufferSize) ? kHalfBuffer : 0;
- PoolType::Fill(SpanType(reinterpret_cast<unsigned_type*>(state_ + next_),
- kBufferSize - next_));
- }
- return state_[next_++];
- }
-
- private:
- // Buffer size.
- size_t next_; // index within state_
- result_type state_[kBufferSize];
-};
-
-} // namespace random_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_RANDOM_INTERNAL_POOL_URBG_H_
diff --git a/absl/random/internal/pool_urbg_test.cc b/absl/random/internal/pool_urbg_test.cc
deleted file mode 100644
index 53f4eac..0000000
--- a/absl/random/internal/pool_urbg_test.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/random/internal/pool_urbg.h"
-
-#include <algorithm>
-#include <bitset>
-#include <cmath>
-#include <cstdint>
-#include <iterator>
-
-#include "gtest/gtest.h"
-#include "absl/meta/type_traits.h"
-#include "absl/types/span.h"
-
-using absl::random_internal::PoolURBG;
-using absl::random_internal::RandenPool;
-
-namespace {
-
-// is_randen_pool trait is true when parameterized by an RandenPool
-template <typename T>
-using is_randen_pool = typename absl::disjunction< //
- std::is_same<T, RandenPool<uint8_t>>, //
- std::is_same<T, RandenPool<uint16_t>>, //
- std::is_same<T, RandenPool<uint32_t>>, //
- std::is_same<T, RandenPool<uint64_t>>>; //
-
-// MyFill either calls RandenPool::Fill() or std::generate(..., rng)
-template <typename T, typename V>
-typename absl::enable_if_t<absl::negation<is_randen_pool<T>>::value, void> //
-MyFill(T& rng, absl::Span<V> data) { // NOLINT(runtime/references)
- std::generate(std::begin(data), std::end(data), rng);
-}
-
-template <typename T, typename V>
-typename absl::enable_if_t<is_randen_pool<T>::value, void> //
-MyFill(T& rng, absl::Span<V> data) { // NOLINT(runtime/references)
- rng.Fill(data);
-}
-
-template <typename EngineType>
-class PoolURBGTypedTest : public ::testing::Test {};
-
-using EngineTypes = ::testing::Types< //
- RandenPool<uint8_t>, //
- RandenPool<uint16_t>, //
- RandenPool<uint32_t>, //
- RandenPool<uint64_t>, //
- PoolURBG<uint8_t, 2>, //
- PoolURBG<uint16_t, 2>, //
- PoolURBG<uint32_t, 2>, //
- PoolURBG<uint64_t, 2>, //
- PoolURBG<unsigned int, 8>, // NOLINT(runtime/int)
- PoolURBG<unsigned long, 8>, // NOLINT(runtime/int)
- PoolURBG<unsigned long int, 4>, // NOLINT(runtime/int)
- PoolURBG<unsigned long long, 4>>; // NOLINT(runtime/int)
-
-TYPED_TEST_SUITE(PoolURBGTypedTest, EngineTypes);
-
-// This test is checks that the engines meet the URBG interface requirements
-// defined in [rand.req.urbg].
-TYPED_TEST(PoolURBGTypedTest, URBGInterface) {
- using E = TypeParam;
- using T = typename E::result_type;
-
- static_assert(std::is_copy_constructible<E>::value,
- "engine must be copy constructible");
-
- static_assert(absl::is_copy_assignable<E>::value,
- "engine must be copy assignable");
-
- E e;
- const E x;
-
- e();
-
- static_assert(std::is_same<decltype(e()), T>::value,
- "return type of operator() must be result_type");
-
- E u0(x);
- u0();
-
- E u1 = e;
- u1();
-}
-
-// This validates that sequences are independent.
-TYPED_TEST(PoolURBGTypedTest, VerifySequences) {
- using E = TypeParam;
- using result_type = typename E::result_type;
-
- E rng;
- (void)rng(); // Discard one value.
-
- constexpr int kNumOutputs = 64;
- result_type a[kNumOutputs];
- result_type b[kNumOutputs];
- std::fill(std::begin(b), std::end(b), 0);
-
- // Fill a using Fill or generate, depending on the engine type.
- {
- E x = rng;
- MyFill(x, absl::MakeSpan(a));
- }
-
- // Fill b using std::generate().
- {
- E x = rng;
- std::generate(std::begin(b), std::end(b), x);
- }
-
- // Test that generated sequence changed as sequence of bits, i.e. if about
- // half of the bites were flipped between two non-correlated values.
- size_t changed_bits = 0;
- size_t unchanged_bits = 0;
- size_t total_set = 0;
- size_t total_bits = 0;
- size_t equal_count = 0;
- for (size_t i = 0; i < kNumOutputs; ++i) {
- equal_count += (a[i] == b[i]) ? 1 : 0;
- std::bitset<sizeof(result_type) * 8> bitset(a[i] ^ b[i]);
- changed_bits += bitset.count();
- unchanged_bits += bitset.size() - bitset.count();
-
- std::bitset<sizeof(result_type) * 8> a_set(a[i]);
- std::bitset<sizeof(result_type) * 8> b_set(b[i]);
- total_set += a_set.count() + b_set.count();
- total_bits += 2 * 8 * sizeof(result_type);
- }
- // On average, half the bits are changed between two calls.
- EXPECT_LE(changed_bits, 0.60 * (changed_bits + unchanged_bits));
- EXPECT_GE(changed_bits, 0.40 * (changed_bits + unchanged_bits));
-
- // verify using a quick normal-approximation to the binomial.
- EXPECT_NEAR(total_set, total_bits * 0.5, 4 * std::sqrt(total_bits))
- << "@" << total_set / static_cast<double>(total_bits);
-
- // Also, A[i] == B[i] with probability (1/range) * N.
- // Give this a pretty wide latitude, though.
- const double kExpected = kNumOutputs / (1.0 * sizeof(result_type) * 8);
- EXPECT_LE(equal_count, 1.0 + kExpected);
-}
-
-} // namespace
-
-/*
-$ nanobenchmarks 1 RandenPool construct
-$ nanobenchmarks 1 PoolURBG construct
-
-RandenPool<uint32_t> | 1 | 1000 | 48482.00 ticks | 48.48 ticks | 13.9 ns
-RandenPool<uint32_t> | 10 | 2000 | 1028795.00 ticks | 51.44 ticks | 14.7 ns
-RandenPool<uint32_t> | 100 | 1000 | 5119968.00 ticks | 51.20 ticks | 14.6 ns
-RandenPool<uint32_t> | 1000 | 500 | 25867936.00 ticks | 51.74 ticks | 14.8 ns
-
-RandenPool<uint64_t> | 1 | 1000 | 49921.00 ticks | 49.92 ticks | 14.3 ns
-RandenPool<uint64_t> | 10 | 2000 | 1208269.00 ticks | 60.41 ticks | 17.3 ns
-RandenPool<uint64_t> | 100 | 1000 | 5844955.00 ticks | 58.45 ticks | 16.7 ns
-RandenPool<uint64_t> | 1000 | 500 | 28767404.00 ticks | 57.53 ticks | 16.4 ns
-
-PoolURBG<uint32_t,8> | 1 | 1000 | 86431.00 ticks | 86.43 ticks | 24.7 ns
-PoolURBG<uint32_t,8> | 10 | 1000 | 206191.00 ticks | 20.62 ticks | 5.9 ns
-PoolURBG<uint32_t,8> | 100 | 1000 | 1516049.00 ticks | 15.16 ticks | 4.3 ns
-PoolURBG<uint32_t,8> | 1000 | 500 | 7613936.00 ticks | 15.23 ticks | 4.4 ns
-
-PoolURBG<uint64_t,4> | 1 | 1000 | 96668.00 ticks | 96.67 ticks | 27.6 ns
-PoolURBG<uint64_t,4> | 10 | 1000 | 282423.00 ticks | 28.24 ticks | 8.1 ns
-PoolURBG<uint64_t,4> | 100 | 1000 | 2609587.00 ticks | 26.10 ticks | 7.5 ns
-PoolURBG<uint64_t,4> | 1000 | 500 | 12408757.00 ticks | 24.82 ticks | 7.1 ns
-
-*/
diff --git a/absl/random/internal/randen_benchmarks.cc b/absl/random/internal/randen_benchmarks.cc
index ec086ce..1acc2c3 100644
--- a/absl/random/internal/randen_benchmarks.cc
+++ b/absl/random/internal/randen_benchmarks.cc
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#include "absl/random/internal/randen.h"
-
#include <cstdint>
#include <cstdio>
#include <cstring>
@@ -21,6 +19,8 @@
#include "absl/base/internal/raw_logging.h"
#include "absl/random/internal/nanobenchmark.h"
#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen.h"
+#include "absl/random/internal/randen_detect.h"
#include "absl/random/internal/randen_engine.h"
#include "absl/random/internal/randen_hwaes.h"
#include "absl/random/internal/randen_slow.h"
@@ -28,6 +28,7 @@
namespace {
+using absl::random_internal::CPUSupportsRandenHwAes;
using absl::random_internal::Randen;
using absl::random_internal::RandenHwAes;
using absl::random_internal::RandenSlow;
@@ -151,14 +152,14 @@
const FuncInput unpredictable = (argc != 999);
static const FuncInput inputs[] = {unpredictable * 100, unpredictable * 1000};
-#if !defined(ABSL_INTERNAL_DISABLE_AES) && ABSL_HAVE_ACCELERATED_AES
- Measure<AbsorbFn<RandenHwAes>>("Absorb (HwAes)", inputs);
-#endif
+ if (CPUSupportsRandenHwAes()) {
+ Measure<AbsorbFn<RandenHwAes>>("Absorb (HwAes)", inputs);
+ }
Measure<AbsorbFn<RandenSlow>>("Absorb (Slow)", inputs);
-#if !defined(ABSL_INTERNAL_DISABLE_AES) && ABSL_HAVE_ACCELERATED_AES
- Measure<GenerateFn<RandenHwAes>>("Generate (HwAes)", inputs);
-#endif
+ if (CPUSupportsRandenHwAes()) {
+ Measure<GenerateFn<RandenHwAes>>("Generate (HwAes)", inputs);
+ }
Measure<GenerateFn<RandenSlow>>("Generate (Slow)", inputs);
// Measure the production engine.
diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc
index bdeab87..63e8379 100644
--- a/absl/random/internal/randen_detect.cc
+++ b/absl/random/internal/randen_detect.cc
@@ -19,10 +19,21 @@
#include "absl/random/internal/randen_detect.h"
+#if defined(__APPLE__) && defined(__aarch64__)
+#if defined(__has_include)
+#if __has_include(<arm/cpu_capabilities_public.h>)
+#include <arm/cpu_capabilities_public.h>
+#endif
+#endif
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#endif
+
#include <cstdint>
#include <cstring>
#include "absl/random/internal/platform.h"
+#include "absl/types/optional.h" // IWYU pragma: keep
#if !defined(__UCLIBC__) && defined(__GLIBC__) && \
(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16))
@@ -63,7 +74,7 @@
// On linux, just use the c-library getauxval call.
#if defined(ABSL_INTERNAL_USE_LINUX_GETAUXVAL)
-extern "C" unsigned long getauxval(unsigned long type); // NOLINT(runtime/int)
+#include <sys/auxv.h>
static uint32_t GetAuxval(uint32_t hwcap_type) {
return static_cast<uint32_t>(getauxval(hwcap_type));
@@ -102,6 +113,19 @@
#endif
+#if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
+template <typename T>
+static absl::optional<T> ReadSysctlByName(const char* name) {
+ T val;
+ size_t val_size = sizeof(T);
+ int ret = sysctlbyname(name, &val, &val_size, nullptr, 0);
+ if (ret == -1) {
+ return absl::nullopt;
+ }
+ return val;
+}
+#endif
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace random_internal {
@@ -129,7 +153,9 @@
// cpu capabilities, and should allow us to enable crypto in the android
// builds where it is supported.
//
-// 3. Use the default for the compiler architecture.
+// 3. When __APPLE__ is defined on AARCH64, use sysctlbyname().
+//
+// 4. Use the default for the compiler architecture.
//
bool CPUSupportsRandenHwAes() {
@@ -178,8 +204,36 @@
return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0);
#endif
+#elif defined(__APPLE__) && defined(ABSL_ARCH_AARCH64)
+ // 3. Use sysctlbyname.
+
+ // Newer XNU kernels support querying all capabilities in a single
+ // sysctlbyname.
+#if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES)
+ static const absl::optional<uint64_t> caps =
+ ReadSysctlByName<uint64_t>("hw.optional.arm.caps");
+ if (caps.has_value()) {
+ constexpr uint64_t kNeonAndAesCaps =
+ (uint64_t{1} << CAP_BIT_AdvSIMD) | (uint64_t{1} << CAP_BIT_FEAT_AES);
+ return (*caps & kNeonAndAesCaps) == kNeonAndAesCaps;
+ }
+#endif
+
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview
+ static const absl::optional<int> adv_simd =
+ ReadSysctlByName<int>("hw.optional.AdvSIMD");
+ if (adv_simd.value_or(0) == 0) {
+ return false;
+ }
+ // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855
+ static const absl::optional<int> feat_aes =
+ ReadSysctlByName<int>("hw.optional.arm.FEAT_AES");
+ if (feat_aes.value_or(0) == 0) {
+ return false;
+ }
+ return true;
#else // ABSL_INTERNAL_USE_GETAUXVAL
- // 3. By default, assume that the compiler default.
+ // 4. By default, assume that the compiler default.
return ABSL_HAVE_ACCELERATED_AES ? true : false;
#endif
@@ -215,9 +269,6 @@
// __asm __volatile("mrs %0, id_aa64isar0_el1" :"=&r" (val));
//
// * Use a CPUID-style heuristic database.
- //
- // * On Apple (__APPLE__), AES is available on Arm v8.
- // https://stackoverflow.com/questions/45637888/how-to-determine-armv8-features-at-runtime-on-ios
}
#if defined(__clang__)
diff --git a/absl/random/internal/randen_engine.h b/absl/random/internal/randen_engine.h
index fe2d9f6..925e1bb 100644
--- a/absl/random/internal/randen_engine.h
+++ b/absl/random/internal/randen_engine.h
@@ -18,9 +18,10 @@
#include <algorithm>
#include <cinttypes>
#include <cstdlib>
-#include <iostream>
+#include <istream>
#include <iterator>
#include <limits>
+#include <ostream>
#include <type_traits>
#include "absl/base/internal/endian.h"
diff --git a/absl/random/internal/randen_hwaes_test.cc b/absl/random/internal/randen_hwaes_test.cc
index 00d96ef..0378972 100644
--- a/absl/random/internal/randen_hwaes_test.cc
+++ b/absl/random/internal/randen_hwaes_test.cc
@@ -89,7 +89,7 @@
LOG(INFO) << "HasRandenHwAesImplementation = " << x;
int y = absl::random_internal::CPUSupportsRandenHwAes();
- LOG(INFO) << "CPUSupportsRandenHwAes = " << x;
+ LOG(INFO) << "CPUSupportsRandenHwAes = " << y;
if (!x || !y) {
LOG(INFO) << "Skipping Randen HWAES tests.";
diff --git a/absl/random/internal/salted_seed_seq_test.cc b/absl/random/internal/salted_seed_seq_test.cc
index 0bf19a6..6f48c61 100644
--- a/absl/random/internal/salted_seed_seq_test.cc
+++ b/absl/random/internal/salted_seed_seq_test.cc
@@ -33,14 +33,18 @@
template <typename Sseq>
void ConformsToInterface() {
// Check that the SeedSequence can be default-constructed.
- { Sseq default_constructed_seq; }
+ {
+ Sseq default_constructed_seq;
+ }
// Check that the SeedSequence can be constructed with two iterators.
{
uint32_t init_array[] = {1, 3, 5, 7, 9};
Sseq iterator_constructed_seq(std::begin(init_array), std::end(init_array));
}
// Check that the SeedSequence can be std::initializer_list-constructed.
- { Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13}; }
+ {
+ Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13};
+ }
// Check that param() and size() return state provided to constructor.
{
uint32_t init_array[] = {1, 2, 3, 4, 5};
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc
index 1041302..8099ec7 100644
--- a/absl/random/internal/seed_material.cc
+++ b/absl/random/internal/seed_material.cc
@@ -23,17 +23,23 @@
#endif
#include <algorithm>
+#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
#include <cstring>
+#include <string>
+#include <vector>
+#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
#if defined(__native_client__)
@@ -167,24 +173,27 @@
size_t buffer_size = sizeof(uint32_t) * values.size();
int dev_urandom = open(kEntropyFile, O_RDONLY);
- bool success = (-1 != dev_urandom);
- if (!success) {
+ if (dev_urandom < 0) {
+ ABSL_RAW_LOG(ERROR, "Failed to open /dev/urandom.");
return false;
}
- while (success && buffer_size > 0) {
+ while (buffer_size > 0) {
ssize_t bytes_read = read(dev_urandom, buffer, buffer_size);
int read_error = errno;
- success = (bytes_read > 0);
- if (success) {
- buffer += bytes_read;
- buffer_size -= static_cast<size_t>(bytes_read);
- } else if (bytes_read == -1 && read_error == EINTR) {
- success = true; // Need to try again.
+ if (bytes_read == -1 && read_error == EINTR) {
+ // Interrupted, try again.
+ continue;
+ } else if (bytes_read <= 0) {
+ // EOF, or error.
+ break;
}
+ buffer += bytes_read;
+ buffer_size -= static_cast<size_t>(bytes_read);
}
+
close(dev_urandom);
- return success;
+ return buffer_size == 0;
}
bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
@@ -251,8 +260,7 @@
static const auto salt_material = []() -> absl::optional<uint32_t> {
uint32_t salt_value = 0;
- if (random_internal::ReadSeedMaterialFromOSEntropy(
- MakeSpan(&salt_value, 1))) {
+ if (ReadSeedMaterialFromOSEntropy(absl::MakeSpan(&salt_value, 1))) {
return salt_value;
}
diff --git a/absl/random/internal/seed_material.h b/absl/random/internal/seed_material.h
index 4be10e9..b671a8c 100644
--- a/absl/random/internal/seed_material.h
+++ b/absl/random/internal/seed_material.h
@@ -21,7 +21,7 @@
#include <string>
#include <vector>
-#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
@@ -54,7 +54,7 @@
// to the C++ Standard "Seed Sequence" concept [rand.req.seedseq].
//
// If values.data() == nullptr, the behavior is undefined.
-ABSL_MUST_USE_RESULT
+[[nodiscard]]
bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values);
// Attempts to fill a span of uint32_t-values using variates generated by an
@@ -65,8 +65,8 @@
//
// If urbg == nullptr or values.data() == nullptr, the behavior is undefined.
template <typename URBG>
-ABSL_MUST_USE_RESULT bool ReadSeedMaterialFromURBG(
- URBG* urbg, absl::Span<uint32_t> values) {
+[[nodiscard]] bool ReadSeedMaterialFromURBG(URBG* urbg,
+ absl::Span<uint32_t> values) {
random_internal::FastUniformBits<uint32_t> distr;
assert(urbg != nullptr && values.data() != nullptr);
@@ -94,7 +94,7 @@
//
// Salt is obtained only once and stored in static variable.
//
-// May return empty value if optaining the salt was not possible.
+// May return empty value if obtaining the salt was not possible.
absl::optional<uint32_t> GetSaltMaterial();
} // namespace random_internal
diff --git a/absl/random/internal/seed_material_test.cc b/absl/random/internal/seed_material_test.cc
index 6db2820..45db765 100644
--- a/absl/random/internal/seed_material_test.cc
+++ b/absl/random/internal/seed_material_test.cc
@@ -15,12 +15,15 @@
#include "absl/random/internal/seed_material.h"
#include <bitset>
+#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <random>
+#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/types/span.h"
#ifdef __ANDROID__
// Android assert messages only go to system log, so death tests cannot inspect
diff --git a/absl/random/internal/traits_test.cc b/absl/random/internal/traits_test.cc
index a844887..2164582 100644
--- a/absl/random/internal/traits_test.cc
+++ b/absl/random/internal/traits_test.cc
@@ -104,14 +104,11 @@
TEST(TraitsTest, IsWideningConvertibleTest) {
constexpr bool kInvalid = false;
- CheckWideningConvertsToSelf<
- uint8_t, uint16_t, uint32_t, uint64_t,
- int8_t, int16_t, int32_t, int64_t,
- float, double>();
- CheckNotWideningConvertibleWithSigned<
- uint8_t, uint16_t, uint32_t, uint64_t>();
- CheckWideningConvertsToLargerTypes<
- uint8_t, uint16_t, uint32_t, uint64_t>();
+ CheckWideningConvertsToSelf<uint8_t, uint16_t, uint32_t, uint64_t, int8_t,
+ int16_t, int32_t, int64_t, float, double>();
+ CheckNotWideningConvertibleWithSigned<uint8_t, uint16_t, uint32_t,
+ uint64_t>();
+ CheckWideningConvertsToLargerTypes<uint8_t, uint16_t, uint32_t, uint64_t>();
CheckWideningConvertsTo<float, double>();
CheckWideningConvertsTo<uint16_t, float>();
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h
index db737e1..d230073 100644
--- a/absl/random/internal/uniform_helper.h
+++ b/absl/random/internal/uniform_helper.h
@@ -201,8 +201,8 @@
}
template <typename IntType>
-absl::enable_if_t<IsIntegral<IntType>::value, bool>
-is_uniform_range_valid(IntType a, IntType b) {
+absl::enable_if_t<IsIntegral<IntType>::value, bool> is_uniform_range_valid(
+ IntType a, IntType b) {
return a <= b;
}
diff --git a/absl/random/internal/wide_multiply.h b/absl/random/internal/wide_multiply.h
index 891e363..b125681 100644
--- a/absl/random/internal/wide_multiply.h
+++ b/absl/random/internal/wide_multiply.h
@@ -75,7 +75,6 @@
c00 + (c64a << 64) + (c64b << 64)};
}
-
template <>
struct wide_multiply<uint128> {
using input_type = uint128;
diff --git a/absl/random/log_uniform_int_distribution.h b/absl/random/log_uniform_int_distribution.h
index 4afff8f..cbd5e0c 100644
--- a/absl/random/log_uniform_int_distribution.h
+++ b/absl/random/log_uniform_int_distribution.h
@@ -21,11 +21,8 @@
#include <istream>
#include <limits>
#include <ostream>
-#include <type_traits>
-#include "absl/numeric/bits.h"
-#include "absl/random/internal/fastmath.h"
-#include "absl/random/internal/generate_real.h"
+#include "absl/base/config.h"
#include "absl/random/internal/iostream_state_saver.h"
#include "absl/random/internal/traits.h"
#include "absl/random/uniform_int_distribution.h"
diff --git a/absl/random/log_uniform_int_distribution_test.cc b/absl/random/log_uniform_int_distribution_test.cc
index 5df3eda..2530c9e 100644
--- a/absl/random/log_uniform_int_distribution_test.cc
+++ b/absl/random/log_uniform_int_distribution_test.cc
@@ -148,8 +148,8 @@
const auto bucket_index = [base_log, is_2, ¶m](int32_t x) {
uint64_t y = static_cast<uint64_t>(x) - param.min();
return (y == 0) ? 0
- : is_2 ? static_cast<int>(1 + std::log2(y))
- : static_cast<int>(1 + std::log(y) * base_log);
+ : is_2 ? static_cast<int>(1 + std::log2(y))
+ : static_cast<int>(1 + std::log(y) * base_log);
};
const int max_bucket = bucket_index(param.max()); // inclusive
const size_t trials = 15 + (max_bucket + 1) * 10;
diff --git a/absl/random/mock_distributions.h b/absl/random/mock_distributions.h
index b379262..1983547 100644
--- a/absl/random/mock_distributions.h
+++ b/absl/random/mock_distributions.h
@@ -17,14 +17,14 @@
// -----------------------------------------------------------------------------
//
// This file contains mock distribution functions for use alongside an
-// `absl::MockingBitGen` object within the Googletest testing framework. Such
+// `absl::MockingBitGen` object within the GoogleTest testing framework. Such
// mocks are useful to provide deterministic values as return values within
// (otherwise random) Abseil distribution functions.
//
// The return type of each function is a mock expectation object which
// is used to set the match result.
//
-// More information about the Googletest testing framework is available at
+// More information about the GoogleTest testing framework is available at
// https://github.com/google/googletest
//
// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
diff --git a/absl/random/mock_distributions_test.cc b/absl/random/mock_distributions_test.cc
index 05e313c..622aff7 100644
--- a/absl/random/mock_distributions_test.cc
+++ b/absl/random/mock_distributions_test.cc
@@ -75,14 +75,7 @@
EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
}
-TEST(MockUniform, OutOfBoundsIsAllowed) {
- absl::UnvalidatedMockingBitGen gen;
-
- EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 100)).WillOnce(Return(0));
- EXPECT_EQ(absl::Uniform<int>(gen, 1, 100), 0);
-}
-
-TEST(ValidatedMockDistributions, UniformUInt128Works) {
+TEST(MockDistributions, UniformUInt128BoundariesAreAllowed) {
absl::MockingBitGen gen;
EXPECT_CALL(absl::MockUniform<absl::uint128>(), Call(gen))
@@ -90,7 +83,7 @@
EXPECT_EQ(absl::Uniform<absl::uint128>(gen), absl::Uint128Max());
}
-TEST(ValidatedMockDistributions, UniformDoubleBoundaryCases) {
+TEST(MockDistributions, UniformDoubleBoundaryCasesAreAllowed) {
absl::MockingBitGen gen;
EXPECT_CALL(absl::MockUniform<double>(), Call(gen, 1.0, 10.0))
@@ -114,7 +107,7 @@
std::nextafter(1.0, std::numeric_limits<double>::infinity()));
}
-TEST(ValidatedMockDistributions, UniformDoubleEmptyRangeCases) {
+TEST(MockDistributions, UniformDoubleEmptyRangesAllowTheBoundary) {
absl::MockingBitGen gen;
ON_CALL(absl::MockUniform<double>(), Call(absl::IntervalOpen, gen, 1.0, 1.0))
@@ -134,7 +127,7 @@
1.0);
}
-TEST(ValidatedMockDistributions, UniformIntEmptyRangeCases) {
+TEST(MockDistributions, UniformIntEmptyRangeCasesAllowTheBoundary) {
absl::MockingBitGen gen;
ON_CALL(absl::MockUniform<int>(), Call(absl::IntervalOpen, gen, 1, 1))
@@ -150,7 +143,7 @@
EXPECT_EQ(absl::Uniform<int>(absl::IntervalClosedOpen, gen, 1, 1), 1);
}
-TEST(ValidatedMockUniformDeathTest, Examples) {
+TEST(MockUniformDeathTest, OutOfBoundsValuesAreRejected) {
absl::MockingBitGen gen;
EXPECT_DEATH_IF_SUPPORTED(
@@ -252,7 +245,7 @@
" 101 is not in \\[1, 100\\]");
}
-TEST(ValidatedMockUniformDeathTest, DoubleBoundaryCases) {
+TEST(MockUniformDeathTest, OutOfBoundsDoublesAreRejected) {
absl::MockingBitGen gen;
EXPECT_DEATH_IF_SUPPORTED(
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
index 041989d..1680ff4 100644
--- a/absl/random/mocking_bit_gen.h
+++ b/absl/random/mocking_bit_gen.h
@@ -17,12 +17,12 @@
// -----------------------------------------------------------------------------
//
// This file includes an `absl::MockingBitGen` class to use as a mock within the
-// Googletest testing framework. Such a mock is useful to provide deterministic
+// GoogleTest testing framework. Such a mock is useful to provide deterministic
// values as return values within (otherwise random) Abseil distribution
// functions. Such determinism within a mock is useful within testing frameworks
// to test otherwise indeterminate APIs.
//
-// More information about the Googletest testing framework is available at
+// More information about the GoogleTest testing framework is available at
// https://github.com/google/googletest
#ifndef ABSL_RANDOM_MOCKING_BIT_GEN_H_
@@ -34,9 +34,8 @@
#include <utility>
#include "gmock/gmock.h"
-#include "absl/base/attributes.h"
#include "absl/base/config.h"
-#include "absl/base/internal/fast_type_id.h"
+#include "absl/base/fast_type_id.h"
#include "absl/container/flat_hash_map.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/mock_helpers.h"
@@ -52,13 +51,53 @@
template <typename>
struct DistributionCaller;
class MockHelpers;
+} // namespace random_internal
-// Implements MockingBitGen with an option to turn on extra validation.
-template <bool EnableValidation>
-class MockingBitGenImpl {
+// MockingBitGen
+//
+// `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class
+// which can act in place of an `absl::BitGen` URBG within tests using the
+// GoogleTest testing framework.
+//
+// Usage:
+//
+// Use an `absl::MockingBitGen` along with a mock distribution object (within
+// mock_distributions.h) inside Googletest constructs such as ON_CALL(),
+// EXPECT_TRUE(), etc. to produce deterministic results conforming to the
+// distribution's API contract.
+//
+// Example:
+//
+// // Mock a call to an `absl::Bernoulli` distribution using Googletest
+// absl::MockingBitGen bitgen;
+//
+// ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5))
+// .WillByDefault(testing::Return(true));
+// EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5));
+//
+// // Mock a call to an `absl::Uniform` distribution within Googletest
+// absl::MockingBitGen bitgen;
+//
+// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_))
+// .WillByDefault([] (int low, int high) {
+// return low + (high - low) / 2;
+// });
+//
+// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5);
+// EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35);
+//
+// At this time, only mock distributions supplied within the Abseil random
+// library are officially supported.
+//
+// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
+// the call to absl::Uniform and related methods, otherwise mocking will fail
+// since the underlying implementation creates a type-specific pointer which
+// will be distinct across different DLL boundaries.
+//
+class MockingBitGen {
public:
- MockingBitGenImpl() = default;
- ~MockingBitGenImpl() = default;
+ MockingBitGen() = default;
+ ~MockingBitGen() = default;
// URBG interface
using result_type = absl::BitGen::result_type;
@@ -136,27 +175,25 @@
// distribution parameters of the expectation.
template <typename ResultT, typename ArgTupleT, typename SelfT,
typename ValidatorT>
- auto RegisterMock(SelfT&, base_internal::FastTypeIdType type, ValidatorT)
+ auto RegisterMock(SelfT&, FastTypeIdType type, ValidatorT)
-> decltype(GetMockFnType(std::declval<ResultT>(),
std::declval<ArgTupleT>()))& {
- using ActualValidatorT =
- std::conditional_t<EnableValidation, ValidatorT, NoOpValidator>;
using MockFnType = decltype(GetMockFnType(std::declval<ResultT>(),
std::declval<ArgTupleT>()));
using WrappedFnType = absl::conditional_t<
- std::is_same<SelfT, ::testing::NiceMock<MockingBitGenImpl>>::value,
+ std::is_same<SelfT, ::testing::NiceMock<MockingBitGen>>::value,
::testing::NiceMock<MockFnType>,
absl::conditional_t<
- std::is_same<SelfT, ::testing::NaggyMock<MockingBitGenImpl>>::value,
+ std::is_same<SelfT, ::testing::NaggyMock<MockingBitGen>>::value,
::testing::NaggyMock<MockFnType>,
absl::conditional_t<
std::is_same<SelfT,
- ::testing::StrictMock<MockingBitGenImpl>>::value,
+ ::testing::StrictMock<MockingBitGen>>::value,
::testing::StrictMock<MockFnType>, MockFnType>>>;
using ImplT =
- FunctionHolderImpl<WrappedFnType, ActualValidatorT, ResultT, ArgTupleT>;
+ FunctionHolderImpl<WrappedFnType, ValidatorT, ResultT, ArgTupleT>;
auto& mock = mocks_[type];
if (!mock) {
mock = absl::make_unique<ImplT>();
@@ -166,8 +203,8 @@
// MockingBitGen::InvokeMock
//
- // InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
- // mocks registered on MockingBitGen.
+ // bool InvokeMock(key_id, args_tuple*, result*) is the entrypoint
+ // for invoking mocks registered on MockingBitGen.
//
// When no mocks are registered on the provided FastTypeIdType, returns false.
// Otherwise attempts to invoke the mock function ResultT(Args...) that
@@ -175,18 +212,16 @@
// Requires tuple_args to point to a ArgTupleT, which is a std::tuple<Args...>
// used to invoke the mock function.
// Requires result to point to a ResultT, which is the result of the call.
- inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
+ inline bool InvokeMock(FastTypeIdType key_id, void* args_tuple,
void* result) {
// Trigger a mock, if there exists one that matches `param`.
- auto it = mocks_.find(type);
+ auto it = mocks_.find(key_id);
if (it == mocks_.end()) return false;
it->second->Apply(args_tuple, result);
return true;
}
- absl::flat_hash_map<base_internal::FastTypeIdType,
- std::unique_ptr<FunctionHolder>>
- mocks_;
+ absl::flat_hash_map<FastTypeIdType, std::unique_ptr<FunctionHolder>> mocks_;
absl::BitGen gen_;
template <typename>
@@ -196,58 +231,6 @@
// InvokeMock
};
-} // namespace random_internal
-
-// MockingBitGen
-//
-// `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class
-// which can act in place of an `absl::BitGen` URBG within tests using the
-// Googletest testing framework.
-//
-// Usage:
-//
-// Use an `absl::MockingBitGen` along with a mock distribution object (within
-// mock_distributions.h) inside Googletest constructs such as ON_CALL(),
-// EXPECT_TRUE(), etc. to produce deterministic results conforming to the
-// distribution's API contract.
-//
-// Example:
-//
-// // Mock a call to an `absl::Bernoulli` distribution using Googletest
-// absl::MockingBitGen bitgen;
-//
-// ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5))
-// .WillByDefault(testing::Return(true));
-// EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5));
-//
-// // Mock a call to an `absl::Uniform` distribution within Googletest
-// absl::MockingBitGen bitgen;
-//
-// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_))
-// .WillByDefault([] (int low, int high) {
-// return low + (high - low) / 2;
-// });
-//
-// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5);
-// EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35);
-//
-// At this time, only mock distributions supplied within the Abseil random
-// library are officially supported.
-//
-// EXPECT_CALL and ON_CALL need to be made within the same DLL component as
-// the call to absl::Uniform and related methods, otherwise mocking will fail
-// since the underlying implementation creates a type-specific pointer which
-// will be distinct across different DLL boundaries.
-//
-using MockingBitGen = random_internal::MockingBitGenImpl<true>;
-
-// UnvalidatedMockingBitGen
-//
-// UnvalidatedMockingBitGen is a variant of MockingBitGen which does no extra
-// validation.
-using UnvalidatedMockingBitGen ABSL_DEPRECATED("Use MockingBitGen instead") =
- random_internal::MockingBitGenImpl<false>;
-
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/random/poisson_distribution.h b/absl/random/poisson_distribution.h
index f457308..ae2e095 100644
--- a/absl/random/poisson_distribution.h
+++ b/absl/random/poisson_distribution.h
@@ -17,11 +17,12 @@
#include <cassert>
#include <cmath>
+#include <cstdint>
#include <istream>
#include <limits>
#include <ostream>
-#include <type_traits>
+#include "absl/base/config.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/fastmath.h"
#include "absl/random/internal/generate_real.h"
@@ -48,8 +49,8 @@
// the distribution results are limited to the max() value.
//
// The goals of this implementation are to provide good performance while still
-// beig thread-safe: This limits the implementation to not using lgamma provided
-// by <math.h>.
+// being thread-safe: This limits the implementation to not using lgamma
+// provided by <math.h>.
//
template <typename IntType = int>
class poisson_distribution {
diff --git a/absl/random/poisson_distribution_test.cc b/absl/random/poisson_distribution_test.cc
index 5475596..3a1d238 100644
--- a/absl/random/poisson_distribution_test.cc
+++ b/absl/random/poisson_distribution_test.cc
@@ -106,7 +106,6 @@
0.0), // denorm_max
};
-
constexpr int kCount = 1000;
absl::InsecureBitGen gen;
for (const double m : kParams) {
diff --git a/absl/random/random.h b/absl/random/random.h
index 7672086..b55b361 100644
--- a/absl/random/random.h
+++ b/absl/random/random.h
@@ -31,12 +31,13 @@
#ifndef ABSL_RANDOM_RANDOM_H_
#define ABSL_RANDOM_RANDOM_H_
+#include <cstdint>
#include <random>
+#include "absl/base/config.h"
#include "absl/random/distributions.h" // IWYU pragma: export
-#include "absl/random/internal/nonsecure_base.h" // IWYU pragma: export
-#include "absl/random/internal/pcg_engine.h" // IWYU pragma: export
-#include "absl/random/internal/pool_urbg.h"
+#include "absl/random/internal/nonsecure_base.h"
+#include "absl/random/internal/pcg_engine.h"
#include "absl/random/internal/randen_engine.h"
#include "absl/random/seed_sequences.h" // IWYU pragma: export
@@ -94,31 +95,46 @@
// types on modern x86, ARM, and PPC architectures.
//
// This type is thread-compatible, but not thread-safe.
+class BitGen : private random_internal::NonsecureURBGBase<
+ random_internal::randen_engine<uint64_t>> {
+ using Base = random_internal::NonsecureURBGBase<
+ random_internal::randen_engine<uint64_t>>;
-// ---------------------------------------------------------------------------
-// absl::BitGen member functions
-// ---------------------------------------------------------------------------
+ public:
+ using result_type = typename Base::result_type;
-// absl::BitGen::operator()()
-//
-// Calls the BitGen, returning a generated value.
+ // BitGen()
+ // BitGen(SeedSequence seed_seq)
+ //
+ // Copy disallowed.
+ // Move allowed.
+ using Base::Base;
+ using Base::operator=;
-// absl::BitGen::min()
-//
-// Returns the smallest possible value from this bit generator.
+ // BitGen::min()
+ //
+ // Returns the smallest possible value from this bit generator.
+ using Base::min;
-// absl::BitGen::max()
-//
-// Returns the largest possible value from this bit generator.
+ // BitGen::max()
+ //
+ // Returns the largest possible value from this bit generator.
+ using Base::max;
-// absl::BitGen::discard(num)
-//
-// Advances the internal state of this bit generator by `num` times, and
-// discards the intermediate results.
-// ---------------------------------------------------------------------------
+ // BitGen::discard(num)
+ //
+ // Advances the internal state of this bit generator by `num` times, and
+ // discards the intermediate results.
+ using Base::discard;
-using BitGen = random_internal::NonsecureURBGBase<
- random_internal::randen_engine<uint64_t>>;
+ // BitGen::operator()()
+ //
+ // Invoke the URBG, returning a generated value.
+ using Base::operator();
+
+ using Base::operator==;
+ using Base::operator!=;
+};
// -----------------------------------------------------------------------------
// absl::InsecureBitGen
@@ -156,32 +172,51 @@
// `absl::InsecureBitGen` is not cryptographically secure.
//
// Prefer `absl::BitGen` over `absl::InsecureBitGen` as the general type is
-// often fast enough for the vast majority of applications.
-
-using InsecureBitGen =
- random_internal::NonsecureURBGBase<random_internal::pcg64_2018_engine>;
-
-// ---------------------------------------------------------------------------
-// absl::InsecureBitGen member functions
-// ---------------------------------------------------------------------------
-
-// absl::InsecureBitGen::operator()()
+// often fast enough for the vast majority of applications. However, it is
+// reasonable to use `absl::InsecureBitGen` in tests or when using a URBG
+// in small isolated tasks such as in `std::shuffle`.
//
-// Calls the InsecureBitGen, returning a generated value.
+// This type is thread-compatible, but not thread-safe.
+class InsecureBitGen : private random_internal::NonsecureURBGBase<
+ random_internal::pcg64_2018_engine> {
+ using Base =
+ random_internal::NonsecureURBGBase<random_internal::pcg64_2018_engine>;
-// absl::InsecureBitGen::min()
-//
-// Returns the smallest possible value from this bit generator.
+ public:
+ using result_type = typename Base::result_type;
-// absl::InsecureBitGen::max()
-//
-// Returns the largest possible value from this bit generator.
+ // InsecureBitGen()
+ // InsecureBitGen(SeedSequence seed_seq)
+ //
+ // Copy disallowed.
+ // Move allowed.
+ using Base::Base;
+ using Base::operator=;
-// absl::InsecureBitGen::discard(num)
-//
-// Advances the internal state of this bit generator by `num` times, and
-// discards the intermediate results.
-// ---------------------------------------------------------------------------
+ // InsecureBitGen::min()
+ //
+ // Returns the smallest possible value from this bit generator.
+ using Base::min;
+
+ // InsecureBitGen::max()
+ //
+ // Returns the largest possible value from this bit generator.
+ using Base::max;
+
+ // InsecureBitGen::discard(num)
+ //
+ // Advances the internal state of this bit generator by `num` times, and
+ // discards the intermediate results.
+ using Base::discard;
+
+ // InsecureBitGen::operator()()
+ //
+ // Invoke the URBG, returning a generated value.
+ using Base::operator();
+
+ using Base::operator==;
+ using Base::operator!=;
+};
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/random/seed_gen_exception.cc b/absl/random/seed_gen_exception.cc
index fdcb54a..6fb4ad3 100644
--- a/absl/random/seed_gen_exception.cc
+++ b/absl/random/seed_gen_exception.cc
@@ -14,9 +14,8 @@
#include "absl/random/seed_gen_exception.h"
-#include <iostream>
-
#include "absl/base/config.h"
+#include "absl/base/internal/raw_logging.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -36,7 +35,7 @@
#ifdef ABSL_HAVE_EXCEPTIONS
throw absl::SeedGenException();
#else
- std::cerr << kExceptionMessage << std::endl;
+ ABSL_RAW_LOG(FATAL, "%s", kExceptionMessage);
std::terminate();
#endif
}
diff --git a/absl/random/seed_sequences.cc b/absl/random/seed_sequences.cc
index 426eafd..316381b 100644
--- a/absl/random/seed_sequences.cc
+++ b/absl/random/seed_sequences.cc
@@ -14,14 +14,18 @@
#include "absl/random/seed_sequences.h"
-#include "absl/random/internal/pool_urbg.h"
+#include <iterator>
+
+#include "absl/base/config.h"
+#include "absl/random/internal/entropy_pool.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
SeedSeq MakeSeedSeq() {
SeedSeq::result_type seed_material[8];
- random_internal::RandenPool<uint32_t>::Fill(absl::MakeSpan(seed_material));
+ random_internal::GetEntropyFromRandenPool(&seed_material[0],
+ sizeof(seed_material[0]) * 8);
return SeedSeq(std::begin(seed_material), std::end(seed_material));
}
diff --git a/absl/random/seed_sequences.h b/absl/random/seed_sequences.h
index 33970be..dacc5b9 100644
--- a/absl/random/seed_sequences.h
+++ b/absl/random/seed_sequences.h
@@ -80,8 +80,7 @@
//
template <typename URBG>
SeedSeq CreateSeedSeqFrom(URBG* urbg) {
- SeedSeq::result_type
- seed_material[random_internal::kEntropyBlocksNeeded];
+ SeedSeq::result_type seed_material[random_internal::kEntropyBlocksNeeded];
if (!random_internal::ReadSeedMaterialFromURBG(
urbg, absl::MakeSpan(seed_material))) {
diff --git a/absl/random/uniform_int_distribution.h b/absl/random/uniform_int_distribution.h
index fae8025..0dc7c62 100644
--- a/absl/random/uniform_int_distribution.h
+++ b/absl/random/uniform_int_distribution.h
@@ -31,8 +31,9 @@
#include <cassert>
#include <istream>
#include <limits>
-#include <type_traits>
+#include <ostream>
+#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/iostream_state_saver.h"
diff --git a/absl/random/uniform_int_distribution_test.cc b/absl/random/uniform_int_distribution_test.cc
index b40d618..8134ab6 100644
--- a/absl/random/uniform_int_distribution_test.cc
+++ b/absl/random/uniform_int_distribution_test.cc
@@ -114,8 +114,8 @@
TYPED_TEST(UniformIntDistributionTest, ViolatesPreconditionsDeathTest) {
#if GTEST_HAS_DEATH_TEST
// Hi < Lo
- EXPECT_DEBUG_DEATH({ absl::uniform_int_distribution<TypeParam> dist(10, 1); },
- "");
+ EXPECT_DEBUG_DEATH(
+ { absl::uniform_int_distribution<TypeParam> dist(10, 1); }, "");
#endif // GTEST_HAS_DEATH_TEST
#if defined(NDEBUG)
// opt-mode, for invalid parameters, will generate a garbage value,
diff --git a/absl/random/uniform_real_distribution.h b/absl/random/uniform_real_distribution.h
index 1968334..8bef946 100644
--- a/absl/random/uniform_real_distribution.h
+++ b/absl/random/uniform_real_distribution.h
@@ -37,8 +37,10 @@
#include <cstdint>
#include <istream>
#include <limits>
+#include <ostream>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/generate_real.h"
diff --git a/absl/random/uniform_real_distribution_test.cc b/absl/random/uniform_real_distribution_test.cc
index 260aac9..4d544ca 100644
--- a/absl/random/uniform_real_distribution_test.cc
+++ b/absl/random/uniform_real_distribution_test.cc
@@ -190,7 +190,7 @@
#ifdef _MSC_VER
#pragma warning(push)
-#pragma warning(disable:4756) // Constant arithmetic overflow.
+#pragma warning(disable : 4756) // Constant arithmetic overflow.
#endif
TYPED_TEST(UniformRealDistributionTest, ViolatesPreconditionsDeathTest) {
using DistributionType = absl::uniform_real_distribution<TypeParam>;
diff --git a/absl/random/zipf_distribution.h b/absl/random/zipf_distribution.h
index 03497b1..21e3b70 100644
--- a/absl/random/zipf_distribution.h
+++ b/absl/random/zipf_distribution.h
@@ -22,6 +22,7 @@
#include <ostream>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/random/internal/iostream_state_saver.h"
#include "absl/random/internal/traits.h"
#include "absl/random/uniform_real_distribution.h"
@@ -57,8 +58,8 @@
public:
using distribution_type = zipf_distribution;
- // Preconditions: k > 0, v > 0, q > 1
- // The precondidtions are validated when NDEBUG is not defined via
+ // Preconditions: k >= 0, v > 0, q > 1
+ // The preconditions are validated when NDEBUG is not defined via
// a pair of assert() directives.
// If NDEBUG is defined and either or both of these parameters take invalid
// values, the behavior of the class is undefined.
@@ -152,7 +153,7 @@
: k_(k), q_(q), v_(v), one_minus_q_(1 - q) {
assert(q > 1);
assert(v > 0);
- assert(k > 0);
+ assert(k >= 0);
one_minus_q_inv_ = 1 / one_minus_q_;
// Setup for the ZRI algorithm (pg 17 of the paper).
@@ -221,7 +222,7 @@
const double v = uniform_double(g);
const double u = p.hxm_ + v * p.hx0_minus_hxm_;
const double x = p.hinv(u);
- k = rint(x); // std::floor(x + 0.5);
+ k = rint(x); // std::floor(x + 0.5);
if (k > static_cast<double>(p.k())) continue; // reject k > max_k
if (k - x <= p.s_) break;
const double h = p.h(k + 0.5);
diff --git a/absl/random/zipf_distribution_test.cc b/absl/random/zipf_distribution_test.cc
index 801ec4f..71548ca 100644
--- a/absl/random/zipf_distribution_test.cc
+++ b/absl/random/zipf_distribution_test.cc
@@ -176,15 +176,15 @@
const double x = v_ + i;
// H(n, q-1)
- const double hnqm1 =
- (q_ == 2.0) ? (1.0 / x)
- : (q_ == 3.0) ? (1.0 / (x * x)) : std::pow(x, -qm1);
+ const double hnqm1 = (q_ == 2.0) ? (1.0 / x)
+ : (q_ == 3.0) ? (1.0 / (x * x))
+ : std::pow(x, -qm1);
sum_hnq_m1 += hnqm1;
// H(n, q)
- const double hnq =
- (q_ == 2.0) ? (1.0 / (x * x))
- : (q_ == 3.0) ? (1.0 / (x * x * x)) : std::pow(x, -q_);
+ const double hnq = (q_ == 2.0) ? (1.0 / (x * x))
+ : (q_ == 3.0) ? (1.0 / (x * x * x))
+ : std::pow(x, -q_);
sum_hnq_ += hnq;
hnq_.push_back(hnq);
if (i > 1000 && hnq <= 1e-10) {
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index 8822e0f..b61abeb 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -58,6 +58,7 @@
"//absl/base:raw_logging_internal",
"//absl/base:strerror",
"//absl/container:inlined_vector",
+ "//absl/debugging:leak_check",
"//absl/debugging:stacktrace",
"//absl/debugging:symbolize",
"//absl/functional:function_ref",
@@ -80,8 +81,19 @@
"//absl/strings",
"//absl/strings:cord",
"//absl/strings:str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_binary(
+ name = "status_benchmark",
+ testonly = True,
+ srcs = ["status_benchmark.cc"],
+ tags = ["benchmark"],
+ deps = [
+ ":status",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -126,8 +138,20 @@
"//absl/types:any",
"//absl/types:variant",
"//absl/utility",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
+ ],
+)
+
+cc_binary(
+ name = "statusor_benchmark",
+ testonly = True,
+ srcs = ["statusor_benchmark.cc"],
+ tags = ["benchmark"],
+ deps = [
+ ":status",
+ ":statusor",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -146,7 +170,7 @@
":statusor",
"//absl/base:config",
"//absl/strings:string_view",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -161,7 +185,7 @@
":status_matchers",
":statusor",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index 24c01e7..e140365 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -35,6 +35,7 @@
absl::core_headers
absl::function_ref
absl::inlined_vector
+ absl::leak_check
absl::memory
absl::no_destructor
absl::nullability
@@ -42,8 +43,8 @@
absl::raw_logging_internal
absl::span
absl::stacktrace
- absl::strerror
absl::str_format
+ absl::strerror
absl::strings
absl::symbolize
PUBLIC
diff --git a/absl/status/internal/status_internal.cc b/absl/status/internal/status_internal.cc
index a915675..9884189 100644
--- a/absl/status/internal/status_internal.cc
+++ b/absl/status/internal/status_internal.cc
@@ -28,6 +28,7 @@
#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
+#include "absl/debugging/leak_check.h"
#include "absl/debugging/stacktrace.h"
#include "absl/debugging/symbolize.h"
#include "absl/memory/memory.h"
@@ -188,7 +189,7 @@
return true;
}
-absl::Nonnull<StatusRep*> StatusRep::CloneAndUnref() const {
+StatusRep* absl_nonnull StatusRep::CloneAndUnref() const {
// Optimization: no need to create a clone if we already have a refcount of 1.
if (ref_.load(std::memory_order_acquire) == 1) {
// All StatusRep instances are heap allocated and mutable, therefore this
@@ -234,12 +235,14 @@
}
}
-absl::Nonnull<std::string*> MakeCheckFailString(
- absl::Nonnull<const absl::Status*> status,
- absl::Nonnull<const char*> prefix) {
- return new std::string(
- absl::StrCat(prefix, " (",
- status->ToString(StatusToStringMode::kWithEverything), ")"));
+const char* absl_nonnull MakeCheckFailString(
+ const absl::Status* absl_nonnull status, const char* absl_nonnull prefix) {
+ // There's no need to free this string since the process is crashing.
+ return absl::IgnoreLeak(
+ new std::string(absl::StrCat(
+ prefix, " (",
+ status->ToString(StatusToStringMode::kWithEverything), ")")))
+ ->c_str();
}
} // namespace status_internal
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h
index c9f4383..45b90f3 100644
--- a/absl/status/internal/status_internal.h
+++ b/absl/status/internal/status_internal.h
@@ -100,7 +100,7 @@
// Returns an equivalent heap allocated StatusRep with refcount 1.
//
// `this` is not safe to be used after calling as it may have been deleted.
- absl::Nonnull<StatusRep*> CloneAndUnref() const;
+ StatusRep* absl_nonnull CloneAndUnref() const;
private:
mutable std::atomic<int32_t> ref_;
@@ -120,9 +120,8 @@
//
// This is an internal implementation detail for Abseil logging.
ABSL_ATTRIBUTE_PURE_FUNCTION
-absl::Nonnull<std::string*> MakeCheckFailString(
- absl::Nonnull<const absl::Status*> status,
- absl::Nonnull<const char*> prefix);
+const char* absl_nonnull MakeCheckFailString(
+ const absl::Status* absl_nonnull status, const char* absl_nonnull prefix);
} // namespace status_internal
diff --git a/absl/status/internal/status_matchers.cc b/absl/status/internal/status_matchers.cc
index 908b70b..c2912bb 100644
--- a/absl/status/internal/status_matchers.cc
+++ b/absl/status/internal/status_matchers.cc
@@ -30,14 +30,14 @@
namespace status_internal {
void StatusIsMatcherCommonImpl::DescribeTo(std::ostream* os) const {
- *os << ", has a status code that ";
+ *os << "has a status code that ";
code_matcher_.DescribeTo(os);
*os << ", and has an error message that ";
message_matcher_.DescribeTo(os);
}
void StatusIsMatcherCommonImpl::DescribeNegationTo(std::ostream* os) const {
- *os << ", or has a status code that ";
+ *os << "either has a status code that ";
code_matcher_.DescribeNegationTo(os);
*os << ", or has an error message that ";
message_matcher_.DescribeNegationTo(os);
@@ -49,7 +49,8 @@
::testing::StringMatchResultListener inner_listener;
if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
*result_listener << (inner_listener.str().empty()
- ? "whose status code is wrong"
+ ? status.ok() ? "which is OK"
+ : "whose status code is wrong"
: "which has a status code " +
inner_listener.str());
return false;
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
index 6760315..e986611 100644
--- a/absl/status/internal/statusor_internal.h
+++ b/absl/status/internal/statusor_internal.h
@@ -39,7 +39,8 @@
struct HasConversionOperatorToStatusOr : std::false_type {};
template <typename T, typename U>
-void test(char (*)[sizeof(std::declval<U>().operator absl::StatusOr<T>())]);
+void test(char (*absl_nullable)[sizeof(
+ std::declval<U>().operator absl::StatusOr<T>())]);
template <typename T, typename U>
struct HasConversionOperatorToStatusOr<T, U, decltype(test<T, U>(0))>
@@ -185,7 +186,7 @@
class Helper {
public:
// Move type-agnostic error handling to the .cc.
- static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>);
+ static void HandleInvalidStatusCtorArg(Status* absl_nonnull);
[[noreturn]] static void Crash(const absl::Status& status);
};
@@ -194,7 +195,7 @@
// This abstraction is here mostly for the gcc performance fix.
template <typename T, typename... Args>
ABSL_ATTRIBUTE_NONNULL(1)
-void PlacementNew(absl::Nonnull<void*> p, Args&&... args) {
+void PlacementNew(void* absl_nonnull p, Args&&... args) {
new (p) T(std::forward<Args>(args)...);
}
diff --git a/absl/status/status.cc b/absl/status/status.cc
index 745ab88..963dab6 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -91,16 +91,12 @@
return os << StatusCodeToString(code);
}
-absl::Nonnull<const std::string*> Status::EmptyString() {
+const std::string* absl_nonnull Status::EmptyString() {
static const absl::NoDestructor<std::string> kEmpty;
return kEmpty.get();
}
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr const char Status::kMovedFromString[];
-#endif
-
-absl::Nonnull<const std::string*> Status::MovedFromString() {
+const std::string* absl_nonnull Status::MovedFromString() {
static const absl::NoDestructor<std::string> kMovedFrom(kMovedFromString);
return kMovedFrom.get();
}
@@ -112,7 +108,7 @@
}
}
-absl::Nonnull<status_internal::StatusRep*> Status::PrepareToModify(
+status_internal::StatusRep* absl_nonnull Status::PrepareToModify(
uintptr_t rep) {
if (IsInlined(rep)) {
return new status_internal::StatusRep(InlinedRepToCode(rep),
@@ -410,7 +406,7 @@
MessageForErrnoToStatus(error_number, message));
}
-absl::Nonnull<const char*> StatusMessageAsCStr(const Status& status) {
+const char* absl_nonnull StatusMessageAsCStr(const Status& status) {
// As an internal implementation detail, we guarantee that if status.message()
// is non-empty, then the resulting string_view is null terminated.
auto sv_message = status.message();
diff --git a/absl/status/status.h b/absl/status/status.h
index 6cfe49f..4516822 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -623,15 +623,15 @@
// REQUIRES: !ok()
// Ensures rep is not inlined or shared with any other Status.
- static absl::Nonnull<status_internal::StatusRep*> PrepareToModify(
+ static status_internal::StatusRep* absl_nonnull PrepareToModify(
uintptr_t rep);
// MSVC 14.0 limitation requires the const.
static constexpr const char kMovedFromString[] =
"Status accessed after move.";
- static absl::Nonnull<const std::string*> EmptyString();
- static absl::Nonnull<const std::string*> MovedFromString();
+ static const std::string* absl_nonnull EmptyString();
+ static const std::string* absl_nonnull MovedFromString();
// Returns whether rep contains an inlined representation.
// See rep_ for details.
@@ -649,8 +649,8 @@
// Converts between StatusRep* and the external uintptr_t representation used
// by rep_. See rep_ for details.
- static uintptr_t PointerToRep(status_internal::StatusRep* r);
- static absl::Nonnull<const status_internal::StatusRep*> RepToPointer(
+ static uintptr_t PointerToRep(status_internal::StatusRep* absl_nonnull r);
+ static const status_internal::StatusRep* absl_nonnull RepToPointer(
uintptr_t r);
static std::string ToStringSlow(uintptr_t rep, StatusToStringMode mode);
@@ -902,14 +902,14 @@
return CodeToInlinedRep(absl::StatusCode::kInternal) | 2;
}
-inline absl::Nonnull<const status_internal::StatusRep*> Status::RepToPointer(
+inline const status_internal::StatusRep* absl_nonnull Status::RepToPointer(
uintptr_t rep) {
assert(!IsInlined(rep));
return reinterpret_cast<const status_internal::StatusRep*>(rep);
}
inline uintptr_t Status::PointerToRep(
- absl::Nonnull<status_internal::StatusRep*> rep) {
+ status_internal::StatusRep* absl_nonnull rep) {
return reinterpret_cast<uintptr_t>(rep);
}
@@ -934,7 +934,7 @@
// If the status's message is empty, the empty string is returned.
//
// StatusMessageAsCStr exists for C support. Use `status.message()` in C++.
-absl::Nonnull<const char*> StatusMessageAsCStr(
+const char* absl_nonnull StatusMessageAsCStr(
const Status& status ABSL_ATTRIBUTE_LIFETIME_BOUND);
ABSL_NAMESPACE_END
diff --git a/absl/status/status_benchmark.cc b/absl/status/status_benchmark.cc
new file mode 100644
index 0000000..a9146fb
--- /dev/null
+++ b/absl/status/status_benchmark.cc
@@ -0,0 +1,37 @@
+// Copyright 2025 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <utility>
+#include "absl/status/status.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_CreateOk(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::Status s; // ok.
+ benchmark::DoNotOptimize(s);
+ }
+}
+BENCHMARK(BM_CreateOk);
+
+void BM_CreateBad(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::Status s(absl::StatusCode::kInvalidArgument, "message");
+ benchmark::DoNotOptimize(s);
+ }
+}
+BENCHMARK(BM_CreateBad);
+
+} // namespace
diff --git a/absl/status/status_matchers_test.cc b/absl/status/status_matchers_test.cc
index 3af0305..b8ccaa4 100644
--- a/absl/status/status_matchers_test.cc
+++ b/absl/status/status_matchers_test.cc
@@ -17,6 +17,8 @@
// -----------------------------------------------------------------------------
#include "absl/status/status_matchers.h"
+#include <string>
+
#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "gtest/gtest.h"
@@ -29,7 +31,9 @@
using ::absl_testing::IsOk;
using ::absl_testing::IsOkAndHolds;
using ::absl_testing::StatusIs;
+using ::testing::Eq;
using ::testing::Gt;
+using ::testing::MatchesRegex;
TEST(StatusMatcherTest, StatusIsOk) { EXPECT_THAT(absl::OkStatus(), IsOk()); }
@@ -66,6 +70,13 @@
"actual");
}
+template <typename MatcherType, typename Value>
+std::string Explain(const MatcherType& m, const Value& x) {
+ ::testing::StringMatchResultListener listener;
+ ExplainMatchResult(m, x, &listener);
+ return listener.str();
+}
+
TEST(StatusMatcherTest, StatusIs) {
absl::Status unknown = absl::UnknownError("unbekannt");
absl::Status invalid = absl::InvalidArgumentError("ungueltig");
@@ -78,6 +89,20 @@
EXPECT_THAT(invalid, StatusIs(3));
EXPECT_THAT(invalid,
StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
+
+ auto m = StatusIs(absl::StatusCode::kInternal, "internal error");
+ EXPECT_THAT(
+ ::testing::DescribeMatcher<absl::Status>(m),
+ MatchesRegex(
+ "has a status code that .*, and has an error message that .*"));
+ EXPECT_THAT(
+ ::testing::DescribeMatcher<absl::Status>(m, /*negation=*/true),
+ MatchesRegex(
+ "either has a status code that .*, or has an error message that .*"));
+ EXPECT_THAT(Explain(m, absl::InvalidArgumentError("internal error")),
+ Eq("whose status code is wrong"));
+ EXPECT_THAT(Explain(m, absl::InternalError("unexpected error")),
+ Eq("whose error message is wrong"));
}
TEST(StatusMatcherTest, StatusOrIs) {
@@ -94,6 +119,23 @@
EXPECT_THAT(invalid, StatusIs(3));
EXPECT_THAT(invalid,
StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
+
+ auto m = StatusIs(absl::StatusCode::kInternal, "internal error");
+ EXPECT_THAT(
+ ::testing::DescribeMatcher<absl::StatusOr<int>>(m),
+ MatchesRegex(
+ "has a status code that .*, and has an error message that .*"));
+ EXPECT_THAT(
+ ::testing::DescribeMatcher<absl::StatusOr<int>>(m, /*negation=*/true),
+ MatchesRegex(
+ "either has a status code that .*, or has an error message that .*"));
+ EXPECT_THAT(Explain(m, absl::StatusOr<int>(57)), Eq("which is OK"));
+ EXPECT_THAT(Explain(m, absl::StatusOr<int>(
+ absl::InvalidArgumentError("internal error"))),
+ Eq("whose status code is wrong"));
+ EXPECT_THAT(
+ Explain(m, absl::StatusOr<int>(absl::InternalError("unexpected error"))),
+ Eq("whose error message is wrong"));
}
TEST(StatusMatcherTest, StatusIsFailure) {
diff --git a/absl/status/status_payload_printer.h b/absl/status/status_payload_printer.h
index f22255e..fc55515 100644
--- a/absl/status/status_payload_printer.h
+++ b/absl/status/status_payload_printer.h
@@ -35,8 +35,8 @@
// NOTE: This is an internal API and the design is subject to change in the
// future in a non-backward-compatible way. Since it's only meant for debugging
// purpose, you should not rely on it in any critical logic.
-using StatusPayloadPrinter = absl::Nullable<absl::optional<std::string> (*)(
- absl::string_view, const absl::Cord&)>;
+using StatusPayloadPrinter = absl::optional<std::string> (*absl_nullable)(
+ absl::string_view, const absl::Cord&);
// Sets the global payload printer. Only one printer should be set per process.
// If multiple printers are set, it's undefined which one will be used.
diff --git a/absl/status/statusor.cc b/absl/status/statusor.cc
index 7e6b334..d8f66a6 100644
--- a/absl/status/statusor.cc
+++ b/absl/status/statusor.cc
@@ -55,7 +55,7 @@
BadStatusOrAccess::BadStatusOrAccess(BadStatusOrAccess&& other)
: status_(std::move(other.status_)) {}
-absl::Nonnull<const char*> BadStatusOrAccess::what() const noexcept {
+const char* absl_nonnull BadStatusOrAccess::what() const noexcept {
InitWhat();
return what_.c_str();
}
@@ -70,7 +70,7 @@
namespace internal_statusor {
-void Helper::HandleInvalidStatusCtorArg(absl::Nonnull<absl::Status*> status) {
+void Helper::HandleInvalidStatusCtorArg(absl::Status* absl_nonnull status) {
const char* kMessage =
"An OK status is not a valid constructor argument to StatusOr<T>";
#ifdef NDEBUG
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index b1da45e..6142a2f 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -93,7 +93,7 @@
//
// The pointer of this string is guaranteed to be valid until any non-const
// function is invoked on the exception object.
- absl::Nonnull<const char*> what() const noexcept override;
+ const char* absl_nonnull what() const noexcept override;
// BadStatusOrAccess::status()
//
@@ -464,7 +464,7 @@
// Returns a reference to the current `absl::Status` contained within the
// `absl::StatusOr<T>`. If `absl::StatusOr<T>` contains a `T`, then this
// function returns `absl::OkStatus()`.
- const Status& status() const&;
+ ABSL_MUST_USE_RESULT const Status& status() const&;
Status status() &&;
// StatusOr<T>::value()
@@ -520,8 +520,8 @@
// REQUIRES: `this->ok() == true`, otherwise the behavior is undefined.
//
// Use `this->ok()` to verify that there is a current value.
- const T* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
- T* operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND;
+ const T* absl_nonnull operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
+ T* absl_nonnull operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND;
// StatusOr<T>::value_or()
//
@@ -756,13 +756,13 @@
}
template <typename T>
-absl::Nonnull<const T*> StatusOr<T>::operator->() const {
+const T* absl_nonnull StatusOr<T>::operator->() const {
this->EnsureOk();
return &this->data_;
}
template <typename T>
-absl::Nonnull<T*> StatusOr<T>::operator->() {
+T* absl_nonnull StatusOr<T>::operator->() {
this->EnsureOk();
return &this->data_;
}
diff --git a/absl/status/statusor_benchmark.cc b/absl/status/statusor_benchmark.cc
new file mode 100644
index 0000000..bb99547
--- /dev/null
+++ b/absl/status/statusor_benchmark.cc
@@ -0,0 +1,480 @@
+// Copyright 2025 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_StatusOrInt_CtorStatus(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(absl::CancelledError());
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CtorStatus);
+
+void BM_StatusOrInt_CtorStatusWithMessage(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CtorStatusWithMessage);
+
+void BM_StatusOrInt_CopyCtor_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CopyCtor_Error);
+
+void BM_StatusOrInt_CopyCtor_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(42);
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CopyCtor_Ok);
+
+void BM_StatusOrInt_MoveCtor_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_MoveCtor_Error);
+
+void BM_StatusOrInt_MoveCtor_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(42);
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_MoveCtor_Ok);
+
+void BM_StatusOrInt_CopyAssign_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CopyAssign_Error);
+
+void BM_StatusOrInt_CopyAssign_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(42);
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_CopyAssign_Ok);
+
+void BM_StatusOrInt_MoveAssign_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_MoveAssign_Error);
+
+void BM_StatusOrInt_MoveAssign_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> original(42);
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrInt_MoveAssign_Ok);
+
+void BM_StatusOrInt_OkMethod_Error(benchmark::State& state) {
+ absl::StatusOr<int> status(
+ absl::UnknownError("This string is 28 characters"));
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.ok());
+ }
+}
+BENCHMARK(BM_StatusOrInt_OkMethod_Error);
+
+void BM_StatusOrInt_OkMethod_Ok(benchmark::State& state) {
+ absl::StatusOr<int> status(42);
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.ok());
+ }
+}
+BENCHMARK(BM_StatusOrInt_OkMethod_Ok);
+
+void BM_StatusOrInt_StatusMethod_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.status().ok());
+ }
+}
+BENCHMARK(BM_StatusOrInt_StatusMethod_Error);
+
+void BM_StatusOrInt_StatusMethod_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(std::move(status).status().ok());
+ }
+}
+BENCHMARK(BM_StatusOrInt_StatusMethod_Ok);
+
+void BM_StatusOrInt_StatusMethodRvalue_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(std::move(status).status().ok());
+ }
+}
+BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Error);
+
+void BM_StatusOrInt_StatusMethodRvalue_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<int> status(42);
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(std::move(status).status());
+ }
+}
+BENCHMARK(BM_StatusOrInt_StatusMethodRvalue_Ok);
+
+void BM_StatusOrString_CtorStatus(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status(absl::CancelledError());
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CtorStatus);
+
+void BM_StatusOrString_CtorStatusWithMessage(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CtorStatusWithMessage);
+
+void BM_StatusOrString_CopyCtor_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status(original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CopyCtor_Error);
+
+void BM_StatusOrString_CopyCtor_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original("This string is 28 characters");
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status(original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CopyCtor_Ok);
+
+void BM_StatusOrString_MoveCtor_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status(std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_MoveCtor_Error);
+
+void BM_StatusOrString_MoveCtor_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original("This string is 28 characters");
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status(std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_MoveCtor_Ok);
+
+void BM_StatusOrString_CopyAssign_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CopyAssign_Error);
+
+void BM_StatusOrString_CopyAssign_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original("This string is 28 characters");
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = original);
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_CopyAssign_Ok);
+
+void BM_StatusOrString_MoveAssign_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_MoveAssign_Error);
+
+void BM_StatusOrString_MoveAssign_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> original("This string is 28 characters");
+ benchmark::DoNotOptimize(original);
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status = std::move(original));
+ benchmark::DoNotOptimize(status);
+ }
+}
+BENCHMARK(BM_StatusOrString_MoveAssign_Ok);
+
+void BM_StatusOrString_OkMethod_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.ok());
+ }
+}
+BENCHMARK(BM_StatusOrString_OkMethod_Error);
+
+void BM_StatusOrString_OkMethod_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.ok());
+ }
+}
+BENCHMARK(BM_StatusOrString_OkMethod_Ok);
+
+void BM_StatusOrString_StatusMethod_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.status().ok());
+ }
+}
+BENCHMARK(BM_StatusOrString_StatusMethod_Error);
+
+void BM_StatusOrString_StatusMethod_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(status.status().ok());
+ }
+}
+BENCHMARK(BM_StatusOrString_StatusMethod_Ok);
+
+void BM_StatusOrString_StatusMethodRvalue_Error(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status(
+ absl::UnknownError("This string is 28 characters"));
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(std::move(status).status());
+ }
+}
+BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Error);
+
+void BM_StatusOrString_StatusMethodRvalue_Ok(benchmark::State& state) {
+ for (auto _ : state) {
+ absl::StatusOr<std::string> status("This string is 28 characters");
+ benchmark::DoNotOptimize(status);
+ benchmark::DoNotOptimize(std::move(status).status());
+ }
+}
+BENCHMARK(BM_StatusOrString_StatusMethodRvalue_Ok);
+
+// Benchmarks comparing a few alternative ways of structuring an interface
+// for returning an int64 on success or an error. See (a), (b), (c), (d)
+// below for the variants.
+bool bm_cond = true;
+
+bool SimpleIntInterface(int64_t* v) ABSL_ATTRIBUTE_NOINLINE;
+bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg)
+ ABSL_ATTRIBUTE_NOINLINE;
+absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v)
+ ABSL_ATTRIBUTE_NOINLINE;
+absl::StatusOr<int64_t> SimpleIntStatusOrInterface() ABSL_ATTRIBUTE_NOINLINE;
+
+// (a): Just a boolean return value with an out int64* parameter
+bool SimpleIntInterface(int64_t* v) {
+ benchmark::DoNotOptimize(bm_cond);
+ if (bm_cond) {
+ *v = 42;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// (b): A boolean return value and a string error message filled in on failure
+// and an out int64* parameter filled on success
+bool SimpleIntInterfaceWithErrorMessage(int64_t* v, std::string* msg) {
+ benchmark::DoNotOptimize(bm_cond);
+ if (bm_cond) {
+ *v = 42;
+ return true;
+ } else {
+ *msg = "This is an error message";
+ return false;
+ }
+}
+
+// (c): A Status return value with an out int64* parameter on success
+absl::Status SimpleIntInterfaceWithErrorStatus(int64_t* v) {
+ benchmark::DoNotOptimize(bm_cond);
+ if (bm_cond) {
+ *v = 42;
+ return absl::OkStatus();
+ } else {
+ return absl::UnknownError("This is an error message");
+ }
+}
+
+// (d): A StatusOr<int64> return value
+absl::StatusOr<int64_t> SimpleIntStatusOrInterface() {
+ benchmark::DoNotOptimize(bm_cond);
+ if (bm_cond) {
+ return 42;
+ } else {
+ return absl::StatusOr<int64_t>(
+ absl::UnknownError("This is an error message"));
+ }
+}
+
+void SetCondition(benchmark::State& state) {
+ bm_cond = (state.range(0) == 0);
+ state.SetLabel(bm_cond ? "Success" : "Failure");
+}
+
+void BM_SimpleIntInterface(benchmark::State& state) {
+ SetCondition(state);
+ int64_t sum = 0;
+ for (auto s : state) {
+ int64_t v;
+ if (SimpleIntInterface(&v)) {
+ sum += v;
+ }
+ benchmark::DoNotOptimize(sum);
+ }
+}
+
+void BM_SimpleIntInterfaceMsg(benchmark::State& state) {
+ SetCondition(state);
+ int64_t sum = 0;
+ std::string msg;
+ for (auto s : state) {
+ int64_t v;
+ if (SimpleIntInterfaceWithErrorMessage(&v, &msg)) {
+ sum += v;
+ }
+ benchmark::DoNotOptimize(sum);
+ benchmark::DoNotOptimize(msg);
+ }
+}
+
+void BM_SimpleIntInterfaceStatus(benchmark::State& state) {
+ SetCondition(state);
+ int64_t sum = 0;
+ for (auto s : state) {
+ int64_t v;
+ auto result = SimpleIntInterfaceWithErrorStatus(&v);
+ if (result.ok()) {
+ sum += v;
+ }
+ benchmark::DoNotOptimize(sum);
+ }
+}
+
+void BM_SimpleIntStatusOrInterface(benchmark::State& state) {
+ SetCondition(state);
+ int64_t sum = 0;
+ for (auto s : state) {
+ auto v_s = SimpleIntStatusOrInterface();
+ if (v_s.ok()) {
+ sum += *v_s;
+ }
+ benchmark::DoNotOptimize(sum);
+ }
+}
+
+// Ordered like this so all the success path benchmarks (Arg(0)) show up,
+// then all the failure benchmarks (Arg(1))
+BENCHMARK(BM_SimpleIntInterface)->Arg(0);
+BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(0);
+BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(0);
+BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(0);
+BENCHMARK(BM_SimpleIntInterface)->Arg(1);
+BENCHMARK(BM_SimpleIntInterfaceMsg)->Arg(1);
+BENCHMARK(BM_SimpleIntInterfaceStatus)->Arg(1);
+BENCHMARK(BM_SimpleIntStatusOrInterface)->Arg(1);
+
+} // namespace
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index 8341040..17a3384 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -459,7 +459,7 @@
EXPECT_EQ(p, *source);
}
- // Move asssignment
+ // Move assignment
{
const auto p = std::make_shared<int>(17);
absl::StatusOr<std::shared_ptr<int>> source(p);
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 2cc014e..bb152ac 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -104,6 +104,7 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
+ "//absl/base:iterator_traits_internal",
"//absl/base:nullability",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate",
@@ -146,8 +147,8 @@
visibility = ["//visibility:private"],
deps = [
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -166,13 +167,14 @@
"//absl/base:core_headers",
"//absl/container:fixed_array",
"//absl/log:check",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "escaping_benchmark",
+ testonly = True,
srcs = [
"escaping_benchmark.cc",
"internal/escaping_test_common.h",
@@ -183,8 +185,7 @@
deps = [
":strings",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -197,8 +198,8 @@
deps = [
":strings",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -221,8 +222,8 @@
deps = [
":has_ostream_operator",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -235,21 +236,22 @@
deps = [
":strings",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "ascii_benchmark",
+ testonly = True,
srcs = ["ascii_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":strings",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "//absl/random",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -262,13 +264,30 @@
copts = ABSL_TEST_COPTS,
deps = [
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
+ name = "damerau_levenshtein_distance_benchmark",
+ testonly = True,
+ srcs = [
+ "internal/damerau_levenshtein_distance_benchmark.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["benchmark"],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":strings",
+ "@google_benchmark//:benchmark_main",
+ ],
+)
+
+cc_binary(
name = "memutil_benchmark",
+ testonly = True,
srcs = [
"internal/memutil.h",
"internal/memutil_benchmark.cc",
@@ -279,8 +298,7 @@
deps = [
":strings",
"//absl/base:core_headers",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -296,8 +314,8 @@
deps = [
":strings",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -311,9 +329,10 @@
visibility = ["//visibility:private"],
deps = [
":internal",
+ ":string_view",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -326,13 +345,14 @@
deps = [
":strings",
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "string_view_benchmark",
+ testonly = True,
srcs = ["string_view_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
@@ -342,8 +362,8 @@
":strings",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "//absl/random",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -359,14 +379,14 @@
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "charset_benchmark",
- size = "small",
+ testonly = True,
srcs = [
"charset_benchmark.cc",
],
@@ -378,8 +398,7 @@
deps = [
":charset",
"//absl/log:check",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -392,7 +411,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":string_view",
- "//absl/base:core_headers",
+ "//absl/base:config",
],
)
@@ -405,8 +424,8 @@
deps = [
":charset",
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -437,19 +456,16 @@
],
deps = [
":strings",
- "//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
+ "//absl/base:nullability",
"//absl/base:raw_logging_internal",
- "//absl/base:throw_delegate",
"//absl/container:compressed_tuple",
"//absl/container:container_memory",
"//absl/container:inlined_vector",
- "//absl/container:layout",
"//absl/crc:crc_cord_state",
"//absl/functional:function_ref",
- "//absl/meta:type_traits",
"//absl/types:span",
],
)
@@ -465,8 +481,8 @@
":cord_rep_test_util",
":strings",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -484,8 +500,8 @@
"//absl/base:config",
"//absl/base:raw_logging_internal",
"//absl/cleanup",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -501,8 +517,8 @@
":strings",
"//absl/base:config",
"//absl/base:raw_logging_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -519,8 +535,8 @@
":strings",
"//absl/base:config",
"//absl/base:raw_logging_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -535,8 +551,8 @@
":cord_rep_test_util",
"//absl/base:config",
"//absl/crc:crc_cord_state",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -559,8 +575,8 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/synchronization",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -570,7 +586,6 @@
"cord.cc",
"cord_analysis.cc",
"cord_analysis.h",
- "cord_buffer.cc",
],
hdrs = [
"cord.h",
@@ -580,14 +595,11 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":cord_internal",
- ":cordz_functions",
":cordz_info",
- ":cordz_statistics",
":cordz_update_scope",
":cordz_update_tracker",
":internal",
":strings",
- "//absl/base",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:endian",
@@ -597,6 +609,7 @@
"//absl/crc:crc32c",
"//absl/crc:crc_cord_state",
"//absl/functional:function_ref",
+ "//absl/hash:weakly_mixed_integer",
"//absl/meta:type_traits",
"//absl/numeric:bits",
"//absl/types:compare",
@@ -611,9 +624,7 @@
hdrs = ["internal/cordz_handle.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl:__subpackages__",
- ],
+ visibility = ["//absl:__subpackages__"],
deps = [
"//absl/base:config",
"//absl/base:no_destructor",
@@ -654,9 +665,7 @@
hdrs = ["internal/cordz_update_scope.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = [
- "//absl:__subpackages__",
- ],
+ visibility = ["//absl:__subpackages__"],
deps = [
":cord_internal",
":cordz_info",
@@ -677,8 +686,8 @@
":cordz_update_scope",
":cordz_update_tracker",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -738,8 +747,8 @@
":cordz_functions",
":cordz_test_helpers",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -757,8 +766,8 @@
"//absl/synchronization",
"//absl/synchronization:thread_pool",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -779,8 +788,8 @@
"//absl/debugging:stacktrace",
"//absl/debugging:symbolize",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -801,8 +810,8 @@
"//absl/crc:crc_cord_state",
"//absl/synchronization",
"//absl/synchronization:thread_pool",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -823,8 +832,8 @@
"//absl/synchronization",
"//absl/synchronization:thread_pool",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -875,7 +884,7 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:nullability",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
)
@@ -892,8 +901,8 @@
":string_view",
"//absl/base:config",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -927,8 +936,8 @@
"//absl/random",
"//absl/types:compare",
"//absl/types:optional",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -938,7 +947,6 @@
srcs = ["cordz_test.cc"],
copts = ABSL_TEST_COPTS,
tags = [
- "benchmark",
"no_test_android_arm",
"no_test_android_arm64",
"no_test_android_x86",
@@ -961,8 +969,8 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -975,13 +983,30 @@
deps = [
":strings",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
+ name = "substitute_benchmark",
+ testonly = True,
+ srcs = ["substitute_benchmark.cc"],
+ copts = ABSL_TEST_COPTS,
+ tags = [
+ "benchmark",
+ ],
+ visibility = ["//visibility:private"],
+ deps = [
+ ":strings",
+ "//absl/base:core_headers",
+ "@google_benchmark//:benchmark_main",
+ ],
+)
+
+cc_binary(
name = "str_replace_benchmark",
+ testonly = True,
srcs = ["str_replace_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
@@ -989,8 +1014,7 @@
deps = [
":strings",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1002,8 +1026,8 @@
visibility = ["//visibility:private"],
deps = [
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1019,13 +1043,14 @@
"//absl/container:btree",
"//absl/container:flat_hash_map",
"//absl/container:node_hash_map",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "str_split_benchmark",
+ testonly = True,
srcs = ["str_split_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
@@ -1033,8 +1058,7 @@
deps = [
":strings",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1046,21 +1070,21 @@
visibility = ["//visibility:private"],
deps = [
":internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "ostringstream_benchmark",
+ testonly = True,
srcs = ["internal/ostringstream_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1076,8 +1100,8 @@
deps = [
"//absl/base:core_headers",
"//absl/meta:type_traits",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1091,21 +1115,21 @@
":strings",
"//absl/base:core_headers",
"//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "str_join_benchmark",
+ testonly = True,
srcs = ["str_join_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":strings",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1118,23 +1142,25 @@
deps = [
":str_format",
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/base:config",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "str_cat_benchmark",
+ testonly = True,
srcs = ["str_cat_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
+ ":str_format",
":strings",
"//absl/random",
"//absl/random:distributions",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1156,13 +1182,14 @@
"//absl/numeric:int128",
"//absl/random",
"//absl/random:distributions",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "numbers_benchmark",
+ testonly = True,
srcs = ["numbers_benchmark.cc"],
copts = ABSL_TEST_COPTS,
tags = ["benchmark"],
@@ -1172,8 +1199,7 @@
"//absl/base:raw_logging_internal",
"//absl/random",
"//absl/random:distributions",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1185,8 +1211,8 @@
visibility = ["//visibility:private"],
deps = [
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1198,8 +1224,8 @@
":pow10_helper",
":str_format",
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1214,8 +1240,8 @@
":strings",
"//absl/base:config",
"//absl/log:check",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1230,13 +1256,14 @@
deps = [
":strings",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "charconv_benchmark",
+ testonly = True,
srcs = [
"charconv_benchmark.cc",
],
@@ -1245,8 +1272,7 @@
],
deps = [
":strings",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -1291,6 +1317,7 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
+ ":internal",
":strings",
"//absl/base:config",
"//absl/base:core_headers",
@@ -1319,8 +1346,8 @@
"//absl/base:config",
"//absl/base:core_headers",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1335,8 +1362,9 @@
":str_format",
":str_format_internal",
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "//absl/random",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1349,8 +1377,8 @@
":str_format",
":str_format_internal",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1361,8 +1389,8 @@
visibility = ["//visibility:private"],
deps = [
":str_format_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1373,8 +1401,8 @@
visibility = ["//visibility:private"],
deps = [
":str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1396,8 +1424,8 @@
"//absl/numeric:int128",
"//absl/types:optional",
"//absl/types:span",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1409,8 +1437,8 @@
deps = [
":cord",
":str_format_internal",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1424,8 +1452,8 @@
":string_view",
"//absl/base:config",
"//absl/base:core_headers",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1447,8 +1475,8 @@
deps = [
":pow10_helper",
":str_format",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -1475,7 +1503,7 @@
deps = [
":str_format",
":strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 3a1619e..547ef26 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -84,6 +84,7 @@
absl::core_headers
absl::endian
absl::int128
+ absl::iterator_traits_internal
absl::memory
absl::nullability
absl::raw_logging_internal
@@ -100,7 +101,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::core_headers
+ absl::config
absl::string_view
PUBLIC
)
@@ -242,6 +243,7 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::string_view
absl::strings_internal
absl::base
absl::core_headers
@@ -371,6 +373,7 @@
DEPS
absl::strings
absl::str_format
+ absl::config
absl::core_headers
GTest::gmock_main
)
@@ -516,6 +519,7 @@
absl::utility
absl::int128
absl::span
+ absl::strings_internal
)
absl_cc_test(
@@ -543,6 +547,7 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::random_random
absl::str_format
absl::str_format_internal
absl::strings
@@ -700,7 +705,6 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::compressed_tuple
absl::config
absl::container_memory
@@ -975,7 +979,6 @@
"cord.cc"
"cord_analysis.cc"
"cord_analysis.h"
- "cord_buffer.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -998,6 +1001,7 @@
absl::span
absl::strings
absl::type_traits
+ absl::weakly_mixed_integer
PUBLIC
)
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
index 20a696a..4cd9ff9 100644
--- a/absl/strings/ascii.cc
+++ b/absl/strings/ascii.cc
@@ -19,10 +19,8 @@
#include <cstring>
#include <string>
-#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/nullability.h"
-#include "absl/base/optimization.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -177,10 +175,17 @@
return static_cast<signed char>(u) < threshold;
}
-// Force-inline so the compiler won't merge the short and long implementations.
template <bool ToUpper>
-ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr void AsciiStrCaseFoldImpl(
- absl::Nonnull<char*> p, size_t size) {
+constexpr bool AsciiInAZRangeNaive(unsigned char c) {
+ constexpr unsigned char a = (ToUpper ? 'a' : 'A');
+ constexpr unsigned char z = (ToUpper ? 'z' : 'Z');
+ return a <= c && c <= z;
+}
+
+template <bool ToUpper, bool Naive>
+constexpr void AsciiStrCaseFoldImpl(char* absl_nonnull dst,
+ const char* absl_nullable src,
+ size_t size) {
// The upper- and lowercase versions of ASCII characters differ by only 1 bit.
// When we need to flip the case, we can xor with this bit to achieve the
// desired result. Note that the choice of 'a' and 'A' here is arbitrary. We
@@ -189,29 +194,37 @@
constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A';
for (size_t i = 0; i < size; ++i) {
- unsigned char v = static_cast<unsigned char>(p[i]);
- v ^= AsciiInAZRange<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
- p[i] = static_cast<char>(v);
+ unsigned char v = static_cast<unsigned char>(src[i]);
+ if ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 (Naive) {
+ v ^= AsciiInAZRangeNaive<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
+ } else {
+ v ^= AsciiInAZRange<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
+ }
+ dst[i] = static_cast<char>(v);
}
}
-// The string size threshold for starting using the long string version.
-constexpr size_t kCaseFoldThreshold = 16;
-
-// No-inline so the compiler won't merge the short and long implementations.
-template <bool ToUpper>
-ABSL_ATTRIBUTE_NOINLINE constexpr void AsciiStrCaseFoldLong(
- absl::Nonnull<char*> p, size_t size) {
- ABSL_ASSUME(size >= kCaseFoldThreshold);
- AsciiStrCaseFoldImpl<ToUpper>(p, size);
-}
-
// Splitting to short and long strings to allow vectorization decisions
// to be made separately in the long and short cases.
+// Using slightly different implementations so the compiler won't optimize them
+// into the same code (the non-naive version is needed for SIMD, so for short
+// strings it's not important).
+// `src` may be null iff `size` is zero.
template <bool ToUpper>
-constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p, size_t size) {
- size < kCaseFoldThreshold ? AsciiStrCaseFoldImpl<ToUpper>(p, size)
- : AsciiStrCaseFoldLong<ToUpper>(p, size);
+constexpr void AsciiStrCaseFold(char* absl_nonnull dst,
+ const char* absl_nullable src, size_t size) {
+ size < 16 ? AsciiStrCaseFoldImpl<ToUpper, /*Naive=*/true>(dst, src, size)
+ : AsciiStrCaseFoldImpl<ToUpper, /*Naive=*/false>(dst, src, size);
+}
+
+void AsciiStrToLower(char* absl_nonnull dst, const char* absl_nullable src,
+ size_t n) {
+ return AsciiStrCaseFold<false>(dst, src, n);
+}
+
+void AsciiStrToUpper(char* absl_nonnull dst, const char* absl_nullable src,
+ size_t n) {
+ return AsciiStrCaseFold<true>(dst, src, n);
}
static constexpr size_t ValidateAsciiCasefold() {
@@ -222,8 +235,8 @@
for (unsigned int i = 0; i < num_chars; ++i) {
uppered[i] = lowered[i] = static_cast<char>(i);
}
- AsciiStrCaseFold<false>(&lowered[0], num_chars);
- AsciiStrCaseFold<true>(&uppered[0], num_chars);
+ AsciiStrCaseFold<false>(&lowered[0], &lowered[0], num_chars);
+ AsciiStrCaseFold<true>(&uppered[0], &uppered[0], num_chars);
for (size_t i = 0; i < num_chars; ++i) {
const char ch = static_cast<char>(i),
ch_upper = ('a' <= ch && ch <= 'z' ? 'A' + (ch - 'a') : ch),
@@ -240,15 +253,17 @@
} // namespace ascii_internal
-void AsciiStrToLower(absl::Nonnull<std::string*> s) {
- return ascii_internal::AsciiStrCaseFold<false>(&(*s)[0], s->size());
+void AsciiStrToLower(std::string* absl_nonnull s) {
+ char* p = &(*s)[0];
+ return ascii_internal::AsciiStrCaseFold<false>(p, p, s->size());
}
-void AsciiStrToUpper(absl::Nonnull<std::string*> s) {
- return ascii_internal::AsciiStrCaseFold<true>(&(*s)[0], s->size());
+void AsciiStrToUpper(std::string* absl_nonnull s) {
+ char* p = &(*s)[0];
+ return ascii_internal::AsciiStrCaseFold<true>(p, p, s->size());
}
-void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str) {
+void RemoveExtraAsciiWhitespace(std::string* absl_nonnull str) {
auto stripped = StripAsciiWhitespace(*str);
if (stripped.empty()) {
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index c238f4d..ca0747e 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -55,10 +55,12 @@
#include <algorithm>
#include <cstddef>
#include <string>
+#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/nullability.h"
+#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/string_view.h"
namespace absl {
@@ -74,6 +76,12 @@
// Declaration for the array of characters to lower-case characters.
ABSL_DLL extern const char kToLower[256];
+void AsciiStrToLower(char* absl_nonnull dst, const char* absl_nullable src,
+ size_t n);
+
+void AsciiStrToUpper(char* absl_nonnull dst, const char* absl_nullable src,
+ size_t n);
+
} // namespace ascii_internal
// ascii_isalpha()
@@ -131,32 +139,42 @@
//
// Determines whether the given character can be represented as a decimal
// digit character (i.e. {0-9}).
-inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; }
+inline constexpr bool ascii_isdigit(unsigned char c) {
+ return c >= '0' && c <= '9';
+}
// ascii_isprint()
//
// Determines whether the given character is printable, including spaces.
-inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; }
+inline constexpr bool ascii_isprint(unsigned char c) {
+ return c >= 32 && c < 127;
+}
// ascii_isgraph()
//
// Determines whether the given character has a graphical representation.
-inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; }
+inline constexpr bool ascii_isgraph(unsigned char c) {
+ return c > 32 && c < 127;
+}
// ascii_isupper()
//
// Determines whether the given character is uppercase.
-inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; }
+inline constexpr bool ascii_isupper(unsigned char c) {
+ return c >= 'A' && c <= 'Z';
+}
// ascii_islower()
//
// Determines whether the given character is lowercase.
-inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; }
+inline constexpr bool ascii_islower(unsigned char c) {
+ return c >= 'a' && c <= 'z';
+}
// ascii_isascii()
//
// Determines whether the given character is ASCII.
-inline bool ascii_isascii(unsigned char c) { return c < 128; }
+inline constexpr bool ascii_isascii(unsigned char c) { return c < 128; }
// ascii_tolower()
//
@@ -167,11 +185,22 @@
}
// Converts the characters in `s` to lowercase, changing the contents of `s`.
-void AsciiStrToLower(absl::Nonnull<std::string*> s);
+void AsciiStrToLower(std::string* absl_nonnull s);
// Creates a lowercase string from a given absl::string_view.
-ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) {
- std::string result(s);
+[[nodiscard]] inline std::string AsciiStrToLower(absl::string_view s) {
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(&result, s.size());
+ ascii_internal::AsciiStrToLower(&result[0], s.data(), s.size());
+ return result;
+}
+
+// Creates a lowercase string from a given std::string&&.
+//
+// (Template is used to lower priority of this overload.)
+template <int&... DoNotSpecify>
+[[nodiscard]] inline std::string AsciiStrToLower(std::string&& s) {
+ std::string result = std::move(s);
absl::AsciiStrToLower(&result);
return result;
}
@@ -185,58 +214,69 @@
}
// Converts the characters in `s` to uppercase, changing the contents of `s`.
-void AsciiStrToUpper(absl::Nonnull<std::string*> s);
+void AsciiStrToUpper(std::string* absl_nonnull s);
// Creates an uppercase string from a given absl::string_view.
-ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) {
- std::string result(s);
+[[nodiscard]] inline std::string AsciiStrToUpper(absl::string_view s) {
+ std::string result;
+ strings_internal::STLStringResizeUninitialized(&result, s.size());
+ ascii_internal::AsciiStrToUpper(&result[0], s.data(), s.size());
+ return result;
+}
+
+// Creates an uppercase string from a given std::string&&.
+//
+// (Template is used to lower priority of this overload.)
+template <int&... DoNotSpecify>
+[[nodiscard]] inline std::string AsciiStrToUpper(std::string&& s) {
+ std::string result = std::move(s);
absl::AsciiStrToUpper(&result);
return result;
}
// Returns absl::string_view with whitespace stripped from the beginning of the
// given string_view.
-ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace(
- absl::string_view str) {
+[[nodiscard]] inline absl::string_view StripLeadingAsciiWhitespace(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND) {
auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace);
return str.substr(static_cast<size_t>(it - str.begin()));
}
// Strips in place whitespace from the beginning of the given string.
-inline void StripLeadingAsciiWhitespace(absl::Nonnull<std::string*> str) {
+inline void StripLeadingAsciiWhitespace(std::string* absl_nonnull str) {
auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace);
str->erase(str->begin(), it);
}
// Returns absl::string_view with whitespace stripped from the end of the given
// string_view.
-ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace(
- absl::string_view str) {
+[[nodiscard]] inline absl::string_view StripTrailingAsciiWhitespace(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND) {
auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace);
return str.substr(0, static_cast<size_t>(str.rend() - it));
}
// Strips in place whitespace from the end of the given string
-inline void StripTrailingAsciiWhitespace(absl::Nonnull<std::string*> str) {
+inline void StripTrailingAsciiWhitespace(std::string* absl_nonnull str) {
auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace);
str->erase(static_cast<size_t>(str->rend() - it));
}
// Returns absl::string_view with whitespace stripped from both ends of the
// given string_view.
-ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace(
- absl::string_view str) {
+[[nodiscard]] inline absl::string_view StripAsciiWhitespace(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND) {
return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str));
}
// Strips in place whitespace from both ends of the given string
-inline void StripAsciiWhitespace(absl::Nonnull<std::string*> str) {
+inline void StripAsciiWhitespace(std::string* absl_nonnull str) {
StripTrailingAsciiWhitespace(str);
StripLeadingAsciiWhitespace(str);
}
// Removes leading, trailing, and consecutive internal whitespace.
-void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str);
+void RemoveExtraAsciiWhitespace(std::string* absl_nonnull str);
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc
index 4ae7317..435090d 100644
--- a/absl/strings/ascii_benchmark.cc
+++ b/absl/strings/ascii_benchmark.cc
@@ -12,15 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/ascii.h"
-
#include <algorithm>
+#include <array>
#include <cctype>
#include <cstddef>
#include <string>
-#include <array>
-#include <random>
+#include "absl/random/random.h"
+#include "absl/strings/ascii.h"
#include "benchmark/benchmark.h"
namespace {
@@ -28,10 +27,8 @@
std::array<unsigned char, 256> MakeShuffledBytes() {
std::array<unsigned char, 256> bytes;
for (size_t i = 0; i < 256; ++i) bytes[i] = static_cast<unsigned char>(i);
- std::random_device rd;
- std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()});
- std::mt19937 g(seed);
- std::shuffle(bytes.begin(), bytes.end(), g);
+ absl::InsecureBitGen gen;
+ std::shuffle(bytes.begin(), bytes.end(), gen);
return bytes;
}
@@ -102,7 +99,7 @@
BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_toupper);
static void BM_StrToLower(benchmark::State& state) {
- const int size = state.range(0);
+ const size_t size = static_cast<size_t>(state.range(0));
std::string s(size, 'X');
for (auto _ : state) {
benchmark::DoNotOptimize(s);
@@ -116,7 +113,7 @@
->Range(64, 1 << 26);
static void BM_StrToUpper(benchmark::State& state) {
- const int size = state.range(0);
+ const size_t size = static_cast<size_t>(state.range(0));
std::string s(size, 'x');
for (auto _ : state) {
benchmark::DoNotOptimize(s);
@@ -129,4 +126,32 @@
->RangeMultiplier(2)
->Range(64, 1 << 26);
+static void BM_StrToUpperFromRvalref(benchmark::State& state) {
+ const size_t size = static_cast<size_t>(state.range(0));
+ std::string s(size, 'X');
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(s);
+ std::string res = absl::AsciiStrToUpper(std::string(s));
+ benchmark::DoNotOptimize(res);
+ }
+}
+BENCHMARK(BM_StrToUpperFromRvalref)
+ ->DenseRange(0, 32)
+ ->RangeMultiplier(2)
+ ->Range(64, 1 << 26);
+
+static void BM_StrToLowerFromRvalref(benchmark::State& state) {
+ const size_t size = static_cast<size_t>(state.range(0));
+ std::string s(size, 'x');
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(s);
+ std::string res = absl::AsciiStrToLower(std::string(s));
+ benchmark::DoNotOptimize(res);
+ }
+}
+BENCHMARK(BM_StrToLowerFromRvalref)
+ ->DenseRange(0, 32)
+ ->RangeMultiplier(2)
+ ->Range(64, 1 << 26);
+
} // namespace
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
index 8885bb1..fe1083a 100644
--- a/absl/strings/ascii_test.cc
+++ b/absl/strings/ascii_test.cc
@@ -192,11 +192,17 @@
const absl::string_view sp(str2);
const std::string long_str("ABCDEFGHIJKLMNOPQRSTUVWXYZ1!a");
std::string mutable_str("_`?@[{AMNOPQRSTUVWXYZ");
+ auto fun = []() -> std::string { return "PQRSTU"; };
EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
EXPECT_EQ("abcdefghijklmnopqrstuvwxyz1!a", absl::AsciiStrToLower(long_str));
+ EXPECT_EQ("pqrstu", absl::AsciiStrToLower(fun()));
+
+ // An empty `string_view` specifically exercises the case where a null data
+ // pointer is passed to internal functions.
+ EXPECT_EQ("", absl::AsciiStrToLower(absl::string_view()));
absl::AsciiStrToLower(&mutable_str);
EXPECT_EQ("_`?@[{amnopqrstuvwxyz", mutable_str);
@@ -213,11 +219,17 @@
const std::string str2("_`?@[{amnopqrstuvwxyz");
const absl::string_view sp(str2);
const std::string long_str("abcdefghijklmnopqrstuvwxyz1!A");
+ auto fun = []() -> std::string { return "pqrstu"; };
EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf));
EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str));
EXPECT_EQ("_`?@[{AMNOPQRSTUVWXYZ", absl::AsciiStrToUpper(sp));
EXPECT_EQ("ABCDEFGHIJKLMNOPQRSTUVWXYZ1!A", absl::AsciiStrToUpper(long_str));
+ EXPECT_EQ("PQRSTU", absl::AsciiStrToUpper(fun()));
+
+ // An empty `string_view` specifically exercises the case where a null data
+ // pointer is passed to internal functions.
+ EXPECT_EQ("", absl::AsciiStrToUpper(absl::string_view()));
char mutable_buf[] = "Mutable";
std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc
index 0c9227f..6f36773 100644
--- a/absl/strings/charconv.cc
+++ b/absl/strings/charconv.cc
@@ -120,7 +120,7 @@
// Parsing a smaller N will produce something finite.
static constexpr int kEiselLemireMaxExclusiveExp10 = 309;
- static double MakeNan(absl::Nonnull<const char*> tagp) {
+ static double MakeNan(const char* absl_nonnull tagp) {
#if ABSL_HAVE_BUILTIN(__builtin_nan)
// Use __builtin_nan() if available since it has a fix for
// https://bugs.llvm.org/show_bug.cgi?id=37778
@@ -193,7 +193,7 @@
static constexpr int kEiselLemireMinInclusiveExp10 = -46 - 18;
static constexpr int kEiselLemireMaxExclusiveExp10 = 39;
- static float MakeNan(absl::Nonnull<const char*> tagp) {
+ static float MakeNan(const char* absl_nonnull tagp) {
#if ABSL_HAVE_BUILTIN(__builtin_nanf)
// Use __builtin_nanf() if available since it has a fix for
// https://bugs.llvm.org/show_bug.cgi?id=37778
@@ -345,7 +345,7 @@
// `value` must be wider than the requested bit width.
//
// Returns the number of bits shifted.
-int TruncateToBitWidth(int bit_width, absl::Nonnull<uint128*> value) {
+int TruncateToBitWidth(int bit_width, uint128* absl_nonnull value) {
const int current_bit_width = BitWidth(*value);
const int shift = current_bit_width - bit_width;
*value >>= shift;
@@ -357,18 +357,15 @@
// the appropriate double, and returns true.
template <typename FloatType>
bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative,
- absl::Nonnull<FloatType*> value) {
+ FloatType* absl_nonnull value) {
if (input.type == strings_internal::FloatType::kNan) {
- // A bug in both clang < 7 and gcc would cause the compiler to optimize
- // away the buffer we are building below. Declaring the buffer volatile
- // avoids the issue, and has no measurable performance impact in
- // microbenchmarks.
+ // A bug in gcc would cause the compiler to optimize away the buffer we are
+ // building below. Declaring the buffer volatile avoids the issue, and has
+ // no measurable performance impact in microbenchmarks.
//
- // https://bugs.llvm.org/show_bug.cgi?id=37778
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113
constexpr ptrdiff_t kNanBufferSize = 128;
-#if (defined(__GNUC__) && !defined(__clang__)) || \
- (defined(__clang__) && __clang_major__ < 7)
+#if (defined(__GNUC__) && !defined(__clang__))
volatile char n_char_sequence[kNanBufferSize];
#else
char n_char_sequence[kNanBufferSize];
@@ -392,7 +389,7 @@
return true;
}
if (input.mantissa == 0) {
- *value = negative ? -0.0 : 0.0;
+ *value = negative ? -0.0f : 0.0f;
return true;
}
return false;
@@ -406,8 +403,8 @@
// number is stored in *value.
template <typename FloatType>
void EncodeResult(const CalculatedFloat& calculated, bool negative,
- absl::Nonnull<absl::from_chars_result*> result,
- absl::Nonnull<FloatType*> value) {
+ absl::from_chars_result* absl_nonnull result,
+ FloatType* absl_nonnull value) {
if (calculated.exponent == kOverflow) {
result->ec = std::errc::result_out_of_range;
*value = negative ? -std::numeric_limits<FloatType>::max()
@@ -415,7 +412,7 @@
return;
} else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) {
result->ec = std::errc::result_out_of_range;
- *value = negative ? -0.0 : 0.0;
+ *value = negative ? -0.0f : 0.0f;
return;
}
*value = FloatTraits<FloatType>::Make(
@@ -453,7 +450,7 @@
// Zero and negative values of `shift` are accepted, in which case the word is
// shifted left, as necessary.
uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact,
- absl::Nonnull<bool*> output_exact) {
+ bool* absl_nonnull output_exact) {
if (shift <= 0) {
*output_exact = input_exact;
return static_cast<uint64_t>(value << -shift);
@@ -687,12 +684,11 @@
// this function returns false) is both fast and correct.
template <typename FloatType>
bool EiselLemire(const strings_internal::ParsedFloat& input, bool negative,
- absl::Nonnull<FloatType*> value,
- absl::Nonnull<std::errc*> ec) {
+ FloatType* absl_nonnull value, std::errc* absl_nonnull ec) {
uint64_t man = input.mantissa;
int exp10 = input.exponent;
if (exp10 < FloatTraits<FloatType>::kEiselLemireMinInclusiveExp10) {
- *value = negative ? -0.0 : 0.0;
+ *value = negative ? -0.0f : 0.0f;
*ec = std::errc::result_out_of_range;
return true;
} else if (exp10 >= FloatTraits<FloatType>::kEiselLemireMaxExclusiveExp10) {
@@ -845,7 +841,7 @@
if (negative) {
ret_bits |= 0x8000000000000000u;
}
- *value = absl::bit_cast<double>(ret_bits);
+ *value = static_cast<FloatType>(absl::bit_cast<double>(ret_bits));
return true;
} else if (FloatTraits<FloatType>::kTargetBits == 32) {
uint32_t ret_bits = (static_cast<uint32_t>(ret_exp2) << 23) |
@@ -853,7 +849,7 @@
if (negative) {
ret_bits |= 0x80000000u;
}
- *value = absl::bit_cast<float>(ret_bits);
+ *value = static_cast<FloatType>(absl::bit_cast<float>(ret_bits));
return true;
}
#endif // ABSL_BIT_PACK_FLOATS
@@ -861,9 +857,9 @@
}
template <typename FloatType>
-from_chars_result FromCharsImpl(absl::Nonnull<const char*> first,
- absl::Nonnull<const char*> last,
- FloatType& value, chars_format fmt_flags) {
+from_chars_result FromCharsImpl(const char* absl_nonnull first,
+ const char* absl_nonnull last, FloatType& value,
+ chars_format fmt_flags) {
from_chars_result result;
result.ptr = first; // overwritten on successful parse
result.ec = std::errc();
@@ -893,7 +889,7 @@
result.ec = std::errc::invalid_argument;
} else {
result.ptr = first + 1;
- value = negative ? -0.0 : 0.0;
+ value = negative ? -0.0f : 0.0f;
}
return result;
}
@@ -948,14 +944,14 @@
}
} // namespace
-from_chars_result from_chars(absl::Nonnull<const char*> first,
- absl::Nonnull<const char*> last, double& value,
+from_chars_result from_chars(const char* absl_nonnull first,
+ const char* absl_nonnull last, double& value,
chars_format fmt) {
return FromCharsImpl(first, last, value, fmt);
}
-from_chars_result from_chars(absl::Nonnull<const char*> first,
- absl::Nonnull<const char*> last, float& value,
+from_chars_result from_chars(const char* absl_nonnull first,
+ const char* absl_nonnull last, float& value,
chars_format fmt) {
return FromCharsImpl(first, last, value, fmt);
}
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h
index be25090..e5733f8 100644
--- a/absl/strings/charconv.h
+++ b/absl/strings/charconv.h
@@ -45,7 +45,7 @@
// characters that were successfully parsed. If none was found, `ptr` is set
// to the `first` argument to from_chars.
struct from_chars_result {
- absl::Nonnull<const char*> ptr;
+ const char* absl_nonnull ptr;
std::errc ec;
};
@@ -77,13 +77,13 @@
// format that strtod() accepts, except that a "0x" prefix is NOT matched.
// (In particular, in `hex` mode, the input "0xff" results in the largest
// matching pattern "0".)
-absl::from_chars_result from_chars(absl::Nonnull<const char*> first,
- absl::Nonnull<const char*> last,
+absl::from_chars_result from_chars(const char* absl_nonnull first,
+ const char* absl_nonnull last,
double& value, // NOLINT
chars_format fmt = chars_format::general);
-absl::from_chars_result from_chars(absl::Nonnull<const char*> first,
- absl::Nonnull<const char*> last,
+absl::from_chars_result from_chars(const char* absl_nonnull first,
+ const char* absl_nonnull last,
float& value, // NOLINT
chars_format fmt = chars_format::general);
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc
index e8c7371..0ee9363 100644
--- a/absl/strings/charconv_benchmark.cc
+++ b/absl/strings/charconv_benchmark.cc
@@ -12,12 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/charconv.h"
-
#include <cstdlib>
#include <cstring>
#include <string>
+#include "absl/strings/charconv.h"
#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/charset.h b/absl/strings/charset.h
index ff4e81a..04ad459 100644
--- a/absl/strings/charset.h
+++ b/absl/strings/charset.h
@@ -46,15 +46,13 @@
#ifndef ABSL_STRINGS_CHARSET_H_
#define ABSL_STRINGS_CHARSET_H_
-#include <cstddef>
#include <cstdint>
-#include <cstring>
-#include "absl/base/macros.h"
-#include "absl/base/port.h"
+#include "absl/base/config.h"
#include "absl/strings/string_view.h"
namespace absl {
+ABSL_NAMESPACE_BEGIN
class CharSet {
public:
@@ -159,6 +157,7 @@
uint64_t m_[4];
};
+ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_CHARSET_H_
diff --git a/absl/strings/charset_benchmark.cc b/absl/strings/charset_benchmark.cc
index bf7ae56..7133985 100644
--- a/absl/strings/charset_benchmark.cc
+++ b/absl/strings/charset_benchmark.cc
@@ -14,9 +14,9 @@
#include <cstdint>
-#include "benchmark/benchmark.h"
#include "absl/log/check.h"
#include "absl/strings/charset.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index f0f4f31..e53f914 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -75,21 +75,19 @@
using ::absl::cord_internal::kInlinedVectorSize;
using ::absl::cord_internal::kMaxBytesToCopy;
-static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
- absl::Nonnull<std::ostream*> os, int indent = 0);
-static bool VerifyNode(absl::Nonnull<CordRep*> root,
- absl::Nonnull<CordRep*> start_node);
+static void DumpNode(CordRep* absl_nonnull nonnull_rep, bool include_data,
+ std::ostream* absl_nonnull os, int indent = 0);
+static bool VerifyNode(CordRep* absl_nonnull root,
+ CordRep* absl_nonnull start_node);
-static inline absl::Nullable<CordRep*> VerifyTree(
- absl::Nullable<CordRep*> node) {
+static inline CordRep* absl_nullable VerifyTree(CordRep* absl_nullable node) {
assert(node == nullptr || VerifyNode(node, node));
static_cast<void>(&VerifyNode);
return node;
}
-static absl::Nonnull<CordRepFlat*> CreateFlat(absl::Nonnull<const char*> data,
- size_t length,
- size_t alloc_hint) {
+static CordRepFlat* absl_nonnull CreateFlat(const char* absl_nonnull data,
+ size_t length, size_t alloc_hint) {
CordRepFlat* flat = CordRepFlat::New(length + alloc_hint);
flat->length = length;
memcpy(flat->Data(), data, length);
@@ -98,8 +96,8 @@
// Creates a new flat or Btree out of the specified array.
// The returned node has a refcount of 1.
-static absl::Nonnull<CordRep*> NewBtree(absl::Nonnull<const char*> data,
- size_t length, size_t alloc_hint) {
+static CordRep* absl_nonnull NewBtree(const char* absl_nonnull data,
+ size_t length, size_t alloc_hint) {
if (length <= kMaxFlatLength) {
return CreateFlat(data, length, alloc_hint);
}
@@ -112,8 +110,8 @@
// Create a new tree out of the specified array.
// The returned node has a refcount of 1.
-static absl::Nullable<CordRep*> NewTree(absl::Nullable<const char*> data,
- size_t length, size_t alloc_hint) {
+static CordRep* absl_nullable NewTree(const char* absl_nullable data,
+ size_t length, size_t alloc_hint) {
if (length == 0) return nullptr;
return NewBtree(data, length, alloc_hint);
}
@@ -121,7 +119,7 @@
namespace cord_internal {
void InitializeCordRepExternal(absl::string_view data,
- absl::Nonnull<CordRepExternal*> rep) {
+ CordRepExternal* absl_nonnull rep) {
assert(!data.empty());
rep->length = data.size();
rep->tag = EXTERNAL;
@@ -135,7 +133,7 @@
// and not wasteful, we move the string into an external cord rep, preserving
// the already allocated string contents.
// Requires the provided string length to be larger than `kMaxInline`.
-static absl::Nonnull<CordRep*> CordRepFromString(std::string&& src) {
+static CordRep* absl_nonnull CordRepFromString(std::string&& src) {
assert(src.length() > cord_internal::kMaxInline);
if (
// String is short: copy data to avoid external block overhead.
@@ -163,17 +161,12 @@
// --------------------------------------------------------------------
// Cord::InlineRep functions
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr unsigned char Cord::InlineRep::kMaxInline;
-#endif
-
-inline void Cord::InlineRep::set_data(absl::Nonnull<const char*> data,
- size_t n) {
+inline void Cord::InlineRep::set_data(const char* absl_nonnull data, size_t n) {
static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
data_.set_inline_data(data, n);
}
-inline absl::Nonnull<char*> Cord::InlineRep::set_data(size_t n) {
+inline char* absl_nonnull Cord::InlineRep::set_data(size_t n) {
assert(n <= kMaxInline);
ResetToEmpty();
set_inline_size(n);
@@ -197,13 +190,13 @@
// Returns `rep` converted into a CordRepBtree.
// Directly returns `rep` if `rep` is already a CordRepBtree.
-static absl::Nonnull<CordRepBtree*> ForceBtree(CordRep* rep) {
+static CordRepBtree* absl_nonnull ForceBtree(CordRep* rep) {
return rep->IsBtree()
? rep->btree()
: CordRepBtree::Create(cord_internal::RemoveCrcNode(rep));
}
-void Cord::InlineRep::AppendTreeToInlined(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::AppendTreeToInlined(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(!is_tree());
if (!data_.is_empty()) {
@@ -213,7 +206,7 @@
EmplaceTree(tree, method);
}
-void Cord::InlineRep::AppendTreeToTree(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::AppendTreeToTree(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(is_tree());
const CordzUpdateScope scope(data_.cordz_info(), method);
@@ -221,7 +214,7 @@
SetTree(tree, scope);
}
-void Cord::InlineRep::AppendTree(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::AppendTree(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(tree != nullptr);
assert(tree->length != 0);
@@ -233,7 +226,7 @@
}
}
-void Cord::InlineRep::PrependTreeToInlined(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::PrependTreeToInlined(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(!is_tree());
if (!data_.is_empty()) {
@@ -243,7 +236,7 @@
EmplaceTree(tree, method);
}
-void Cord::InlineRep::PrependTreeToTree(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::PrependTreeToTree(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(is_tree());
const CordzUpdateScope scope(data_.cordz_info(), method);
@@ -251,7 +244,7 @@
SetTree(tree, scope);
}
-void Cord::InlineRep::PrependTree(absl::Nonnull<CordRep*> tree,
+void Cord::InlineRep::PrependTree(CordRep* absl_nonnull tree,
MethodIdentifier method) {
assert(tree != nullptr);
assert(tree->length != 0);
@@ -267,9 +260,10 @@
// suitable leaf is found, the function will update the length field for all
// nodes to account for the size increase. The append region address will be
// written to region and the actual size increase will be written to size.
-static inline bool PrepareAppendRegion(
- absl::Nonnull<CordRep*> root, absl::Nonnull<absl::Nullable<char*>*> region,
- absl::Nonnull<size_t*> size, size_t max_length) {
+static inline bool PrepareAppendRegion(CordRep* absl_nonnull root,
+ char* absl_nullable* absl_nonnull region,
+ size_t* absl_nonnull size,
+ size_t max_length) {
if (root->IsBtree() && root->refcount.IsOne()) {
Span<char> span = root->btree()->GetAppendBuffer(max_length);
if (!span.empty()) {
@@ -472,11 +466,11 @@
CommitTree(root, rep, scope, method);
}
-inline absl::Nonnull<CordRep*> Cord::TakeRep() const& {
+inline CordRep* absl_nonnull Cord::TakeRep() const& {
return CordRep::Ref(contents_.tree());
}
-inline absl::Nonnull<CordRep*> Cord::TakeRep() && {
+inline CordRep* absl_nonnull Cord::TakeRep() && {
CordRep* rep = contents_.tree();
contents_.clear();
return rep;
@@ -534,7 +528,7 @@
contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord);
}
-static CordRep::ExtractResult ExtractAppendBuffer(absl::Nonnull<CordRep*> rep,
+static CordRep::ExtractResult ExtractAppendBuffer(CordRep* absl_nonnull rep,
size_t min_capacity) {
switch (rep->tag) {
case cord_internal::BTREE:
@@ -781,9 +775,9 @@
return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0);
}
-int CompareChunks(absl::Nonnull<absl::string_view*> lhs,
- absl::Nonnull<absl::string_view*> rhs,
- absl::Nonnull<size_t*> size_to_compare) {
+int CompareChunks(absl::string_view* absl_nonnull lhs,
+ absl::string_view* absl_nonnull rhs,
+ size_t* absl_nonnull size_to_compare) {
size_t compared_size = std::min(lhs->size(), rhs->size());
assert(*size_to_compare >= compared_size);
*size_to_compare -= compared_size;
@@ -881,7 +875,7 @@
SetCrcCordState(std::move(state));
}
-absl::Nullable<const crc_internal::CrcCordState*> Cord::MaybeGetCrcCordState()
+const crc_internal::CrcCordState* absl_nullable Cord::MaybeGetCrcCordState()
const {
if (!contents_.is_tree() || !contents_.tree()->IsCrc()) {
return nullptr;
@@ -899,8 +893,8 @@
inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size,
size_t size_to_compare) const {
- auto advance = [](absl::Nonnull<Cord::ChunkIterator*> it,
- absl::Nonnull<absl::string_view*> chunk) {
+ auto advance = [](Cord::ChunkIterator* absl_nonnull it,
+ absl::string_view* absl_nonnull chunk) {
if (!chunk->empty()) return true;
++*it;
if (it->bytes_remaining_ == 0) return false;
@@ -930,8 +924,8 @@
inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size,
size_t size_to_compare) const {
- auto advance = [](absl::Nonnull<Cord::ChunkIterator*> it,
- absl::Nonnull<absl::string_view*> chunk) {
+ auto advance = [](Cord::ChunkIterator* absl_nonnull it,
+ absl::string_view* absl_nonnull chunk) {
if (!chunk->empty()) return true;
++*it;
if (it->bytes_remaining_ == 0) return false;
@@ -981,7 +975,9 @@
size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size());
assert(size_to_compare >= compared_size);
- int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size);
+ int memcmp_res = compared_size > 0 ? ::memcmp(lhs_chunk.data(),
+ rhs_chunk.data(), compared_size)
+ : 0;
if (compared_size == size_to_compare || memcmp_res != 0) {
return ComputeCompareResult<ResultType>(memcmp_res);
}
@@ -1053,7 +1049,7 @@
return s;
}
-void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
+void CopyCordToString(const Cord& src, std::string* absl_nonnull dst) {
if (!src.contents_.is_tree()) {
src.contents_.CopyTo(dst);
} else {
@@ -1062,7 +1058,7 @@
}
}
-void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
+void AppendCordToString(const Cord& src, std::string* absl_nonnull dst) {
const size_t cur_dst_size = dst->size();
const size_t new_dst_size = cur_dst_size + src.size();
absl::strings_internal::STLStringResizeUninitializedAmortized(dst,
@@ -1071,10 +1067,10 @@
src.CopyToArrayImpl(append_ptr);
}
-void Cord::CopyToArraySlowPath(absl::Nonnull<char*> dst) const {
+void Cord::CopyToArraySlowPath(char* absl_nonnull dst) const {
assert(contents_.is_tree());
absl::string_view fragment;
- if (GetFlatAux(contents_.tree(), &fragment)) {
+ if (GetFlatAux(contents_.tree(), &fragment) && !fragment.empty()) {
memcpy(dst, fragment.data(), fragment.size());
return;
}
@@ -1397,8 +1393,8 @@
return absl::string_view(new_buffer, total_size);
}
-/* static */ bool Cord::GetFlatAux(absl::Nonnull<CordRep*> rep,
- absl::Nonnull<absl::string_view*> fragment) {
+/* static */ bool Cord::GetFlatAux(CordRep* absl_nonnull rep,
+ absl::string_view* absl_nonnull fragment) {
assert(rep != nullptr);
if (rep->length == 0) {
*fragment = absl::string_view();
@@ -1432,7 +1428,7 @@
}
/* static */ void Cord::ForEachChunkAux(
- absl::Nonnull<absl::cord_internal::CordRep*> rep,
+ absl::cord_internal::CordRep* absl_nonnull rep,
absl::FunctionRef<void(absl::string_view)> callback) {
assert(rep != nullptr);
if (rep->length == 0) return;
@@ -1457,8 +1453,8 @@
}
}
-static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
- absl::Nonnull<std::ostream*> os, int indent) {
+static void DumpNode(CordRep* absl_nonnull nonnull_rep, bool include_data,
+ std::ostream* absl_nonnull os, int indent) {
CordRep* rep = nonnull_rep;
const int kIndentStep = 1;
for (;;) {
@@ -1504,17 +1500,17 @@
}
}
-static std::string ReportError(absl::Nonnull<CordRep*> root,
- absl::Nonnull<CordRep*> node) {
+static std::string ReportError(CordRep* absl_nonnull root,
+ CordRep* absl_nonnull node) {
std::ostringstream buf;
buf << "Error at node " << node << " in:";
DumpNode(root, true, &buf);
return buf.str();
}
-static bool VerifyNode(absl::Nonnull<CordRep*> root,
- absl::Nonnull<CordRep*> start_node) {
- absl::InlinedVector<absl::Nonnull<CordRep*>, 2> worklist;
+static bool VerifyNode(CordRep* absl_nonnull root,
+ CordRep* absl_nonnull start_node) {
+ absl::InlinedVector<CordRep* absl_nonnull, 2> worklist;
worklist.push_back(start_node);
do {
CordRep* node = worklist.back();
diff --git a/absl/strings/cord.h b/absl/strings/cord.h
index 69aa8ef..7afa419 100644
--- a/absl/strings/cord.h
+++ b/absl/strings/cord.h
@@ -61,6 +61,7 @@
#define ABSL_STRINGS_CORD_H_
#include <algorithm>
+#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
@@ -68,18 +69,17 @@
#include <iterator>
#include <string>
#include <type_traits>
+#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/endian.h"
-#include "absl/base/internal/per_thread_tls.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
-#include "absl/base/port.h"
-#include "absl/container/inlined_vector.h"
#include "absl/crc/internal/crc_cord_state.h"
#include "absl/functional/function_ref.h"
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/cord_analysis.h"
#include "absl/strings/cord_buffer.h"
@@ -88,12 +88,10 @@
#include "absl/strings/internal/cord_rep_btree.h"
#include "absl/strings/internal/cord_rep_btree_reader.h"
#include "absl/strings/internal/cord_rep_crc.h"
-#include "absl/strings/internal/cordz_functions.h"
+#include "absl/strings/internal/cord_rep_flat.h"
#include "absl/strings/internal/cordz_info.h"
-#include "absl/strings/internal/cordz_statistics.h"
#include "absl/strings/internal/cordz_update_scope.h"
#include "absl/strings/internal/cordz_update_tracker.h"
-#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/internal/string_constant.h"
#include "absl/strings/string_view.h"
#include "absl/types/compare.h"
@@ -105,8 +103,8 @@
class CordTestPeer;
template <typename Releaser>
Cord MakeCordFromExternal(absl::string_view, Releaser&&);
-void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
-void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
+void CopyCordToString(const Cord& src, std::string* absl_nonnull dst);
+void AppendCordToString(const Cord& src, std::string* absl_nonnull dst);
// Cord memory accounting modes
enum class CordMemoryAccounting {
@@ -420,8 +418,7 @@
// guarantee that pointers previously returned by `dst->data()` remain valid
// even if `*dst` had enough capacity to hold `src`. If `*dst` is a new
// object, prefer to simply use the conversion operator to `std::string`.
- friend void CopyCordToString(const Cord& src,
- absl::Nonnull<std::string*> dst);
+ friend void CopyCordToString(const Cord& src, std::string* absl_nonnull dst);
// AppendCordToString()
//
@@ -433,7 +430,7 @@
// `dst->data()`. If `*dst` is a new object, prefer to simply use the
// conversion operator to `std::string`.
friend void AppendCordToString(const Cord& src,
- absl::Nonnull<std::string*> dst);
+ std::string* absl_nonnull dst);
class CharIterator;
@@ -470,7 +467,7 @@
using iterator_category = std::input_iterator_tag;
using value_type = absl::string_view;
using difference_type = ptrdiff_t;
- using pointer = absl::Nonnull<const value_type*>;
+ using pointer = const value_type* absl_nonnull;
using reference = value_type;
ChunkIterator() = default;
@@ -491,13 +488,13 @@
using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader;
// Constructs a `begin()` iterator from `tree`.
- explicit ChunkIterator(absl::Nonnull<cord_internal::CordRep*> tree);
+ explicit ChunkIterator(cord_internal::CordRep* absl_nonnull tree);
// Constructs a `begin()` iterator from `cord`.
- explicit ChunkIterator(absl::Nonnull<const Cord*> cord);
+ explicit ChunkIterator(const Cord* absl_nonnull cord);
// Initializes this instance from a tree. Invoked by constructors.
- void InitTree(absl::Nonnull<cord_internal::CordRep*> tree);
+ void InitTree(cord_internal::CordRep* absl_nonnull tree);
// Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than
// `current_chunk_.size()`.
@@ -515,7 +512,7 @@
// The current leaf, or `nullptr` if the iterator points to short data.
// If the current chunk is a substring node, current_leaf_ points to the
// underlying flat or external node.
- absl::Nullable<absl::cord_internal::CordRep*> current_leaf_ = nullptr;
+ absl::cord_internal::CordRep* absl_nullable current_leaf_ = nullptr;
// The number of bytes left in the `Cord` over which we are iterating.
size_t bytes_remaining_ = 0;
@@ -572,13 +569,13 @@
using iterator = ChunkIterator;
using const_iterator = ChunkIterator;
- explicit ChunkRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {}
+ explicit ChunkRange(const Cord* absl_nonnull cord) : cord_(cord) {}
ChunkIterator begin() const;
ChunkIterator end() const;
private:
- absl::Nonnull<const Cord*> cord_;
+ const Cord* absl_nonnull cord_;
};
// Cord::Chunks()
@@ -631,7 +628,7 @@
using iterator_category = std::input_iterator_tag;
using value_type = char;
using difference_type = ptrdiff_t;
- using pointer = absl::Nonnull<const char*>;
+ using pointer = const char* absl_nonnull;
using reference = const char&;
CharIterator() = default;
@@ -641,12 +638,11 @@
bool operator==(const CharIterator& other) const;
bool operator!=(const CharIterator& other) const;
reference operator*() const;
- pointer operator->() const;
friend Cord;
private:
- explicit CharIterator(absl::Nonnull<const Cord*> cord)
+ explicit CharIterator(const Cord* absl_nonnull cord)
: chunk_iterator_(cord) {}
ChunkIterator chunk_iterator_;
@@ -658,14 +654,14 @@
// advanced as a separate `Cord`. `n_bytes` must be less than or equal to the
// number of bytes within the Cord; otherwise, behavior is undefined. It is
// valid to pass `char_end()` and `0`.
- static Cord AdvanceAndRead(absl::Nonnull<CharIterator*> it, size_t n_bytes);
+ static Cord AdvanceAndRead(CharIterator* absl_nonnull it, size_t n_bytes);
// Cord::Advance()
//
// Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than
// or equal to the number of bytes remaining within the Cord; otherwise,
// behavior is undefined. It is valid to pass `char_end()` and `0`.
- static void Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes);
+ static void Advance(CharIterator* absl_nonnull it, size_t n_bytes);
// Cord::ChunkRemaining()
//
@@ -674,6 +670,13 @@
// `it` must be dereferenceable.
static absl::string_view ChunkRemaining(const CharIterator& it);
+ // Cord::Distance()
+ //
+ // Returns the distance between `first` and `last`, as if
+ // `std::distance(first, last)` was called.
+ static ptrdiff_t Distance(const CharIterator& first,
+ const CharIterator& last);
+
// Cord::char_begin()
//
// Returns an iterator to the first character of the `Cord`.
@@ -714,13 +717,13 @@
using iterator = CharIterator;
using const_iterator = CharIterator;
- explicit CharRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {}
+ explicit CharRange(const Cord* absl_nonnull cord) : cord_(cord) {}
CharIterator begin() const;
CharIterator end() const;
private:
- absl::Nonnull<const Cord*> cord_;
+ const Cord* absl_nonnull cord_;
};
// Cord::Chars()
@@ -779,7 +782,7 @@
CharIterator Find(const absl::Cord& needle) const;
// Supports absl::Cord as a sink object for absl::Format().
- friend void AbslFormatFlush(absl::Nonnull<absl::Cord*> cord,
+ friend void AbslFormatFlush(absl::Cord* absl_nonnull cord,
absl::string_view part) {
cord->Append(part);
}
@@ -882,7 +885,7 @@
}
#endif
- friend absl::Nullable<const CordzInfo*> GetCordzInfoForTesting(
+ friend const CordzInfo* absl_nullable GetCordzInfoForTesting(
const Cord& cord);
// Calls the provided function once for each cord chunk, in order. Unlike
@@ -911,21 +914,21 @@
InlineRep& operator=(InlineRep&& src) noexcept;
explicit constexpr InlineRep(absl::string_view sv,
- absl::Nullable<CordRep*> rep);
+ CordRep* absl_nullable rep);
- void Swap(absl::Nonnull<InlineRep*> rhs);
+ void Swap(InlineRep* absl_nonnull rhs);
size_t size() const;
// Returns nullptr if holding pointer
- absl::Nullable<const char*> data() const;
+ const char* absl_nullable data() const;
// Discards pointer, if any
- void set_data(absl::Nonnull<const char*> data, size_t n);
- absl::Nonnull<char*> set_data(size_t n); // Write data to the result
+ void set_data(const char* absl_nonnull data, size_t n);
+ char* absl_nonnull set_data(size_t n); // Write data to the result
// Returns nullptr if holding bytes
- absl::Nullable<absl::cord_internal::CordRep*> tree() const;
- absl::Nonnull<absl::cord_internal::CordRep*> as_tree() const;
- absl::Nonnull<const char*> as_chars() const;
+ absl::cord_internal::CordRep* absl_nullable tree() const;
+ absl::cord_internal::CordRep* absl_nonnull as_tree() const;
+ const char* absl_nonnull as_chars() const;
// Returns non-null iff was holding a pointer
- absl::Nullable<absl::cord_internal::CordRep*> clear();
+ absl::cord_internal::CordRep* absl_nullable clear();
// Converts to pointer if necessary.
void reduce_size(size_t n); // REQUIRES: holding data
void remove_prefix(size_t n); // REQUIRES: holding data
@@ -934,64 +937,56 @@
// Creates a CordRepFlat instance from the current inlined data with `extra'
// bytes of desired additional capacity.
- absl::Nonnull<CordRepFlat*> MakeFlatWithExtraCapacity(size_t extra);
+ CordRepFlat* absl_nonnull MakeFlatWithExtraCapacity(size_t extra);
// Sets the tree value for this instance. `rep` must not be null.
// Requires the current instance to hold a tree, and a lock to be held on
// any CordzInfo referenced by this instance. The latter is enforced through
// the CordzUpdateScope argument. If the current instance is sampled, then
// the CordzInfo instance is updated to reference the new `rep` value.
- void SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope);
+ void SetTree(CordRep* absl_nonnull rep, const CordzUpdateScope& scope);
// Identical to SetTree(), except that `rep` is allowed to be null, in
// which case the current instance is reset to an empty value.
- void SetTreeOrEmpty(absl::Nullable<CordRep*> rep,
+ void SetTreeOrEmpty(CordRep* absl_nullable rep,
const CordzUpdateScope& scope);
// Sets the tree value for this instance, and randomly samples this cord.
// This function disregards existing contents in `data_`, and should be
// called when a Cord is 'promoted' from an 'uninitialized' or 'inlined'
// value to a non-inlined (tree / ring) value.
- void EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method);
+ void EmplaceTree(CordRep* absl_nonnull rep, MethodIdentifier method);
// Identical to EmplaceTree, except that it copies the parent stack from
// the provided `parent` data if the parent is sampled.
- void EmplaceTree(absl::Nonnull<CordRep*> rep, const InlineData& parent,
+ void EmplaceTree(CordRep* absl_nonnull rep, const InlineData& parent,
MethodIdentifier method);
// Commits the change of a newly created, or updated `rep` root value into
// this cord. `old_rep` indicates the old (inlined or tree) value of the
// cord, and determines if the commit invokes SetTree() or EmplaceTree().
- void CommitTree(absl::Nullable<const CordRep*> old_rep,
- absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope,
+ void CommitTree(const CordRep* absl_nullable old_rep,
+ CordRep* absl_nonnull rep, const CordzUpdateScope& scope,
MethodIdentifier method);
- void AppendTreeToInlined(absl::Nonnull<CordRep*> tree,
+ void AppendTreeToInlined(CordRep* absl_nonnull tree,
MethodIdentifier method);
- void AppendTreeToTree(absl::Nonnull<CordRep*> tree,
- MethodIdentifier method);
- void AppendTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method);
- void PrependTreeToInlined(absl::Nonnull<CordRep*> tree,
+ void AppendTreeToTree(CordRep* absl_nonnull tree, MethodIdentifier method);
+ void AppendTree(CordRep* absl_nonnull tree, MethodIdentifier method);
+ void PrependTreeToInlined(CordRep* absl_nonnull tree,
MethodIdentifier method);
- void PrependTreeToTree(absl::Nonnull<CordRep*> tree,
- MethodIdentifier method);
- void PrependTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method);
+ void PrependTreeToTree(CordRep* absl_nonnull tree, MethodIdentifier method);
+ void PrependTree(CordRep* absl_nonnull tree, MethodIdentifier method);
bool IsSame(const InlineRep& other) const { return data_ == other.data_; }
- void CopyTo(absl::Nonnull<std::string*> dst) const {
- // memcpy is much faster when operating on a known size. On most supported
- // platforms, the small string optimization is large enough that resizing
- // to 15 bytes does not cause a memory allocation.
- absl::strings_internal::STLStringResizeUninitialized(dst, kMaxInline);
- data_.copy_max_inline_to(&(*dst)[0]);
- // erase is faster than resize because the logic for memory allocation is
- // not needed.
- dst->erase(inline_size());
+ // Copies the inline contents into `dst`. Assumes the cord is not empty.
+ void CopyTo(std::string* absl_nonnull dst) const {
+ data_.CopyInlineToString(dst);
}
// Copies the inline contents into `dst`. Assumes the cord is not empty.
- void CopyToArray(absl::Nonnull<char*> dst) const;
+ void CopyToArray(char* absl_nonnull dst) const;
bool is_tree() const { return data_.is_tree(); }
@@ -1004,12 +999,12 @@
}
// Returns the profiled CordzInfo, or nullptr if not sampled.
- absl::Nullable<absl::cord_internal::CordzInfo*> cordz_info() const {
+ absl::cord_internal::CordzInfo* absl_nullable cordz_info() const {
return data_.cordz_info();
}
// Sets the profiled CordzInfo.
- void set_cordz_info(absl::Nonnull<cord_internal::CordzInfo*> cordz_info) {
+ void set_cordz_info(cord_internal::CordzInfo* absl_nonnull cordz_info) {
assert(cordz_info != nullptr);
data_.set_cordz_info(cordz_info);
}
@@ -1041,19 +1036,19 @@
InlineRep contents_;
// Helper for GetFlat() and TryFlat().
- static bool GetFlatAux(absl::Nonnull<absl::cord_internal::CordRep*> rep,
- absl::Nonnull<absl::string_view*> fragment);
+ static bool GetFlatAux(absl::cord_internal::CordRep* absl_nonnull rep,
+ absl::string_view* absl_nonnull fragment);
// Helper for ForEachChunk().
static void ForEachChunkAux(
- absl::Nonnull<absl::cord_internal::CordRep*> rep,
+ absl::cord_internal::CordRep* absl_nonnull rep,
absl::FunctionRef<void(absl::string_view)> callback);
// The destructor for non-empty Cords.
void DestroyCordSlow();
// Out-of-line implementation of slower parts of logic.
- void CopyToArraySlowPath(absl::Nonnull<char*> dst) const;
+ void CopyToArraySlowPath(char* absl_nonnull dst) const;
int CompareSlowPath(absl::string_view rhs, size_t compared_size,
size_t size_to_compare) const;
int CompareSlowPath(const Cord& rhs, size_t compared_size,
@@ -1070,8 +1065,8 @@
// Returns a new reference to contents_.tree(), or steals an existing
// reference if called on an rvalue.
- absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() const&;
- absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() &&;
+ absl::cord_internal::CordRep* absl_nonnull TakeRep() const&;
+ absl::cord_internal::CordRep* absl_nonnull TakeRep() &&;
// Helper for Append().
template <typename C>
@@ -1103,17 +1098,17 @@
hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
chunk.size());
});
- return H::combine(combiner.finalize(std::move(hash_state)), size());
+ return H::combine(combiner.finalize(std::move(hash_state)),
+ hash_internal::WeaklyMixedInteger{size()});
}
friend class CrcCord;
void SetCrcCordState(crc_internal::CrcCordState state);
- absl::Nullable<const crc_internal::CrcCordState*> MaybeGetCrcCordState()
- const;
+ const crc_internal::CrcCordState* absl_nullable MaybeGetCrcCordState() const;
CharIterator FindImpl(CharIterator it, absl::string_view needle) const;
- void CopyToArrayImpl(absl::Nonnull<char*> dst) const;
+ void CopyToArrayImpl(char* absl_nonnull dst) const;
};
ABSL_NAMESPACE_END
@@ -1133,14 +1128,14 @@
// Does non-template-specific `CordRepExternal` initialization.
// Requires `data` to be non-empty.
void InitializeCordRepExternal(absl::string_view data,
- absl::Nonnull<CordRepExternal*> rep);
+ CordRepExternal* absl_nonnull rep);
// Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer
// to it. Requires `data` to be non-empty.
template <typename Releaser>
// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
-absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data,
- Releaser&& releaser) {
+CordRep* absl_nonnull NewExternalRep(absl::string_view data,
+ Releaser&& releaser) {
assert(!data.empty());
using ReleaserType = absl::decay_t<Releaser>;
CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
@@ -1152,7 +1147,7 @@
// Overload for function reference types that dispatches using a function
// pointer because there are no `alignof()` or `sizeof()` a function reference.
// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
-inline absl::Nonnull<CordRep*> NewExternalRep(
+inline CordRep* absl_nonnull NewExternalRep(
absl::string_view data, void (&releaser)(absl::string_view)) {
return NewExternalRep(data, &releaser);
}
@@ -1176,7 +1171,7 @@
}
constexpr Cord::InlineRep::InlineRep(absl::string_view sv,
- absl::Nullable<CordRep*> rep)
+ CordRep* absl_nullable rep)
: data_(sv, rep) {}
inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src)
@@ -1215,7 +1210,7 @@
return *this;
}
-inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) {
+inline void Cord::InlineRep::Swap(Cord::InlineRep* absl_nonnull rhs) {
if (rhs == this) {
return;
}
@@ -1223,22 +1218,22 @@
swap(data_, rhs->data_);
}
-inline absl::Nullable<const char*> Cord::InlineRep::data() const {
+inline const char* absl_nullable Cord::InlineRep::data() const {
return is_tree() ? nullptr : data_.as_chars();
}
-inline absl::Nonnull<const char*> Cord::InlineRep::as_chars() const {
+inline const char* absl_nonnull Cord::InlineRep::as_chars() const {
assert(!data_.is_tree());
return data_.as_chars();
}
-inline absl::Nonnull<absl::cord_internal::CordRep*> Cord::InlineRep::as_tree()
+inline absl::cord_internal::CordRep* absl_nonnull Cord::InlineRep::as_tree()
const {
assert(data_.is_tree());
return data_.as_tree();
}
-inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::tree()
+inline absl::cord_internal::CordRep* absl_nullable Cord::InlineRep::tree()
const {
if (is_tree()) {
return as_tree();
@@ -1251,7 +1246,7 @@
return is_tree() ? as_tree()->length : inline_size();
}
-inline absl::Nonnull<cord_internal::CordRepFlat*>
+inline cord_internal::CordRepFlat* absl_nonnull
Cord::InlineRep::MakeFlatWithExtraCapacity(size_t extra) {
static_assert(cord_internal::kMinFlatLength >= sizeof(data_), "");
size_t len = data_.inline_size();
@@ -1261,21 +1256,21 @@
return result;
}
-inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep,
+inline void Cord::InlineRep::EmplaceTree(CordRep* absl_nonnull rep,
MethodIdentifier method) {
assert(rep);
data_.make_tree(rep);
CordzInfo::MaybeTrackCord(data_, method);
}
-inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep,
+inline void Cord::InlineRep::EmplaceTree(CordRep* absl_nonnull rep,
const InlineData& parent,
MethodIdentifier method) {
data_.make_tree(rep);
CordzInfo::MaybeTrackCord(data_, parent, method);
}
-inline void Cord::InlineRep::SetTree(absl::Nonnull<CordRep*> rep,
+inline void Cord::InlineRep::SetTree(CordRep* absl_nonnull rep,
const CordzUpdateScope& scope) {
assert(rep);
assert(data_.is_tree());
@@ -1283,7 +1278,7 @@
scope.SetCordRep(rep);
}
-inline void Cord::InlineRep::SetTreeOrEmpty(absl::Nullable<CordRep*> rep,
+inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* absl_nullable rep,
const CordzUpdateScope& scope) {
assert(data_.is_tree());
if (rep) {
@@ -1294,8 +1289,8 @@
scope.SetCordRep(rep);
}
-inline void Cord::InlineRep::CommitTree(absl::Nullable<const CordRep*> old_rep,
- absl::Nonnull<CordRep*> rep,
+inline void Cord::InlineRep::CommitTree(const CordRep* absl_nullable old_rep,
+ CordRep* absl_nonnull rep,
const CordzUpdateScope& scope,
MethodIdentifier method) {
if (old_rep) {
@@ -1305,7 +1300,7 @@
}
}
-inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::clear() {
+inline absl::cord_internal::CordRep* absl_nullable Cord::InlineRep::clear() {
if (is_tree()) {
CordzInfo::MaybeUntrackCord(cordz_info());
}
@@ -1314,7 +1309,7 @@
return result;
}
-inline void Cord::InlineRep::CopyToArray(absl::Nonnull<char*> dst) const {
+inline void Cord::InlineRep::CopyToArray(char* absl_nonnull dst) const {
assert(!is_tree());
size_t n = inline_size();
assert(n != 0);
@@ -1498,7 +1493,7 @@
return EqualsImpl(rhs, rhs_size);
}
-inline void Cord::CopyToArrayImpl(absl::Nonnull<char*> dst) const {
+inline void Cord::CopyToArrayImpl(char* absl_nonnull dst) const {
if (!contents_.is_tree()) {
if (!empty()) contents_.CopyToArray(dst);
} else {
@@ -1507,7 +1502,7 @@
}
inline void Cord::ChunkIterator::InitTree(
- absl::Nonnull<cord_internal::CordRep*> tree) {
+ cord_internal::CordRep* absl_nonnull tree) {
tree = cord_internal::SkipCrcNode(tree);
if (tree->tag == cord_internal::BTREE) {
current_chunk_ = btree_reader_.Init(tree->btree());
@@ -1518,12 +1513,12 @@
}
inline Cord::ChunkIterator::ChunkIterator(
- absl::Nonnull<cord_internal::CordRep*> tree) {
+ cord_internal::CordRep* absl_nonnull tree) {
bytes_remaining_ = tree->length;
InitTree(tree);
}
-inline Cord::ChunkIterator::ChunkIterator(absl::Nonnull<const Cord*> cord) {
+inline Cord::ChunkIterator::ChunkIterator(const Cord* absl_nonnull cord) {
if (CordRep* tree = cord->contents_.tree()) {
bytes_remaining_ = tree->length;
if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) {
@@ -1659,17 +1654,13 @@
return *chunk_iterator_->data();
}
-inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const {
- return chunk_iterator_->data();
-}
-
-inline Cord Cord::AdvanceAndRead(absl::Nonnull<CharIterator*> it,
+inline Cord Cord::AdvanceAndRead(CharIterator* absl_nonnull it,
size_t n_bytes) {
assert(it != nullptr);
return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes);
}
-inline void Cord::Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes) {
+inline void Cord::Advance(CharIterator* absl_nonnull it, size_t n_bytes) {
assert(it != nullptr);
it->chunk_iterator_.AdvanceBytes(n_bytes);
}
@@ -1678,6 +1669,12 @@
return *it.chunk_iterator_;
}
+inline ptrdiff_t Cord::Distance(const CharIterator& first,
+ const CharIterator& last) {
+ return static_cast<ptrdiff_t>(first.chunk_iterator_.bytes_remaining_ -
+ last.chunk_iterator_.bytes_remaining_);
+}
+
inline Cord::CharIterator Cord::char_begin() const {
return CharIterator(this);
}
diff --git a/absl/strings/cord_analysis.cc b/absl/strings/cord_analysis.cc
index 19b0fa4..dcbc826 100644
--- a/absl/strings/cord_analysis.cc
+++ b/absl/strings/cord_analysis.cc
@@ -39,15 +39,15 @@
template <Mode mode>
struct CordRepRef {
// Instantiates a CordRepRef instance.
- explicit CordRepRef(absl::Nonnull<const CordRep*> r) : rep(r) {}
+ explicit CordRepRef(const CordRep* absl_nonnull r) : rep(r) {}
// Creates a child reference holding the provided child.
// Overloaded to add cumulative reference count for kFairShare.
- CordRepRef Child(absl::Nonnull<const CordRep*> child) const {
+ CordRepRef Child(const CordRep* absl_nonnull child) const {
return CordRepRef(child);
}
- absl::Nonnull<const CordRep*> rep;
+ const CordRep* absl_nonnull rep;
};
// RawUsage holds the computed total number of bytes.
@@ -66,7 +66,7 @@
struct RawUsage<Mode::kTotalMorePrecise> {
size_t total = 0;
// TODO(b/289250880): Replace this with a flat_hash_set.
- std::unordered_set<absl::Nonnull<const CordRep*>> counted;
+ std::unordered_set<const CordRep* absl_nonnull> counted;
void Add(size_t size, CordRepRef<Mode::kTotalMorePrecise> repref) {
if (counted.insert(repref.rep).second) {
@@ -90,15 +90,15 @@
template <>
struct CordRepRef<Mode::kFairShare> {
// Creates a CordRepRef with the provided rep and top (parent) fraction.
- explicit CordRepRef(absl::Nonnull<const CordRep*> r, double frac = 1.0)
+ explicit CordRepRef(const CordRep* absl_nonnull r, double frac = 1.0)
: rep(r), fraction(MaybeDiv(frac, r->refcount.Get())) {}
// Returns a CordRepRef with a fraction of `this->fraction / child.refcount`
- CordRepRef Child(absl::Nonnull<const CordRep*> child) const {
+ CordRepRef Child(const CordRep* absl_nonnull child) const {
return CordRepRef(child, fraction);
}
- absl::Nonnull<const CordRep*> rep;
+ const CordRep* absl_nonnull rep;
double fraction;
};
@@ -150,7 +150,7 @@
}
template <Mode mode>
-size_t GetEstimatedUsage(absl::Nonnull<const CordRep*> rep) {
+size_t GetEstimatedUsage(const CordRep* absl_nonnull rep) {
// Zero initialized memory usage totals.
RawUsage<mode> raw_usage;
@@ -179,15 +179,15 @@
} // namespace
-size_t GetEstimatedMemoryUsage(absl::Nonnull<const CordRep*> rep) {
+size_t GetEstimatedMemoryUsage(const CordRep* absl_nonnull rep) {
return GetEstimatedUsage<Mode::kTotal>(rep);
}
-size_t GetEstimatedFairShareMemoryUsage(absl::Nonnull<const CordRep*> rep) {
+size_t GetEstimatedFairShareMemoryUsage(const CordRep* absl_nonnull rep) {
return GetEstimatedUsage<Mode::kFairShare>(rep);
}
-size_t GetMorePreciseMemoryUsage(absl::Nonnull<const CordRep*> rep) {
+size_t GetMorePreciseMemoryUsage(const CordRep* absl_nonnull rep) {
return GetEstimatedUsage<Mode::kTotalMorePrecise>(rep);
}
diff --git a/absl/strings/cord_analysis.h b/absl/strings/cord_analysis.h
index f8ce348..db50f3a 100644
--- a/absl/strings/cord_analysis.h
+++ b/absl/strings/cord_analysis.h
@@ -29,7 +29,7 @@
// Returns the *approximate* number of bytes held in full or in part by this
// Cord (which may not remain the same between invocations). Cords that share
// memory could each be "charged" independently for the same shared memory.
-size_t GetEstimatedMemoryUsage(absl::Nonnull<const CordRep*> rep);
+size_t GetEstimatedMemoryUsage(const CordRep* absl_nonnull rep);
// Returns the *approximate* number of bytes held in full or in part by this
// Cord for the distinct memory held by this cord. This is similar to
@@ -47,13 +47,13 @@
//
// This is more expensive than `GetEstimatedMemoryUsage()` as it requires
// deduplicating all memory references.
-size_t GetMorePreciseMemoryUsage(absl::Nonnull<const CordRep*> rep);
+size_t GetMorePreciseMemoryUsage(const CordRep* absl_nonnull rep);
// Returns the *approximate* number of bytes held in full or in part by this
// CordRep weighted by the sharing ratio of that data. For example, if some data
// edge is shared by 4 different Cords, then each cord is attribute 1/4th of
// the total memory usage as a 'fair share' of the total memory usage.
-size_t GetEstimatedFairShareMemoryUsage(absl::Nonnull<const CordRep*> rep);
+size_t GetEstimatedFairShareMemoryUsage(const CordRep* absl_nonnull rep);
} // namespace cord_internal
ABSL_NAMESPACE_END
diff --git a/absl/strings/cord_buffer.cc b/absl/strings/cord_buffer.cc
deleted file mode 100644
index fad6269..0000000
--- a/absl/strings/cord_buffer.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2022 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/strings/cord_buffer.h"
-
-#include <cstddef>
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr size_t CordBuffer::kDefaultLimit;
-constexpr size_t CordBuffer::kCustomLimit;
-#endif
-
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc
index eaf6d71..55007bb 100644
--- a/absl/strings/cord_test.cc
+++ b/absl/strings/cord_test.cc
@@ -1309,6 +1309,7 @@
absl::Cord c;
c.Append(absl::Cord(std::string(100, 'x')));
absl::Cord other_ref = c; // Prevent inplace appends
+ EXPECT_THAT(other_ref, testing::Eq(c));
MaybeHarden(c);
c.Append(absl::Cord(std::string(200, 'y')));
c.RemoveSuffix(200);
@@ -1665,6 +1666,7 @@
auto releaser = [&invoked](absl::string_view) { invoked = true; };
{
auto c = absl::MakeCordFromExternal("", releaser);
+ EXPECT_THAT(c, testing::Eq(""));
EXPECT_TRUE(invoked);
}
}
@@ -1679,6 +1681,7 @@
auto releaser = [&invoked](absl::string_view) { invoked = true; };
{
auto c = absl::MakeCordFromExternal(large_dummy, releaser);
+ EXPECT_THAT(c, testing::Eq(large_dummy));
EXPECT_FALSE(invoked);
}
EXPECT_TRUE(invoked);
@@ -2167,6 +2170,7 @@
absl::Cord cord;
for (char c : expected) {
absl::Cord shared(cord);
+ EXPECT_THAT(cord, testing::Eq(shared));
cord.Append(absl::string_view(&c, 1));
MaybeHarden(cord);
}
@@ -2514,6 +2518,10 @@
absl::Cord::CharRange range = cord.Chars();
EXPECT_EQ(range.begin() == range.end(), cord.empty());
EXPECT_EQ(range.begin() != range.end(), !cord.empty());
+ EXPECT_EQ(absl::Cord::Distance(range.begin(), range.end()),
+ static_cast<ptrdiff_t>(cord.size()));
+ EXPECT_EQ(absl::Cord::Distance(range.end(), range.begin()),
+ -static_cast<ptrdiff_t>(cord.size()));
size_t i = 0;
absl::Cord::CharIterator pre_iter = cord.char_begin();
@@ -2530,8 +2538,6 @@
EXPECT_EQ(*pre_iter, *post_iter);
EXPECT_EQ(&*pre_iter, &*post_iter);
- EXPECT_EQ(&*pre_iter, pre_iter.operator->());
-
const char* character_address = &*pre_iter;
absl::Cord::CharIterator copy = pre_iter;
++copy;
@@ -2546,19 +2552,29 @@
absl::Cord::CharIterator advance_iter = range.begin();
absl::Cord::Advance(&advance_iter, i);
EXPECT_EQ(pre_iter, advance_iter);
+ EXPECT_EQ(absl::Cord::Distance(range.begin(), advance_iter),
+ static_cast<ptrdiff_t>(i));
advance_iter = range.begin();
EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, i), cord.Subcord(0, i));
EXPECT_EQ(pre_iter, advance_iter);
+ EXPECT_EQ(absl::Cord::Distance(range.begin(), advance_iter),
+ static_cast<ptrdiff_t>(i));
advance_iter = pre_iter;
absl::Cord::Advance(&advance_iter, cord.size() - i);
EXPECT_EQ(range.end(), advance_iter);
+ EXPECT_EQ(absl::Cord::Distance(range.begin(), advance_iter),
+ static_cast<ptrdiff_t>(cord.size()));
+ EXPECT_EQ(absl::Cord::Distance(advance_iter, range.end()), 0);
advance_iter = pre_iter;
EXPECT_EQ(absl::Cord::AdvanceAndRead(&advance_iter, cord.size() - i),
cord.Subcord(i, cord.size() - i));
EXPECT_EQ(range.end(), advance_iter);
+ EXPECT_EQ(absl::Cord::Distance(range.begin(), advance_iter),
+ static_cast<ptrdiff_t>(cord.size()));
+ EXPECT_EQ(absl::Cord::Distance(advance_iter, range.end()), 0);
++i;
++pre_iter;
@@ -2640,16 +2656,25 @@
MaybeHarden(cord);
+
for (size_t chunk_size :
{kChunkSize1, kChunkSize2, kChunkSize3, kChunkSize4}) {
absl::Cord::CharIterator it = cord.char_begin();
+ size_t it_remaining = cord.size();
+ size_t it_advanced = 0;
size_t offset = 0;
while (offset < data.length()) {
+ EXPECT_EQ(absl::Cord::Distance(it, cord.char_end()), it_remaining);
+ EXPECT_EQ(absl::Cord::Distance(cord.char_begin(), it), it_advanced);
const size_t n = std::min<size_t>(data.length() - offset, chunk_size);
absl::Cord chunk = cord.AdvanceAndRead(&it, n);
ASSERT_EQ(chunk.size(), n);
ASSERT_EQ(chunk.Compare(data.substr(offset, n)), 0);
offset += n;
+ it_remaining -= n;
+ it_advanced += n;
+ EXPECT_EQ(absl::Cord::Distance(it, cord.char_end()), it_remaining);
+ EXPECT_EQ(absl::Cord::Distance(cord.char_begin(), it), it_advanced);
}
}
}
@@ -3278,6 +3303,26 @@
EXPECT_EQ(absl::HashOf(c3), absl::HashOf(absl::string_view()));
}
+// This must not be static to avoid aggressive optimizations.
+ABSL_ATTRIBUTE_WEAK
+size_t FalseReport(const absl::Cord& a, bool f);
+
+ABSL_ATTRIBUTE_NOINLINE
+size_t FalseReport(const absl::Cord& a, bool f) {
+ absl::Cord b;
+ const absl::Cord& ref = f ? b : a;
+ // Test that sanitizers report nothing here. Without
+ // InlineData::Rep::annotated_this() compiler can unconditionally load
+ // poisoned parts, assuming that local variable is fully accessible.
+ return ref.size();
+}
+
+TEST(CordSanitizerTest, SanitizesCordFalseReport) {
+ absl::Cord c;
+ for (int i = 0; i < 1000; ++i) c.Append("a");
+ FalseReport(c, false);
+}
+
TEST(CrcCordTest, ChecksummedEmptyCordEstimateMemoryUsage) {
absl::Cord cord;
cord.SetExpectedChecksum(0);
diff --git a/absl/strings/cordz_test_helpers.h b/absl/strings/cordz_test_helpers.h
index 619f13c..66232db 100644
--- a/absl/strings/cordz_test_helpers.h
+++ b/absl/strings/cordz_test_helpers.h
@@ -34,16 +34,15 @@
ABSL_NAMESPACE_BEGIN
// Returns the CordzInfo for the cord, or nullptr if the cord is not sampled.
-inline absl::Nullable<const cord_internal::CordzInfo*> GetCordzInfoForTesting(
+inline const cord_internal::CordzInfo* GetCordzInfoForTesting(
const Cord& cord) {
if (!cord.contents_.is_tree()) return nullptr;
return cord.contents_.cordz_info();
}
// Returns true if the provided cordz_info is in the list of sampled cords.
-inline bool CordzInfoIsListed(
- absl::Nonnull<const cord_internal::CordzInfo*> cordz_info,
- cord_internal::CordzSampleToken token = {}) {
+inline bool CordzInfoIsListed(const cord_internal::CordzInfo* cordz_info,
+ cord_internal::CordzSampleToken token = {}) {
for (const cord_internal::CordzInfo& info : token) {
if (cordz_info == &info) return true;
}
@@ -121,7 +120,7 @@
// Wrapper struct managing a small CordRep `rep`
struct TestCordRep {
- absl::Nonnull<cord_internal::CordRepFlat*> rep;
+ cord_internal::CordRepFlat* rep;
TestCordRep() {
rep = cord_internal::CordRepFlat::New(100);
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index 4ffef94..e551c66 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -15,6 +15,7 @@
#include "absl/strings/escaping.h"
#include <algorithm>
+#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -24,6 +25,7 @@
#include <utility>
#include "absl/base/config.h"
+#include "absl/base/internal/endian.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/unaligned_access.h"
#include "absl/base/nullability.h"
@@ -57,7 +59,7 @@
}
inline bool IsSurrogate(char32_t c, absl::string_view src,
- absl::Nullable<std::string*> error) {
+ std::string* absl_nullable error) {
if (c >= 0xD800 && c <= 0xDFFF) {
if (error) {
*error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
@@ -74,49 +76,49 @@
//
// Unescapes C escape sequences and is the reverse of CEscape().
//
-// If 'source' is valid, stores the unescaped string and its size in
-// 'dest' and 'dest_len' respectively, and returns true. Otherwise
-// returns false and optionally stores the error description in
-// 'error'. Set 'error' to nullptr to disable error reporting.
+// If `src` is valid, stores the unescaped string `dst`, and returns
+// true. Otherwise returns false and optionally stores the error
+// description in `error`. Set `error` to nullptr to disable error
+// reporting.
//
-// 'dest' should point to a buffer that is at least as big as 'source'.
-// 'source' and 'dest' may be the same.
-//
-// NOTE: any changes to this function must also be reflected in the older
-// UnescapeCEscapeSequences().
+// `src` and `dst` may use the same underlying buffer.
// ----------------------------------------------------------------------
-bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
- absl::Nonnull<char*> dest,
- absl::Nonnull<ptrdiff_t*> dest_len,
- absl::Nullable<std::string*> error) {
- char* d = dest;
- const char* p = source.data();
- const char* end = p + source.size();
- const char* last_byte = end - 1;
- // Small optimization for case where source = dest and there's no escaping
- while (p == d && p < end && *p != '\\') p++, d++;
+bool CUnescapeInternal(absl::string_view src, bool leave_nulls_escaped,
+ std::string* absl_nonnull dst,
+ std::string* absl_nullable error) {
+ strings_internal::STLStringResizeUninitialized(dst, src.size());
- while (p < end) {
- if (*p != '\\') {
- *d++ = *p++;
+ absl::string_view::size_type p = 0; // Current src position.
+ std::string::size_type d = 0; // Current dst position.
+
+ // When unescaping in-place, skip any prefix that does not have escaping.
+ if (src.data() == dst->data()) {
+ while (p < src.size() && src[p] != '\\') p++, d++;
+ }
+
+ while (p < src.size()) {
+ if (src[p] != '\\') {
+ (*dst)[d++] = src[p++];
} else {
- if (++p > last_byte) { // skip past the '\\'
- if (error) *error = "String cannot end with \\";
+ if (++p >= src.size()) { // skip past the '\\'
+ if (error != nullptr) {
+ *error = "String cannot end with \\";
+ }
return false;
}
- switch (*p) {
- case 'a': *d++ = '\a'; break;
- case 'b': *d++ = '\b'; break;
- case 'f': *d++ = '\f'; break;
- case 'n': *d++ = '\n'; break;
- case 'r': *d++ = '\r'; break;
- case 't': *d++ = '\t'; break;
- case 'v': *d++ = '\v'; break;
- case '\\': *d++ = '\\'; break;
- case '?': *d++ = '\?'; break; // \? Who knew?
- case '\'': *d++ = '\''; break;
- case '"': *d++ = '\"'; break;
+ switch (src[p]) {
+ case 'a': (*dst)[d++] = '\a'; break;
+ case 'b': (*dst)[d++] = '\b'; break;
+ case 'f': (*dst)[d++] = '\f'; break;
+ case 'n': (*dst)[d++] = '\n'; break;
+ case 'r': (*dst)[d++] = '\r'; break;
+ case 't': (*dst)[d++] = '\t'; break;
+ case 'v': (*dst)[d++] = '\v'; break;
+ case '\\': (*dst)[d++] = '\\'; break;
+ case '?': (*dst)[d++] = '\?'; break;
+ case '\'': (*dst)[d++] = '\''; break;
+ case '"': (*dst)[d++] = '\"'; break;
case '0':
case '1':
case '2':
@@ -126,188 +128,170 @@
case '6':
case '7': {
// octal digit: 1 to 3 digits
- const char* octal_start = p;
- unsigned int ch = static_cast<unsigned int>(*p - '0'); // digit 1
- if (p < last_byte && is_octal_digit(p[1]))
- ch = ch * 8 + static_cast<unsigned int>(*++p - '0'); // digit 2
- if (p < last_byte && is_octal_digit(p[1]))
- ch = ch * 8 + static_cast<unsigned int>(*++p - '0'); // digit 3
+ auto octal_start = p;
+ unsigned int ch = static_cast<unsigned int>(src[p] - '0'); // digit 1
+ if (p + 1 < src.size() && is_octal_digit(src[p + 1]))
+ ch = ch * 8 + static_cast<unsigned int>(src[++p] - '0'); // digit 2
+ if (p + 1 < src.size() && is_octal_digit(src[p + 1]))
+ ch = ch * 8 + static_cast<unsigned int>(src[++p] - '0'); // digit 3
if (ch > 0xff) {
- if (error) {
- *error = "Value of \\" +
- std::string(octal_start,
- static_cast<size_t>(p + 1 - octal_start)) +
- " exceeds 0xff";
+ if (error != nullptr) {
+ *error =
+ "Value of \\" +
+ std::string(src.substr(octal_start, p + 1 - octal_start)) +
+ " exceeds 0xff";
}
return false;
}
if ((ch == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
- const size_t octal_size = static_cast<size_t>(p + 1 - octal_start);
- *d++ = '\\';
- memmove(d, octal_start, octal_size);
- d += octal_size;
+ (*dst)[d++] = '\\';
+ while (octal_start <= p) {
+ (*dst)[d++] = src[octal_start++];
+ }
break;
}
- *d++ = static_cast<char>(ch);
+ (*dst)[d++] = static_cast<char>(ch);
break;
}
case 'x':
case 'X': {
- if (p >= last_byte) {
- if (error) *error = "String cannot end with \\x";
+ if (p + 1 >= src.size()) {
+ if (error != nullptr) {
+ *error = "String cannot end with \\x";
+ }
return false;
- } else if (!absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
- if (error) *error = "\\x cannot be followed by a non-hex digit";
+ } else if (!absl::ascii_isxdigit(
+ static_cast<unsigned char>(src[p + 1]))) {
+ if (error != nullptr) {
+ *error = "\\x cannot be followed by a non-hex digit";
+ }
return false;
}
unsigned int ch = 0;
- const char* hex_start = p;
- while (p < last_byte &&
- absl::ascii_isxdigit(static_cast<unsigned char>(p[1])))
+ auto hex_start = p;
+ while (p + 1 < src.size() &&
+ absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
// Arbitrarily many hex digits
- ch = (ch << 4) + hex_digit_to_int(*++p);
+ ch = (ch << 4) + hex_digit_to_int(src[++p]);
+ }
if (ch > 0xFF) {
- if (error) {
+ if (error != nullptr) {
*error = "Value of \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start)) +
+ std::string(src.substr(hex_start, p + 1 - hex_start)) +
" exceeds 0xff";
}
return false;
}
if ((ch == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
- const size_t hex_size = static_cast<size_t>(p + 1 - hex_start);
- *d++ = '\\';
- memmove(d, hex_start, hex_size);
- d += hex_size;
+ (*dst)[d++] = '\\';
+ while (hex_start <= p) {
+ (*dst)[d++] = src[hex_start++];
+ }
break;
}
- *d++ = static_cast<char>(ch);
+ (*dst)[d++] = static_cast<char>(ch);
break;
}
case 'u': {
// \uhhhh => convert 4 hex digits to UTF-8
char32_t rune = 0;
- const char* hex_start = p;
- if (p + 4 >= end) {
- if (error) {
- *error = "\\u must be followed by 4 hex digits: \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start));
+ auto hex_start = p;
+ if (p + 4 >= src.size()) {
+ if (error != nullptr) {
+ *error = "\\u must be followed by 4 hex digits";
}
return false;
}
for (int i = 0; i < 4; ++i) {
// Look one char ahead.
- if (absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
- rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p.
+ if (absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
+ rune = (rune << 4) + hex_digit_to_int(src[++p]);
} else {
- if (error) {
+ if (error != nullptr) {
*error = "\\u must be followed by 4 hex digits: \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start));
+ std::string(src.substr(hex_start, p + 1 - hex_start));
}
return false;
}
}
if ((rune == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
- *d++ = '\\';
- memmove(d, hex_start, 5); // u0000
- d += 5;
+ (*dst)[d++] = '\\';
+ while (hex_start <= p) {
+ (*dst)[d++] = src[hex_start++];
+ }
break;
}
- if (IsSurrogate(rune, absl::string_view(hex_start, 5), error)) {
+ if (IsSurrogate(rune, src.substr(hex_start, 5), error)) {
return false;
}
- d += strings_internal::EncodeUTF8Char(d, rune);
+ d += strings_internal::EncodeUTF8Char(dst->data() + d, rune);
break;
}
case 'U': {
// \Uhhhhhhhh => convert 8 hex digits to UTF-8
char32_t rune = 0;
- const char* hex_start = p;
- if (p + 8 >= end) {
- if (error) {
- *error = "\\U must be followed by 8 hex digits: \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start));
+ auto hex_start = p;
+ if (p + 8 >= src.size()) {
+ if (error != nullptr) {
+ *error = "\\U must be followed by 8 hex digits";
}
return false;
}
for (int i = 0; i < 8; ++i) {
// Look one char ahead.
- if (absl::ascii_isxdigit(static_cast<unsigned char>(p[1]))) {
+ if (absl::ascii_isxdigit(static_cast<unsigned char>(src[p + 1]))) {
// Don't change rune until we're sure this
// is within the Unicode limit, but do advance p.
- uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p);
+ uint32_t newrune = (rune << 4) + hex_digit_to_int(src[++p]);
if (newrune > 0x10FFFF) {
- if (error) {
- *error = "Value of \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start)) +
- " exceeds Unicode limit (0x10FFFF)";
+ if (error != nullptr) {
+ *error =
+ "Value of \\" +
+ std::string(src.substr(hex_start, p + 1 - hex_start)) +
+ " exceeds Unicode limit (0x10FFFF)";
}
return false;
} else {
rune = newrune;
}
} else {
- if (error) {
+ if (error != nullptr) {
*error = "\\U must be followed by 8 hex digits: \\" +
- std::string(hex_start,
- static_cast<size_t>(p + 1 - hex_start));
+ std::string(src.substr(hex_start, p + 1 - hex_start));
}
return false;
}
}
if ((rune == 0) && leave_nulls_escaped) {
// Copy the escape sequence for the null character
- *d++ = '\\';
- memmove(d, hex_start, 9); // U00000000
- d += 9;
+ (*dst)[d++] = '\\';
+ // U00000000
+ while (hex_start <= p) {
+ (*dst)[d++] = src[hex_start++];
+ }
break;
}
- if (IsSurrogate(rune, absl::string_view(hex_start, 9), error)) {
+ if (IsSurrogate(rune, src.substr(hex_start, 9), error)) {
return false;
}
- d += strings_internal::EncodeUTF8Char(d, rune);
+ d += strings_internal::EncodeUTF8Char(dst->data() + d, rune);
break;
}
default: {
- if (error) *error = std::string("Unknown escape sequence: \\") + *p;
+ if (error != nullptr) {
+ *error = std::string("Unknown escape sequence: \\") + src[p];
+ }
return false;
}
}
- p++; // read past letter we escaped
+ p++; // Read past letter we escaped.
}
}
- *dest_len = d - dest;
- return true;
-}
-// ----------------------------------------------------------------------
-// CUnescapeInternal()
-//
-// Same as above but uses a std::string for output. 'source' and 'dest'
-// may be the same.
-// ----------------------------------------------------------------------
-bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
- absl::Nonnull<std::string*> dest,
- absl::Nullable<std::string*> error) {
- strings_internal::STLStringResizeUninitialized(dest, source.size());
-
- ptrdiff_t dest_size;
- if (!CUnescapeInternal(source,
- leave_nulls_escaped,
- &(*dest)[0],
- &dest_size,
- error)) {
- return false;
- }
- dest->erase(static_cast<size_t>(dest_size));
+ dst->erase(d);
return true;
}
@@ -368,7 +352,7 @@
}
/* clang-format off */
-constexpr unsigned char kCEscapedLen[256] = {
+constexpr std::array<unsigned char, 256> kCEscapedLen = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
@@ -388,6 +372,40 @@
};
/* clang-format on */
+constexpr uint32_t MakeCEscapedLittleEndianUint32(size_t c) {
+ size_t char_len = kCEscapedLen[c];
+ if (char_len == 1) {
+ return static_cast<uint32_t>(c);
+ }
+ if (char_len == 2) {
+ switch (c) {
+ case '\n':
+ return '\\' | (static_cast<uint32_t>('n') << 8);
+ case '\r':
+ return '\\' | (static_cast<uint32_t>('r') << 8);
+ case '\t':
+ return '\\' | (static_cast<uint32_t>('t') << 8);
+ case '\"':
+ return '\\' | (static_cast<uint32_t>('\"') << 8);
+ case '\'':
+ return '\\' | (static_cast<uint32_t>('\'') << 8);
+ case '\\':
+ return '\\' | (static_cast<uint32_t>('\\') << 8);
+ }
+ }
+ return static_cast<uint32_t>('\\' | (('0' + (c / 64)) << 8) |
+ (('0' + ((c % 64) / 8)) << 16) |
+ (('0' + (c % 8)) << 24));
+}
+
+template <size_t... indexes>
+inline constexpr std::array<uint32_t, sizeof...(indexes)>
+MakeCEscapedLittleEndianUint32Array(std::index_sequence<indexes...>) {
+ return {MakeCEscapedLittleEndianUint32(indexes)...};
+}
+constexpr std::array<uint32_t, 256> kCEscapedLittleEndianUint32Array =
+ MakeCEscapedLittleEndianUint32Array(std::make_index_sequence<256>());
+
// Calculates the length of the C-style escaped version of 'src'.
// Assumes that non-printable characters are escaped using octal sequences, and
// that UTF-8 bytes are not handled specially.
@@ -414,67 +432,39 @@
}
void CEscapeAndAppendInternal(absl::string_view src,
- absl::Nonnull<std::string*> dest) {
+ std::string* absl_nonnull dest) {
size_t escaped_len = CEscapedLength(src);
if (escaped_len == src.size()) {
dest->append(src.data(), src.size());
return;
}
+ // We keep 3 slop bytes so that we can call `little_endian::Store32`
+ // invariably regardless of the length of the escaped character.
+ constexpr size_t slop_bytes = 3;
size_t cur_dest_len = dest->size();
- ABSL_INTERNAL_CHECK(
- cur_dest_len <= std::numeric_limits<size_t>::max() - escaped_len,
- "std::string size overflow");
- strings_internal::STLStringResizeUninitialized(dest,
- cur_dest_len + escaped_len);
+ size_t new_dest_len = cur_dest_len + escaped_len + slop_bytes;
+ ABSL_INTERNAL_CHECK(new_dest_len > cur_dest_len, "std::string size overflow");
+ strings_internal::AppendUninitializedTraits<std::string>::Append(
+ dest, escaped_len + slop_bytes);
char* append_ptr = &(*dest)[cur_dest_len];
for (char c : src) {
- size_t char_len = kCEscapedLen[static_cast<unsigned char>(c)];
- if (char_len == 1) {
- *append_ptr++ = c;
- } else if (char_len == 2) {
- switch (c) {
- case '\n':
- *append_ptr++ = '\\';
- *append_ptr++ = 'n';
- break;
- case '\r':
- *append_ptr++ = '\\';
- *append_ptr++ = 'r';
- break;
- case '\t':
- *append_ptr++ = '\\';
- *append_ptr++ = 't';
- break;
- case '\"':
- *append_ptr++ = '\\';
- *append_ptr++ = '\"';
- break;
- case '\'':
- *append_ptr++ = '\\';
- *append_ptr++ = '\'';
- break;
- case '\\':
- *append_ptr++ = '\\';
- *append_ptr++ = '\\';
- break;
- }
- } else {
- *append_ptr++ = '\\';
- *append_ptr++ = '0' + static_cast<unsigned char>(c) / 64;
- *append_ptr++ = '0' + (static_cast<unsigned char>(c) % 64) / 8;
- *append_ptr++ = '0' + static_cast<unsigned char>(c) % 8;
- }
+ unsigned char uc = static_cast<unsigned char>(c);
+ size_t char_len = kCEscapedLen[uc];
+ uint32_t little_endian_uint32 = kCEscapedLittleEndianUint32Array[uc];
+ little_endian::Store32(append_ptr, little_endian_uint32);
+ append_ptr += char_len;
}
+ dest->resize(new_dest_len - slop_bytes);
}
// Reverses the mapping in Base64EscapeInternal; see that method's
// documentation for details of the mapping.
-bool Base64UnescapeInternal(absl::Nullable<const char*> src_param, size_t szsrc,
- absl::Nullable<char*> dest, size_t szdest,
- absl::Nonnull<const signed char*> unbase64,
- absl::Nonnull<size_t*> len) {
+bool Base64UnescapeInternal(const char* absl_nullable src_param, size_t szsrc,
+ char* absl_nullable dest, size_t szdest,
+ const std::array<signed char, 256>& unbase64,
+ size_t* absl_nonnull len) {
static const char kPad64Equals = '=';
static const char kPad64Dot = '.';
@@ -738,7 +728,7 @@
// where the value of "Base64[]" was replaced by one of k(WebSafe)Base64Chars
// in the internal escaping.cc.
/* clang-format off */
-constexpr signed char kUnBase64[] = {
+constexpr std::array<signed char, 256> kUnBase64 = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -773,7 +763,7 @@
-1, -1, -1, -1, -1, -1, -1, -1
};
-constexpr signed char kUnWebSafeBase64[] = {
+constexpr std::array<signed char, 256> kUnWebSafeBase64 = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -810,9 +800,9 @@
/* clang-format on */
template <typename String>
-bool Base64UnescapeInternal(absl::Nullable<const char*> src, size_t slen,
- absl::Nonnull<String*> dest,
- absl::Nonnull<const signed char*> unbase64) {
+bool Base64UnescapeInternal(const char* absl_nullable src, size_t slen,
+ String* absl_nonnull dest,
+ const std::array<signed char, 256>& unbase64) {
// Determine the size of the output string. Base64 encodes every 3 bytes into
// 4 characters. Any leftover chars are added directly for good measure.
const size_t dest_len = 3 * (slen / 4) + (slen % 4);
@@ -837,7 +827,7 @@
}
/* clang-format off */
-constexpr char kHexValueLenient[256] = {
+constexpr std::array<char, 256> kHexValueLenient = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -856,7 +846,7 @@
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-constexpr signed char kHexValueStrict[256] = {
+constexpr std::array<signed char, 256> kHexValueStrict = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -880,7 +870,7 @@
// or a string. This works because we use the [] operator to access
// individual characters at a time.
template <typename T>
-void HexStringToBytesInternal(absl::Nullable<const char*> from, T to,
+void HexStringToBytesInternal(const char* absl_nullable from, T to,
size_t num) {
for (size_t i = 0; i < num; i++) {
to[i] = static_cast<char>(kHexValueLenient[from[i * 2] & 0xFF] << 4) +
@@ -891,7 +881,7 @@
// This is a templated function so that T can be either a char* or a
// std::string.
template <typename T>
-void BytesToHexStringInternal(absl::Nullable<const unsigned char*> src, T dest,
+void BytesToHexStringInternal(const unsigned char* absl_nullable src, T dest,
size_t num) {
auto dest_ptr = &dest[0];
for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
@@ -907,8 +897,8 @@
//
// See CUnescapeInternal() for implementation details.
// ----------------------------------------------------------------------
-bool CUnescape(absl::string_view source, absl::Nonnull<std::string*> dest,
- absl::Nullable<std::string*> error) {
+bool CUnescape(absl::string_view source, std::string* absl_nonnull dest,
+ std::string* absl_nullable error) {
return CUnescapeInternal(source, kUnescapeNulls, dest, error);
}
@@ -930,23 +920,23 @@
return CEscapeInternal(src, true, true);
}
-bool Base64Unescape(absl::string_view src, absl::Nonnull<std::string*> dest) {
+bool Base64Unescape(absl::string_view src, std::string* absl_nonnull dest) {
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
}
bool WebSafeBase64Unescape(absl::string_view src,
- absl::Nonnull<std::string*> dest) {
+ std::string* absl_nonnull dest) {
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
}
-void Base64Escape(absl::string_view src, absl::Nonnull<std::string*> dest) {
+void Base64Escape(absl::string_view src, std::string* absl_nonnull dest) {
strings_internal::Base64EscapeInternal(
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
true, strings_internal::kBase64Chars);
}
void WebSafeBase64Escape(absl::string_view src,
- absl::Nonnull<std::string*> dest) {
+ std::string* absl_nonnull dest) {
strings_internal::Base64EscapeInternal(
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
false, strings_internal::kWebSafeBase64Chars);
@@ -968,8 +958,7 @@
return dest;
}
-bool HexStringToBytes(absl::string_view hex,
- absl::Nonnull<std::string*> bytes) {
+bool HexStringToBytes(absl::string_view hex, std::string* absl_nonnull bytes) {
std::string output;
size_t num_bytes = hex.size() / 2;
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h
index 3f34fbf..3aaf39c 100644
--- a/absl/strings/escaping.h
+++ b/absl/strings/escaping.h
@@ -71,12 +71,12 @@
// ...
// }
// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t");
-bool CUnescape(absl::string_view source, absl::Nonnull<std::string*> dest,
- absl::Nullable<std::string*> error);
+bool CUnescape(absl::string_view source, std::string* absl_nonnull dest,
+ std::string* absl_nullable error);
// Overload of `CUnescape()` with no error reporting.
inline bool CUnescape(absl::string_view source,
- absl::Nonnull<std::string*> dest) {
+ std::string* absl_nonnull dest) {
return CUnescape(source, dest, nullptr);
}
@@ -126,7 +126,7 @@
// Encodes a `src` string into a base64-encoded 'dest' string with padding
// characters. This function conforms with RFC 4648 section 4 (base64) and RFC
// 2045.
-void Base64Escape(absl::string_view src, absl::Nonnull<std::string*> dest);
+void Base64Escape(absl::string_view src, std::string* absl_nonnull dest);
std::string Base64Escape(absl::string_view src);
// WebSafeBase64Escape()
@@ -134,8 +134,7 @@
// Encodes a `src` string into a base64 string, like Base64Escape() does, but
// outputs '-' instead of '+' and '_' instead of '/', and does not pad 'dest'.
// This function conforms with RFC 4648 section 5 (base64url).
-void WebSafeBase64Escape(absl::string_view src,
- absl::Nonnull<std::string*> dest);
+void WebSafeBase64Escape(absl::string_view src, std::string* absl_nonnull dest);
std::string WebSafeBase64Escape(absl::string_view src);
// Base64Unescape()
@@ -145,7 +144,7 @@
// `src` contains invalid characters, `dest` is cleared and returns `false`.
// If padding is included (note that `Base64Escape()` does produce it), it must
// be correct. In the padding, '=' and '.' are treated identically.
-bool Base64Unescape(absl::string_view src, absl::Nonnull<std::string*> dest);
+bool Base64Unescape(absl::string_view src, std::string* absl_nonnull dest);
// WebSafeBase64Unescape()
//
@@ -155,7 +154,7 @@
// included (note that `WebSafeBase64Escape()` does not produce it), it must be
// correct. In the padding, '=' and '.' are treated identically.
bool WebSafeBase64Unescape(absl::string_view src,
- absl::Nonnull<std::string*> dest);
+ std::string* absl_nonnull dest);
// HexStringToBytes()
//
@@ -163,8 +162,8 @@
// output string. If `hex` does not consist of valid hexadecimal data, this
// function returns false and leaves `bytes` in an unspecified state. Returns
// true on success.
-ABSL_MUST_USE_RESULT bool HexStringToBytes(absl::string_view hex,
- absl::Nonnull<std::string*> bytes);
+[[nodiscard]] bool HexStringToBytes(absl::string_view hex,
+ std::string* absl_nonnull bytes);
// HexStringToBytes()
//
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc
index f792226..32b8f6e 100644
--- a/absl/strings/escaping_benchmark.cc
+++ b/absl/strings/escaping_benchmark.cc
@@ -12,19 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/escaping.h"
-
#include <cstdint>
-#include <cstdio>
-#include <cstring>
#include <memory>
#include <random>
#include <string>
-#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/escaping.h"
#include "absl/strings/internal/escaping_test_common.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
namespace {
@@ -33,9 +31,12 @@
for (int i = 0; i < 50; i++) {
src += "\\x55";
}
- std::string dest;
for (auto _ : state) {
- absl::CUnescape(src, &dest);
+ std::string dest;
+ benchmark::DoNotOptimize(src);
+ bool result = absl::CUnescape(src, &dest);
+ benchmark::DoNotOptimize(result);
+ benchmark::DoNotOptimize(dest);
}
}
BENCHMARK(BM_CUnescapeHexString);
@@ -47,22 +48,45 @@
raw += std::string(test_set.plaintext);
}
}
-
- // The actual benchmark loop is tiny...
- std::string escaped;
for (auto _ : state) {
+ std::string escaped;
+ benchmark::DoNotOptimize(raw);
absl::WebSafeBase64Escape(raw, &escaped);
+ benchmark::DoNotOptimize(escaped);
}
-
- // We want to be sure the compiler doesn't throw away the loop above,
- // and the easiest way to ensure that is to round-trip the results and verify
- // them.
- std::string round_trip;
- absl::WebSafeBase64Unescape(escaped, &round_trip);
- ABSL_RAW_CHECK(round_trip == raw, "");
}
BENCHMARK(BM_WebSafeBase64Escape_string);
+void BM_HexStringToBytes(benchmark::State& state) {
+ const int size = state.range(0);
+ std::string input, output;
+ for (int i = 0; i < size; ++i) input += "1c";
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(input);
+ bool result = absl::HexStringToBytes(input, &output);
+ benchmark::DoNotOptimize(result);
+ benchmark::DoNotOptimize(output);
+ }
+}
+BENCHMARK(BM_HexStringToBytes)->Range(1, 1 << 8);
+
+void BM_HexStringToBytes_Fail(benchmark::State& state) {
+ std::string binary;
+ absl::string_view hex_input1 = "1c2f003";
+ absl::string_view hex_input2 = "1c2f0032f40123456789abcdef**";
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(hex_input1);
+ bool result1 = absl::HexStringToBytes(hex_input1, &binary);
+ benchmark::DoNotOptimize(result1);
+ benchmark::DoNotOptimize(binary);
+ benchmark::DoNotOptimize(hex_input2);
+ bool result2 = absl::HexStringToBytes(hex_input2, &binary);
+ benchmark::DoNotOptimize(result2);
+ benchmark::DoNotOptimize(binary);
+ }
+}
+BENCHMARK(BM_HexStringToBytes_Fail);
+
// Used for the CEscape benchmarks
const char kStringValueNoEscape[] = "1234567890";
const char kStringValueSomeEscaped[] = "123\n56789\xA1";
@@ -76,7 +100,9 @@
}
for (auto _ : state) {
- absl::CEscape(src);
+ benchmark::DoNotOptimize(src);
+ std::string result = absl::CEscape(src);
+ benchmark::DoNotOptimize(result);
}
}
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
index 25cb685..4786c88 100644
--- a/absl/strings/escaping_test.cc
+++ b/absl/strings/escaping_test.cc
@@ -169,15 +169,25 @@
EXPECT_TRUE(absl::CUnescape(val.escaped, &out));
EXPECT_EQ(out, val.unescaped);
}
- std::string bad[] = {"\\u1", // too short
- "\\U1", // too short
- "\\Uffffff", // exceeds 0x10ffff (largest Unicode)
- "\\U00110000", // exceeds 0x10ffff (largest Unicode)
- "\\uD835", // surrogate character (D800-DFFF)
- "\\U0000DD04", // surrogate character (D800-DFFF)
- "\\777", // exceeds 0xff
- "\\xABCD"}; // exceeds 0xff
- for (const std::string& e : bad) {
+ constexpr absl::string_view bad[] = {
+ "\\u1", // too short
+ "\\U1", // too short
+ "\\Uffffff", // exceeds 0x10ffff (largest Unicode)
+ "\\U00110000", // exceeds 0x10ffff (largest Unicode)
+ "\\uD835", // surrogate character (D800-DFFF)
+ "\\U0000DD04", // surrogate character (D800-DFFF)
+ "\\777", // exceeds 0xff
+ "\\xABCD", // exceeds 0xff
+ "endswith\\", // ends with "\"
+ "endswith\\x", // ends with "\x"
+ "endswith\\X", // ends with "\X"
+ "\\x.2345678", // non-hex follows "\x"
+ "\\X.2345678", // non-hex follows "\X"
+ "\\u.2345678", // non-hex follows "\U"
+ "\\U.2345678", // non-hex follows "\U"
+ "\\.unknown", // unknown escape sequence
+ };
+ for (const auto e : bad) {
std::string error;
std::string out;
EXPECT_FALSE(absl::CUnescape(e, &out, &error));
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc
index 46b5289..9185f1f 100644
--- a/absl/strings/internal/charconv_bigint.cc
+++ b/absl/strings/internal/charconv_bigint.cc
@@ -279,7 +279,7 @@
// Either way, [begin, decimal_point) will contain the set of dropped digits
// that require an exponent adjustment.
const char* decimal_point = std::find(begin, end, '.');
- exponent_adjust += (decimal_point - begin);
+ exponent_adjust += static_cast<int>(decimal_point - begin);
}
return exponent_adjust;
}
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h
index cb29767..2c7a336 100644
--- a/absl/strings/internal/charconv_bigint.h
+++ b/absl/strings/internal/charconv_bigint.h
@@ -17,7 +17,7 @@
#include <algorithm>
#include <cstdint>
-#include <iostream>
+#include <ostream>
#include <string>
#include "absl/base/config.h"
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc
index a8b9945..7bbf16d 100644
--- a/absl/strings/internal/charconv_bigint_test.cc
+++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -176,7 +176,7 @@
TEST(BigUnsigned, MultiplyByOverflow) {
{
- // Check that multiplcation overflow predictably truncates.
+ // Check that multiplication overflow predictably truncates.
// A big int with all bits on.
BigUnsigned<4> all_bits_on("340282366920938463463374607431768211455");
diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h
index f0060f1..cf1f703 100644
--- a/absl/strings/internal/cord_internal.h
+++ b/absl/strings/internal/cord_internal.h
@@ -19,16 +19,17 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
-#include <type_traits>
+#include <cstring>
+#include <string>
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/endian.h"
-#include "absl/base/internal/invoke.h"
+#include "absl/base/macros.h"
+#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/container/internal/container_memory.h"
-#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
// We can only add poisoning if we can detect consteval executions.
@@ -356,16 +357,15 @@
struct Rank0 {};
struct Rank1 : Rank0 {};
-template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
- Releaser, absl::string_view>>
+template <typename Releaser,
+ typename = ::std::invoke_result_t<Releaser, absl::string_view>>
void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view data) {
- ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
+ ::std::invoke(std::forward<Releaser>(releaser), data);
}
-template <typename Releaser,
- typename = ::absl::base_internal::invoke_result_t<Releaser>>
+template <typename Releaser, typename = ::std::invoke_result_t<Releaser>>
void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view) {
- ::absl::base_internal::invoke(std::forward<Releaser>(releaser));
+ ::std::invoke(std::forward<Releaser>(releaser));
}
// We use CompressedTuple so that we can benefit from EBCO.
@@ -635,6 +635,19 @@
poison();
}
+ void CopyInlineToString(std::string* dst) const {
+ assert(!is_tree());
+ // As Cord can store only 15 bytes it is smaller than std::string's
+ // small string optimization buffer size. Therefore we will always trigger
+ // the fast assign short path.
+ //
+ // Copying with a size equal to the maximum allows more efficient, wider
+ // stores to be used and no branching.
+ dst->assign(rep_.SanitizerSafeCopy().as_chars(), kMaxInline);
+ // After the copy we then change the size and put in a 0 byte.
+ dst->erase(inline_size());
+ }
+
void copy_max_inline_to(char* dst) const {
assert(!is_tree());
memcpy(dst, rep_.SanitizerSafeCopy().as_chars(), kMaxInline);
@@ -713,35 +726,53 @@
GetOrNull(chars, 13),
GetOrNull(chars, 14)} {}
+#ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
+ // Break compiler optimization for cases when value is allocated on the
+ // stack. Compiler assumes that the the variable is fully accessible
+ // regardless of our poisoning.
+ // Missing report: https://github.com/llvm/llvm-project/issues/100640
+ const Rep* self() const {
+ const Rep* volatile ptr = this;
+ return ptr;
+ }
+ Rep* self() {
+ Rep* volatile ptr = this;
+ return ptr;
+ }
+#else
+ constexpr const Rep* self() const { return this; }
+ constexpr Rep* self() { return this; }
+#endif
+
// Disable sanitizer as we must always be able to read `tag`.
ABSL_CORD_INTERNAL_NO_SANITIZE
int8_t tag() const { return reinterpret_cast<const int8_t*>(this)[0]; }
- void set_tag(int8_t rhs) { reinterpret_cast<int8_t*>(this)[0] = rhs; }
+ void set_tag(int8_t rhs) { reinterpret_cast<int8_t*>(self())[0] = rhs; }
- char* as_chars() { return data + 1; }
- const char* as_chars() const { return data + 1; }
+ char* as_chars() { return self()->data + 1; }
+ const char* as_chars() const { return self()->data + 1; }
- bool is_tree() const { return (tag() & 1) != 0; }
+ bool is_tree() const { return (self()->tag() & 1) != 0; }
size_t inline_size() const {
- ABSL_ASSERT(!is_tree());
- return static_cast<size_t>(tag()) >> 1;
+ ABSL_ASSERT(!self()->is_tree());
+ return static_cast<size_t>(self()->tag()) >> 1;
}
void set_inline_size(size_t size) {
ABSL_ASSERT(size <= kMaxInline);
- set_tag(static_cast<int8_t>(size << 1));
+ self()->set_tag(static_cast<int8_t>(size << 1));
}
- CordRep* tree() const { return as_tree.rep; }
- void set_tree(CordRep* rhs) { as_tree.rep = rhs; }
+ CordRep* tree() const { return self()->as_tree.rep; }
+ void set_tree(CordRep* rhs) { self()->as_tree.rep = rhs; }
- cordz_info_t cordz_info() const { return as_tree.cordz_info; }
- void set_cordz_info(cordz_info_t rhs) { as_tree.cordz_info = rhs; }
+ cordz_info_t cordz_info() const { return self()->as_tree.cordz_info; }
+ void set_cordz_info(cordz_info_t rhs) { self()->as_tree.cordz_info = rhs; }
void make_tree(CordRep* tree) {
- as_tree.rep = tree;
- as_tree.cordz_info = kNullCordzInfo;
+ self()->as_tree.rep = tree;
+ self()->as_tree.cordz_info = kNullCordzInfo;
}
#ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
diff --git a/absl/strings/internal/cord_rep_btree.cc b/absl/strings/internal/cord_rep_btree.cc
index 05bd0e2..33ea820 100644
--- a/absl/strings/internal/cord_rep_btree.cc
+++ b/absl/strings/internal/cord_rep_btree.cc
@@ -36,10 +36,6 @@
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr size_t CordRepBtree::kMaxCapacity;
-#endif
-
namespace {
using NodeStack = CordRepBtree * [CordRepBtree::kMaxDepth];
diff --git a/absl/strings/internal/cordz_info.cc b/absl/strings/internal/cordz_info.cc
index b7c7fed..4baaecd 100644
--- a/absl/strings/internal/cordz_info.cc
+++ b/absl/strings/internal/cordz_info.cc
@@ -34,10 +34,6 @@
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr size_t CordzInfo::kMaxStackDepth;
-#endif
-
ABSL_CONST_INIT CordzInfo::List CordzInfo::global_list_{absl::kConstInit};
namespace {
diff --git a/absl/strings/internal/cordz_info.h b/absl/strings/internal/cordz_info.h
index 2dc9d16..aa92a8f 100644
--- a/absl/strings/internal/cordz_info.h
+++ b/absl/strings/internal/cordz_info.h
@@ -291,10 +291,15 @@
inline void CordzInfo::UnsafeSetCordRep(CordRep* rep) { rep_ = rep; }
+// Android local modification: locally silence an incorrect warning that
+// causes build failures in code that uses -Werror.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wthread-safety-negative"
inline CordRep* CordzInfo::RefCordRep() const ABSL_LOCKS_EXCLUDED(mutex_) {
MutexLock lock(&mutex_);
return rep_ ? CordRep::Ref(rep_) : nullptr;
}
+#pragma clang diagnostic pop
} // namespace cord_internal
ABSL_NAMESPACE_END
diff --git a/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc b/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc
new file mode 100644
index 0000000..76d6db4
--- /dev/null
+++ b/absl/strings/internal/damerau_levenshtein_distance_benchmark.cc
@@ -0,0 +1,56 @@
+// Copyright 2022 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "absl/strings/internal/damerau_levenshtein_distance.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+std::string MakeTestString(int desired_length, int num_edits) {
+ std::string test(desired_length, 'x');
+ for (int i = 0; (i < num_edits) && (i * 8 < desired_length); ++i) {
+ test[i * 8] = 'y';
+ }
+ return test;
+}
+
+void BenchmarkArgs(benchmark::internal::Benchmark* benchmark) {
+ // Each column is 8 bytes.
+ const auto string_size = {1, 8, 64, 100};
+ const auto num_edits = {1, 2, 16, 16, 64, 80};
+ const auto distance_cap = {1, 2, 3, 16, 64, 80};
+ for (const int s : string_size) {
+ for (const int n : num_edits) {
+ for (const int d : distance_cap) {
+ if (n > s) continue;
+ benchmark->Args({s, n, d});
+ }
+ }
+ }
+}
+
+using absl::strings_internal::CappedDamerauLevenshteinDistance;
+void BM_Distance(benchmark::State& state) {
+ std::string s1 = MakeTestString(state.range(0), 0);
+ std::string s2 = MakeTestString(state.range(0), state.range(1));
+ const size_t cap = state.range(2);
+ for (auto _ : state) {
+ CappedDamerauLevenshteinDistance(s1, s2, cap);
+ }
+}
+BENCHMARK(BM_Distance)->Apply(BenchmarkArgs);
+
+} // namespace
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc
index 61e323a..1186752 100644
--- a/absl/strings/internal/memutil_benchmark.cc
+++ b/absl/strings/internal/memutil_benchmark.cc
@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/internal/memutil.h"
-
#include <algorithm>
#include <cstdlib>
-#include "benchmark/benchmark.h"
#include "absl/strings/ascii.h"
+#include "absl/strings/internal/memutil.h"
+#include "benchmark/benchmark.h"
// We fill the haystack with aaaaaaaaaaaaaaaaaa...aaaab.
// That gives us:
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc
index 5979f18..a95cf4d 100644
--- a/absl/strings/internal/ostringstream_benchmark.cc
+++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/internal/ostringstream.h"
-
#include <sstream>
#include <string>
+#include "absl/strings/internal/ostringstream.h"
#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index eeb2108..01e4e42 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -26,6 +26,7 @@
#include <cstring>
#include <cwchar>
#include <string>
+#include <string_view>
#include <type_traits>
#include "absl/base/config.h"
@@ -34,13 +35,10 @@
#include "absl/numeric/int128.h"
#include "absl/strings/internal/str_format/extension.h"
#include "absl/strings/internal/str_format/float_conversion.h"
+#include "absl/strings/internal/utf8.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
@@ -311,68 +309,16 @@
conv.has_left_flag());
}
-struct ShiftState {
- bool saw_high_surrogate = false;
- uint8_t bits = 0;
-};
-
-// Converts `v` from UTF-16 or UTF-32 to UTF-8 and writes to `buf`. `buf` is
-// assumed to have enough space for the output. `s` is used to carry state
-// between successive calls with a UTF-16 surrogate pair. Returns the number of
-// chars written, or `static_cast<size_t>(-1)` on failure.
-//
-// This is basically std::wcrtomb(), but always outputting UTF-8 instead of
-// respecting the current locale.
-inline size_t WideToUtf8(wchar_t wc, char *buf, ShiftState &s) {
- const auto v = static_cast<uint32_t>(wc);
- if (v < 0x80) {
- *buf = static_cast<char>(v);
- return 1;
- } else if (v < 0x800) {
- *buf++ = static_cast<char>(0xc0 | (v >> 6));
- *buf = static_cast<char>(0x80 | (v & 0x3f));
- return 2;
- } else if (v < 0xd800 || (v - 0xe000) < 0x2000) {
- *buf++ = static_cast<char>(0xe0 | (v >> 12));
- *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
- *buf = static_cast<char>(0x80 | (v & 0x3f));
- return 3;
- } else if ((v - 0x10000) < 0x100000) {
- *buf++ = static_cast<char>(0xf0 | (v >> 18));
- *buf++ = static_cast<char>(0x80 | ((v >> 12) & 0x3f));
- *buf++ = static_cast<char>(0x80 | ((v >> 6) & 0x3f));
- *buf = static_cast<char>(0x80 | (v & 0x3f));
- return 4;
- } else if (v < 0xdc00) {
- s.saw_high_surrogate = true;
- s.bits = static_cast<uint8_t>(v & 0x3);
- const uint8_t high_bits = ((v >> 6) & 0xf) + 1;
- *buf++ = static_cast<char>(0xf0 | (high_bits >> 2));
- *buf =
- static_cast<char>(0x80 | static_cast<uint8_t>((high_bits & 0x3) << 4) |
- static_cast<uint8_t>((v >> 2) & 0xf));
- return 2;
- } else if (v < 0xe000 && s.saw_high_surrogate) {
- *buf++ = static_cast<char>(0x80 | static_cast<uint8_t>(s.bits << 4) |
- static_cast<uint8_t>((v >> 6) & 0xf));
- *buf = static_cast<char>(0x80 | (v & 0x3f));
- s.saw_high_surrogate = false;
- s.bits = 0;
- return 2;
- } else {
- return static_cast<size_t>(-1);
- }
-}
-
inline bool ConvertStringArg(const wchar_t *v,
size_t len,
const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
FixedArray<char> mb(len * 4);
- ShiftState s;
+ strings_internal::ShiftState s;
size_t chars_written = 0;
for (size_t i = 0; i < len; ++i) {
- const size_t chars = WideToUtf8(v[i], &mb[chars_written], s);
+ const size_t chars =
+ strings_internal::WideToUtf8(v[i], &mb[chars_written], s);
if (chars == static_cast<size_t>(-1)) { return false; }
chars_written += chars;
}
@@ -382,8 +328,8 @@
bool ConvertWCharTImpl(wchar_t v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
char mb[4];
- ShiftState s;
- const size_t chars_written = WideToUtf8(v, mb, s);
+ strings_internal::ShiftState s;
+ const size_t chars_written = strings_internal::WideToUtf8(v, mb, s);
return chars_written != static_cast<size_t>(-1) && !s.saw_high_surrogate &&
ConvertStringArg(string_view(mb, chars_written), conv, sink);
}
@@ -510,13 +456,11 @@
return {ConvertStringArg(v, conv, sink)};
}
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
StringConvertResult FormatConvertImpl(std::wstring_view v,
const FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
return {ConvertStringArg(v.data(), v.size(), conv, sink)};
}
-#endif
StringPtrConvertResult FormatConvertImpl(const char* v,
const FormatConversionSpecImpl conv,
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 309161d..021013f 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -26,6 +26,7 @@
#include <memory>
#include <sstream>
#include <string>
+#include <string_view>
#include <type_traits>
#include <utility>
@@ -37,10 +38,6 @@
#include "absl/strings/internal/str_format/extension.h"
#include "absl/strings/string_view.h"
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -228,7 +225,6 @@
StringConvertResult FormatConvertImpl(string_view v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
StringConvertResult FormatConvertImpl(std::wstring_view v,
FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
@@ -239,7 +235,6 @@
return FormatConvertImpl(absl::string_view(v.data(), v.size()), conv, sink);
}
#endif // !ABSL_USES_STD_STRING_VIEW
-#endif // ABSL_HAVE_STD_STRING_VIEW
using StringPtrConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
FormatConversionCharSetInternal::s,
@@ -651,15 +646,10 @@
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const wchar_t*, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring, __VA_ARGS__)
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_( \
__VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::wstring_view, __VA_ARGS__)
-#else
-#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
- ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_NO_WSTRING_VIEW_(__VA_ARGS__)
-#endif
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index baffe05..e4fa44e 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -27,6 +27,7 @@
#include <set>
#include <sstream>
#include <string>
+#include <string_view>
#include <thread> // NOLINT
#include <type_traits>
#include <vector>
@@ -46,10 +47,6 @@
#include "absl/types/optional.h"
#include "absl/types/span.h"
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
-#include <string_view>
-#endif
-
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
@@ -322,10 +319,8 @@
TestStringConvert(std::string("hello"));
TestStringConvert(std::wstring(L"hello"));
TestStringConvert(string_view("hello"));
-#if defined(ABSL_HAVE_STD_STRING_VIEW)
TestStringConvert(std::string_view("hello"));
TestStringConvert(std::wstring_view(L"hello"));
-#endif // ABSL_HAVE_STD_STRING_VIEW
}
TEST_F(FormatConvertTest, NullString) {
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc
index 2a0ceb1..2d441c2 100644
--- a/absl/strings/internal/str_format/extension.cc
+++ b/absl/strings/internal/str_format/extension.cc
@@ -33,28 +33,6 @@
return s;
}
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-
-#define ABSL_INTERNAL_X_VAL(id) \
- constexpr absl::FormatConversionChar FormatConversionCharInternal::id;
-ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
-#undef ABSL_INTERNAL_X_VAL
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone;
-
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
- constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
-ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
-#undef ABSL_INTERNAL_CHAR_SET_CASE
-
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
-
-#endif // ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-
bool FormatSinkImpl::PutPaddedString(string_view value, int width,
int precision, bool left) {
size_t space_remaining = 0;
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 694c126..fc4dc4f 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -16,11 +16,13 @@
#include "absl/strings/internal/str_format/extension.h"
+#include <cstddef>
#include <random>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/random/random.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
@@ -44,8 +46,7 @@
namespace {
std::string MakeRandomString(size_t len) {
- std::random_device rd;
- std::mt19937 gen(rd());
+ absl::InsecureBitGen gen;
std::uniform_int_distribution<> dis('a', 'z');
std::string s(len, '0');
for (char& c : s) {
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index 8edf520..aa31998 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -17,6 +17,7 @@
#include <string.h>
#include <algorithm>
+#include <array>
#include <cassert>
#include <cmath>
#include <limits>
@@ -159,7 +160,7 @@
// See the current block of digits.
absl::string_view CurrentDigits() const {
- return absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+ return absl::string_view(&digits_[kDigitsPerChunk - size_], size_);
}
// Advance the current view of digits.
@@ -234,7 +235,7 @@
size_t decimal_start_;
size_t decimal_end_;
- char digits_[kDigitsPerChunk];
+ std::array<char, kDigitsPerChunk> digits_;
size_t size_ = 0;
absl::Span<uint32_t> data_;
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc
index c4b2470..068091c 100644
--- a/absl/strings/internal/str_format/output.cc
+++ b/absl/strings/internal/str_format/output.cc
@@ -33,9 +33,11 @@
void BufferRawSink::Write(string_view v) {
size_t to_write = std::min(v.size(), size_);
- std::memcpy(buffer_, v.data(), to_write);
- buffer_ += to_write;
- size_ -= to_write;
+ if (to_write > 0) {
+ std::memcpy(buffer_, v.data(), to_write);
+ buffer_ += to_write;
+ size_ -= to_write;
+ }
total_written_ += v.size();
}
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h
index b1d6d5f..329b060 100644
--- a/absl/strings/internal/str_format/parser.h
+++ b/absl/strings/internal/str_format/parser.h
@@ -132,8 +132,10 @@
has_error_ = other.has_error_;
items_ = other.items_;
size_t text_size = items_.empty() ? 0 : items_.back().text_end;
- data_.reset(new char[text_size]);
- memcpy(data_.get(), other.data_.get(), text_size);
+ data_ = std::make_unique<char[]>(text_size);
+ if (text_size > 0) {
+ memcpy(data_.get(), other.data_.get(), text_size);
+ }
return *this;
}
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 3e730c7..31fcf6d 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -43,6 +43,7 @@
#include <utility>
#include "absl/base/config.h"
+#include "absl/base/internal/iterator_traits.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/internal/ostringstream.h"
#include "absl/strings/internal/resize_uninitialized.h"
@@ -228,9 +229,8 @@
// range will be traversed twice: once to calculate the total needed size, and
// then again to copy the elements and delimiters to the output string.
template <typename Iterator,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<Iterator>::iterator_category,
- std::forward_iterator_tag>::value>::type>
+ typename = std::enable_if_t<
+ base_internal::IsAtLeastForwardIterator<Iterator>::value>>
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
NoFormatter) {
std::string result;
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index 11ea96f..ed1f117 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -253,6 +253,10 @@
(std::is_same<First, absl::string_view>::value ||
std::is_same<Second, absl::string_view>::value)>;
+template <typename StringType, typename ElementType, std::size_t Size>
+using ShouldUseLifetimeBoundForArray = std::integral_constant<
+ bool, std::is_same<StringType, std::string>::value &&
+ std::is_same<ElementType, absl::string_view>::value>;
// This class implements the range that is returned by absl::StrSplit(). This
// class has templated conversion operators that allow it to be implicitly
@@ -344,7 +348,38 @@
return ConvertToPair<First, Second>();
}
+ // Returns an array with its elements set to the first few strings returned by
+ // the begin() iterator. If there is not a corresponding value the empty
+ // string is used.
+ template <typename ElementType, std::size_t Size,
+ std::enable_if_t<ShouldUseLifetimeBoundForArray<
+ StringType, ElementType, Size>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::array<ElementType, Size>() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
+ return ConvertToArray<ElementType, Size>();
+ }
+
+ template <typename ElementType, std::size_t Size,
+ std::enable_if_t<!ShouldUseLifetimeBoundForArray<
+ StringType, ElementType, Size>::value,
+ std::nullptr_t> = nullptr>
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator std::array<ElementType, Size>() const {
+ return ConvertToArray<ElementType, Size>();
+ }
+
private:
+ template <typename ElementType, std::size_t Size>
+ std::array<ElementType, Size> ConvertToArray() const {
+ std::array<ElementType, Size> a;
+ auto it = begin();
+ for (std::size_t i = 0; i < Size && it != end(); ++i, ++it) {
+ a[i] = ElementType(*it);
+ }
+ return a;
+ }
+
template <typename First, typename Second>
std::pair<First, Second> ConvertToPair() const {
absl::string_view first, second;
diff --git a/absl/strings/internal/string_constant.h b/absl/strings/internal/string_constant.h
index f68b17d..d52c330 100644
--- a/absl/strings/internal/string_constant.h
+++ b/absl/strings/internal/string_constant.h
@@ -50,11 +50,6 @@
"The input string_view must point to constant data.");
};
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-template <typename T>
-constexpr absl::string_view StringConstant<T>::value;
-#endif
-
// Factory function for `StringConstant` instances.
// It supports callables that have a constexpr default constructor and a
// constexpr operator().
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc
index 7ecb93d..61945f5 100644
--- a/absl/strings/internal/utf8.cc
+++ b/absl/strings/internal/utf8.cc
@@ -16,11 +16,17 @@
#include "absl/strings/internal/utf8.h"
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+
+#include "absl/base/config.h"
+
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace strings_internal {
-size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
+size_t EncodeUTF8Char(char* buffer, char32_t utf8_char) {
if (utf8_char <= 0x7F) {
*buffer = static_cast<char>(utf8_char);
return 1;
@@ -48,6 +54,95 @@
}
}
+size_t WideToUtf8(wchar_t wc, char* buf, ShiftState& s) {
+ // Reinterpret the output buffer `buf` as `unsigned char*` for subsequent
+ // bitwise operations. This ensures well-defined behavior for bit
+ // manipulations (avoiding issues with signed `char`) and is safe under C++
+ // aliasing rules, as `unsigned char` can alias any type.
+ auto* ubuf = reinterpret_cast<unsigned char*>(buf);
+ const uint32_t v = static_cast<uint32_t>(wc);
+ constexpr size_t kError = static_cast<size_t>(-1);
+
+ if (v <= 0x007F) {
+ // 1-byte sequence (U+0000 to U+007F).
+ // 0xxxxxxx.
+ ubuf[0] = (0b0111'1111 & v);
+ s = {}; // Reset surrogate state.
+ return 1;
+ } else if (0x0080 <= v && v <= 0x07FF) {
+ // 2-byte sequence (U+0080 to U+07FF).
+ // 110xxxxx 10xxxxxx.
+ ubuf[0] = 0b1100'0000 | (0b0001'1111 & (v >> 6));
+ ubuf[1] = 0b1000'0000 | (0b0011'1111 & v);
+ s = {}; // Reset surrogate state.
+ return 2;
+ } else if ((0x0800 <= v && v <= 0xD7FF) || (0xE000 <= v && v <= 0xFFFF)) {
+ // 3-byte sequence (U+0800 to U+D7FF or U+E000 to U+FFFF).
+ // Excludes surrogate code points U+D800-U+DFFF.
+ // 1110xxxx 10xxxxxx 10xxxxxx.
+ ubuf[0] = 0b1110'0000 | (0b0000'1111 & (v >> 12));
+ ubuf[1] = 0b1000'0000 | (0b0011'1111 & (v >> 6));
+ ubuf[2] = 0b1000'0000 | (0b0011'1111 & v);
+ s = {}; // Reset surrogate state.
+ return 3;
+ } else if (0xD800 <= v && v <= 0xDBFF) {
+ // High Surrogate (U+D800 to U+DBFF).
+ // This part forms the first two bytes of an eventual 4-byte UTF-8 sequence.
+ const unsigned char high_bits_val = (0b0000'1111 & (v >> 6)) + 1;
+
+ // First byte of the 4-byte UTF-8 sequence (11110xxx).
+ ubuf[0] = 0b1111'0000 | (0b0000'0111 & (high_bits_val >> 2));
+ // Second byte of the 4-byte UTF-8 sequence (10xxxxxx).
+ ubuf[1] = 0b1000'0000 | //
+ (0b0011'0000 & (high_bits_val << 4)) | //
+ (0b0000'1111 & (v >> 2));
+ // Set state for high surrogate after writing to buffer.
+ s = {true, static_cast<unsigned char>(0b0000'0011 & v)};
+ return 2; // Wrote 2 bytes, expecting 2 more from a low surrogate.
+ } else if (0xDC00 <= v && v <= 0xDFFF) {
+ // Low Surrogate (U+DC00 to U+DFFF).
+ // This part forms the last two bytes of a 4-byte UTF-8 sequence,
+ // using state from a preceding high surrogate.
+ if (!s.saw_high_surrogate) {
+ // Error: Isolated low surrogate without a preceding high surrogate.
+ // s remains in its current (problematic) state.
+ // Caller should handle error.
+ return kError;
+ }
+
+ // Third byte of the 4-byte UTF-8 sequence (10xxxxxx).
+ ubuf[0] = 0b1000'0000 | //
+ (0b0011'0000 & (s.bits << 4)) | //
+ (0b0000'1111 & (v >> 6));
+ // Fourth byte of the 4-byte UTF-8 sequence (10xxxxxx).
+ ubuf[1] = 0b1000'0000 | (0b0011'1111 & v);
+
+ s = {}; // Reset surrogate state, pair complete.
+ return 2; // Wrote 2 more bytes, completing the 4-byte sequence.
+ } else if constexpr (0xFFFF < std::numeric_limits<wchar_t>::max()) {
+ // Conditionally compile the 4-byte direct conversion branch.
+ // This block is compiled only if wchar_t can represent values > 0xFFFF.
+ // It's placed after surrogate checks to ensure surrogates are handled by
+ // their specific logic. This inner 'if' is the runtime check for the 4-byte
+ // range. At this point, v is known not to be in the 1, 2, or 3-byte BMP
+ // ranges, nor is it a surrogate code point.
+ if (0x10000 <= v && v <= 0x10FFFF) {
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx.
+ ubuf[0] = 0b1111'0000 | (0b0000'0111 & (v >> 18));
+ ubuf[1] = 0b1000'0000 | (0b0011'1111 & (v >> 12));
+ ubuf[2] = 0b1000'0000 | (0b0011'1111 & (v >> 6));
+ ubuf[3] = 0b1000'0000 | (0b0011'1111 & v);
+ s = {}; // Reset surrogate state.
+ return 4;
+ }
+ }
+
+ // Invalid wchar_t value (e.g., out of Unicode range, or unhandled after all
+ // checks).
+ s = {}; // Reset surrogate state.
+ return kError;
+}
+
} // namespace strings_internal
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h
index 32fb109..ed1db11 100644
--- a/absl/strings/internal/utf8.h
+++ b/absl/strings/internal/utf8.h
@@ -41,7 +41,21 @@
// characters into buffer, however never will more than kMaxEncodedUTF8Size
// bytes be written, regardless of the value of utf8_char.
enum { kMaxEncodedUTF8Size = 4 };
-size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
+size_t EncodeUTF8Char(char* buffer, char32_t utf8_char);
+
+struct ShiftState {
+ bool saw_high_surrogate = false;
+ unsigned char bits = 0;
+};
+
+// Converts `wc` from UTF-16 or UTF-32 to UTF-8 and writes to `buf`. `buf` is
+// assumed to have enough space for the output. `s` is used to carry state
+// between successive calls with a UTF-16 surrogate pair. Returns the number of
+// chars written, or `static_cast<size_t>(-1)` on failure.
+//
+// This is basically std::wcrtomb(), but always outputting UTF-8 instead of
+// respecting the current locale.
+size_t WideToUtf8(wchar_t wc, char* buf, ShiftState& s);
} // namespace strings_internal
ABSL_NAMESPACE_END
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc
index 88dd503..b88d7bb 100644
--- a/absl/strings/internal/utf8_test.cc
+++ b/absl/strings/internal/utf8_test.cc
@@ -14,14 +14,29 @@
#include "absl/strings/internal/utf8.h"
+#include <cstddef>
#include <cstdint>
+#include <cstring>
+#include <string>
+#include <type_traits>
#include <utility>
+#include <vector>
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/port.h"
+#include "absl/strings/string_view.h"
namespace {
+using ::absl::strings_internal::kMaxEncodedUTF8Size;
+using ::absl::strings_internal::ShiftState;
+using ::absl::strings_internal::WideToUtf8;
+using ::testing::StartsWith;
+using ::testing::TestParamInfo;
+using ::testing::TestWithParam;
+using ::testing::ValuesIn;
+
#if !defined(__cpp_char8_t)
#if defined(__clang__)
#pragma clang diagnostic push
@@ -33,12 +48,12 @@
{0x00010000, u8"\U00010000"},
{0x0000FFFF, u8"\U0000FFFF"},
{0x0010FFFD, u8"\U0010FFFD"}};
- for (auto &test : tests) {
+ for (auto& test : tests) {
char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
- char *buf0_written =
+ char* buf0_written =
&buf0[absl::strings_internal::EncodeUTF8Char(buf0, test.first)];
- char *buf1_written =
+ char* buf1_written =
&buf1[absl::strings_internal::EncodeUTF8Char(buf1, test.first)];
int apparent_length = 7;
while (buf0[apparent_length - 1] == '\x00' &&
@@ -63,4 +78,182 @@
#endif
#endif // !defined(__cpp_char8_t)
+struct WideToUtf8TestCase {
+ std::string description;
+ wchar_t input;
+ std::string expected_utf8_str;
+ size_t expected_bytes_written;
+ ShiftState initial_state = {false, 0};
+ ShiftState expected_state = {false, 0};
+};
+
+std::vector<WideToUtf8TestCase> GetWideToUtf8TestCases() {
+ constexpr size_t kError = static_cast<size_t>(-1);
+ std::vector<WideToUtf8TestCase> cases = {
+ {"ASCII_A", L'A', "A", 1},
+ {"NullChar", L'\0', std::string("\0", 1), 1},
+ {"ASCII_Max_7F", L'\x7F', "\x7F", 1},
+
+ {"TwoByte_Min_80", L'\u0080', "\xC2\x80", 2},
+ {"PoundSign_A3", L'\u00A3', "\xC2\xA3", 2},
+ {"TwoByte_Max_7FF", L'\u07FF', "\xDF\xBF", 2},
+
+ {"ThreeByte_Min_800", L'\u0800', "\xE0\xA0\x80", 3},
+ {"EuroSign_20AC", L'\u20AC', "\xE2\x82\xAC", 3},
+ {"BMP_MaxBeforeSurrogates_D7FF", L'\uD7FF', "\xED\x9F\xBF", 3},
+ {"BMP_FFFF", L'\uFFFF', "\xEF\xBF\xBF", 3},
+
+ {"IsolatedHighSurr_D800", L'\xD800', "\xF0\x90", 2, {}, {true, 0}},
+ {"IsolatedHighSurr_DBFF", L'\xDBFF', "\xF4\x8F", 2, {}, {true, 3}},
+
+ {"HighSurr_D800_after_HighD800",
+ L'\xD800',
+ "\xF0\x90",
+ 2,
+ {true, 0},
+ {true, 0}},
+ {"HighSurr_DBFF_after_HighDBFF",
+ L'\xDBFF',
+ "\xF4\x8F",
+ 2,
+ {true, 3},
+ {true, 3}},
+
+ {"LowSurr_DC00_after_HighD800", L'\xDC00', "\x80\x80", 2, {true, 0}, {}},
+ {"LowSurr_DFFD_after_HighDBFF", L'\xDFFD', "\xBF\xBD", 2, {true, 3}, {}},
+ {"LowSurr_DC00_with_InitialState_saw_high_bits_1",
+ L'\xDC00',
+ "\x90\x80",
+ 2,
+ {true, 1},
+ {}},
+
+ // Final state = initial on error.
+ {"Error_IsolatedLowSurr_DC00_NoPriorHigh", L'\xDC00', "", kError, {}, {}},
+ {"Error_IsolatedLowSurr_DFFF_NoPriorHigh", L'\xDFFF', "", kError, {}, {}},
+
+#if (defined(WCHAR_MAX) && WCHAR_MAX > 0xFFFF)
+ {"DirectSupplementaryChars_U10000", static_cast<wchar_t>(0x10000),
+ "\xF0\x90\x80\x80", 4},
+ {"DirectSupplementaryChars_U10FFFD", static_cast<wchar_t>(0x10FFFD),
+ "\xF4\x8F\xBF\xBD", 4},
+#endif
+ };
+
+ wchar_t minus_one = static_cast<wchar_t>(-1);
+ if constexpr (sizeof(wchar_t) == 2) {
+ cases.push_back({"WChar_MinusOne_as_FFFF", minus_one, "\xEF\xBF\xBF", 3});
+ } else {
+ cases.push_back(
+ {"Error_WChar_MinusOne_as_FFFFFFFF", minus_one, "", kError, {}, {}});
+ }
+
+ if constexpr (sizeof(wchar_t) >= 4) {
+#ifdef WCHAR_MAX
+ if (static_cast<uintmax_t>(WCHAR_MAX) >= 0x110000UL) {
+ cases.push_back({"Error_OutOfRange_110000",
+ static_cast<wchar_t>(0x110000UL),
+ "",
+ kError,
+ {},
+ {}});
+ }
+#else
+ cases.push_back({"Error_OutOfRange_110000_fallback",
+ static_cast<wchar_t>(0x110000UL),
+ "",
+ kError,
+ {},
+ {}});
+#endif
+ }
+ return cases;
+}
+
+class WideToUtf8ParamTest : public TestWithParam<WideToUtf8TestCase> {};
+
+TEST_P(WideToUtf8ParamTest, SingleCharConversion) {
+ const auto& test_case = GetParam();
+ ShiftState state = test_case.initial_state;
+ constexpr char kFillChar = '\xAB';
+ std::string buffer(32, kFillChar);
+
+ size_t bytes_written = WideToUtf8(test_case.input, buffer.data(), state);
+
+ EXPECT_EQ(bytes_written, test_case.expected_bytes_written);
+ EXPECT_THAT(buffer, StartsWith(test_case.expected_utf8_str));
+
+ // The remaining bytes should be unchanged.
+ ASSERT_LT(test_case.expected_utf8_str.length(), buffer.size());
+ EXPECT_EQ(buffer[test_case.expected_utf8_str.length()], kFillChar);
+
+ EXPECT_EQ(state.saw_high_surrogate,
+ test_case.expected_state.saw_high_surrogate);
+ EXPECT_EQ(state.bits, test_case.expected_state.bits);
+}
+
+INSTANTIATE_TEST_SUITE_P(WideCharToUtf8Conversion, WideToUtf8ParamTest,
+ ValuesIn(GetWideToUtf8TestCases()),
+ [](auto info) { return info.param.description; });
+
+// Comprehensive test string for validating wchar_t to UTF-8 conversion.
+// This string is designed to cover a variety of Unicode character types and
+// sequences:
+// 1. Basic ASCII characters (within names, numbers, and spacing).
+// 2. Common 2-byte UTF-8 sequences:
+// - Accented Latin characters (e.g., 'á' in "Holá").
+// - Hebrew text with combining vowel points (e.g., "שָׁלוֹם").
+// 3. Common 3-byte UTF-8 sequences:
+// - Currency symbols (e.g., '€').
+// - CJK characters (e.g., "你好", "中").
+// - Components of complex emojis like the Zero Width Joiner (ZWJ) and
+// Heart symbol.
+// 4. Various 4-byte UTF-8 sequences (representing Supplementary Plane
+// characters):
+// - An emoji with a skin tone modifier ("👍🏻").
+// - A flag emoji composed of regional indicators ("🇺🇸").
+// - A complex ZWJ emoji sequence ("👩❤️💋👨") combining
+// SP characters (👩, 💋, 👨) with BMP characters (ZWJ and ❤️).
+// - These are critical for testing the correct handling of surrogate pairs
+// when wchar_t is 2 bytes (e.g., on Windows).
+// The goal is to ensure accurate conversion across a diverse set of
+// characters.
+//
+// clang-format off
+#define WIDE_STRING_LITERAL L"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
+#define UTF8_STRING_LITERAL u8"Holá €1 你好 שָׁלוֹם 👍🏻🇺🇸👩❤️💋👨 中"
+// clang-format on
+
+absl::string_view GetUtf8TestString() {
+ // `u8""` forces UTF-8 encoding; MSVC will default to e.g. CP1252 (and warn)
+ // without it. However, the resulting character type differs between pre-C++20
+ // (`char`) and C++20 (`char8_t`). So deduce the right character type for all
+ // C++ versions, init it with UTF-8, then `memcpy()` to get the result as a
+ // `char*`
+ static absl::string_view kUtf8TestString = [] {
+ using ConstChar8T = std::remove_reference_t<decltype(*u8"a")>;
+ constexpr ConstChar8T kOutputUtf8[] = UTF8_STRING_LITERAL;
+ static char output[sizeof kOutputUtf8];
+ std::memcpy(output, kOutputUtf8, sizeof kOutputUtf8);
+ return output;
+ }();
+
+ return kUtf8TestString;
+}
+
+TEST(WideToUtf8, FullString) {
+ std::string buffer(kMaxEncodedUTF8Size * sizeof(WIDE_STRING_LITERAL), '\0');
+ char* buffer_ptr = buffer.data();
+
+ ShiftState state;
+ for (const wchar_t wc : WIDE_STRING_LITERAL) {
+ buffer_ptr += WideToUtf8(wc, buffer_ptr, state);
+ }
+
+ EXPECT_THAT(buffer, StartsWith(GetUtf8TestString()));
+}
+
+#undef WIDE_STRING_LITERAL
+#undef UTF8_STRING_LITERAL
+
} // namespace
diff --git a/absl/strings/match.h b/absl/strings/match.h
index 1eeafbb..ce4fe78 100644
--- a/absl/strings/match.h
+++ b/absl/strings/match.h
@@ -55,22 +55,32 @@
// StartsWith()
//
// Returns whether a given string `text` begins with `prefix`.
-inline bool StartsWith(absl::string_view text,
- absl::string_view prefix) noexcept {
- return prefix.empty() ||
- (text.size() >= prefix.size() &&
- memcmp(text.data(), prefix.data(), prefix.size()) == 0);
+inline constexpr bool StartsWith(absl::string_view text,
+ absl::string_view prefix) noexcept {
+ if (prefix.empty()) {
+ return true;
+ }
+ if (text.size() < prefix.size()) {
+ return false;
+ }
+ absl::string_view possible_match = text.substr(0, prefix.size());
+
+ return possible_match == prefix;
}
// EndsWith()
//
// Returns whether a given string `text` ends with `suffix`.
-inline bool EndsWith(absl::string_view text,
- absl::string_view suffix) noexcept {
- return suffix.empty() ||
- (text.size() >= suffix.size() &&
- memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
- suffix.size()) == 0);
+inline constexpr bool EndsWith(absl::string_view text,
+ absl::string_view suffix) noexcept {
+ if (suffix.empty()) {
+ return true;
+ }
+ if (text.size() < suffix.size()) {
+ return false;
+ }
+ absl::string_view possible_match = text.substr(text.size() - suffix.size());
+ return possible_match == suffix;
}
// StrContainsIgnoreCase()
//
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index b57d9e8..a83fd2c 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -18,6 +18,7 @@
#include "absl/strings/numbers.h"
#include <algorithm>
+#include <array>
#include <cassert>
#include <cfloat> // for DBL_DIG and FLT_DIG
#include <cmath> // for HUGE_VAL
@@ -46,7 +47,7 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
-bool SimpleAtof(absl::string_view str, absl::Nonnull<float*> out) {
+bool SimpleAtof(absl::string_view str, float* absl_nonnull out) {
*out = 0.0;
str = StripAsciiWhitespace(str);
// std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one
@@ -77,7 +78,7 @@
return true;
}
-bool SimpleAtod(absl::string_view str, absl::Nonnull<double*> out) {
+bool SimpleAtod(absl::string_view str, double* absl_nonnull out) {
*out = 0.0;
str = StripAsciiWhitespace(str);
// std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one
@@ -108,7 +109,7 @@
return true;
}
-bool SimpleAtob(absl::string_view str, absl::Nonnull<bool*> out) {
+bool SimpleAtob(absl::string_view str, bool* absl_nonnull out) {
ABSL_RAW_CHECK(out != nullptr, "Output pointer must not be nullptr.");
if (EqualsIgnoreCase(str, "true") || EqualsIgnoreCase(str, "t") ||
EqualsIgnoreCase(str, "yes") || EqualsIgnoreCase(str, "y") ||
@@ -167,7 +168,7 @@
constexpr uint64_t kDivisionBy100Div = 1 << 20;
// Encode functions write the ASCII output of input `n` to `out_str`.
-inline char* EncodeHundred(uint32_t n, absl::Nonnull<char*> out_str) {
+inline char* EncodeHundred(uint32_t n, char* absl_nonnull out_str) {
int num_digits = static_cast<int>(n - 10) >> 8;
uint32_t div10 = (n * kDivisionBy10Mul) / kDivisionBy10Div;
uint32_t mod10 = n - 10u * div10;
@@ -177,7 +178,7 @@
return out_str + 2 + num_digits;
}
-inline char* EncodeTenThousand(uint32_t n, absl::Nonnull<char*> out_str) {
+inline char* EncodeTenThousand(uint32_t n, char* absl_nonnull out_str) {
// We split lower 2 digits and upper 2 digits of n into 2 byte consecutive
// blocks. 123 -> [\0\1][\0\23]. We divide by 10 both blocks
// (it's 1 division + zeroing upper bits), and compute modulo 10 as well "in
@@ -233,8 +234,8 @@
return tens;
}
-inline ABSL_ATTRIBUTE_ALWAYS_INLINE absl::Nonnull<char*> EncodeFullU32(
- uint32_t n, absl::Nonnull<char*> out_str) {
+inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* absl_nonnull EncodeFullU32(
+ uint32_t n, char* absl_nonnull out_str) {
if (n < 10) {
*out_str = static_cast<char>('0' + n);
return out_str + 1;
@@ -283,7 +284,7 @@
} // namespace
-void numbers_internal::PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf) {
+void numbers_internal::PutTwoDigits(uint32_t i, char* absl_nonnull buf) {
assert(i < 100);
uint32_t base = kTwoZeroBytes;
uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div;
@@ -292,15 +293,15 @@
little_endian::Store16(buf, static_cast<uint16_t>(base));
}
-absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
- uint32_t n, absl::Nonnull<char*> out_str) {
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+ uint32_t n, char* absl_nonnull out_str) {
out_str = EncodeFullU32(n, out_str);
*out_str = '\0';
return out_str;
}
-absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
- int32_t i, absl::Nonnull<char*> buffer) {
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+ int32_t i, char* absl_nonnull buffer) {
uint32_t u = static_cast<uint32_t>(i);
if (i < 0) {
*buffer++ = '-';
@@ -314,15 +315,15 @@
return buffer;
}
-absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
- uint64_t i, absl::Nonnull<char*> buffer) {
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+ uint64_t i, char* absl_nonnull buffer) {
buffer = EncodeFullU64(i, buffer);
*buffer = '\0';
return buffer;
}
-absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
- int64_t i, absl::Nonnull<char*> buffer) {
+char* absl_nonnull numbers_internal::FastIntToBuffer(
+ int64_t i, char* absl_nonnull buffer) {
uint64_t u = static_cast<uint64_t>(i);
if (i < 0) {
*buffer++ = '-';
@@ -463,7 +464,7 @@
// Since we'd like to know if the fractional part of d is close to a half,
// we multiply it by 65536 and see if the fractional part is close to 32768.
// (The number doesn't have to be a power of two,but powers of two are faster)
- uint64_t d64k = d * 65536;
+ uint64_t d64k = static_cast<uint64_t>(d * 65536);
uint32_t dddddd; // A 6-digit decimal integer.
if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) {
// OK, it's fairly likely that precision was lost above, which is
@@ -477,7 +478,8 @@
// value we're representing, of course, is M.mmm... * 2^exp2.
int exp2;
double m = std::frexp(value, &exp2);
- uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0);
+ uint64_t mantissa =
+ static_cast<uint64_t>(m * (32768.0 * 65536.0 * 65536.0 * 65536.0));
// std::frexp returns an m value in the range [0.5, 1.0), however we
// can't multiply it by 2^64 and convert to an integer because some FPUs
// throw an exception when converting an number higher than 2^63 into an
@@ -544,7 +546,7 @@
// Helper function for fast formatting of floating-point.
// The result is the same as "%g", a.k.a. "%.6g".
size_t numbers_internal::SixDigitsToBuffer(double d,
- absl::Nonnull<char*> const buffer) {
+ char* absl_nonnull const buffer) {
static_assert(std::numeric_limits<float>::is_iec559,
"IEEE-754/IEC-559 support only");
@@ -674,7 +676,7 @@
// Represents integer values of digits.
// Uses 36 to indicate an invalid character since we support
// bases up to 36.
-static const int8_t kAsciiToInt[256] = {
+static constexpr std::array<int8_t, 256> kAsciiToInt = {
36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s.
36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5,
@@ -692,9 +694,9 @@
// Parse the sign and optional hex or oct prefix in text.
inline bool safe_parse_sign_and_base(
- absl::Nonnull<absl::string_view*> text /*inout*/,
- absl::Nonnull<int*> base_ptr /*inout*/,
- absl::Nonnull<bool*> negative_ptr /*output*/) {
+ absl::string_view* absl_nonnull text /*inout*/,
+ int* absl_nonnull base_ptr /*inout*/,
+ bool* absl_nonnull negative_ptr /*output*/) {
if (text->data() == nullptr) {
return false;
}
@@ -979,7 +981,7 @@
template <typename IntType>
inline bool safe_parse_positive_int(absl::string_view text, int base,
- absl::Nonnull<IntType*> value_p) {
+ IntType* absl_nonnull value_p) {
IntType value = 0;
const IntType vmax = std::numeric_limits<IntType>::max();
assert(vmax > 0);
@@ -1016,7 +1018,7 @@
template <typename IntType>
inline bool safe_parse_negative_int(absl::string_view text, int base,
- absl::Nonnull<IntType*> value_p) {
+ IntType* absl_nonnull value_p) {
IntType value = 0;
const IntType vmin = std::numeric_limits<IntType>::min();
assert(vmin < 0);
@@ -1061,7 +1063,7 @@
// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html
template <typename IntType>
inline bool safe_int_internal(absl::string_view text,
- absl::Nonnull<IntType*> value_p, int base) {
+ IntType* absl_nonnull value_p, int base) {
*value_p = 0;
bool negative;
if (!safe_parse_sign_and_base(&text, &base, &negative)) {
@@ -1076,7 +1078,7 @@
template <typename IntType>
inline bool safe_uint_internal(absl::string_view text,
- absl::Nonnull<IntType*> value_p, int base) {
+ IntType* absl_nonnull value_p, int base) {
*value_p = 0;
bool negative;
if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) {
@@ -1110,32 +1112,52 @@
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
-bool safe_strto32_base(absl::string_view text, absl::Nonnull<int32_t*> value,
+bool safe_strto8_base(absl::string_view text, int8_t* absl_nonnull value,
+ int base) {
+ return safe_int_internal<int8_t>(text, value, base);
+}
+
+bool safe_strto16_base(absl::string_view text, int16_t* absl_nonnull value,
+ int base) {
+ return safe_int_internal<int16_t>(text, value, base);
+}
+
+bool safe_strto32_base(absl::string_view text, int32_t* absl_nonnull value,
int base) {
return safe_int_internal<int32_t>(text, value, base);
}
-bool safe_strto64_base(absl::string_view text, absl::Nonnull<int64_t*> value,
+bool safe_strto64_base(absl::string_view text, int64_t* absl_nonnull value,
int base) {
return safe_int_internal<int64_t>(text, value, base);
}
-bool safe_strto128_base(absl::string_view text, absl::Nonnull<int128*> value,
+bool safe_strto128_base(absl::string_view text, int128* absl_nonnull value,
int base) {
return safe_int_internal<absl::int128>(text, value, base);
}
-bool safe_strtou32_base(absl::string_view text, absl::Nonnull<uint32_t*> value,
+bool safe_strtou8_base(absl::string_view text, uint8_t* absl_nonnull value,
+ int base) {
+ return safe_uint_internal<uint8_t>(text, value, base);
+}
+
+bool safe_strtou16_base(absl::string_view text, uint16_t* absl_nonnull value,
+ int base) {
+ return safe_uint_internal<uint16_t>(text, value, base);
+}
+
+bool safe_strtou32_base(absl::string_view text, uint32_t* absl_nonnull value,
int base) {
return safe_uint_internal<uint32_t>(text, value, base);
}
-bool safe_strtou64_base(absl::string_view text, absl::Nonnull<uint64_t*> value,
+bool safe_strtou64_base(absl::string_view text, uint64_t* absl_nonnull value,
int base) {
return safe_uint_internal<uint64_t>(text, value, base);
}
-bool safe_strtou128_base(absl::string_view text, absl::Nonnull<uint128*> value,
+bool safe_strtou128_base(absl::string_view text, uint128* absl_nonnull value,
int base) {
return safe_uint_internal<absl::uint128>(text, value, base);
}
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index 739dbb2..9c67974 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -32,6 +32,7 @@
#endif
#include <cstddef>
+#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <ctime>
@@ -39,6 +40,7 @@
#include <string>
#include <type_traits>
+#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/endian.h"
#include "absl/base/macros.h"
@@ -60,8 +62,8 @@
// encountered, this function returns `false`, leaving `out` in an unspecified
// state.
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str,
- absl::Nonnull<int_type*> out);
+[[nodiscard]] bool SimpleAtoi(absl::string_view str,
+ int_type* absl_nonnull out);
// SimpleAtof()
//
@@ -72,8 +74,7 @@
// allowed formats for `str`, except SimpleAtof() is locale-independent and will
// always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state.
-ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str,
- absl::Nonnull<float*> out);
+[[nodiscard]] bool SimpleAtof(absl::string_view str, float* absl_nonnull out);
// SimpleAtod()
//
@@ -84,8 +85,7 @@
// allowed formats for `str`, except SimpleAtod is locale-independent and will
// always use the "C" locale. If any errors are encountered, this function
// returns `false`, leaving `out` in an unspecified state.
-ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str,
- absl::Nonnull<double*> out);
+[[nodiscard]] bool SimpleAtod(absl::string_view str, double* absl_nonnull out);
// SimpleAtob()
//
@@ -95,8 +95,7 @@
// are interpreted as boolean `false`: "false", "f", "no", "n", "0". If any
// errors are encountered, this function returns `false`, leaving `out` in an
// unspecified state.
-ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str,
- absl::Nonnull<bool*> out);
+[[nodiscard]] bool SimpleAtob(absl::string_view str, bool* absl_nonnull out);
// SimpleHexAtoi()
//
@@ -109,14 +108,14 @@
// by this function. If any errors are encountered, this function returns
// `false`, leaving `out` in an unspecified state.
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str,
- absl::Nonnull<int_type*> out);
+[[nodiscard]] bool SimpleHexAtoi(absl::string_view str,
+ int_type* absl_nonnull out);
// Overloads of SimpleHexAtoi() for 128 bit integers.
-ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(
- absl::string_view str, absl::Nonnull<absl::int128*> out);
-ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(
- absl::string_view str, absl::Nonnull<absl::uint128*> out);
+[[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str,
+ absl::int128* absl_nonnull out);
+[[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str,
+ absl::uint128* absl_nonnull out);
ABSL_NAMESPACE_END
} // namespace absl
@@ -127,6 +126,18 @@
ABSL_NAMESPACE_BEGIN
namespace numbers_internal {
+template <typename int_type>
+constexpr bool is_signed() {
+ if constexpr (std::is_arithmetic<int_type>::value) {
+ // Use std::numeric_limits<T>::is_signed where it's defined to work.
+ return std::numeric_limits<int_type>::is_signed;
+ }
+ // TODO(jorg): This signed-ness check is used because it works correctly
+ // with enums, and it also serves to check that int_type is not a pointer.
+ // If one day something like std::is_signed<enum E> works, switch to it.
+ return static_cast<int_type>(1) - 2 < 0;
+}
+
// Digit conversion.
ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef
ABSL_DLL extern const char
@@ -138,22 +149,30 @@
// PutTwoDigits(42, buf);
// // buf[0] == '4'
// // buf[1] == '2'
-void PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf);
+void PutTwoDigits(uint32_t i, char* absl_nonnull buf);
// safe_strto?() functions for implementing SimpleAtoi()
-bool safe_strto32_base(absl::string_view text, absl::Nonnull<int32_t*> value,
+bool safe_strto8_base(absl::string_view text, int8_t* absl_nonnull value,
+ int base);
+bool safe_strto16_base(absl::string_view text, int16_t* absl_nonnull value,
int base);
-bool safe_strto64_base(absl::string_view text, absl::Nonnull<int64_t*> value,
+bool safe_strto32_base(absl::string_view text, int32_t* absl_nonnull value,
+ int base);
+bool safe_strto64_base(absl::string_view text, int64_t* absl_nonnull value,
int base);
bool safe_strto128_base(absl::string_view text,
- absl::Nonnull<absl::int128*> value, int base);
-bool safe_strtou32_base(absl::string_view text, absl::Nonnull<uint32_t*> value,
+ absl::int128* absl_nonnull value, int base);
+bool safe_strtou8_base(absl::string_view text, uint8_t* absl_nonnull value,
+ int base);
+bool safe_strtou16_base(absl::string_view text, uint16_t* absl_nonnull value,
int base);
-bool safe_strtou64_base(absl::string_view text, absl::Nonnull<uint64_t*> value,
+bool safe_strtou32_base(absl::string_view text, uint32_t* absl_nonnull value,
+ int base);
+bool safe_strtou64_base(absl::string_view text, uint64_t* absl_nonnull value,
int base);
bool safe_strtou128_base(absl::string_view text,
- absl::Nonnull<absl::uint128*> value, int base);
+ absl::uint128* absl_nonnull value, int base);
static const int kFastToBufferSize = 32;
static const int kSixDigitsToBufferSize = 16;
@@ -164,33 +183,30 @@
// outside the range 0.0001-999999 are output using scientific notation
// (1.23456e+06). This routine is heavily optimized.
// Required buffer size is `kSixDigitsToBufferSize`.
-size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer);
+size_t SixDigitsToBuffer(double d, char* absl_nonnull buffer);
// WARNING: These functions may write more characters than necessary, because
// they are intended for speed. All functions take an output buffer
// as an argument and return a pointer to the last byte they wrote, which is the
// terminating '\0'. At most `kFastToBufferSize` bytes are written.
-absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer)
+char* absl_nonnull FastIntToBuffer(int32_t i, char* absl_nonnull buffer)
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
-absl::Nonnull<char*> FastIntToBuffer(uint32_t n, absl::Nonnull<char*> out_str)
+char* absl_nonnull FastIntToBuffer(uint32_t n, char* absl_nonnull out_str)
ABSL_INTERNAL_NEED_MIN_SIZE(out_str, kFastToBufferSize);
-absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer)
+char* absl_nonnull FastIntToBuffer(int64_t i, char* absl_nonnull buffer)
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
-absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer)
+char* absl_nonnull FastIntToBuffer(uint64_t i, char* absl_nonnull buffer)
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
// For enums and integer types that are not an exact match for the types above,
// use templates to call the appropriate one of the four overloads above.
template <typename int_type>
-absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer)
+char* absl_nonnull FastIntToBuffer(int_type i, char* absl_nonnull buffer)
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) {
static_assert(sizeof(i) <= 64 / 8,
"FastIntToBuffer works only with 64-bit-or-less integers.");
- // TODO(jorg): This signed-ness check is used because it works correctly
- // with enums, and it also serves to check that int_type is not a pointer.
- // If one day something like std::is_signed<enum E> works, switch to it.
// These conditions are constexpr bools to suppress MSVC warning C4127.
- constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0;
+ constexpr bool kIsSigned = is_signed<int_type>();
constexpr bool kUse64Bit = sizeof(i) > 32 / 8;
if (kIsSigned) {
if (kUse64Bit) {
@@ -210,39 +226,52 @@
// Implementation of SimpleAtoi, generalized to support arbitrary base (used
// with base different from 10 elsewhere in Abseil implementation).
template <typename int_type>
-ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s,
- absl::Nonnull<int_type*> out,
- int base) {
- static_assert(sizeof(*out) == 4 || sizeof(*out) == 8,
- "SimpleAtoi works only with 32-bit or 64-bit integers.");
+[[nodiscard]] bool safe_strtoi_base(absl::string_view s,
+ int_type* absl_nonnull out, int base) {
+ static_assert(sizeof(*out) == 1 || sizeof(*out) == 2 || sizeof(*out) == 4 ||
+ sizeof(*out) == 8,
+ "SimpleAtoi works only with 8, 16, 32, or 64-bit integers.");
static_assert(!std::is_floating_point<int_type>::value,
"Use SimpleAtof or SimpleAtod instead.");
bool parsed;
- // TODO(jorg): This signed-ness check is used because it works correctly
- // with enums, and it also serves to check that int_type is not a pointer.
- // If one day something like std::is_signed<enum E> works, switch to it.
// These conditions are constexpr bools to suppress MSVC warning C4127.
- constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0;
- constexpr bool kUse64Bit = sizeof(*out) == 64 / 8;
+ constexpr bool kIsSigned = is_signed<int_type>();
+ constexpr int kIntTypeSize = sizeof(*out) * 8;
if (kIsSigned) {
- if (kUse64Bit) {
+ if (kIntTypeSize == 64) {
int64_t val;
parsed = numbers_internal::safe_strto64_base(s, &val, base);
*out = static_cast<int_type>(val);
- } else {
+ } else if (kIntTypeSize == 32) {
int32_t val;
parsed = numbers_internal::safe_strto32_base(s, &val, base);
*out = static_cast<int_type>(val);
+ } else if (kIntTypeSize == 16) {
+ int16_t val;
+ parsed = numbers_internal::safe_strto16_base(s, &val, base);
+ *out = static_cast<int_type>(val);
+ } else if (kIntTypeSize == 8) {
+ int8_t val;
+ parsed = numbers_internal::safe_strto8_base(s, &val, base);
+ *out = static_cast<int_type>(val);
}
} else {
- if (kUse64Bit) {
+ if (kIntTypeSize == 64) {
uint64_t val;
parsed = numbers_internal::safe_strtou64_base(s, &val, base);
*out = static_cast<int_type>(val);
- } else {
+ } else if (kIntTypeSize == 32) {
uint32_t val;
parsed = numbers_internal::safe_strtou32_base(s, &val, base);
*out = static_cast<int_type>(val);
+ } else if (kIntTypeSize == 16) {
+ uint16_t val;
+ parsed = numbers_internal::safe_strtou16_base(s, &val, base);
+ *out = static_cast<int_type>(val);
+ } else if (kIntTypeSize == 8) {
+ uint8_t val;
+ parsed = numbers_internal::safe_strtou8_base(s, &val, base);
+ *out = static_cast<int_type>(val);
}
}
return parsed;
@@ -254,7 +283,7 @@
// without the terminating null character. Thus `out` must be of length >= 16.
// Returns the number of non-pad digits of the output (it can never be zero
// since 0 has one digit).
-inline size_t FastHexToBufferZeroPad16(uint64_t val, absl::Nonnull<char*> out) {
+inline size_t FastHexToBufferZeroPad16(uint64_t val, char* absl_nonnull out) {
#ifdef ABSL_INTERNAL_HAVE_SSSE3
uint64_t be = absl::big_endian::FromHost64(val);
const auto kNibbleMask = _mm_set1_epi8(0xf);
@@ -280,34 +309,34 @@
} // namespace numbers_internal
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str,
- absl::Nonnull<int_type*> out) {
+[[nodiscard]] bool SimpleAtoi(absl::string_view str,
+ int_type* absl_nonnull out) {
return numbers_internal::safe_strtoi_base(str, out, 10);
}
-ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
- absl::Nonnull<absl::int128*> out) {
+[[nodiscard]] inline bool SimpleAtoi(absl::string_view str,
+ absl::int128* absl_nonnull out) {
return numbers_internal::safe_strto128_base(str, out, 10);
}
-ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
- absl::Nonnull<absl::uint128*> out) {
+[[nodiscard]] inline bool SimpleAtoi(absl::string_view str,
+ absl::uint128* absl_nonnull out) {
return numbers_internal::safe_strtou128_base(str, out, 10);
}
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleHexAtoi(absl::string_view str,
- absl::Nonnull<int_type*> out) {
+[[nodiscard]] bool SimpleHexAtoi(absl::string_view str,
+ int_type* absl_nonnull out) {
return numbers_internal::safe_strtoi_base(str, out, 16);
}
-ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(
- absl::string_view str, absl::Nonnull<absl::int128*> out) {
+[[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str,
+ absl::int128* absl_nonnull out) {
return numbers_internal::safe_strto128_base(str, out, 16);
}
-ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(
- absl::string_view str, absl::Nonnull<absl::uint128*> out) {
+[[nodiscard]] inline bool SimpleHexAtoi(absl::string_view str,
+ absl::uint128* absl_nonnull out) {
return numbers_internal::safe_strtou128_base(str, out, 16);
}
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc
index e7cb60a..c58f861 100644
--- a/absl/strings/numbers_benchmark.cc
+++ b/absl/strings/numbers_benchmark.cc
@@ -19,12 +19,12 @@
#include <type_traits>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/random/distributions.h"
#include "absl/random/random.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 75c2dcf..1a82087 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -34,13 +34,13 @@
#include <random>
#include <set>
#include <string>
+#include <type_traits>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/log/log.h"
#include "absl/numeric/int128.h"
-#include "absl/random/distributions.h"
#include "absl/random/random.h"
#include "absl/strings/internal/numbers_test_common.h"
#include "absl/strings/internal/ostringstream.h"
@@ -53,10 +53,14 @@
using absl::SimpleAtoi;
using absl::SimpleHexAtoi;
using absl::numbers_internal::kSixDigitsToBufferSize;
+using absl::numbers_internal::safe_strto16_base;
using absl::numbers_internal::safe_strto32_base;
using absl::numbers_internal::safe_strto64_base;
+using absl::numbers_internal::safe_strto8_base;
+using absl::numbers_internal::safe_strtou16_base;
using absl::numbers_internal::safe_strtou32_base;
using absl::numbers_internal::safe_strtou64_base;
+using absl::numbers_internal::safe_strtou8_base;
using absl::numbers_internal::SixDigitsToBuffer;
using absl::strings_internal::Itoa;
using absl::strings_internal::strtouint32_test_cases;
@@ -256,9 +260,7 @@
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
- std::string s;
- // (u)int128 can be streamed but not StrCat'd.
- absl::strings_internal::OStringStream(&s) << in_value;
+ std::string s = absl::StrCat(in_value);
int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x))
<< "in_value=" << in_value << " s=" << s << " x=" << x;
@@ -270,15 +272,71 @@
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiBad(in_val_type in_value) {
- std::string s;
- // (u)int128 can be streamed but not StrCat'd.
- absl::strings_internal::OStringStream(&s) << in_value;
+ std::string s = absl::StrCat(in_value);
int_type x;
EXPECT_FALSE(SimpleAtoi(s, &x));
EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
}
TEST(NumbersTest, Atoi) {
+ // SimpleAtoi(absl::string_view, int8_t)
+ VerifySimpleAtoiGood<int8_t>(0, 0);
+ VerifySimpleAtoiGood<int8_t>(42, 42);
+ VerifySimpleAtoiGood<int8_t>(-42, -42);
+
+ VerifySimpleAtoiGood<int8_t>(std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::min());
+ VerifySimpleAtoiGood<int8_t>(std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int8_t>::max());
+
+ VerifySimpleAtoiBad<int8_t>(std::numeric_limits<uint8_t>::max());
+ VerifySimpleAtoiBad<int8_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleAtoiBad<int8_t>(std::numeric_limits<int16_t>::max());
+
+ // SimpleAtoi(absl::string_view, uint8_t)
+ VerifySimpleAtoiGood<uint8_t>(0, 0);
+ VerifySimpleAtoiGood<uint8_t>(42, 42);
+ VerifySimpleAtoiBad<uint8_t>(-42);
+
+ VerifySimpleAtoiBad<uint8_t>(std::numeric_limits<int8_t>::min());
+ VerifySimpleAtoiGood<uint8_t>(std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int8_t>::max());
+ VerifySimpleAtoiGood<uint8_t>(std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint8_t>::max());
+
+ VerifySimpleAtoiBad<uint8_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleAtoiBad<uint8_t>(std::numeric_limits<int16_t>::max());
+ VerifySimpleAtoiBad<uint8_t>(std::numeric_limits<uint16_t>::max());
+
+ // SimpleAtoi(absl::string_view, uint16_t)
+ VerifySimpleAtoiGood<int16_t>(0, 0);
+ VerifySimpleAtoiGood<int16_t>(42, 42);
+ VerifySimpleAtoiGood<int16_t>(-42, -42);
+
+ VerifySimpleAtoiGood<int16_t>(std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::min());
+ VerifySimpleAtoiGood<int16_t>(std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int16_t>::max());
+
+ VerifySimpleAtoiBad<int16_t>(std::numeric_limits<uint16_t>::max());
+ VerifySimpleAtoiBad<int16_t>(std::numeric_limits<int32_t>::min());
+ VerifySimpleAtoiBad<int16_t>(std::numeric_limits<int32_t>::max());
+
+ // SimpleAtoi(absl::string_view, uint16_t)
+ VerifySimpleAtoiGood<uint16_t>(0, 0);
+ VerifySimpleAtoiGood<uint16_t>(42, 42);
+ VerifySimpleAtoiBad<uint16_t>(-42);
+
+ VerifySimpleAtoiBad<uint16_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleAtoiGood<uint16_t>(std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int16_t>::max());
+ VerifySimpleAtoiGood<uint16_t>(std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint16_t>::max());
+
+ VerifySimpleAtoiBad<uint16_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleAtoiBad<uint16_t>(std::numeric_limits<int32_t>::max());
+ VerifySimpleAtoiBad<uint16_t>(std::numeric_limits<uint32_t>::max());
+
// SimpleAtoi(absl::string_view, int32_t)
VerifySimpleAtoiGood<int32_t>(0, 0);
VerifySimpleAtoiGood<int32_t>(42, 42);
@@ -381,6 +439,7 @@
VerifySimpleAtoiBad<absl::int128>(std::numeric_limits<absl::uint128>::max());
// Some other types
+ VerifySimpleAtoiGood<short>(-42, -42); // NOLINT: runtime-int
VerifySimpleAtoiGood<int>(-42, -42);
VerifySimpleAtoiGood<int32_t>(-42, -42);
VerifySimpleAtoiGood<uint32_t>(42, 42);
@@ -677,10 +736,14 @@
template <typename int_type, typename in_val_type>
void VerifySimpleHexAtoiGood(in_val_type in_value, int_type exp_value) {
std::string s;
- // uint128 can be streamed but not StrCat'd
absl::strings_internal::OStringStream strm(&s);
if (in_value >= 0) {
- strm << std::hex << in_value;
+ if constexpr (std::is_arithmetic<in_val_type>::value) {
+ absl::StrAppend(&s, absl::Hex(in_value));
+ } else {
+ // absl::Hex doesn't work with absl::(u)int128.
+ strm << std::hex << in_value;
+ }
} else {
// Inefficient for small integers, but works with all integral types.
strm << "-" << std::hex << -absl::uint128(in_value);
@@ -698,10 +761,14 @@
template <typename int_type, typename in_val_type>
void VerifySimpleHexAtoiBad(in_val_type in_value) {
std::string s;
- // uint128 can be streamed but not StrCat'd
absl::strings_internal::OStringStream strm(&s);
if (in_value >= 0) {
- strm << std::hex << in_value;
+ if constexpr (std::is_arithmetic<in_val_type>::value) {
+ absl::StrAppend(&s, absl::Hex(in_value));
+ } else {
+ // absl::Hex doesn't work with absl::(u)int128.
+ strm << std::hex << in_value;
+ }
} else {
// Inefficient for small integers, but works with all integral types.
strm << "-" << std::hex << -absl::uint128(in_value);
@@ -713,6 +780,54 @@
}
TEST(NumbersTest, HexAtoi) {
+ // SimpleHexAtoi(absl::string_view, int8_t)
+ VerifySimpleHexAtoiGood<int8_t>(0, 0);
+ VerifySimpleHexAtoiGood<int8_t>(0x42, 0x42);
+ VerifySimpleHexAtoiGood<int8_t>(-0x42, -0x42);
+
+ VerifySimpleHexAtoiGood<int8_t>(std::numeric_limits<int8_t>::min(),
+ std::numeric_limits<int8_t>::min());
+ VerifySimpleHexAtoiGood<int8_t>(std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int8_t>::max());
+
+ // SimpleHexAtoi(absl::string_view, uint8_t)
+ VerifySimpleHexAtoiGood<uint8_t>(0, 0);
+ VerifySimpleHexAtoiGood<uint8_t>(0x42, 0x42);
+ VerifySimpleHexAtoiBad<uint8_t>(-0x42);
+
+ VerifySimpleHexAtoiBad<uint8_t>(std::numeric_limits<int8_t>::min());
+ VerifySimpleHexAtoiGood<uint8_t>(std::numeric_limits<int8_t>::max(),
+ std::numeric_limits<int8_t>::max());
+ VerifySimpleHexAtoiGood<uint8_t>(std::numeric_limits<uint8_t>::max(),
+ std::numeric_limits<uint8_t>::max());
+ VerifySimpleHexAtoiBad<uint8_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleHexAtoiBad<uint8_t>(std::numeric_limits<int16_t>::max());
+ VerifySimpleHexAtoiBad<uint8_t>(std::numeric_limits<uint16_t>::max());
+
+ // SimpleHexAtoi(absl::string_view, int16_t)
+ VerifySimpleHexAtoiGood<int16_t>(0, 0);
+ VerifySimpleHexAtoiGood<int16_t>(0x42, 0x42);
+ VerifySimpleHexAtoiGood<int16_t>(-0x42, -0x42);
+
+ VerifySimpleHexAtoiGood<int16_t>(std::numeric_limits<int16_t>::min(),
+ std::numeric_limits<int16_t>::min());
+ VerifySimpleHexAtoiGood<int16_t>(std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int16_t>::max());
+
+ // SimpleHexAtoi(absl::string_view, uint16_t)
+ VerifySimpleHexAtoiGood<uint16_t>(0, 0);
+ VerifySimpleHexAtoiGood<uint16_t>(0x42, 0x42);
+ VerifySimpleHexAtoiBad<uint16_t>(-0x42);
+
+ VerifySimpleHexAtoiBad<uint16_t>(std::numeric_limits<int16_t>::min());
+ VerifySimpleHexAtoiGood<uint16_t>(std::numeric_limits<int16_t>::max(),
+ std::numeric_limits<int16_t>::max());
+ VerifySimpleHexAtoiGood<uint16_t>(std::numeric_limits<uint16_t>::max(),
+ std::numeric_limits<uint16_t>::max());
+ VerifySimpleHexAtoiBad<uint16_t>(std::numeric_limits<int32_t>::min());
+ VerifySimpleHexAtoiBad<uint16_t>(std::numeric_limits<int32_t>::max());
+ VerifySimpleHexAtoiBad<uint16_t>(std::numeric_limits<uint32_t>::max());
+
// SimpleHexAtoi(absl::string_view, int32_t)
VerifySimpleHexAtoiGood<int32_t>(0, 0);
VerifySimpleHexAtoiGood<int32_t>(0x42, 0x42);
@@ -790,6 +905,7 @@
std::numeric_limits<absl::uint128>::max());
// Some other types
+ VerifySimpleHexAtoiGood<short>(-0x42, -0x42); // NOLINT: runtime-int
VerifySimpleHexAtoiGood<int>(-0x42, -0x42);
VerifySimpleHexAtoiGood<int32_t>(-0x42, -0x42);
VerifySimpleHexAtoiGood<uint32_t>(0x42, 0x42);
@@ -816,6 +932,154 @@
EXPECT_EQ(0x34234324, value);
}
+TEST(stringtest, safe_strto8_base) {
+ int8_t value;
+ EXPECT_TRUE(safe_strto8_base("0x34", &value, 16));
+ EXPECT_EQ(0x34, value);
+
+ EXPECT_TRUE(safe_strto8_base("0X34", &value, 16));
+ EXPECT_EQ(0x34, value);
+
+ EXPECT_TRUE(safe_strto8_base("34", &value, 16));
+ EXPECT_EQ(0x34, value);
+
+ EXPECT_TRUE(safe_strto8_base("0", &value, 16));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto8_base(" \t\n -0x34", &value, 16));
+ EXPECT_EQ(-0x34, value);
+
+ EXPECT_TRUE(safe_strto8_base(" \t\n -34", &value, 16));
+ EXPECT_EQ(-0x34, value);
+
+ EXPECT_TRUE(safe_strto8_base("76", &value, 8));
+ EXPECT_EQ(076, value);
+
+ EXPECT_TRUE(safe_strto8_base("-0123", &value, 8));
+ EXPECT_EQ(-0123, value);
+
+ EXPECT_FALSE(safe_strto8_base("183", &value, 8));
+
+ // Autodetect base.
+ EXPECT_TRUE(safe_strto8_base("0", &value, 0));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto8_base("077", &value, 0));
+ EXPECT_EQ(077, value); // Octal interpretation
+
+ // Leading zero indicates octal, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto8_base("088", &value, 0));
+
+ // Leading 0x indicated hex, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto8_base("0xG", &value, 0));
+
+ // Base-10 version.
+ EXPECT_TRUE(safe_strto8_base("124", &value, 10));
+ EXPECT_EQ(124, value);
+
+ EXPECT_TRUE(safe_strto8_base("0", &value, 10));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto8_base(" \t\n -124", &value, 10));
+ EXPECT_EQ(-124, value);
+
+ EXPECT_TRUE(safe_strto8_base("124 \n\t ", &value, 10));
+ EXPECT_EQ(124, value);
+
+ // Invalid ints.
+ EXPECT_FALSE(safe_strto8_base("", &value, 10));
+ EXPECT_FALSE(safe_strto8_base(" ", &value, 10));
+ EXPECT_FALSE(safe_strto8_base("abc", &value, 10));
+ EXPECT_FALSE(safe_strto8_base("34a", &value, 10));
+ EXPECT_FALSE(safe_strto8_base("34.3", &value, 10));
+
+ // Out of bounds.
+ EXPECT_FALSE(safe_strto8_base("128", &value, 10));
+ EXPECT_FALSE(safe_strto8_base("-129", &value, 10));
+
+ // String version.
+ EXPECT_TRUE(safe_strto8_base(std::string("0x12"), &value, 16));
+ EXPECT_EQ(0x12, value);
+
+ // Base-10 string version.
+ EXPECT_TRUE(safe_strto8_base("123", &value, 10));
+ EXPECT_EQ(123, value);
+}
+
+TEST(stringtest, safe_strto16_base) {
+ int16_t value;
+ EXPECT_TRUE(safe_strto16_base("0x3423", &value, 16));
+ EXPECT_EQ(0x3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("0X3423", &value, 16));
+ EXPECT_EQ(0x3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("3423", &value, 16));
+ EXPECT_EQ(0x3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("0", &value, 16));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto16_base(" \t\n -0x3423", &value, 16));
+ EXPECT_EQ(-0x3423, value);
+
+ EXPECT_TRUE(safe_strto16_base(" \t\n -3423", &value, 16));
+ EXPECT_EQ(-0x3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("34567", &value, 8));
+ EXPECT_EQ(034567, value);
+
+ EXPECT_TRUE(safe_strto16_base("-01234", &value, 8));
+ EXPECT_EQ(-01234, value);
+
+ EXPECT_FALSE(safe_strto16_base("1834", &value, 8));
+
+ // Autodetect base.
+ EXPECT_TRUE(safe_strto16_base("0", &value, 0));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto16_base("077", &value, 0));
+ EXPECT_EQ(077, value); // Octal interpretation
+
+ // Leading zero indicates octal, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto16_base("088", &value, 0));
+
+ // Leading 0x indicated hex, but then followed by invalid digit.
+ EXPECT_FALSE(safe_strto16_base("0xG", &value, 0));
+
+ // Base-10 version.
+ EXPECT_TRUE(safe_strto16_base("3423", &value, 10));
+ EXPECT_EQ(3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("0", &value, 10));
+ EXPECT_EQ(0, value);
+
+ EXPECT_TRUE(safe_strto16_base(" \t\n -3423", &value, 10));
+ EXPECT_EQ(-3423, value);
+
+ EXPECT_TRUE(safe_strto16_base("3423 \n\t ", &value, 10));
+ EXPECT_EQ(3423, value);
+
+ // Invalid ints.
+ EXPECT_FALSE(safe_strto16_base("", &value, 10));
+ EXPECT_FALSE(safe_strto16_base(" ", &value, 10));
+ EXPECT_FALSE(safe_strto16_base("abc", &value, 10));
+ EXPECT_FALSE(safe_strto16_base("324a", &value, 10));
+ EXPECT_FALSE(safe_strto16_base("4234.3", &value, 10));
+
+ // Out of bounds.
+ EXPECT_FALSE(safe_strto16_base("32768", &value, 10));
+ EXPECT_FALSE(safe_strto16_base("-32769", &value, 10));
+
+ // String version.
+ EXPECT_TRUE(safe_strto16_base(std::string("0x1234"), &value, 16));
+ EXPECT_EQ(0x1234, value);
+
+ // Base-10 string version.
+ EXPECT_TRUE(safe_strto16_base("1234", &value, 10));
+ EXPECT_EQ(1234, value);
+}
+
TEST(stringtest, safe_strto32_base) {
int32_t value;
EXPECT_TRUE(safe_strto32_base("0x34234324", &value, 16));
@@ -890,76 +1154,6 @@
EXPECT_EQ(1234, value);
}
-TEST(stringtest, safe_strto32_range) {
- // These tests verify underflow/overflow behaviour.
- int32_t value;
- EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
- EXPECT_EQ(std::numeric_limits<int32_t>::max(), value);
-
- EXPECT_TRUE(safe_strto32_base("-2147483648", &value, 10));
- EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
-
- EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
- EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
-}
-
-TEST(stringtest, safe_strto64_range) {
- // These tests verify underflow/overflow behaviour.
- int64_t value;
- EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
- EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
-
- EXPECT_TRUE(safe_strto64_base("-9223372036854775808", &value, 10));
- EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
-
- EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
- EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
-}
-
-TEST(stringtest, safe_strto32_leading_substring) {
- // These tests verify this comment in numbers.h:
- // On error, returns false, and sets *value to: [...]
- // conversion of leading substring if available ("123@@@" -> 123)
- // 0 if no leading substring available
- int32_t value;
- EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 10));
- EXPECT_EQ(4069, value);
-
- EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 8));
- EXPECT_EQ(0406, value);
-
- EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 10));
- EXPECT_EQ(4069, value);
-
- EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 16));
- EXPECT_EQ(0x4069ba, value);
-
- EXPECT_FALSE(safe_strto32_base("@@@", &value, 10));
- EXPECT_EQ(0, value); // there was no leading substring
-}
-
-TEST(stringtest, safe_strto64_leading_substring) {
- // These tests verify this comment in numbers.h:
- // On error, returns false, and sets *value to: [...]
- // conversion of leading substring if available ("123@@@" -> 123)
- // 0 if no leading substring available
- int64_t value;
- EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 10));
- EXPECT_EQ(4069, value);
-
- EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 8));
- EXPECT_EQ(0406, value);
-
- EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 10));
- EXPECT_EQ(4069, value);
-
- EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 16));
- EXPECT_EQ(0x4069ba, value);
-
- EXPECT_FALSE(safe_strto64_base("@@@", &value, 10));
- EXPECT_EQ(0, value); // there was no leading substring
-}
-
TEST(stringtest, safe_strto64_base) {
int64_t value;
EXPECT_TRUE(safe_strto64_base("0x3423432448783446", &value, 16));
@@ -1031,18 +1225,155 @@
EXPECT_EQ(1234, value);
}
+TEST(stringtest, safe_strto8_range) {
+ // These tests verify underflow/overflow behaviour.
+ int8_t value;
+ EXPECT_FALSE(safe_strto8_base("128", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int8_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto8_base("-128", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int8_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto8_base("-129", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int8_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto16_range) {
+ // These tests verify underflow/overflow behaviour.
+ int16_t value;
+ EXPECT_FALSE(safe_strto16_base("32768", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int16_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto16_base("-32768", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int16_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto16_base("-32769", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int16_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto32_range) {
+ // These tests verify underflow/overflow behaviour.
+ int32_t value;
+ EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto32_base("-2147483648", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto64_range) {
+ // These tests verify underflow/overflow behaviour.
+ int64_t value;
+ EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), value);
+
+ EXPECT_TRUE(safe_strto64_base("-9223372036854775808", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+
+ EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10));
+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value);
+}
+
+TEST(stringtest, safe_strto8_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int8_t value;
+ EXPECT_FALSE(safe_strto8_base("069@@@", &value, 10));
+ EXPECT_EQ(69, value);
+
+ EXPECT_FALSE(safe_strto8_base("01769@@@", &value, 8));
+ EXPECT_EQ(0176, value);
+
+ EXPECT_FALSE(safe_strto8_base("069balloons", &value, 10));
+ EXPECT_EQ(69, value);
+
+ EXPECT_FALSE(safe_strto8_base("07bland", &value, 16));
+ EXPECT_EQ(0x7b, value);
+
+ EXPECT_FALSE(safe_strto8_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
+TEST(stringtest, safe_strto16_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int16_t value;
+ EXPECT_FALSE(safe_strto16_base("04069@@@", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto16_base("04069@@@", &value, 8));
+ EXPECT_EQ(0406, value);
+
+ EXPECT_FALSE(safe_strto16_base("04069balloons", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto16_base("069balloons", &value, 16));
+ EXPECT_EQ(0x69ba, value);
+
+ EXPECT_FALSE(safe_strto16_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
+TEST(stringtest, safe_strto32_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int32_t value;
+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 8));
+ EXPECT_EQ(0406, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 16));
+ EXPECT_EQ(0x4069ba, value);
+
+ EXPECT_FALSE(safe_strto32_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
+TEST(stringtest, safe_strto64_leading_substring) {
+ // These tests verify this comment in numbers.h:
+ // On error, returns false, and sets *value to: [...]
+ // conversion of leading substring if available ("123@@@" -> 123)
+ // 0 if no leading substring available
+ int64_t value;
+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 8));
+ EXPECT_EQ(0406, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 10));
+ EXPECT_EQ(4069, value);
+
+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 16));
+ EXPECT_EQ(0x4069ba, value);
+
+ EXPECT_FALSE(safe_strto64_base("@@@", &value, 10));
+ EXPECT_EQ(0, value); // there was no leading substring
+}
+
const size_t kNumRandomTests = 10000;
-template <typename IntType>
-void test_random_integer_parse_base(bool (*parse_func)(absl::string_view,
- IntType* value,
- int base)) {
- using RandomEngine = std::minstd_rand0;
- std::random_device rd;
- RandomEngine rng(rd());
+template <typename IntType,
+ bool parse_func(absl::string_view, IntType* value, int base)>
+void test_random_integer_parse_base() {
+ absl::InsecureBitGen rng;
std::uniform_int_distribution<IntType> random_int(
std::numeric_limits<IntType>::min());
- std::uniform_int_distribution<int> random_base(2, 35);
+ std::uniform_int_distribution<int> random_base(2, 36);
for (size_t i = 0; i < kNumRandomTests; i++) {
IntType value = random_int(rng);
int base = random_base(rng);
@@ -1070,33 +1401,36 @@
}
}
+TEST(stringtest, safe_strto16_random) {
+ test_random_integer_parse_base<int16_t, safe_strto16_base>();
+}
TEST(stringtest, safe_strto32_random) {
- test_random_integer_parse_base<int32_t>(&safe_strto32_base);
+ test_random_integer_parse_base<int32_t, safe_strto32_base>();
}
TEST(stringtest, safe_strto64_random) {
- test_random_integer_parse_base<int64_t>(&safe_strto64_base);
+ test_random_integer_parse_base<int64_t, safe_strto64_base>();
+}
+TEST(stringtest, safe_strtou16_random) {
+ test_random_integer_parse_base<uint16_t, safe_strtou16_base>();
}
TEST(stringtest, safe_strtou32_random) {
- test_random_integer_parse_base<uint32_t>(&safe_strtou32_base);
+ test_random_integer_parse_base<uint32_t, safe_strtou32_base>();
}
TEST(stringtest, safe_strtou64_random) {
- test_random_integer_parse_base<uint64_t>(&safe_strtou64_base);
+ test_random_integer_parse_base<uint64_t, safe_strtou64_base>();
}
TEST(stringtest, safe_strtou128_random) {
- // random number generators don't work for uint128, and
- // uint128 can be streamed but not StrCat'd, so this code must be custom
+ // random number generators don't work for uint128 so this code must be custom
// implemented for uint128, but is generally the same as what's above.
// test_random_integer_parse_base<absl::uint128>(
// &absl::numbers_internal::safe_strtou128_base);
- using RandomEngine = std::minstd_rand0;
using IntType = absl::uint128;
constexpr auto parse_func = &absl::numbers_internal::safe_strtou128_base;
- std::random_device rd;
- RandomEngine rng(rd());
+ absl::InsecureBitGen rng;
std::uniform_int_distribution<uint64_t> random_uint64(
std::numeric_limits<uint64_t>::min());
- std::uniform_int_distribution<int> random_base(2, 35);
+ std::uniform_int_distribution<int> random_base(2, 36);
for (size_t i = 0; i < kNumRandomTests; i++) {
IntType value = random_uint64(rng);
@@ -1111,34 +1445,28 @@
EXPECT_EQ(parsed_value, value);
// Test overflow
- std::string s;
- absl::strings_internal::OStringStream(&s)
- << std::numeric_limits<IntType>::max() << value;
- EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+ &parsed_value, base));
// Test underflow
- s.clear();
- absl::strings_internal::OStringStream(&s) << "-" << value;
- EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ EXPECT_FALSE(parse_func(absl::StrCat("-", value), &parsed_value, base));
}
}
TEST(stringtest, safe_strto128_random) {
- // random number generators don't work for int128, and
- // int128 can be streamed but not StrCat'd, so this code must be custom
+ // random number generators don't work for int128 so this code must be custom
// implemented for int128, but is generally the same as what's above.
// test_random_integer_parse_base<absl::int128>(
// &absl::numbers_internal::safe_strto128_base);
- using RandomEngine = std::minstd_rand0;
using IntType = absl::int128;
constexpr auto parse_func = &absl::numbers_internal::safe_strto128_base;
- std::random_device rd;
- RandomEngine rng(rd());
+ absl::InsecureBitGen rng;
std::uniform_int_distribution<int64_t> random_int64(
std::numeric_limits<int64_t>::min());
std::uniform_int_distribution<uint64_t> random_uint64(
std::numeric_limits<uint64_t>::min());
- std::uniform_int_distribution<int> random_base(2, 35);
+ std::uniform_int_distribution<int> random_base(2, 36);
for (size_t i = 0; i < kNumRandomTests; ++i) {
int64_t high = random_int64(rng);
@@ -1155,16 +1483,70 @@
EXPECT_EQ(parsed_value, value);
// Test overflow
- std::string s;
- absl::strings_internal::OStringStream(&s)
- << std::numeric_limits<IntType>::max() << value;
- EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+ &parsed_value, base));
// Test underflow
- s.clear();
- absl::strings_internal::OStringStream(&s)
- << std::numeric_limits<IntType>::min() << value;
- EXPECT_FALSE(parse_func(s, &parsed_value, base));
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::min(), value),
+ &parsed_value, base));
+ }
+}
+
+TEST(stringtest, safe_strtou8_exhaustive) {
+ // Testing the entire space for uint8_t since it is small.
+ using IntType = uint8_t;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strtou8_base;
+
+ for (int i = std::numeric_limits<IntType>::min();
+ i <= std::numeric_limits<IntType>::max(); i++) {
+ IntType value = static_cast<IntType>(i);
+ for (int base = 2; base <= 36; base++) {
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+ &parsed_value, base));
+ // Test underflow
+ EXPECT_FALSE(parse_func(absl::StrCat("-", value), &parsed_value, base));
+ }
+ }
+}
+
+TEST(stringtest, safe_strto8_exhaustive) {
+ // Testing the entire space for int8_t since it is small.
+ using IntType = int8_t;
+ constexpr auto parse_func = &absl::numbers_internal::safe_strto8_base;
+
+ for (int i = std::numeric_limits<IntType>::min();
+ i <= std::numeric_limits<IntType>::max(); i++) {
+ IntType value = static_cast<IntType>(i);
+ for (int base = 2; base <= 36; base++) {
+ std::string str_value;
+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
+ IntType parsed_value;
+
+ // Test successful parse
+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
+ EXPECT_EQ(parsed_value, value);
+
+ // Test overflow
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value),
+ &parsed_value, base));
+ // Test underflow
+ EXPECT_FALSE(
+ parse_func(absl::StrCat(std::numeric_limits<IntType>::min(), value),
+ &parsed_value, base));
+ }
}
}
@@ -1434,6 +1816,134 @@
}
}
+TEST(StrToInt8, Partial) {
+ struct Int8TestLine {
+ std::string input;
+ bool status;
+ int8_t value;
+ };
+ const int8_t int8_min = std::numeric_limits<int8_t>::min();
+ const int8_t int8_max = std::numeric_limits<int8_t>::max();
+ Int8TestLine int8_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(int8_min, int8_max), false, int8_min},
+ {absl::StrCat(int8_max, int8_max), false, int8_max},
+ };
+
+ for (const Int8TestLine& test_line : int8_test_line) {
+ int8_t value = -2;
+ bool status = safe_strto8_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto8_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto8_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToUint8, Partial) {
+ struct Uint8TestLine {
+ std::string input;
+ bool status;
+ uint8_t value;
+ };
+ const uint8_t uint8_max = std::numeric_limits<uint8_t>::max();
+ Uint8TestLine uint8_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(uint8_max, uint8_max), false, uint8_max},
+ };
+
+ for (const Uint8TestLine& test_line : uint8_test_line) {
+ uint8_t value = 2;
+ bool status = safe_strtou8_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou8_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou8_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToInt16, Partial) {
+ struct Int16TestLine {
+ std::string input;
+ bool status;
+ int16_t value;
+ };
+ const int16_t int16_min = std::numeric_limits<int16_t>::min();
+ const int16_t int16_max = std::numeric_limits<int16_t>::max();
+ Int16TestLine int16_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(int16_min, int16_max), false, int16_min},
+ {absl::StrCat(int16_max, int16_max), false, int16_max},
+ };
+
+ for (const Int16TestLine& test_line : int16_test_line) {
+ int16_t value = -2;
+ bool status = safe_strto16_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto16_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = -2;
+ status = safe_strto16_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
+TEST(StrToUint16, Partial) {
+ struct Uint16TestLine {
+ std::string input;
+ bool status;
+ uint16_t value;
+ };
+ const uint16_t uint16_max = std::numeric_limits<uint16_t>::max();
+ Uint16TestLine uint16_test_line[] = {
+ {"", false, 0},
+ {" ", false, 0},
+ {"-", false, 0},
+ {"123@@@", false, 123},
+ {absl::StrCat(uint16_max, uint16_max), false, uint16_max},
+ };
+
+ for (const Uint16TestLine& test_line : uint16_test_line) {
+ uint16_t value = 2;
+ bool status = safe_strtou16_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou16_base(test_line.input, &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ value = 2;
+ status = safe_strtou16_base(absl::string_view(test_line.input), &value, 10);
+ EXPECT_EQ(test_line.status, status) << test_line.input;
+ EXPECT_EQ(test_line.value, value) << test_line.input;
+ }
+}
+
TEST(StrToInt32, Partial) {
struct Int32TestLine {
std::string input;
@@ -1731,6 +2241,10 @@
}
TEST(FastIntToBuffer, WritesNull) {
+ ExpectWritesNull<int8_t>();
+ ExpectWritesNull<uint8_t>();
+ ExpectWritesNull<int16_t>();
+ ExpectWritesNull<uint16_t>();
ExpectWritesNull<int32_t>();
ExpectWritesNull<uint32_t>();
ExpectWritesNull<int64_t>();
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index c51c137..1f3cfbf 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -42,8 +42,7 @@
namespace {
// Append is merely a version of memcpy that returns the address of the byte
// after the area just overwritten.
-inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out,
- const AlphaNum& x) {
+inline char* absl_nonnull Append(char* absl_nonnull out, const AlphaNum& x) {
// memcpy is allowed to overwrite arbitrary memory, so doing this after the
// call would force an extra fetch of x.size().
char* after = out + x.size();
@@ -159,7 +158,7 @@
assert(((src).size() == 0) || \
(uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
-void AppendPieces(absl::Nonnull<std::string*> dest,
+void AppendPieces(std::string* absl_nonnull dest,
std::initializer_list<absl::string_view> pieces) {
size_t old_size = dest->size();
size_t to_append = 0;
@@ -183,7 +182,7 @@
} // namespace strings_internal
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a) {
ASSERT_NO_OVERLAP(*dest, a);
std::string::size_type old_size = dest->size();
STLStringAppendUninitializedAmortized(dest, a.size());
@@ -193,7 +192,7 @@
assert(out == begin + dest->size());
}
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b) {
ASSERT_NO_OVERLAP(*dest, a);
ASSERT_NO_OVERLAP(*dest, b);
@@ -206,7 +205,7 @@
assert(out == begin + dest->size());
}
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c) {
ASSERT_NO_OVERLAP(*dest, a);
ASSERT_NO_OVERLAP(*dest, b);
@@ -221,7 +220,7 @@
assert(out == begin + dest->size());
}
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
ASSERT_NO_OVERLAP(*dest, a);
ASSERT_NO_OVERLAP(*dest, b);
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index b98adc0..84db0f6 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -101,6 +101,7 @@
#include <vector>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/nullability.h"
#include "absl/base/port.h"
#include "absl/meta/type_traits.h"
@@ -110,6 +111,10 @@
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
+#if !defined(ABSL_USES_STD_STRING_VIEW)
+#include <string_view>
+#endif
+
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -186,29 +191,29 @@
template <typename Int>
explicit Hex(
Int v, PadSpec spec = absl::kNoPad,
- typename std::enable_if<sizeof(Int) == 1 &&
- !std::is_pointer<Int>::value>::type* = nullptr)
+ std::enable_if_t<sizeof(Int) == 1 && !std::is_pointer<Int>::value, bool> =
+ true)
: Hex(spec, static_cast<uint8_t>(v)) {}
template <typename Int>
explicit Hex(
Int v, PadSpec spec = absl::kNoPad,
- typename std::enable_if<sizeof(Int) == 2 &&
- !std::is_pointer<Int>::value>::type* = nullptr)
+ std::enable_if_t<sizeof(Int) == 2 && !std::is_pointer<Int>::value, bool> =
+ true)
: Hex(spec, static_cast<uint16_t>(v)) {}
template <typename Int>
explicit Hex(
Int v, PadSpec spec = absl::kNoPad,
- typename std::enable_if<sizeof(Int) == 4 &&
- !std::is_pointer<Int>::value>::type* = nullptr)
+ std::enable_if_t<sizeof(Int) == 4 && !std::is_pointer<Int>::value, bool> =
+ true)
: Hex(spec, static_cast<uint32_t>(v)) {}
template <typename Int>
explicit Hex(
Int v, PadSpec spec = absl::kNoPad,
- typename std::enable_if<sizeof(Int) == 8 &&
- !std::is_pointer<Int>::value>::type* = nullptr)
+ std::enable_if_t<sizeof(Int) == 8 && !std::is_pointer<Int>::value, bool> =
+ true)
: Hex(spec, static_cast<uint64_t>(v)) {}
template <typename Pointee>
- explicit Hex(absl::Nullable<Pointee*> v, PadSpec spec = absl::kNoPad)
+ explicit Hex(Pointee* absl_nullable v, PadSpec spec = absl::kNoPad)
: Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
template <typename S>
@@ -257,7 +262,7 @@
template <typename Int>
explicit Dec(Int v, PadSpec spec = absl::kNoPad,
- typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr)
+ std::enable_if_t<sizeof(Int) <= 8, bool> = true)
: value(v >= 0 ? static_cast<uint64_t>(v)
: uint64_t{0} - static_cast<uint64_t>(v)),
width(spec == absl::kNoPad ? 1
@@ -354,13 +359,19 @@
ABSL_ATTRIBUTE_LIFETIME_BOUND)
: piece_(&buf.data[0], buf.size) {}
- AlphaNum(absl::Nullable<const char*> c_str // NOLINT(runtime/explicit)
+ AlphaNum(const char* absl_nullable c_str // NOLINT(runtime/explicit)
ABSL_ATTRIBUTE_LIFETIME_BOUND)
: piece_(NullSafeStringView(c_str)) {}
AlphaNum(absl::string_view pc // NOLINT(runtime/explicit)
ABSL_ATTRIBUTE_LIFETIME_BOUND)
: piece_(pc) {}
+#if !defined(ABSL_USES_STD_STRING_VIEW)
+ AlphaNum(std::string_view pc // NOLINT(runtime/explicit)
+ ABSL_ATTRIBUTE_LIFETIME_BOUND)
+ : piece_(pc.data(), pc.size()) {}
+#endif // !ABSL_USES_STD_STRING_VIEW
+
template <typename T, typename = typename std::enable_if<
HasAbslStringify<T>::value>::type>
AlphaNum( // NOLINT(runtime/explicit)
@@ -381,7 +392,7 @@
AlphaNum& operator=(const AlphaNum&) = delete;
absl::string_view::size_type size() const { return piece_.size(); }
- absl::Nullable<const char*> data() const { return piece_.data(); }
+ const char* absl_nullable data() const { return piece_.data(); }
absl::string_view Piece() const { return piece_; }
// Match unscoped enums. Use integral promotion so that a `char`-backed
@@ -451,7 +462,7 @@
// Do not call directly - this is not part of the public API.
std::string CatPieces(std::initializer_list<absl::string_view> pieces);
-void AppendPieces(absl::Nonnull<std::string*> dest,
+void AppendPieces(std::string* absl_nonnull dest,
std::initializer_list<absl::string_view> pieces);
template <typename Integer>
@@ -527,28 +538,28 @@
} // namespace strings_internal
-ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
+[[nodiscard]] inline std::string StrCat() { return std::string(); }
template <typename T>
-ABSL_MUST_USE_RESULT inline std::string StrCat(
+[[nodiscard]] inline std::string StrCat(
strings_internal::EnableIfFastCase<T> a) {
return strings_internal::SingleArgStrCat(a);
}
-ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
+[[nodiscard]] inline std::string StrCat(const AlphaNum& a) {
return std::string(a.data(), a.size());
}
-ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b);
-ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c);
-ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c, const AlphaNum& d);
+[[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b);
+[[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c);
+[[nodiscard]] std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d);
// Support 5 or more arguments
template <typename... AV>
-ABSL_MUST_USE_RESULT inline std::string StrCat(
- const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
- const AlphaNum& e, const AV&... args) {
+[[nodiscard]] inline std::string StrCat(const AlphaNum& a, const AlphaNum& b,
+ const AlphaNum& c, const AlphaNum& d,
+ const AlphaNum& e, const AV&... args) {
return strings_internal::CatPieces(
{a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
static_cast<const AlphaNum&>(args).Piece()...});
@@ -581,18 +592,18 @@
// absl::string_view p = s;
// StrAppend(&s, p);
-inline void StrAppend(absl::Nonnull<std::string*>) {}
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a);
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+inline void StrAppend(std::string* absl_nonnull) {}
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a);
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b);
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c);
-void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c, const AlphaNum& d);
// Support 5 or more arguments
template <typename... AV>
-inline void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
+inline void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
const AlphaNum& b, const AlphaNum& c, const AlphaNum& d,
const AlphaNum& e, const AV&... args) {
strings_internal::AppendPieces(
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc
index 0a851e7..7695e8f 100644
--- a/absl/strings/str_cat_benchmark.cc
+++ b/absl/strings/str_cat_benchmark.cc
@@ -21,12 +21,13 @@
#include <tuple>
#include <utility>
-#include "benchmark/benchmark.h"
#include "absl/random/log_uniform_int_distribution.h"
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
+#include "benchmark/benchmark.h"
namespace {
@@ -111,6 +112,17 @@
}
BENCHMARK(BM_HexCat_By_StrCat);
+void BM_HexCat_By_StrFormat(benchmark::State& state) {
+ int i = 0;
+ for (auto _ : state) {
+ std::string result =
+ absl::StrFormat("%s %x", kStringOne, int64_t{i} + 0x10000000);
+ benchmark::DoNotOptimize(result);
+ i = IncrementAlternatingSign(i);
+ }
+}
+BENCHMARK(BM_HexCat_By_StrFormat);
+
void BM_HexCat_By_Substitute(benchmark::State& state) {
int i = 0;
for (auto _ : state) {
@@ -145,6 +157,18 @@
}
BENCHMARK(BM_DoubleToString_By_SixDigits);
+void BM_FloatToString_By_StrFormat(benchmark::State& state) {
+ int i = 0;
+ float foo = 0.0f;
+ for (auto _ : state) {
+ std::string result =
+ absl::StrFormat("%f != %lld", foo += 1.001f, int64_t{i});
+ benchmark::DoNotOptimize(result);
+ i = IncrementAlternatingSign(i);
+ }
+}
+BENCHMARK(BM_FloatToString_By_StrFormat);
+
template <typename Table, size_t... Index>
void BM_StrAppendImpl(benchmark::State& state, Table table, size_t total_bytes,
std::index_sequence<Index...>) {
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
index 66eddf0..a3bd42c 100644
--- a/absl/strings/str_cat_test.cc
+++ b/absl/strings/str_cat_test.cc
@@ -21,9 +21,11 @@
#include <cstdlib>
#include <limits>
#include <string>
+#include <string_view>
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/config.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
@@ -73,7 +75,7 @@
TEST(StrCat, Enums) {
enum SmallNumbers { One = 1, Ten = 10 } e = Ten;
EXPECT_EQ("10", absl::StrCat(e));
- EXPECT_EQ("-5", absl::StrCat(SmallNumbers(-5)));
+ EXPECT_EQ("1", absl::StrCat(One));
enum class Option { Boxers = 1, Briefs = -1 };
@@ -214,6 +216,12 @@
EXPECT_EQ(result, "");
}
+TEST(StrCat, StdStringView) {
+ std::string_view pieces[] = {"Hello", ", ", "World", "!"};
+ EXPECT_EQ(absl::StrCat(pieces[0], pieces[1], pieces[2], pieces[3]),
+ "Hello, World!");
+}
+
TEST(StrCat, NullConstCharPtr) {
const char* null = nullptr;
EXPECT_EQ(absl::StrCat("mon", null, "key"), "monkey");
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index 76904d3..ffa7f11 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -112,7 +112,7 @@
protected:
explicit UntypedFormatSpec(
- absl::Nonnull<const str_format_internal::ParsedFormatBase*> pc)
+ const str_format_internal::ParsedFormatBase* absl_nonnull pc)
: spec_(pc) {}
private:
@@ -152,7 +152,7 @@
// EXPECT_EQ(8, n);
class FormatCountCapture {
public:
- explicit FormatCountCapture(absl::Nonnull<int*> p) : p_(p) {}
+ explicit FormatCountCapture(int* absl_nonnull p) : p_(p) {}
private:
// FormatCountCaptureHelper is used to define FormatConvertImpl() for this
@@ -161,8 +161,8 @@
// Unused() is here because of the false positive from -Wunused-private-field
// p_ is used in the templated function of the friend FormatCountCaptureHelper
// class.
- absl::Nonnull<int*> Unused() { return p_; }
- absl::Nonnull<int*> p_;
+ int* absl_nonnull Unused() { return p_; }
+ int* absl_nonnull p_;
};
// FormatSpec
@@ -359,8 +359,8 @@
//
// Returns an empty string in case of error.
template <typename... Args>
-ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format,
- const Args&... args) {
+[[nodiscard]] std::string StrFormat(const FormatSpec<Args...>& format,
+ const Args&... args) {
return str_format_internal::FormatPack(
str_format_internal::UntypedFormatSpecImpl::Extract(format),
{str_format_internal::FormatArgImpl(args)...});
@@ -377,7 +377,7 @@
// std::string orig("For example PI is approximately ");
// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14);
template <typename... Args>
-std::string& StrAppendFormat(absl::Nonnull<std::string*> dst,
+std::string& StrAppendFormat(std::string* absl_nonnull dst,
const FormatSpec<Args...>& format,
const Args&... args) {
return str_format_internal::AppendPack(
@@ -396,7 +396,7 @@
//
// std::cout << StreamFormat("%12.6f", 3.14);
template <typename... Args>
-ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat(
+[[nodiscard]] str_format_internal::Streamable StreamFormat(
const FormatSpec<Args...>& format, const Args&... args) {
return str_format_internal::Streamable(
str_format_internal::UntypedFormatSpecImpl::Extract(format),
@@ -437,7 +437,7 @@
// Outputs: "The capital of Mongolia is Ulaanbaatar"
//
template <typename... Args>
-int FPrintF(absl::Nonnull<std::FILE*> output, const FormatSpec<Args...>& format,
+int FPrintF(std::FILE* absl_nonnull output, const FormatSpec<Args...>& format,
const Args&... args) {
return str_format_internal::FprintF(
output, str_format_internal::UntypedFormatSpecImpl::Extract(format),
@@ -466,7 +466,7 @@
// Post-condition: output == "The capital of Mongolia is Ulaanbaatar"
//
template <typename... Args>
-int SNPrintF(absl::Nonnull<char*> output, std::size_t size,
+int SNPrintF(char* absl_nonnull output, std::size_t size,
const FormatSpec<Args...>& format, const Args&... args) {
return str_format_internal::SnprintF(
output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format),
@@ -500,7 +500,7 @@
template <typename T,
typename = typename std::enable_if<std::is_constructible<
str_format_internal::FormatRawSinkImpl, T*>::value>::type>
- FormatRawSink(absl::Nonnull<T*> raw) // NOLINT
+ FormatRawSink(T* absl_nonnull raw) // NOLINT
: sink_(raw) {}
private:
@@ -582,9 +582,9 @@
// return std::move(out);
// }
//
-ABSL_MUST_USE_RESULT inline bool FormatUntyped(
- FormatRawSink raw_sink, const UntypedFormatSpec& format,
- absl::Span<const FormatArg> args) {
+[[nodiscard]] inline bool FormatUntyped(FormatRawSink raw_sink,
+ const UntypedFormatSpec& format,
+ absl::Span<const FormatArg> args) {
return str_format_internal::FormatUntyped(
str_format_internal::FormatRawSinkImpl::Extract(raw_sink),
str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
@@ -609,7 +609,7 @@
//
// Note that unlike with AbslFormatConvert(), AbslStringify() does not allow
// customization of allowed conversion characters. AbslStringify() uses `%v` as
-// the underlying conversion specififer. Additionally, AbslStringify() supports
+// the underlying conversion specifier. Additionally, AbslStringify() supports
// use with absl::StrCat while AbslFormatConvert() does not.
//
// Example:
@@ -857,16 +857,16 @@
}
// Support `absl::Format(&sink, format, args...)`.
- friend void AbslFormatFlush(absl::Nonnull<FormatSink*> sink,
+ friend void AbslFormatFlush(FormatSink* absl_nonnull sink,
absl::string_view v) {
sink->Append(v);
}
private:
friend str_format_internal::FormatSinkImpl;
- explicit FormatSink(absl::Nonnull<str_format_internal::FormatSinkImpl*> s)
+ explicit FormatSink(str_format_internal::FormatSinkImpl* absl_nonnull s)
: sink_(s) {}
- absl::Nonnull<str_format_internal::FormatSinkImpl*> sink_;
+ str_format_internal::FormatSinkImpl* absl_nonnull sink_;
};
// FormatConvertResult
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 3c52be1..969e1f9 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -516,7 +516,13 @@
EXPECT_EQ(result, 17);
EXPECT_EQ(std::string(buffer), "NUMBER: 1234567");
- result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size");
+ // The `output` parameter is annotated nonnull, but we want to test that
+ // it is never written to if the size is zero.
+ // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
+ // warning.
+ char* null_output = nullptr;
+ result =
+ SNPrintF(null_output, 0, "Just checking the %s of the output.", "size");
EXPECT_EQ(result, 37);
}
@@ -545,7 +551,13 @@
std::string size = "size";
- result = SNPrintF(nullptr, 0, "Just checking the %v of the output.", size);
+ // The `output` parameter is annotated nonnull, but we want to test that
+ // it is never written to if the size is zero.
+ // Use a variable instead of passing nullptr directly to avoid a `-Wnonnull`
+ // warning.
+ char* null_output = nullptr;
+ result =
+ SNPrintF(null_output, 0, "Just checking the %v of the output.", size);
EXPECT_EQ(result, 37);
}
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc
index be7a725..ffe6696 100644
--- a/absl/strings/str_join_benchmark.cc
+++ b/absl/strings/str_join_benchmark.cc
@@ -13,13 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/str_join.h"
-
#include <string>
#include <tuple>
-#include <vector>
#include <utility>
+#include <vector>
+#include "absl/strings/str_join.h"
#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc
index a7ab52f..377e30c 100644
--- a/absl/strings/str_replace.cc
+++ b/absl/strings/str_replace.cc
@@ -37,8 +37,8 @@
// occurred.
int ApplySubstitutions(
absl::string_view s,
- absl::Nonnull<std::vector<strings_internal::ViableSubstitution>*> subs_ptr,
- absl::Nonnull<std::string*> result_ptr) {
+ std::vector<strings_internal::ViableSubstitution>* absl_nonnull subs_ptr,
+ std::string* absl_nonnull result_ptr) {
auto& subs = *subs_ptr;
int substitutions = 0;
size_t pos = 0;
@@ -83,7 +83,7 @@
}
int StrReplaceAll(strings_internal::FixedMapping replacements,
- absl::Nonnull<std::string*> target) {
+ std::string* absl_nonnull target) {
return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
}
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h
index e77ced3..91b920b 100644
--- a/absl/strings/str_replace.h
+++ b/absl/strings/str_replace.h
@@ -66,7 +66,7 @@
// {"$who", "Bob"},
// {"#Noun", "Apples"}});
// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
-ABSL_MUST_USE_RESULT std::string StrReplaceAll(
+[[nodiscard]] std::string StrReplaceAll(
absl::string_view s,
std::initializer_list<std::pair<absl::string_view, absl::string_view>>
replacements);
@@ -114,7 +114,7 @@
int StrReplaceAll(
std::initializer_list<std::pair<absl::string_view, absl::string_view>>
replacements,
- absl::Nonnull<std::string*> target);
+ std::string* absl_nonnull target);
// Overload of `StrReplaceAll()` to replace patterns within a given output
// string *in place* with replacements provided within a container of key/value
@@ -130,7 +130,7 @@
// EXPECT_EQ("if (ptr < &foo)", s);
template <typename StrToStrMapping>
int StrReplaceAll(const StrToStrMapping& replacements,
- absl::Nonnull<std::string*> target);
+ std::string* absl_nonnull target);
// Implementation details only, past this point.
namespace strings_internal {
@@ -187,8 +187,8 @@
}
int ApplySubstitutions(absl::string_view s,
- absl::Nonnull<std::vector<ViableSubstitution>*> subs_ptr,
- absl::Nonnull<std::string*> result_ptr);
+ std::vector<ViableSubstitution>* absl_nonnull subs_ptr,
+ std::string* absl_nonnull result_ptr);
} // namespace strings_internal
@@ -204,7 +204,7 @@
template <typename StrToStrMapping>
int StrReplaceAll(const StrToStrMapping& replacements,
- absl::Nonnull<std::string*> target) {
+ std::string* absl_nonnull target) {
auto subs = strings_internal::FindSubstitutions(*target, replacements);
if (subs.empty()) return 0;
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc
index 01331da..cbe7572 100644
--- a/absl/strings/str_replace_benchmark.cc
+++ b/absl/strings/str_replace_benchmark.cc
@@ -12,13 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/str_replace.h"
-
#include <cstring>
#include <string>
-#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_replace.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index ba176fc..7e8e31c 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -444,8 +444,10 @@
// behavior works for:
//
// 1) All standard STL containers including `std::vector`, `std::list`,
-// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
+// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`.
// 2) `std::pair` (which is not actually a container). See below.
+// 3) `std::array`, which is a container but has different behavior due to its
+// fixed size. See below.
//
// Example:
//
@@ -487,6 +489,21 @@
// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
// // p.first == "a", p.second == "b" // "c" is omitted.
//
+//
+// Splitting to `std::array` is similar to splitting to `std::pair`, but for
+// N elements instead of two; missing elements are filled with the empty string
+// and extra elements are discarded.
+//
+// Examples:
+//
+// // Stores first two split strings as the elements in a std::array.
+// std::array<std::string, 2> a = absl::StrSplit("a,b,c", ',');
+// // a[0] == "a", a[1] == "b" // "c" is omitted.
+//
+// // The second element is empty.
+// std::array<std::string, 2> a = absl::StrSplit("a,", ',');
+// // a[0] == "a", a[1] == ""
+//
// The `StrSplit()` function can be used multiple times to perform more
// complicated splitting logic, such as intelligently parsing key-value pairs.
//
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc
index 003a66b..5a2e953 100644
--- a/absl/strings/str_split_benchmark.cc
+++ b/absl/strings/str_split_benchmark.cc
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/str_split.h"
-
#include <cstddef>
#include <iterator>
#include <string>
@@ -21,9 +19,10 @@
#include <unordered_set>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
index df6c460..b083975 100644
--- a/absl/strings/str_split_test.cc
+++ b/absl/strings/str_split_test.cc
@@ -14,6 +14,7 @@
#include "absl/strings/str_split.h"
+#include <array>
#include <cstddef>
#include <cstdint>
#include <deque>
@@ -397,6 +398,12 @@
EXPECT_EQ(p, (std::pair<FirstType, SecondType>("a", "b")));
}
+template <typename StringType, typename Splitter>
+void TestArrayConversionOperator(const Splitter& splitter) {
+ std::array<StringType, 2> a = splitter;
+ EXPECT_THAT(a, ElementsAre("a", "b"));
+}
+
TEST(Splitter, ConversionOperator) {
auto splitter = absl::StrSplit("a,b,c,d", ',');
@@ -467,6 +474,10 @@
TestPairConversionOperator<absl::string_view, std::string>(splitter);
TestPairConversionOperator<std::string, absl::string_view>(splitter);
TestPairConversionOperator<std::string, std::string>(splitter);
+
+ // Tests conversion to std::array
+ TestArrayConversionOperator<std::string>(splitter);
+ TestArrayConversionOperator<absl::string_view>(splitter);
}
// A few additional tests for conversion to std::pair. This conversion is
@@ -511,6 +522,41 @@
}
}
+// std::array tests similar to std::pair tests above, testing fewer, exactly,
+// or more elements than the array size.
+TEST(Splitter, ToArray) {
+ {
+ // Empty string
+ std::array<std::string, 2> p = absl::StrSplit("", ',');
+ EXPECT_THAT(p, ElementsAre("", ""));
+ }
+
+ {
+ // Only first
+ std::array<std::string, 2> p = absl::StrSplit("a", ',');
+ EXPECT_THAT(p, ElementsAre("a", ""));
+ }
+
+ {
+ // Only second
+ std::array<std::string, 2> p = absl::StrSplit(",b", ',');
+ EXPECT_THAT(p, ElementsAre("", "b"));
+ }
+
+ {
+ // First and second.
+ std::array<std::string, 2> p = absl::StrSplit("a,b", ',');
+ EXPECT_THAT(p, ElementsAre("a", "b"));
+ }
+
+ {
+ // First and second and then more stuff that will be ignored.
+ std::array<std::string, 2> p = absl::StrSplit("a,b,c", ',');
+ EXPECT_THAT(p, ElementsAre("a", "b"));
+ // "c" is omitted.
+ }
+}
+
TEST(Splitter, Predicates) {
static const char kTestChars[] = ",a, ,b,";
using absl::AllowEmpty;
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
index 97025c3..33bd1bb 100644
--- a/absl/strings/string_view.cc
+++ b/absl/strings/string_view.cc
@@ -30,10 +30,10 @@
// This is significantly faster for case-sensitive matches with very
// few possible matches.
-absl::Nullable<const char*> memmatch(absl::Nullable<const char*> phaystack,
- size_t haylen,
- absl::Nullable<const char*> pneedle,
- size_t neelen) {
+const char* absl_nullable memmatch(const char* absl_nullable phaystack,
+ size_t haylen,
+ const char* absl_nullable pneedle,
+ size_t neelen) {
if (0 == neelen) {
return phaystack; // even if haylen is 0
}
@@ -233,11 +233,6 @@
return npos;
}
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr string_view::size_type string_view::npos;
-constexpr string_view::size_type string_view::kMaxSize;
-#endif
-
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index ff76001..9a1933b 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -159,15 +159,15 @@
//
// absl::string_view() == absl::string_view("", 0)
// absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0)
-class ABSL_INTERNAL_ATTRIBUTE_VIEW string_view {
+class ABSL_ATTRIBUTE_VIEW string_view {
public:
using traits_type = std::char_traits<char>;
using value_type = char;
- using pointer = absl::Nullable<char*>;
- using const_pointer = absl::Nullable<const char*>;
+ using pointer = char* absl_nullable;
+ using const_pointer = const char* absl_nullable;
using reference = char&;
using const_reference = const char&;
- using const_iterator = absl::Nullable<const char*>;
+ using const_iterator = const char* absl_nullable;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
@@ -197,16 +197,15 @@
// instead (see below).
// The length check is skipped since it is unnecessary and causes code bloat.
constexpr string_view( // NOLINT(runtime/explicit)
- absl::Nonnull<const char*> str)
+ const char* absl_nonnull str)
: ptr_(str), length_(str ? StrlenInternal(str) : 0) {}
- // Implicit constructor of a `string_view` from a `const char*` and length.
- constexpr string_view(absl::Nullable<const char*> data, size_type len)
+ // Constructor of a `string_view` from a `const char*` and length.
+ constexpr string_view(const char* absl_nullable data, size_type len)
: ptr_(data), length_(CheckLengthInternal(len)) {}
- // NOTE: Harmlessly omitted to work around gdb bug.
- // constexpr string_view(const string_view&) noexcept = default;
- // string_view& operator=(const string_view&) noexcept = default;
+ constexpr string_view(const string_view&) noexcept = default;
+ string_view& operator=(const string_view&) noexcept = default;
// Iterators
@@ -293,7 +292,8 @@
// Returns the ith element of the `string_view` using the array operator.
// Note that this operator does not perform any bounds checking.
constexpr const_reference operator[](size_type i) const {
- return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
+ ABSL_HARDENING_ASSERT(i < size());
+ return ptr_[i];
}
// string_view::at()
@@ -302,25 +302,26 @@
// and an exception of type `std::out_of_range` will be thrown on invalid
// access.
constexpr const_reference at(size_type i) const {
- return ABSL_PREDICT_TRUE(i < size())
- ? ptr_[i]
- : ((void)base_internal::ThrowStdOutOfRange(
- "absl::string_view::at"),
- ptr_[i]);
+ if (ABSL_PREDICT_FALSE(i >= size())) {
+ base_internal::ThrowStdOutOfRange("absl::string_view::at");
+ }
+ return ptr_[i];
}
// string_view::front()
//
// Returns the first element of a `string_view`.
constexpr const_reference front() const {
- return ABSL_HARDENING_ASSERT(!empty()), ptr_[0];
+ ABSL_HARDENING_ASSERT(!empty());
+ return ptr_[0];
}
// string_view::back()
//
// Returns the last element of a `string_view`.
constexpr const_reference back() const {
- return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1];
+ ABSL_HARDENING_ASSERT(!empty());
+ return ptr_[size() - 1];
}
// string_view::data()
@@ -394,11 +395,10 @@
// `pos > size`.
// Use absl::ClippedSubstr if you need a truncating substr operation.
constexpr string_view substr(size_type pos = 0, size_type n = npos) const {
- return ABSL_PREDICT_FALSE(pos > length_)
- ? (base_internal::ThrowStdOutOfRange(
- "absl::string_view::substr"),
- string_view())
- : string_view(ptr_ + pos, Min(n, length_ - pos));
+ if (ABSL_PREDICT_FALSE(pos > length_)) {
+ base_internal::ThrowStdOutOfRange("absl::string_view::substr");
+ }
+ return string_view(ptr_ + pos, (std::min)(n, length_ - pos));
}
// string_view::compare()
@@ -409,10 +409,10 @@
// is greater than `x`.
constexpr int compare(string_view x) const noexcept {
return CompareImpl(length_, x.length_,
- Min(length_, x.length_) == 0
+ (std::min)(length_, x.length_) == 0
? 0
: ABSL_INTERNAL_STRING_VIEW_MEMCMP(
- ptr_, x.ptr_, Min(length_, x.length_)));
+ ptr_, x.ptr_, (std::min)(length_, x.length_)));
}
// Overload of `string_view::compare()` for comparing a substring of the
@@ -430,21 +430,21 @@
// Overload of `string_view::compare()` for comparing a `string_view` and a
// a different C-style string `s`.
- constexpr int compare(absl::Nonnull<const char*> s) const {
+ constexpr int compare(const char* absl_nonnull s) const {
return compare(string_view(s));
}
// Overload of `string_view::compare()` for comparing a substring of the
// `string_view` and a different string C-style string `s`.
constexpr int compare(size_type pos1, size_type count1,
- absl::Nonnull<const char*> s) const {
+ const char* absl_nonnull s) const {
return substr(pos1, count1).compare(string_view(s));
}
// Overload of `string_view::compare()` for comparing a substring of the
// `string_view` and a substring of a different C-style string `s`.
constexpr int compare(size_type pos1, size_type count1,
- absl::Nonnull<const char*> s, size_type count2) const {
+ const char* absl_nonnull s, size_type count2) const {
return substr(pos1, count1).compare(string_view(s, count2));
}
@@ -463,14 +463,14 @@
// Overload of `string_view::find()` for finding a substring of a different
// C-style string `s` within the `string_view`.
- size_type find(absl::Nonnull<const char*> s, size_type pos,
+ size_type find(const char* absl_nonnull s, size_type pos,
size_type count) const {
return find(string_view(s, count), pos);
}
// Overload of `string_view::find()` for finding a different C-style string
// `s` within the `string_view`.
- size_type find(absl::Nonnull<const char *> s, size_type pos = 0) const {
+ size_type find(const char* absl_nonnull s, size_type pos = 0) const {
return find(string_view(s), pos);
}
@@ -487,14 +487,14 @@
// Overload of `string_view::rfind()` for finding a substring of a different
// C-style string `s` within the `string_view`.
- size_type rfind(absl::Nonnull<const char*> s, size_type pos,
+ size_type rfind(const char* absl_nonnull s, size_type pos,
size_type count) const {
return rfind(string_view(s, count), pos);
}
// Overload of `string_view::rfind()` for finding a different C-style string
// `s` within the `string_view`.
- size_type rfind(absl::Nonnull<const char*> s, size_type pos = npos) const {
+ size_type rfind(const char* absl_nonnull s, size_type pos = npos) const {
return rfind(string_view(s), pos);
}
@@ -513,15 +513,14 @@
// Overload of `string_view::find_first_of()` for finding a substring of a
// different C-style string `s` within the `string_view`.
- size_type find_first_of(absl::Nonnull<const char*> s, size_type pos,
+ size_type find_first_of(const char* absl_nonnull s, size_type pos,
size_type count) const {
return find_first_of(string_view(s, count), pos);
}
// Overload of `string_view::find_first_of()` for finding a different C-style
// string `s` within the `string_view`.
- size_type find_first_of(absl::Nonnull<const char*> s,
- size_type pos = 0) const {
+ size_type find_first_of(const char* absl_nonnull s, size_type pos = 0) const {
return find_first_of(string_view(s), pos);
}
@@ -540,14 +539,14 @@
// Overload of `string_view::find_last_of()` for finding a substring of a
// different C-style string `s` within the `string_view`.
- size_type find_last_of(absl::Nonnull<const char*> s, size_type pos,
+ size_type find_last_of(const char* absl_nonnull s, size_type pos,
size_type count) const {
return find_last_of(string_view(s, count), pos);
}
// Overload of `string_view::find_last_of()` for finding a different C-style
// string `s` within the `string_view`.
- size_type find_last_of(absl::Nonnull<const char*> s,
+ size_type find_last_of(const char* absl_nonnull s,
size_type pos = npos) const {
return find_last_of(string_view(s), pos);
}
@@ -565,14 +564,14 @@
// Overload of `string_view::find_first_not_of()` for finding a substring of a
// different C-style string `s` within the `string_view`.
- size_type find_first_not_of(absl::Nonnull<const char*> s, size_type pos,
+ size_type find_first_not_of(const char* absl_nonnull s, size_type pos,
size_type count) const {
return find_first_not_of(string_view(s, count), pos);
}
// Overload of `string_view::find_first_not_of()` for finding a different
// C-style string `s` within the `string_view`.
- size_type find_first_not_of(absl::Nonnull<const char*> s,
+ size_type find_first_not_of(const char* absl_nonnull s,
size_type pos = 0) const {
return find_first_not_of(string_view(s), pos);
}
@@ -591,14 +590,14 @@
// Overload of `string_view::find_last_not_of()` for finding a substring of a
// different C-style string `s` within the `string_view`.
- size_type find_last_not_of(absl::Nonnull<const char*> s, size_type pos,
+ size_type find_last_not_of(const char* absl_nonnull s, size_type pos,
size_type count) const {
return find_last_not_of(string_view(s, count), pos);
}
// Overload of `string_view::find_last_not_of()` for finding a different
// C-style string `s` within the `string_view`.
- size_type find_last_not_of(absl::Nonnull<const char*> s,
+ size_type find_last_not_of(const char* absl_nonnull s,
size_type pos = npos) const {
return find_last_not_of(string_view(s), pos);
}
@@ -659,7 +658,7 @@
// The constructor from std::string delegates to this constructor.
// See the comment on that constructor for the rationale.
struct SkipCheckLengthTag {};
- string_view(absl::Nullable<const char*> data, size_type len,
+ string_view(const char* absl_nullable data, size_type len,
SkipCheckLengthTag) noexcept
: ptr_(data), length_(len) {}
@@ -667,10 +666,11 @@
(std::numeric_limits<difference_type>::max)();
static constexpr size_type CheckLengthInternal(size_type len) {
- return ABSL_HARDENING_ASSERT(len <= kMaxSize), len;
+ ABSL_HARDENING_ASSERT(len <= kMaxSize);
+ return len;
}
- static constexpr size_type StrlenInternal(absl::Nonnull<const char*> str) {
+ static constexpr size_type StrlenInternal(const char* absl_nonnull str) {
#if defined(_MSC_VER) && !defined(__clang__)
// MSVC 2017+ can evaluate this at compile-time.
const char* begin = str;
@@ -688,10 +688,6 @@
#endif
}
- static constexpr size_t Min(size_type length_a, size_type length_b) {
- return length_a < length_b ? length_a : length_b;
- }
-
static constexpr int CompareImpl(size_type length_a, size_type length_b,
int compare_result) {
return compare_result == 0 ? static_cast<int>(length_a > length_b) -
@@ -699,7 +695,7 @@
: (compare_result < 0 ? -1 : 1);
}
- absl::Nullable<const char*> ptr_;
+ const char* absl_nullable ptr_;
size_type length_;
};
@@ -760,7 +756,7 @@
// Creates an `absl::string_view` from a pointer `p` even if it's null-valued.
// This function should be used where an `absl::string_view` can be created from
// a possibly-null pointer.
-constexpr string_view NullSafeStringView(absl::Nullable<const char*> p) {
+constexpr string_view NullSafeStringView(const char* absl_nullable p) {
return p ? string_view(p) : string_view();
}
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc
index 98f747c..546f6ed 100644
--- a/absl/strings/string_view_benchmark.cc
+++ b/absl/strings/string_view_benchmark.cc
@@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/strings/string_view.h"
-
#include <algorithm>
#include <cstddef>
#include <cstdint>
@@ -23,11 +21,13 @@
#include <unordered_set>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/attributes.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
+#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "benchmark/benchmark.h"
namespace {
@@ -287,9 +287,7 @@
"found", "a", "large", "mushroom", "and",
"a", "couple", "crickets", "eating", "pie"};
// Create some keys that consist of words in random order.
- std::random_device r;
- std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
- std::mt19937 rng(seed);
+ absl::InsecureBitGen rng;
std::vector<std::string> keys(table_size);
std::vector<int> all_indices;
const int kBlockSize = 1 << 12;
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index e978fc3..0a2a7a9 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -34,7 +34,7 @@
#include "absl/base/config.h"
#include "absl/meta/type_traits.h"
-#if defined(ABSL_HAVE_STD_STRING_VIEW) || defined(__ANDROID__)
+#if defined(ABSL_USES_STD_STRING_VIEW) || defined(__ANDROID__)
// We don't control the death messaging when using std::string_view.
// Android assert messages only go to system log, so death tests cannot inspect
// the message for matching.
@@ -894,7 +894,11 @@
EXPECT_EQ(s.size(), 0u);
#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
- s = absl::string_view(nullptr);
+ // The `str` parameter is annotated nonnull, but we want to test the defensive
+ // null check. Use a variable instead of passing nullptr directly to avoid a
+ // `-Wnonnull` warning.
+ char* null_str = nullptr;
+ s = absl::string_view(null_str);
EXPECT_EQ(s.data(), nullptr);
EXPECT_EQ(s.size(), 0u);
@@ -1076,9 +1080,22 @@
TEST(StringViewTest, ConstexprCompiles) {
constexpr absl::string_view sp;
+ // With `-Wnonnull` turned on, there is no way to test the defensive null
+ // check in the `string_view(const char*)` constructor in a constexpr context,
+ // as the argument needs to be constexpr. The compiler will therefore always
+ // know at compile time that the argument is nullptr and complain because the
+ // parameter is annotated nonnull. We hence turn the warning off for this
+ // test.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+#endif
#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
constexpr absl::string_view cstr(nullptr);
#endif
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
constexpr absl::string_view cstr_len("cstr", 4);
#if defined(ABSL_USES_STD_STRING_VIEW)
@@ -1106,7 +1123,7 @@
#endif
// MSVC 2017+ should be able to construct a constexpr string_view from a cstr.
-#if defined(_MSC_VER) && _MSC_VER >= 1910
+#if defined(_MSC_VER)
#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
#endif
@@ -1142,10 +1159,6 @@
#endif
#endif
-#if !defined(__clang__) || 3 < __clang_major__ || \
- (3 == __clang_major__ && 4 < __clang_minor__)
- // older clang versions (< 3.5) complain that:
- // "cannot perform pointer arithmetic on null pointer"
constexpr absl::string_view::iterator const_begin_empty = sp.begin();
constexpr absl::string_view::iterator const_end_empty = sp.end();
EXPECT_EQ(const_begin_empty, const_end_empty);
@@ -1155,7 +1168,6 @@
constexpr absl::string_view::iterator const_end_nullptr = cstr.end();
EXPECT_EQ(const_begin_nullptr, const_end_nullptr);
#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR
-#endif // !defined(__clang__) || ...
constexpr absl::string_view::iterator const_begin = cstr_len.begin();
constexpr absl::string_view::iterator const_end = cstr_len.end();
diff --git a/absl/strings/strip.h b/absl/strings/strip.h
index e3cda5b..55398ff 100644
--- a/absl/strings/strip.h
+++ b/absl/strings/strip.h
@@ -24,6 +24,7 @@
#include <cstddef>
#include <string>
+#include "absl/base/attributes.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
#include "absl/strings/ascii.h"
@@ -44,8 +45,8 @@
// absl::string_view input("abc");
// EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
// EXPECT_EQ(input, "bc");
-inline bool ConsumePrefix(absl::Nonnull<absl::string_view*> str,
- absl::string_view expected) {
+inline constexpr bool ConsumePrefix(absl::string_view* absl_nonnull str,
+ absl::string_view expected) {
if (!absl::StartsWith(*str, expected)) return false;
str->remove_prefix(expected.size());
return true;
@@ -61,8 +62,8 @@
// absl::string_view input("abcdef");
// EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
// EXPECT_EQ(input, "abc");
-inline bool ConsumeSuffix(absl::Nonnull<absl::string_view*> str,
- absl::string_view expected) {
+inline constexpr bool ConsumeSuffix(absl::string_view* absl_nonnull str,
+ absl::string_view expected) {
if (!absl::EndsWith(*str, expected)) return false;
str->remove_suffix(expected.size());
return true;
@@ -73,8 +74,9 @@
// Returns a view into the input string `str` with the given `prefix` removed,
// but leaving the original string intact. If the prefix does not match at the
// start of the string, returns the original string instead.
-ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix(
- absl::string_view str, absl::string_view prefix) {
+[[nodiscard]] inline constexpr absl::string_view StripPrefix(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ absl::string_view prefix) {
if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size());
return str;
}
@@ -84,8 +86,9 @@
// Returns a view into the input string `str` with the given `suffix` removed,
// but leaving the original string intact. If the suffix does not match at the
// end of the string, returns the original string instead.
-ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix(
- absl::string_view str, absl::string_view suffix) {
+[[nodiscard]] inline constexpr absl::string_view StripSuffix(
+ absl::string_view str ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ absl::string_view suffix) {
if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size());
return str;
}
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index a71f565..3c2ca5d 100644
--- a/absl/strings/substitute.cc
+++ b/absl/strings/substitute.cc
@@ -35,9 +35,10 @@
ABSL_NAMESPACE_BEGIN
namespace substitute_internal {
-void SubstituteAndAppendArray(
- absl::Nonnull<std::string*> output, absl::string_view format,
- absl::Nullable<const absl::string_view*> args_array, size_t num_args) {
+void SubstituteAndAppendArray(std::string* absl_nonnull output,
+ absl::string_view format,
+ const absl::string_view* absl_nullable args_array,
+ size_t num_args) {
// Determine total size needed.
size_t size = 0;
for (size_t i = 0; i < format.size(); i++) {
@@ -109,7 +110,7 @@
assert(target == output->data() + output->size());
}
-Arg::Arg(absl::Nullable<const void*> value) {
+Arg::Arg(const void* absl_nullable value) {
static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
"fix sizeof(scratch_)");
if (value == nullptr) {
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 6c7cba4..c93b1cc 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -106,7 +106,7 @@
// Overloads for string-y things
//
// Explicitly overload `const char*` so the compiler doesn't cast to `bool`.
- Arg(absl::Nullable<const char*> value) // NOLINT(google-explicit-constructor)
+ Arg(const char* absl_nullable value) // NOLINT(google-explicit-constructor)
: piece_(absl::NullSafeStringView(value)) {}
template <typename Allocator>
Arg( // NOLINT
@@ -187,19 +187,20 @@
// vector<bool>::reference and const_reference require special help to convert
// to `Arg` because it requires two user defined conversions.
- template <typename T,
- absl::enable_if_t<
- std::is_class<T>::value &&
- (std::is_same<T, std::vector<bool>::reference>::value ||
- std::is_same<T, std::vector<bool>::const_reference>::value)>* =
- nullptr>
+ template <
+ typename T,
+ std::enable_if_t<
+ std::is_class<T>::value &&
+ (std::is_same<T, std::vector<bool>::reference>::value ||
+ std::is_same<T, std::vector<bool>::const_reference>::value),
+ bool> = true>
Arg(T value) // NOLINT(google-explicit-constructor)
: Arg(static_cast<bool>(value)) {}
// `void*` values, with the exception of `char*`, are printed as
// "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
Arg( // NOLINT(google-explicit-constructor)
- absl::Nullable<const void*> value);
+ const void* absl_nullable value);
// Normal enums are already handled by the integer formatters.
// This overload matches only scoped enums.
@@ -222,12 +223,13 @@
// Internal helper function. Don't call this from outside this implementation.
// This interface may change without notice.
-void SubstituteAndAppendArray(
- absl::Nonnull<std::string*> output, absl::string_view format,
- absl::Nullable<const absl::string_view*> args_array, size_t num_args);
+void SubstituteAndAppendArray(std::string* absl_nonnull output,
+ absl::string_view format,
+ const absl::string_view* absl_nullable args_array,
+ size_t num_args);
#if defined(ABSL_BAD_CALL_IF)
-constexpr int CalculateOneBit(absl::Nonnull<const char*> format) {
+constexpr int CalculateOneBit(const char* absl_nonnull format) {
// Returns:
// * 2^N for '$N' when N is in [0-9]
// * 0 for correct '$' escaping: '$$'.
@@ -236,11 +238,11 @@
: (1 << (*format - '0'));
}
-constexpr const char* SkipNumber(absl::Nonnull<const char*> format) {
+constexpr const char* absl_nonnull SkipNumber(const char* absl_nonnull format) {
return !*format ? format : (format + 1);
}
-constexpr int PlaceholderBitmask(absl::Nonnull<const char*> format) {
+constexpr int PlaceholderBitmask(const char* absl_nonnull format) {
return !*format
? 0
: *format != '$' ? PlaceholderBitmask(format + 1)
@@ -273,12 +275,12 @@
// absl::SubstituteAndAppend(boilerplate, format, args...);
// }
//
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format) {
substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0);
}
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format,
const substitute_internal::Arg& a0) {
const absl::string_view args[] = {a0.piece()};
@@ -286,7 +288,7 @@
ABSL_ARRAYSIZE(args));
}
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1) {
@@ -295,7 +297,7 @@
ABSL_ARRAYSIZE(args));
}
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
@@ -305,7 +307,7 @@
ABSL_ARRAYSIZE(args));
}
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
@@ -317,7 +319,7 @@
ABSL_ARRAYSIZE(args));
}
-inline void SubstituteAndAppend(absl::Nonnull<std::string*> output,
+inline void SubstituteAndAppend(std::string* absl_nonnull output,
absl::string_view format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
@@ -331,7 +333,7 @@
}
inline void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::string_view format,
+ std::string* absl_nonnull output, absl::string_view format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5) {
@@ -342,7 +344,7 @@
}
inline void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::string_view format,
+ std::string* absl_nonnull output, absl::string_view format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -355,7 +357,7 @@
}
inline void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::string_view format,
+ std::string* absl_nonnull output, absl::string_view format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -368,7 +370,7 @@
}
inline void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::string_view format,
+ std::string* absl_nonnull output, absl::string_view format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -382,7 +384,7 @@
}
inline void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::string_view format,
+ std::string* absl_nonnull output, absl::string_view format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -398,16 +400,16 @@
#if defined(ABSL_BAD_CALL_IF)
// This body of functions catches cases where the number of placeholders
// doesn't match the number of data arguments.
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format)
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format)
ABSL_BAD_CALL_IF(
substitute_internal::PlaceholderBitmask(format) != 0,
"There were no substitution arguments "
"but this format string either has a $[0-9] in it or contains "
"an unescaped $ character (use $$ instead)");
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format,
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format,
const substitute_internal::Arg& a0)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1,
"There was 1 substitution argument given, but "
@@ -415,8 +417,8 @@
"one of $1-$9, or contains an unescaped $ character (use "
"$$ instead)");
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format,
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1)
ABSL_BAD_CALL_IF(
@@ -425,8 +427,8 @@
"missing its $0/$1, contains one of $2-$9, or contains an "
"unescaped $ character (use $$ instead)");
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format,
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2)
@@ -436,8 +438,8 @@
"this format string is missing its $0/$1/$2, contains one of "
"$3-$9, or contains an unescaped $ character (use $$ instead)");
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format,
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2,
@@ -448,8 +450,8 @@
"this format string is missing its $0-$3, contains one of "
"$4-$9, or contains an unescaped $ character (use $$ instead)");
-void SubstituteAndAppend(absl::Nonnull<std::string*> output,
- absl::Nonnull<const char*> format,
+void SubstituteAndAppend(std::string* absl_nonnull output,
+ const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2,
@@ -462,7 +464,7 @@
"$5-$9, or contains an unescaped $ character (use $$ instead)");
void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
+ std::string* absl_nonnull output, const char* absl_nonnull format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5)
@@ -473,7 +475,7 @@
"$6-$9, or contains an unescaped $ character (use $$ instead)");
void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
+ std::string* absl_nonnull output, const char* absl_nonnull format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -485,7 +487,7 @@
"$7-$9, or contains an unescaped $ character (use $$ instead)");
void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
+ std::string* absl_nonnull output, const char* absl_nonnull format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -497,7 +499,7 @@
"$8-$9, or contains an unescaped $ character (use $$ instead)");
void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
+ std::string* absl_nonnull output, const char* absl_nonnull format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -510,7 +512,7 @@
"contains an unescaped $ character (use $$ instead)");
void SubstituteAndAppend(
- absl::Nonnull<std::string*> output, absl::Nonnull<const char*> format,
+ std::string* absl_nonnull output, const char* absl_nonnull format,
const substitute_internal::Arg& a0, const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2, const substitute_internal::Arg& a3,
const substitute_internal::Arg& a4, const substitute_internal::Arg& a5,
@@ -539,20 +541,20 @@
// void VarMsg(absl::string_view format, const Args&... args) {
// std::string s = absl::Substitute(format, args...);
-ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
+[[nodiscard]] inline std::string Substitute(absl::string_view format) {
std::string result;
SubstituteAndAppend(&result, format);
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0) {
std::string result;
SubstituteAndAppend(&result, format, a0);
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1) {
std::string result;
@@ -560,7 +562,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) {
std::string result;
@@ -568,7 +570,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3) {
@@ -577,7 +579,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) {
@@ -586,7 +588,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
@@ -596,7 +598,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
@@ -606,7 +608,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
@@ -617,7 +619,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
@@ -628,7 +630,7 @@
return result;
}
-ABSL_MUST_USE_RESULT inline std::string Substitute(
+[[nodiscard]] inline std::string Substitute(
absl::string_view format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
@@ -643,13 +645,13 @@
#if defined(ABSL_BAD_CALL_IF)
// This body of functions catches cases where the number of placeholders
// doesn't match the number of data arguments.
-std::string Substitute(absl::Nonnull<const char*> format)
+std::string Substitute(const char* absl_nonnull format)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0,
"There were no substitution arguments "
"but this format string either has a $[0-9] in it or "
"contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0)
ABSL_BAD_CALL_IF(
substitute_internal::PlaceholderBitmask(format) != 1,
@@ -657,7 +659,7 @@
"this format string is missing its $0, contains one of $1-$9, "
"or contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1)
ABSL_BAD_CALL_IF(
@@ -666,7 +668,7 @@
"this format string is missing its $0/$1, contains one of "
"$2-$9, or contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2)
@@ -676,7 +678,7 @@
"this format string is missing its $0/$1/$2, contains one of "
"$3-$9, or contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2,
@@ -687,7 +689,7 @@
"this format string is missing its $0-$3, contains one of "
"$4-$9, or contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2,
@@ -699,7 +701,7 @@
"this format string is missing its $0-$4, contains one of "
"$5-$9, or contains an unescaped $ character (use $$ instead)");
-std::string Substitute(absl::Nonnull<const char*> format,
+std::string Substitute(const char* absl_nonnull format,
const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1,
const substitute_internal::Arg& a2,
@@ -713,7 +715,7 @@
"$6-$9, or contains an unescaped $ character (use $$ instead)");
std::string Substitute(
- absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
+ const char* absl_nonnull format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
const substitute_internal::Arg& a5, const substitute_internal::Arg& a6)
@@ -724,7 +726,7 @@
"$7-$9, or contains an unescaped $ character (use $$ instead)");
std::string Substitute(
- absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
+ const char* absl_nonnull format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
@@ -736,7 +738,7 @@
"$8-$9, or contains an unescaped $ character (use $$ instead)");
std::string Substitute(
- absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
+ const char* absl_nonnull format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
@@ -748,7 +750,7 @@
"contains an unescaped $ character (use $$ instead)");
std::string Substitute(
- absl::Nonnull<const char*> format, const substitute_internal::Arg& a0,
+ const char* absl_nonnull format, const substitute_internal::Arg& a0,
const substitute_internal::Arg& a1, const substitute_internal::Arg& a2,
const substitute_internal::Arg& a3, const substitute_internal::Arg& a4,
const substitute_internal::Arg& a5, const substitute_internal::Arg& a6,
diff --git a/absl/strings/substitute_benchmark.cc b/absl/strings/substitute_benchmark.cc
new file mode 100644
index 0000000..e58ec86
--- /dev/null
+++ b/absl/strings/substitute_benchmark.cc
@@ -0,0 +1,158 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "absl/strings/str_cat.h"
+#include "absl/strings/substitute.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+void BM_Substitute(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result = absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", s,
+ s, s, s, s, s, s, s, s, s);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_Substitute)->Range(0, 1024);
+
+// Like BM_Substitute, but use char* strings (which must then be copied
+// to STL strings) for all parameters. This demonstrates that it is faster
+// to use absl::Substitute() even if your inputs are char* strings.
+void BM_SubstituteCstr(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result =
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", s.c_str(),
+ s.c_str(), s.c_str(), s.c_str(), s.c_str(), s.c_str(),
+ s.c_str(), s.c_str(), s.c_str(), s.c_str());
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_SubstituteCstr)->Range(0, 1024);
+
+// For comparison with BM_Substitute.
+void BM_StringPrintf(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result = absl::StrCat(s, " ", s, " ", s, " ", s, " ", s, " ", s,
+ " ", s, " ", s, " ", s, " ", s);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_StringPrintf)->Range(0, 1024);
+
+// Benchmark using absl::Substitute() together with SimpleItoa() to print
+// numbers. This demonstrates that absl::Substitute() is faster than
+// StringPrintf() even when the inputs are numbers.
+void BM_SubstituteNumber(benchmark::State& state) {
+ const int n = state.range(0);
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result =
+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $$", n, n + 1, n + 2,
+ n + 3, n + 4, n + 5, n + 6, n + 7, n + 8, n + 9);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_SubstituteNumber)->Arg(0)->Arg(1 << 20);
+
+// For comparison with BM_SubstituteNumber.
+void BM_StrCatNumber(benchmark::State& state) {
+ const int n = state.range(0);
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result =
+ absl::StrCat(n, " ", n + 1, " ", n + 2, " ", n + 3, " ", n + 4, " ",
+ n + 5, " ", n + 6, " ", n + 7, " ", n + 8, " ", n + 9);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_StrCatNumber)->Arg(0)->Arg(1 << 20);
+
+// Benchmark using absl::Substitute() with a single substitution, to test the
+// speed at which it copies simple text. Even in this case, it's faster
+// that StringPrintf().
+void BM_SubstituteSimpleText(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result = absl::Substitute("$0", s.c_str());
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_SubstituteSimpleText)->Range(0, 1024);
+
+// For comparison with BM_SubstituteSimpleText.
+void BM_StrCatSimpleText(benchmark::State& state) {
+ std::string s(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result = absl::StrCat("", s);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_StrCatSimpleText)->Range(0, 1024);
+
+std::string MakeFormatByDensity(int density, bool subs_mode) {
+ std::string format((2 + density) * 10, 'x');
+ for (size_t i = 0; i < 10; ++i) {
+ format[density * i] = subs_mode ? '$' : '%';
+ format[density * i + 1] = subs_mode ? ('0' + i) : 's';
+ }
+ return format;
+}
+
+void BM_SubstituteDensity(benchmark::State& state) {
+ const std::string s(10, 'x');
+ const std::string format = MakeFormatByDensity(state.range(0), true);
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result = absl::Substitute(format, s, s, s, s, s, s, s, s, s, s);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_SubstituteDensity)->Range(0, 256);
+
+void BM_StrCatDensity(benchmark::State& state) {
+ const std::string s(10, 'x');
+ const std::string format(state.range(0), 'x');
+ int64_t bytes = 0;
+ for (auto _ : state) {
+ std::string result =
+ absl::StrCat(s, format, s, format, s, format, s, format, s, format, s,
+ format, s, format, s, format, s, format, s, format);
+ bytes += result.size();
+ }
+ state.SetBytesProcessed(bytes);
+}
+BENCHMARK(BM_StrCatDensity)->Range(0, 256);
+
+} // namespace
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index dafeba3..920928e 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -85,8 +85,8 @@
"//absl/base:config",
"//absl/random",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -124,9 +124,9 @@
],
copts = ABSL_DEFAULT_COPTS,
linkopts = select({
- "//absl:msvc_compiler": [],
- "//absl:clang-cl_compiler": [],
- "//absl:wasm": [],
+ "@rules_cc//cc/compiler:msvc-cl": [],
+ "@rules_cc//cc/compiler:clang-cl": [],
+ "@rules_cc//cc/compiler:emscripten": [],
"//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:public"],
@@ -140,7 +140,9 @@
"//absl/base:core_headers",
"//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
+ "//absl/base:nullability",
"//absl/base:raw_logging_internal",
+ "//absl/base:tracing_internal",
"//absl/debugging:stacktrace",
"//absl/debugging:symbolize",
"//absl/time",
@@ -161,8 +163,8 @@
deps = [
":synchronization",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -177,9 +179,12 @@
],
deps = [
":synchronization",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:tracing_internal",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -194,7 +199,7 @@
":synchronization",
":thread_pool",
"//absl/base:no_destructor",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -209,8 +214,8 @@
"//absl/base:core_headers",
"//absl/log",
"//absl/log:check",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -225,8 +230,7 @@
deps = [
":graphcycles_internal",
"//absl/base:raw_logging_internal",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
+ "@google_benchmark//:benchmark_main",
],
)
@@ -262,9 +266,10 @@
"//absl/log",
"//absl/log:check",
"//absl/memory",
+ "//absl/random",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -276,8 +281,8 @@
deps = [
":synchronization",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -295,7 +300,7 @@
"//absl/base",
"//absl/base:config",
"//absl/base:no_destructor",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
alwayslink = 1,
)
@@ -320,9 +325,12 @@
tags = ["no_test_lexan"],
deps = [
":synchronization",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:tracing_internal",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -340,7 +348,7 @@
"//absl/base:config",
"//absl/strings",
"//absl/time",
- "@com_google_googletest//:gtest",
+ "@googletest//:gtest",
],
alwayslink = 1,
)
@@ -358,7 +366,7 @@
":synchronization",
"//absl/strings",
"//absl/time",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest_main",
],
)
@@ -375,8 +383,8 @@
"//absl/base:config",
"//absl/random",
"//absl/time",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index a0f64e5..9d4844d 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -109,10 +109,13 @@
absl::core_headers
absl::dynamic_annotations
absl::malloc_internal
+ absl::nullability
absl::raw_logging_internal
absl::stacktrace
absl::symbolize
+ absl::tracing_internal
absl::time
+ absl::tracing_internal
Threads::Threads
PUBLIC
)
@@ -140,6 +143,7 @@
DEPS
absl::synchronization
absl::time
+ absl::tracing_internal
GTest::gmock_main
)
@@ -189,6 +193,7 @@
absl::core_headers
absl::log
absl::memory
+ absl::random_random
absl::time
GTest::gmock_main
)
@@ -215,8 +220,12 @@
COPTS
${ABSL_TEST_COPTS}
DEPS
+ absl::base
+ absl::config
+ absl::core_headers
absl::synchronization
absl::time
+ absl::tracing_internal
GTest::gmock_main
)
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
index d2f82da..a530baf 100644
--- a/absl/synchronization/blocking_counter.cc
+++ b/absl/synchronization/blocking_counter.cc
@@ -17,6 +17,7 @@
#include <atomic>
#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/tracing.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -40,6 +41,7 @@
ABSL_RAW_CHECK(count >= 0,
"BlockingCounter::DecrementCount() called too many times");
if (count == 0) {
+ base_internal::TraceSignal(this, TraceObjectKind());
MutexLock l(&lock_);
done_ = true;
return true;
@@ -48,19 +50,23 @@
}
void BlockingCounter::Wait() {
- MutexLock l(&this->lock_);
+ base_internal::TraceWait(this, TraceObjectKind());
+ {
+ MutexLock l(&this->lock_);
- // only one thread may call Wait(). To support more than one thread,
- // implement a counter num_to_exit, like in the Barrier class.
- ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
- num_waiting_++;
+ // only one thread may call Wait(). To support more than one thread,
+ // implement a counter num_to_exit, like in the Barrier class.
+ ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()");
+ num_waiting_++;
- this->lock_.Await(Condition(IsDone, &this->done_));
+ this->lock_.Await(Condition(IsDone, &this->done_));
- // At this point, we know that all threads executing DecrementCount
- // will not touch this object again.
- // Therefore, the thread calling this method is free to delete the object
- // after we return from this method.
+ // At this point, we know that all threads executing DecrementCount
+ // will not touch this object again.
+ // Therefore, the thread calling this method is free to delete the object
+ // after we return from this method.
+ }
+ base_internal::TraceContinue(this, TraceObjectKind());
}
ABSL_NAMESPACE_END
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
index 1908fdb..d0504a1 100644
--- a/absl/synchronization/blocking_counter.h
+++ b/absl/synchronization/blocking_counter.h
@@ -22,6 +22,7 @@
#include <atomic>
+#include "absl/base/internal/tracing.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
@@ -89,6 +90,11 @@
void Wait();
private:
+ // Convenience helper to reduce verbosity at call sites.
+ static inline constexpr base_internal::ObjectKind TraceObjectKind() {
+ return base_internal::ObjectKind::kBlockingCounter;
+ }
+
Mutex lock_;
std::atomic<int> count_;
int num_waiting_ ABSL_GUARDED_BY(lock_);
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
index 06885f5..0c42b56 100644
--- a/absl/synchronization/blocking_counter_test.cc
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -15,9 +15,13 @@
#include "absl/synchronization/blocking_counter.h"
#include <thread> // NOLINT(build/c++11)
+#include <tuple>
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/tracing.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
@@ -76,5 +80,67 @@
#endif
} // namespace
+
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+
+namespace base_internal {
+
+namespace {
+
+using TraceRecord = std::tuple<const void*, ObjectKind>;
+
+thread_local TraceRecord tls_signal;
+thread_local TraceRecord tls_wait;
+thread_local TraceRecord tls_continue;
+
+} // namespace
+
+// Strong extern "C" implementation.
+extern "C" {
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
+ ObjectKind kind) {
+ tls_wait = {object, kind};
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
+ ObjectKind kind) {
+ tls_continue = {object, kind};
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
+ ObjectKind kind) {
+ tls_signal = {object, kind};
+}
+
+} // extern "C"
+
+TEST(BlockingCounterTest, TracesSignal) {
+ BlockingCounter counter(2);
+
+ tls_signal = {};
+ counter.DecrementCount();
+ EXPECT_EQ(tls_signal, TraceRecord(nullptr, ObjectKind::kUnknown));
+
+ tls_signal = {};
+ counter.DecrementCount();
+ EXPECT_EQ(tls_signal, TraceRecord(&counter, ObjectKind::kBlockingCounter));
+}
+
+TEST(BlockingCounterTest, TracesWaitContinue) {
+ BlockingCounter counter(1);
+ counter.DecrementCount();
+
+ tls_wait = {};
+ tls_continue = {};
+ counter.Wait();
+ EXPECT_EQ(tls_wait, TraceRecord(&counter, ObjectKind::kBlockingCounter));
+ EXPECT_EQ(tls_continue, TraceRecord(&counter, ObjectKind::kBlockingCounter));
+}
+
+} // namespace base_internal
+
+#endif // ABSL_HAVE_ATTRIBUTE_WEAK
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index eacaa28..93cd376 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -39,7 +39,8 @@
ABSL_CONST_INIT static base_internal::ThreadIdentity* thread_identity_freelist;
// A per-thread destructor for reclaiming associated ThreadIdentity objects.
-// Since we must preserve their storage we cache them for re-use.
+// Since we must preserve their storage, we cache them for re-use instead of
+// truly destructing the object.
static void ReclaimThreadIdentity(void* v) {
base_internal::ThreadIdentity* identity =
static_cast<base_internal::ThreadIdentity*>(v);
@@ -124,6 +125,9 @@
identity = reinterpret_cast<base_internal::ThreadIdentity*>(
RoundUp(reinterpret_cast<intptr_t>(allocation),
base_internal::PerThreadSynch::kAlignment));
+ // Note that *identity is never constructed.
+ // TODO(b/357097463): change this "one time init" to be a proper
+ // constructor.
OneTimeInitThreadIdentity(identity);
}
ResetThreadIdentityBetweenReuse(identity);
diff --git a/absl/synchronization/internal/futex_waiter.cc b/absl/synchronization/internal/futex_waiter.cc
index 87eb3b2..8945c17 100644
--- a/absl/synchronization/internal/futex_waiter.cc
+++ b/absl/synchronization/internal/futex_waiter.cc
@@ -31,10 +31,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr char FutexWaiter::kName[];
-#endif
-
int FutexWaiter::WaitUntil(std::atomic<int32_t>* v, int32_t val,
KernelTimeout t) {
#ifdef CLOCK_MONOTONIC
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc
index 54823e0..9012801 100644
--- a/absl/synchronization/internal/graphcycles_benchmark.cc
+++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/synchronization/internal/graphcycles.h"
-
#include <algorithm>
#include <cstdint>
#include <vector>
-#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/synchronization/internal/graphcycles.h"
+#include "benchmark/benchmark.h"
namespace {
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
index 47410aa..b7988c4 100644
--- a/absl/synchronization/internal/graphcycles_test.cc
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -15,6 +15,7 @@
#include "absl/synchronization/internal/graphcycles.h"
#include <climits>
+#include <cstdint>
#include <map>
#include <random>
#include <unordered_set>
@@ -461,20 +462,20 @@
TEST(GraphCycles, IntegerOverflow) {
GraphCycles graph_cycles;
- char *buf = (char *)nullptr;
- GraphId prev_id = graph_cycles.GetId(buf);
+ uintptr_t buf = 0;
+ GraphId prev_id = graph_cycles.GetId(reinterpret_cast<void*>(buf));
buf += 1;
- GraphId id = graph_cycles.GetId(buf);
+ GraphId id = graph_cycles.GetId(reinterpret_cast<void*>(buf));
ASSERT_TRUE(graph_cycles.InsertEdge(prev_id, id));
// INT_MAX / 40 is enough to cause an overflow when multiplied by 41.
graph_cycles.TestOnlyAddNodes(INT_MAX / 40);
buf += 1;
- GraphId newid = graph_cycles.GetId(buf);
+ GraphId newid = graph_cycles.GetId(reinterpret_cast<void*>(buf));
graph_cycles.HasEdge(prev_id, newid);
- graph_cycles.RemoveNode(buf);
+ graph_cycles.RemoveNode(reinterpret_cast<void*>(buf));
}
} // namespace synchronization_internal
diff --git a/absl/synchronization/internal/kernel_timeout.cc b/absl/synchronization/internal/kernel_timeout.cc
index 48ea628..252397a 100644
--- a/absl/synchronization/internal/kernel_timeout.cc
+++ b/absl/synchronization/internal/kernel_timeout.cc
@@ -35,11 +35,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr uint64_t KernelTimeout::kNoTimeout;
-constexpr int64_t KernelTimeout::kMaxNanos;
-#endif
-
int64_t KernelTimeout::SteadyClockNow() {
if (!SupportsSteadyClock()) {
return absl::GetCurrentTimeNanos();
diff --git a/absl/synchronization/internal/pthread_waiter.cc b/absl/synchronization/internal/pthread_waiter.cc
index bf700e9..eead9de 100644
--- a/absl/synchronization/internal/pthread_waiter.cc
+++ b/absl/synchronization/internal/pthread_waiter.cc
@@ -58,10 +58,6 @@
};
} // namespace
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr char PthreadWaiter::kName[];
-#endif
-
PthreadWaiter::PthreadWaiter() : waiter_count_(0), wakeup_count_(0) {
const int err = pthread_mutex_init(&mu_, 0);
if (err != 0) {
diff --git a/absl/synchronization/internal/sem_waiter.cc b/absl/synchronization/internal/sem_waiter.cc
index d62dbdc..2119290 100644
--- a/absl/synchronization/internal/sem_waiter.cc
+++ b/absl/synchronization/internal/sem_waiter.cc
@@ -33,10 +33,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr char SemWaiter::kName[];
-#endif
-
SemWaiter::SemWaiter() : wakeups_(0) {
if (sem_init(&sem_, 0, 0) != 0) {
ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno);
diff --git a/absl/synchronization/internal/stdcpp_waiter.cc b/absl/synchronization/internal/stdcpp_waiter.cc
index 355718a..607d683 100644
--- a/absl/synchronization/internal/stdcpp_waiter.cc
+++ b/absl/synchronization/internal/stdcpp_waiter.cc
@@ -30,10 +30,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr char StdcppWaiter::kName[];
-#endif
-
StdcppWaiter::StdcppWaiter() : waiter_count_(0), wakeup_count_(0) {}
bool StdcppWaiter::Wait(KernelTimeout t) {
diff --git a/absl/synchronization/internal/waiter_base.cc b/absl/synchronization/internal/waiter_base.cc
index 46928b4..e9797f8 100644
--- a/absl/synchronization/internal/waiter_base.cc
+++ b/absl/synchronization/internal/waiter_base.cc
@@ -21,10 +21,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr int WaiterBase::kIdlePeriods;
-#endif
-
void WaiterBase::MaybeBecomeIdle() {
base_internal::ThreadIdentity *identity =
base_internal::CurrentThreadIdentityIfPresent();
diff --git a/absl/synchronization/internal/waiter_test.cc b/absl/synchronization/internal/waiter_test.cc
index da13896..6e37415 100644
--- a/absl/synchronization/internal/waiter_test.cc
+++ b/absl/synchronization/internal/waiter_test.cc
@@ -108,7 +108,10 @@
absl::synchronization_internal::KernelTimeout(absl::Seconds(10))));
absl::Duration waited = absl::Now() - start;
EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
+#ifndef _MSC_VER
+ // Skip on MSVC due to flakiness.
EXPECT_LT(waited, absl::Seconds(2));
+#endif
}
TYPED_TEST_P(WaiterTest, WaitTimeWoken) {
diff --git a/absl/synchronization/internal/win32_waiter.cc b/absl/synchronization/internal/win32_waiter.cc
index bd95ff0..b2fe402 100644
--- a/absl/synchronization/internal/win32_waiter.cc
+++ b/absl/synchronization/internal/win32_waiter.cc
@@ -28,10 +28,6 @@
ABSL_NAMESPACE_BEGIN
namespace synchronization_internal {
-#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
-constexpr char Win32Waiter::kName[];
-#endif
-
class Win32Waiter::WinHelper {
public:
static SRWLOCK *GetLock(Win32Waiter *w) {
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index cb3c7e7..5091b8f 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -651,6 +651,13 @@
static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits
static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count
+static_assert((0xab & (kMuWriter | kMuReader)) == (kMuWriter | kMuReader),
+ "The debug allocator's uninitialized pattern (0xab) must be an "
+ "invalid mutex state");
+static_assert((0xcd & (kMuWriter | kMuReader)) == (kMuWriter | kMuReader),
+ "The debug allocator's freed pattern (0xcd) must be an invalid "
+ "mutex state");
+
// Hack to make constant values available to gdb pretty printer
enum {
kGdbMuSpin = kMuSpin,
@@ -1332,7 +1339,7 @@
} else {
snprintf(buf + len, count, " %p", pcs[i]);
}
- len += strlen(&buf[len]);
+ len += static_cast<int>(strlen(&buf[len]));
}
return buf;
}
@@ -1713,25 +1720,44 @@
// NOTE: optimized out when kDebugMode is false.
bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter &&
(v & (kMuWait | kMuDesig)) != kMuWait);
+
// But, we can use an alternate computation of it, that compilers
// currently don't find on their own. When that changes, this function
// can be simplified.
- intptr_t x = (v ^ (kMuWriter | kMuWait)) & (kMuWriter | kMuEvent);
- intptr_t y = (v ^ (kMuWriter | kMuWait)) & (kMuWait | kMuDesig);
- // Claim: "x == 0 && y > 0" is equal to should_try_cas.
- // Also, because kMuWriter and kMuEvent exceed kMuDesig and kMuWait,
- // all possible non-zero values for x exceed all possible values for y.
- // Therefore, (x == 0 && y > 0) == (x < y).
- if (kDebugMode && should_try_cas != (x < y)) {
+ //
+ // should_try_cas is true iff the bits satisfy the following conditions:
+ //
+ // Ev Wr Wa De
+ // equal to 0 1
+ // and not equal to 1 0
+ //
+ // after xoring by 0 1 0 1, this is equivalent to:
+ //
+ // equal to 0 0
+ // and not equal to 1 1, which is the same as:
+ //
+ // smaller than 0 0 1 1
+ static_assert(kMuEvent > kMuWait, "Needed for should_try_cas_fast");
+ static_assert(kMuEvent > kMuDesig, "Needed for should_try_cas_fast");
+ static_assert(kMuWriter > kMuWait, "Needed for should_try_cas_fast");
+ static_assert(kMuWriter > kMuDesig, "Needed for should_try_cas_fast");
+
+ bool should_try_cas_fast =
+ ((v ^ (kMuWriter | kMuDesig)) &
+ (kMuEvent | kMuWriter | kMuWait | kMuDesig)) < (kMuWait | kMuDesig);
+
+ if (kDebugMode && should_try_cas != should_try_cas_fast) {
// We would usually use PRIdPTR here, but is not correctly implemented
// within the android toolchain.
ABSL_RAW_LOG(FATAL, "internal logic error %llx %llx %llx\n",
- static_cast<long long>(v), static_cast<long long>(x),
- static_cast<long long>(y));
+ static_cast<long long>(v),
+ static_cast<long long>(should_try_cas),
+ static_cast<long long>(should_try_cas_fast));
}
- if (x < y && mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
- std::memory_order_release,
- std::memory_order_relaxed)) {
+ if (should_try_cas_fast &&
+ mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter),
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
// fast writer release (writer with no waiters or with designated waker)
} else {
this->UnlockSlow(nullptr /*no waitp*/); // take slow path
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index be3f1f5..78b1c7a 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -70,6 +70,7 @@
#include "absl/base/internal/low_level_alloc.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/base/internal/tsan_mutex_interface.h"
+#include "absl/base/nullability.h"
#include "absl/base/port.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/internal/kernel_timeout.h"
@@ -190,7 +191,7 @@
// If the mutex can be acquired without blocking, does so exclusively and
// returns `true`. Otherwise, returns `false`. Returns `true` with high
// probability if the `Mutex` was free.
- ABSL_MUST_USE_RESULT bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+ [[nodiscard]] bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
// Mutex::AssertHeld()
//
@@ -255,7 +256,7 @@
// If the mutex can be acquired without blocking, acquires this mutex for
// shared access and returns `true`. Otherwise, returns `false`. Returns
// `true` with high probability if the `Mutex` was free or shared.
- ABSL_MUST_USE_RESULT bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
+ [[nodiscard]] bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
// Mutex::AssertReaderHeld()
//
@@ -281,8 +282,7 @@
void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
- ABSL_MUST_USE_RESULT bool WriterTryLock()
- ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+ [[nodiscard]] bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return this->TryLock();
}
@@ -450,7 +450,9 @@
// substantially reduce `Mutex` performance; it should be set only for
// non-production runs. Optimization options may also disable invariant
// checks.
- void EnableInvariantDebugging(void (*invariant)(void*), void* arg);
+ void EnableInvariantDebugging(
+ void (*absl_nullable invariant)(void* absl_nullability_unknown),
+ void* absl_nullability_unknown arg);
// Mutex::EnableDebugLog()
//
@@ -459,7 +461,7 @@
// call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made.
//
// Note: This method substantially reduces `Mutex` performance.
- void EnableDebugLog(const char* name);
+ void EnableDebugLog(const char* absl_nullable name);
// Deadlock detection
@@ -509,20 +511,23 @@
// Post()/Wait() versus associated PerThreadSem; in class for required
// friendship with PerThreadSem.
- static void IncrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w);
- static bool DecrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w,
+ static void IncrementSynchSem(Mutex* absl_nonnull mu,
+ base_internal::PerThreadSynch* absl_nonnull w);
+ static bool DecrementSynchSem(Mutex* absl_nonnull mu,
+ base_internal::PerThreadSynch* absl_nonnull w,
synchronization_internal::KernelTimeout t);
// slow path acquire
- void LockSlowLoop(SynchWaitParams* waitp, int flags);
+ void LockSlowLoop(SynchWaitParams* absl_nonnull waitp, int flags);
// wrappers around LockSlowLoop()
- bool LockSlowWithDeadline(MuHow how, const Condition* cond,
+ bool LockSlowWithDeadline(MuHow absl_nonnull how,
+ const Condition* absl_nullable cond,
synchronization_internal::KernelTimeout t,
int flags);
- void LockSlow(MuHow how, const Condition* cond,
+ void LockSlow(MuHow absl_nonnull how, const Condition* absl_nullable cond,
int flags) ABSL_ATTRIBUTE_COLD;
// slow path release
- void UnlockSlow(SynchWaitParams* waitp) ABSL_ATTRIBUTE_COLD;
+ void UnlockSlow(SynchWaitParams* absl_nullable waitp) ABSL_ATTRIBUTE_COLD;
// TryLock slow path.
bool TryLockSlow();
// ReaderTryLock slow path.
@@ -533,20 +538,21 @@
bool LockWhenCommon(const Condition& cond,
synchronization_internal::KernelTimeout t, bool write);
// Attempt to remove thread s from queue.
- void TryRemove(base_internal::PerThreadSynch* s);
+ void TryRemove(base_internal::PerThreadSynch* absl_nonnull s);
// Block a thread on mutex.
- void Block(base_internal::PerThreadSynch* s);
+ void Block(base_internal::PerThreadSynch* absl_nonnull s);
// Wake a thread; return successor.
- base_internal::PerThreadSynch* Wakeup(base_internal::PerThreadSynch* w);
+ base_internal::PerThreadSynch* absl_nullable Wakeup(
+ base_internal::PerThreadSynch* absl_nonnull w);
void Dtor();
friend class CondVar; // for access to Trans()/Fer().
- void Trans(MuHow how); // used for CondVar->Mutex transfer
- void Fer(
- base_internal::PerThreadSynch* w); // used for CondVar->Mutex transfer
+ void Trans(MuHow absl_nonnull how); // used for CondVar->Mutex transfer
+ void Fer(base_internal::PerThreadSynch* absl_nonnull
+ w); // used for CondVar->Mutex transfer
// Catch the error of writing Mutex when intending MutexLock.
- explicit Mutex(const volatile Mutex* /*ignored*/) {}
+ explicit Mutex(const volatile Mutex* absl_nullable /*ignored*/) {}
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
@@ -581,14 +587,15 @@
// Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
// guaranteed to be locked when this object is constructed. Requires that
// `mu` be dereferenceable.
- explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
+ explicit MutexLock(Mutex* absl_nonnull mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ : mu_(mu) {
this->mu_->Lock();
}
// Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
// the above, the condition given by `cond` is also guaranteed to hold when
// this object is constructed.
- explicit MutexLock(Mutex* mu, const Condition& cond)
+ explicit MutexLock(Mutex* absl_nonnull mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
@@ -602,7 +609,7 @@
~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
private:
- Mutex* const mu_;
+ Mutex* absl_nonnull const mu_;
};
// ReaderMutexLock
@@ -611,11 +618,12 @@
// releases a shared lock on a `Mutex` via RAII.
class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
public:
- explicit ReaderMutexLock(Mutex* mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
+ explicit ReaderMutexLock(Mutex* absl_nonnull mu) ABSL_SHARED_LOCK_FUNCTION(mu)
+ : mu_(mu) {
mu->ReaderLock();
}
- explicit ReaderMutexLock(Mutex* mu, const Condition& cond)
+ explicit ReaderMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
ABSL_SHARED_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->ReaderLockWhen(cond);
@@ -629,7 +637,7 @@
~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
private:
- Mutex* const mu_;
+ Mutex* absl_nonnull const mu_;
};
// WriterMutexLock
@@ -638,12 +646,13 @@
// releases a write (exclusive) lock on a `Mutex` via RAII.
class ABSL_SCOPED_LOCKABLE WriterMutexLock {
public:
- explicit WriterMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ explicit WriterMutexLock(Mutex* absl_nonnull mu)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLock();
}
- explicit WriterMutexLock(Mutex* mu, const Condition& cond)
+ explicit WriterMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLockWhen(cond);
@@ -657,7 +666,7 @@
~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
private:
- Mutex* const mu_;
+ Mutex* absl_nonnull const mu_;
};
// -----------------------------------------------------------------------------
@@ -715,7 +724,8 @@
class Condition {
public:
// A Condition that returns the result of "(*func)(arg)"
- Condition(bool (*func)(void*), void* arg);
+ Condition(bool (*absl_nonnull func)(void* absl_nullability_unknown),
+ void* absl_nullability_unknown arg);
// Templated version for people who are averse to casts.
//
@@ -727,7 +737,8 @@
//
// See class comment for performance advice.
template <typename T>
- Condition(bool (*func)(T*), T* arg);
+ Condition(bool (*absl_nonnull func)(T* absl_nullability_unknown),
+ T* absl_nullability_unknown arg);
// Same as above, but allows for cases where `arg` comes from a pointer that
// is convertible to the function parameter type `T*` but not an exact match.
@@ -741,8 +752,10 @@
// a function template is passed as `func`. Also, the dummy `typename = void`
// template parameter exists just to work around a MSVC mangling bug.
template <typename T, typename = void>
- Condition(bool (*func)(T*),
- typename absl::internal::type_identity<T>::type* arg);
+ Condition(
+ bool (*absl_nonnull func)(T* absl_nullability_unknown),
+ typename absl::internal::type_identity<T>::type* absl_nullability_unknown
+ arg);
// Templated version for invoking a method that returns a `bool`.
//
@@ -753,16 +766,19 @@
// methods to come from base classes. A simpler signature like
// `Condition(T*, bool (T::*)())` does not suffice.
template <typename T>
- Condition(T* object,
- bool (absl::internal::type_identity<T>::type::*method)());
+ Condition(
+ T* absl_nonnull object,
+ bool (absl::internal::type_identity<T>::type::* absl_nonnull method)());
// Same as above, for const members
template <typename T>
- Condition(const T* object,
- bool (absl::internal::type_identity<T>::type::*method)() const);
+ Condition(
+ const T* absl_nonnull object,
+ bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()
+ const);
// A Condition that returns the value of `*cond`
- explicit Condition(const bool* cond);
+ explicit Condition(const bool* absl_nonnull cond);
// Templated version for invoking a functor that returns a `bool`.
// This approach accepts pointers to non-mutable lambdas, `std::function`,
@@ -791,7 +807,7 @@
// `bool operator() const`.
template <typename T, typename E = decltype(static_cast<bool (T::*)() const>(
&T::operator()))>
- explicit Condition(const T* obj)
+ explicit Condition(const T* absl_nonnull obj)
: Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
// A Condition that always returns `true`.
@@ -817,7 +833,8 @@
// Two `Condition` values are guaranteed equal if both their `func` and `arg`
// components are the same. A null pointer is equivalent to a `true`
// condition.
- static bool GuaranteedEqual(const Condition* a, const Condition* b);
+ static bool GuaranteedEqual(const Condition* absl_nullable a,
+ const Condition* absl_nullable b);
private:
// Sizing an allocation for a method pointer can be subtle. In the Itanium
@@ -842,17 +859,17 @@
#endif
// Function with which to evaluate callbacks and/or arguments.
- bool (*eval_)(const Condition*) = nullptr;
+ bool (*absl_nullable eval_)(const Condition* absl_nonnull) = nullptr;
// Either an argument for a function call or an object for a method call.
- void* arg_ = nullptr;
+ void* absl_nullable arg_ = nullptr;
// Various functions eval_ can point to:
- static bool CallVoidPtrFunction(const Condition*);
+ static bool CallVoidPtrFunction(const Condition* absl_nonnull c);
template <typename T>
- static bool CastAndCallFunction(const Condition* c);
+ static bool CastAndCallFunction(const Condition* absl_nonnull c);
template <typename T, typename ConditionMethodPtr>
- static bool CastAndCallMethod(const Condition* c);
+ static bool CastAndCallMethod(const Condition* absl_nonnull c);
// Helper methods for storing, validating, and reading callback arguments.
template <typename T>
@@ -864,11 +881,11 @@
}
template <typename T>
- inline void ReadCallback(T* callback) const {
+ inline void ReadCallback(T* absl_nonnull callback) const {
std::memcpy(callback, callback_, sizeof(*callback));
}
- static bool AlwaysTrue(const Condition*) { return true; }
+ static bool AlwaysTrue(const Condition* absl_nullable) { return true; }
// Used only to create kTrue.
constexpr Condition() : eval_(AlwaysTrue), arg_(nullptr) {}
@@ -922,7 +939,7 @@
// spurious wakeup), then reacquires the `Mutex` and returns.
//
// Requires and ensures that the current thread holds the `Mutex`.
- void Wait(Mutex* mu) {
+ void Wait(Mutex* absl_nonnull mu) {
WaitCommon(mu, synchronization_internal::KernelTimeout::Never());
}
@@ -939,7 +956,7 @@
// to return `true` or `false`.
//
// Requires and ensures that the current thread holds the `Mutex`.
- bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
+ bool WaitWithTimeout(Mutex* absl_nonnull mu, absl::Duration timeout) {
return WaitCommon(mu, synchronization_internal::KernelTimeout(timeout));
}
@@ -958,7 +975,7 @@
// to return `true` or `false`.
//
// Requires and ensures that the current thread holds the `Mutex`.
- bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
+ bool WaitWithDeadline(Mutex* absl_nonnull mu, absl::Time deadline) {
return WaitCommon(mu, synchronization_internal::KernelTimeout(deadline));
}
@@ -977,11 +994,12 @@
// Causes all subsequent uses of this `CondVar` to be logged via
// `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`.
// Note: this method substantially reduces `CondVar` performance.
- void EnableDebugLog(const char* name);
+ void EnableDebugLog(const char* absl_nullable name);
private:
- bool WaitCommon(Mutex* mutex, synchronization_internal::KernelTimeout t);
- void Remove(base_internal::PerThreadSynch* s);
+ bool WaitCommon(Mutex* absl_nonnull mutex,
+ synchronization_internal::KernelTimeout t);
+ void Remove(base_internal::PerThreadSynch* absl_nonnull s);
std::atomic<intptr_t> cv_; // Condition variable state.
CondVar(const CondVar&) = delete;
CondVar& operator=(const CondVar&) = delete;
@@ -997,14 +1015,15 @@
// MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
public:
- explicit MutexLockMaybe(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ explicit MutexLockMaybe(Mutex* absl_nullable mu)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
this->mu_->Lock();
}
}
- explicit MutexLockMaybe(Mutex* mu, const Condition& cond)
+ explicit MutexLockMaybe(Mutex* absl_nullable mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
@@ -1019,7 +1038,7 @@
}
private:
- Mutex* const mu_;
+ Mutex* absl_nullable const mu_;
MutexLockMaybe(const MutexLockMaybe&) = delete;
MutexLockMaybe(MutexLockMaybe&&) = delete;
MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
@@ -1032,12 +1051,13 @@
// mutex before destruction. `Release()` may be called at most once.
class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
public:
- explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
+ explicit ReleasableMutexLock(Mutex* absl_nonnull mu)
+ ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->Lock();
}
- explicit ReleasableMutexLock(Mutex* mu, const Condition& cond)
+ explicit ReleasableMutexLock(Mutex* absl_nonnull mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
@@ -1052,7 +1072,7 @@
void Release() ABSL_UNLOCK_FUNCTION();
private:
- Mutex* mu_;
+ Mutex* absl_nonnull mu_;
ReleasableMutexLock(const ReleasableMutexLock&) = delete;
ReleasableMutexLock(ReleasableMutexLock&&) = delete;
ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
@@ -1084,7 +1104,7 @@
// static
template <typename T, typename ConditionMethodPtr>
-bool Condition::CastAndCallMethod(const Condition* c) {
+bool Condition::CastAndCallMethod(const Condition* absl_nonnull c) {
T* object = static_cast<T*>(c->arg_);
ConditionMethodPtr condition_method_pointer;
c->ReadCallback(&condition_method_pointer);
@@ -1093,7 +1113,7 @@
// static
template <typename T>
-bool Condition::CastAndCallFunction(const Condition* c) {
+bool Condition::CastAndCallFunction(const Condition* absl_nonnull c) {
bool (*function)(T*);
c->ReadCallback(&function);
T* argument = static_cast<T*>(c->arg_);
@@ -1101,7 +1121,9 @@
}
template <typename T>
-inline Condition::Condition(bool (*func)(T*), T* arg)
+inline Condition::Condition(
+ bool (*absl_nonnull func)(T* absl_nullability_unknown),
+ T* absl_nullability_unknown arg)
: eval_(&CastAndCallFunction<T>),
arg_(const_cast<void*>(static_cast<const void*>(arg))) {
static_assert(sizeof(&func) <= sizeof(callback_),
@@ -1111,13 +1133,16 @@
template <typename T, typename>
inline Condition::Condition(
- bool (*func)(T*), typename absl::internal::type_identity<T>::type* arg)
+ bool (*absl_nonnull func)(T* absl_nullability_unknown),
+ typename absl::internal::type_identity<T>::type* absl_nullability_unknown
+ arg)
// Just delegate to the overload above.
: Condition(func, arg) {}
template <typename T>
inline Condition::Condition(
- T* object, bool (absl::internal::type_identity<T>::type::*method)())
+ T* absl_nonnull object,
+ bool (absl::internal::type_identity<T>::type::* absl_nonnull method)())
: eval_(&CastAndCallMethod<T, decltype(method)>), arg_(object) {
static_assert(sizeof(&method) <= sizeof(callback_),
"An overlarge method pointer was passed to Condition.");
@@ -1126,8 +1151,9 @@
template <typename T>
inline Condition::Condition(
- const T* object,
- bool (absl::internal::type_identity<T>::type::*method)() const)
+ const T* absl_nonnull object,
+ bool (absl::internal::type_identity<T>::type::* absl_nonnull method)()
+ const)
: eval_(&CastAndCallMethod<const T, decltype(method)>),
arg_(reinterpret_cast<void*>(const_cast<T*>(object))) {
StoreCallback(method);
@@ -1145,7 +1171,7 @@
// binary; if this function is called a second time with a different function
// pointer, the value is ignored (and will cause an assertion failure in debug
// mode.)
-void RegisterMutexProfiler(void (*fn)(int64_t wait_cycles));
+void RegisterMutexProfiler(void (*absl_nonnull fn)(int64_t wait_cycles));
// Register a hook for Mutex tracing.
//
@@ -1159,8 +1185,9 @@
//
// This has the same ordering and single-use limitations as
// RegisterMutexProfiler() above.
-void RegisterMutexTracer(void (*fn)(const char* msg, const void* obj,
- int64_t wait_cycles));
+void RegisterMutexTracer(void (*absl_nonnull fn)(const char* absl_nonnull msg,
+ const void* absl_nonnull obj,
+ int64_t wait_cycles));
// Register a hook for CondVar tracing.
//
@@ -1174,7 +1201,8 @@
//
// This has the same ordering and single-use limitations as
// RegisterMutexProfiler() above.
-void RegisterCondVarTracer(void (*fn)(const char* msg, const void* cv));
+void RegisterCondVarTracer(void (*absl_nonnull fn)(
+ const char* absl_nonnull msg, const void* absl_nonnull cv));
// EnableMutexInvariantDebugging()
//
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index bb93abc..a3eb3db 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -36,6 +36,7 @@
#include "absl/log/check.h"
#include "absl/log/log.h"
#include "absl/memory/memory.h"
+#include "absl/random/random.h"
#include "absl/synchronization/internal/create_thread_identity.h"
#include "absl/synchronization/internal/thread_pool.h"
#include "absl/time/clock.h"
@@ -1064,8 +1065,7 @@
static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv,
int *running) {
- std::random_device dev;
- std::mt19937 gen(dev());
+ absl::InsecureBitGen gen;
std::uniform_int_distribution<int> random_millis(0, 15);
mu->ReaderLock();
while (*running == 3) {
@@ -1357,7 +1357,7 @@
// Returns true if `actual_delay` is close enough to `expected_delay` to pass
// the timeouts/deadlines test. Otherwise, logs warnings and returns false.
-ABSL_MUST_USE_RESULT
+[[nodiscard]]
static bool DelayIsWithinBounds(absl::Duration expected_delay,
absl::Duration actual_delay) {
bool pass = true;
@@ -1725,7 +1725,7 @@
TEST(Mutex, LoggingAddressReuse) {
// Repeatedly re-create a Mutex with debug logging at the same address.
ScopedInvariantDebugging scoped_debugging;
- alignas(absl::Mutex) char storage[sizeof(absl::Mutex)];
+ alignas(absl::Mutex) unsigned char storage[sizeof(absl::Mutex)];
auto invariant =
+[](void *alive) { EXPECT_TRUE(*static_cast<bool *>(alive)); };
constexpr size_t kIters = 10;
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index 165ba66..a5853ab 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -17,6 +17,7 @@
#include <atomic>
#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
@@ -24,6 +25,7 @@
ABSL_NAMESPACE_BEGIN
void Notification::Notify() {
+ base_internal::TraceSignal(this, TraceObjectKind());
MutexLock l(&this->mutex_);
#ifndef NDEBUG
@@ -45,31 +47,37 @@
}
void Notification::WaitForNotification() const {
+ base_internal::TraceWait(this, TraceObjectKind());
if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
- this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
- &this->notified_yet_));
+ this->mutex_.LockWhen(
+ Condition(&HasBeenNotifiedInternal, &this->notified_yet_));
this->mutex_.Unlock();
}
+ base_internal::TraceContinue(this, TraceObjectKind());
}
bool Notification::WaitForNotificationWithTimeout(
absl::Duration timeout) const {
+ base_internal::TraceWait(this, TraceObjectKind());
bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
if (!notified) {
notified = this->mutex_.LockWhenWithTimeout(
Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout);
this->mutex_.Unlock();
}
+ base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
return notified;
}
bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
+ base_internal::TraceWait(this, TraceObjectKind());
bool notified = HasBeenNotifiedInternal(&this->notified_yet_);
if (!notified) {
notified = this->mutex_.LockWhenWithDeadline(
Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline);
this->mutex_.Unlock();
}
+ base_internal::TraceContinue(notified ? this : nullptr, TraceObjectKind());
return notified;
}
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 8986d9a..1ceffdb 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -53,6 +53,7 @@
#include <atomic>
#include "absl/base/attributes.h"
+#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/time.h"
@@ -74,8 +75,12 @@
// Notification::HasBeenNotified()
//
// Returns the value of the notification's internal "notified" state.
- ABSL_MUST_USE_RESULT bool HasBeenNotified() const {
- return HasBeenNotifiedInternal(&this->notified_yet_);
+ [[nodiscard]] bool HasBeenNotified() const {
+ if (HasBeenNotifiedInternal(&this->notified_yet_)) {
+ base_internal::TraceObserved(this, TraceObjectKind());
+ return true;
+ }
+ return false;
}
// Notification::WaitForNotification()
@@ -108,6 +113,11 @@
void Notify();
private:
+ // Convenience helper to reduce verbosity at call sites.
+ static inline constexpr base_internal::ObjectKind TraceObjectKind() {
+ return base_internal::ObjectKind::kNotification;
+ }
+
static inline bool HasBeenNotifiedInternal(
const std::atomic<bool>* notified_yet) {
return notified_yet->load(std::memory_order_acquire);
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
index 49ce61a..eedad17 100644
--- a/absl/synchronization/notification_test.cc
+++ b/absl/synchronization/notification_test.cc
@@ -15,10 +15,15 @@
#include "absl/synchronization/notification.h"
#include <thread> // NOLINT(build/c++11)
+#include <tuple>
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/config.h"
+#include "absl/base/internal/tracing.h"
#include "absl/synchronization/mutex.h"
+#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -79,7 +84,11 @@
// Allow for a slight early return, to account for quality of implementation
// issues on various platforms.
- const absl::Duration slop = absl::Milliseconds(5);
+ absl::Duration slop = absl::Milliseconds(5);
+#ifdef _MSC_VER
+ // Avoid flakiness on MSVC.
+ slop = absl::Milliseconds(15);
+#endif
EXPECT_LE(delay - slop, elapsed)
<< "WaitForNotificationWithTimeout returned " << delay - elapsed
<< " early (with " << slop << " slop), start time was " << start;
@@ -129,5 +138,93 @@
BasicTests(true, &local_notification2);
}
+#if ABSL_HAVE_ATTRIBUTE_WEAK
+
+namespace base_internal {
+
+namespace {
+
+using TraceRecord = std::tuple<const void*, ObjectKind>;
+
+thread_local TraceRecord tls_signal;
+thread_local TraceRecord tls_wait;
+thread_local TraceRecord tls_continue;
+thread_local TraceRecord tls_observed;
+
+} // namespace
+
+// Strong extern "C" implementation.
+extern "C" {
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceWait)(const void* object,
+ ObjectKind kind) {
+ tls_wait = {object, kind};
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceContinue)(const void* object,
+ ObjectKind kind) {
+ tls_continue = {object, kind};
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceSignal)(const void* object,
+ ObjectKind kind) {
+ tls_signal = {object, kind};
+}
+
+void ABSL_INTERNAL_C_SYMBOL(AbslInternalTraceObserved)(const void* object,
+ ObjectKind kind) {
+ tls_observed = {object, kind};
+}
+
+} // extern "C"
+
+TEST(NotificationTest, TracesNotify) {
+ Notification n;
+ tls_signal = {};
+ n.Notify();
+ EXPECT_EQ(tls_signal, TraceRecord(&n, ObjectKind::kNotification));
+}
+
+TEST(NotificationTest, TracesWaitForNotification) {
+ Notification n;
+ n.Notify();
+ tls_wait = tls_continue = {};
+ n.WaitForNotification();
+ EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
+ EXPECT_EQ(tls_continue, TraceRecord(&n, ObjectKind::kNotification));
+}
+
+TEST(NotificationTest, TracesWaitForNotificationWithTimeout) {
+ Notification n;
+
+ tls_wait = tls_continue = {};
+ n.WaitForNotificationWithTimeout(absl::Milliseconds(1));
+ EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
+ EXPECT_EQ(tls_continue, TraceRecord(nullptr, ObjectKind::kNotification));
+
+ n.Notify();
+ tls_wait = tls_continue = {};
+ n.WaitForNotificationWithTimeout(absl::Milliseconds(1));
+ EXPECT_EQ(tls_wait, TraceRecord(&n, ObjectKind::kNotification));
+ EXPECT_EQ(tls_continue, TraceRecord(&n, ObjectKind::kNotification));
+}
+
+TEST(NotificationTest, TracesHasBeenNotified) {
+ Notification n;
+
+ tls_observed = {};
+ ASSERT_FALSE(n.HasBeenNotified());
+ EXPECT_EQ(tls_observed, TraceRecord(nullptr, ObjectKind::kUnknown));
+
+ n.Notify();
+ tls_observed = {};
+ ASSERT_TRUE(n.HasBeenNotified());
+ EXPECT_EQ(tls_observed, TraceRecord(&n, ObjectKind::kNotification));
+}
+
+} // namespace base_internal
+
+#endif // ABSL_HAVE_ATTRIBUTE_WEAK
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index 05f1f2f..ad0313c 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -57,6 +57,7 @@
"//absl/base:raw_logging_internal",
"//absl/numeric:int128",
"//absl/strings",
+ "//absl/strings:string_view",
"//absl/time/internal/cctz:civil_time",
"//absl/time/internal/cctz:time_zone",
"//absl/types:optional",
@@ -90,18 +91,19 @@
],
copts = ABSL_TEST_COPTS,
data = ["//absl/time/internal/cctz:zoneinfo"],
- env = {"TZDIR": "absl/time/internal/cctz/testdata/zoneinfo"},
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":test_util",
":time",
"//absl/base:config",
"//absl/base:core_headers",
+ "//absl/hash:hash_testing",
"//absl/numeric:int128",
+ "//absl/random",
"//absl/strings:str_format",
"//absl/time/internal/cctz:time_zone",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -125,13 +127,14 @@
":time",
"//absl/flags:flag",
"//absl/flags:reflection",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
-cc_test(
+cc_binary(
name = "time_benchmark",
+ testonly = True,
srcs = [
"civil_time_benchmark.cc",
"clock_benchmark.cc",
@@ -141,7 +144,6 @@
],
copts = ABSL_TEST_COPTS,
data = ["//absl/time/internal/cctz:zoneinfo"],
- env = {"TZDIR": "absl/time/internal/cctz/testdata/zoneinfo"},
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"benchmark",
@@ -153,6 +155,6 @@
"//absl/base:core_headers",
"//absl/flags:flag",
"//absl/hash",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index fe625f2..ea91ba3 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -49,7 +49,7 @@
"internal/cctz/include/cctz/civil_time.h"
"internal/cctz/include/cctz/civil_time_detail.h"
SRCS
- "internal/cctz/src/civil_time_detail.cc"
+ "internal/cctz/src/civil_time_detail.cc"
COPTS
${ABSL_DEFAULT_COPTS}
)
@@ -121,6 +121,8 @@
absl::time
absl::config
absl::core_headers
+ absl::hash_testing
+ absl::random_random
absl::strings
absl::str_format
absl::time_zone
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc
index 65df39d..1773366 100644
--- a/absl/time/civil_time.cc
+++ b/absl/time/civil_time.cc
@@ -14,6 +14,7 @@
#include "absl/time/civil_time.h"
+#include <cerrno>
#include <cstdlib>
#include <ostream>
#include <string>
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
index 19292a9..6e5c35d 100644
--- a/absl/time/civil_time_test.cc
+++ b/absl/time/civil_time_test.cc
@@ -21,6 +21,7 @@
#include "gtest/gtest.h"
#include "absl/base/macros.h"
+#include "absl/hash/hash_testing.h"
#include "absl/strings/str_format.h"
namespace {
@@ -1259,4 +1260,137 @@
}
}
+TEST(CivilTime, SupportsHash) {
+ // To check that every field is used by the hash implementation, test
+ // with values that have all fields the same bar one, for each field.
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilYear(2017),
+ absl::CivilYear(2018),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilMonth(2017, 1),
+ absl::CivilMonth(2017, 2),
+ absl::CivilMonth(2018, 1),
+ absl::CivilMonth(2018, 2),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilDay(2017, 1, 1),
+ absl::CivilDay(2017, 1, 2),
+ absl::CivilDay(2017, 2, 1),
+ absl::CivilDay(2017, 2, 2),
+ absl::CivilDay(2018, 1, 1),
+ absl::CivilDay(2018, 1, 2),
+ absl::CivilDay(2018, 2, 1),
+ absl::CivilDay(2018, 2, 2),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilHour(2017, 1, 1, 0),
+ absl::CivilHour(2017, 1, 1, 1),
+ absl::CivilHour(2017, 1, 2, 0),
+ absl::CivilHour(2017, 1, 2, 1),
+ absl::CivilHour(2017, 2, 1, 0),
+ absl::CivilHour(2017, 2, 1, 1),
+ absl::CivilHour(2017, 2, 2, 0),
+ absl::CivilHour(2017, 2, 2, 1),
+ absl::CivilHour(2018, 1, 1, 0),
+ absl::CivilHour(2018, 1, 1, 1),
+ absl::CivilHour(2018, 1, 2, 0),
+ absl::CivilHour(2018, 1, 2, 1),
+ absl::CivilHour(2018, 2, 1, 0),
+ absl::CivilHour(2018, 2, 1, 1),
+ absl::CivilHour(2018, 2, 2, 0),
+ absl::CivilHour(2018, 2, 2, 1),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilMinute(2017, 1, 1, 0, 0), absl::CivilMinute(2017, 1, 1, 0, 1),
+ absl::CivilMinute(2017, 1, 1, 1, 0), absl::CivilMinute(2017, 1, 1, 1, 1),
+ absl::CivilMinute(2017, 1, 2, 0, 0), absl::CivilMinute(2017, 1, 2, 0, 1),
+ absl::CivilMinute(2017, 1, 2, 1, 0), absl::CivilMinute(2017, 1, 2, 1, 1),
+ absl::CivilMinute(2017, 2, 1, 0, 0), absl::CivilMinute(2017, 2, 1, 0, 1),
+ absl::CivilMinute(2017, 2, 1, 1, 0), absl::CivilMinute(2017, 2, 1, 1, 1),
+ absl::CivilMinute(2017, 2, 2, 0, 0), absl::CivilMinute(2017, 2, 2, 0, 1),
+ absl::CivilMinute(2017, 2, 2, 1, 0), absl::CivilMinute(2017, 2, 2, 1, 1),
+ absl::CivilMinute(2018, 1, 1, 0, 0), absl::CivilMinute(2018, 1, 1, 0, 1),
+ absl::CivilMinute(2018, 1, 1, 1, 0), absl::CivilMinute(2018, 1, 1, 1, 1),
+ absl::CivilMinute(2018, 1, 2, 0, 0), absl::CivilMinute(2018, 1, 2, 0, 1),
+ absl::CivilMinute(2018, 1, 2, 1, 0), absl::CivilMinute(2018, 1, 2, 1, 1),
+ absl::CivilMinute(2018, 2, 1, 0, 0), absl::CivilMinute(2018, 2, 1, 0, 1),
+ absl::CivilMinute(2018, 2, 1, 1, 0), absl::CivilMinute(2018, 2, 1, 1, 1),
+ absl::CivilMinute(2018, 2, 2, 0, 0), absl::CivilMinute(2018, 2, 2, 0, 1),
+ absl::CivilMinute(2018, 2, 2, 1, 0), absl::CivilMinute(2018, 2, 2, 1, 1),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::CivilSecond(2017, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2017, 1, 1, 0, 0, 1),
+ absl::CivilSecond(2017, 1, 1, 0, 1, 0),
+ absl::CivilSecond(2017, 1, 1, 0, 1, 1),
+ absl::CivilSecond(2017, 1, 1, 1, 0, 0),
+ absl::CivilSecond(2017, 1, 1, 1, 0, 1),
+ absl::CivilSecond(2017, 1, 1, 1, 1, 0),
+ absl::CivilSecond(2017, 1, 1, 1, 1, 1),
+ absl::CivilSecond(2017, 1, 2, 0, 0, 0),
+ absl::CivilSecond(2017, 1, 2, 0, 0, 1),
+ absl::CivilSecond(2017, 1, 2, 0, 1, 0),
+ absl::CivilSecond(2017, 1, 2, 0, 1, 1),
+ absl::CivilSecond(2017, 1, 2, 1, 0, 0),
+ absl::CivilSecond(2017, 1, 2, 1, 0, 1),
+ absl::CivilSecond(2017, 1, 2, 1, 1, 0),
+ absl::CivilSecond(2017, 1, 2, 1, 1, 1),
+ absl::CivilSecond(2017, 2, 1, 0, 0, 0),
+ absl::CivilSecond(2017, 2, 1, 0, 0, 1),
+ absl::CivilSecond(2017, 2, 1, 0, 1, 0),
+ absl::CivilSecond(2017, 2, 1, 0, 1, 1),
+ absl::CivilSecond(2017, 2, 1, 1, 0, 0),
+ absl::CivilSecond(2017, 2, 1, 1, 0, 1),
+ absl::CivilSecond(2017, 2, 1, 1, 1, 0),
+ absl::CivilSecond(2017, 2, 1, 1, 1, 1),
+ absl::CivilSecond(2017, 2, 2, 0, 0, 0),
+ absl::CivilSecond(2017, 2, 2, 0, 0, 1),
+ absl::CivilSecond(2017, 2, 2, 0, 1, 0),
+ absl::CivilSecond(2017, 2, 2, 0, 1, 1),
+ absl::CivilSecond(2017, 2, 2, 1, 0, 0),
+ absl::CivilSecond(2017, 2, 2, 1, 0, 1),
+ absl::CivilSecond(2017, 2, 2, 1, 1, 0),
+ absl::CivilSecond(2017, 2, 2, 1, 1, 1),
+ absl::CivilSecond(2018, 1, 1, 0, 0, 0),
+ absl::CivilSecond(2018, 1, 1, 0, 0, 1),
+ absl::CivilSecond(2018, 1, 1, 0, 1, 0),
+ absl::CivilSecond(2018, 1, 1, 0, 1, 1),
+ absl::CivilSecond(2018, 1, 1, 1, 0, 0),
+ absl::CivilSecond(2018, 1, 1, 1, 0, 1),
+ absl::CivilSecond(2018, 1, 1, 1, 1, 0),
+ absl::CivilSecond(2018, 1, 1, 1, 1, 1),
+ absl::CivilSecond(2018, 1, 2, 0, 0, 0),
+ absl::CivilSecond(2018, 1, 2, 0, 0, 1),
+ absl::CivilSecond(2018, 1, 2, 0, 1, 0),
+ absl::CivilSecond(2018, 1, 2, 0, 1, 1),
+ absl::CivilSecond(2018, 1, 2, 1, 0, 0),
+ absl::CivilSecond(2018, 1, 2, 1, 0, 1),
+ absl::CivilSecond(2018, 1, 2, 1, 1, 0),
+ absl::CivilSecond(2018, 1, 2, 1, 1, 1),
+ absl::CivilSecond(2018, 2, 1, 0, 0, 0),
+ absl::CivilSecond(2018, 2, 1, 0, 0, 1),
+ absl::CivilSecond(2018, 2, 1, 0, 1, 0),
+ absl::CivilSecond(2018, 2, 1, 0, 1, 1),
+ absl::CivilSecond(2018, 2, 1, 1, 0, 0),
+ absl::CivilSecond(2018, 2, 1, 1, 0, 1),
+ absl::CivilSecond(2018, 2, 1, 1, 1, 0),
+ absl::CivilSecond(2018, 2, 1, 1, 1, 1),
+ absl::CivilSecond(2018, 2, 2, 0, 0, 0),
+ absl::CivilSecond(2018, 2, 2, 0, 0, 1),
+ absl::CivilSecond(2018, 2, 2, 0, 1, 0),
+ absl::CivilSecond(2018, 2, 2, 0, 1, 1),
+ absl::CivilSecond(2018, 2, 2, 1, 0, 0),
+ absl::CivilSecond(2018, 2, 2, 1, 0, 1),
+ absl::CivilSecond(2018, 2, 2, 1, 1, 0),
+ absl::CivilSecond(2018, 2, 2, 1, 1, 1),
+ }));
+}
+
} // namespace
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 8d0b66f..38c4b63 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -202,7 +202,8 @@
*d = -InfiniteDuration();
return false;
}
- *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
+ *d = time_internal::MakeDuration(static_cast<int64_t>(c),
+ time_internal::GetRepLo(*d));
return true;
}
@@ -239,8 +240,8 @@
template <template <typename> class Operation>
inline Duration ScaleDouble(Duration d, double r) {
Operation<double> op;
- double hi_doub = op(time_internal::GetRepHi(d), r);
- double lo_doub = op(time_internal::GetRepLo(d), r);
+ double hi_doub = op(static_cast<double>(time_internal::GetRepHi(d)), r);
+ double lo_doub = op(static_cast<double>(time_internal::GetRepLo(d)), r);
double hi_int = 0;
double hi_frac = std::modf(hi_doub, &hi_int);
@@ -253,12 +254,15 @@
double lo_frac = std::modf(lo_doub, &lo_int);
// Rolls lo into hi if necessary.
- int64_t lo64 = std::round(lo_frac * kTicksPerSecond);
+ int64_t lo64 = static_cast<int64_t>(std::round(lo_frac * kTicksPerSecond));
Duration ans;
if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
int64_t hi64 = time_internal::GetRepHi(ans);
- if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
+ if (!SafeAddRepHi(static_cast<double>(hi64),
+ static_cast<double>(lo64 / kTicksPerSecond), &ans)) {
+ return ans;
+ }
hi64 = time_internal::GetRepHi(ans);
lo64 %= kTicksPerSecond;
NormalizeTicks(&hi64, &lo64);
@@ -549,50 +553,6 @@
//
// Conversion to other duration types.
//
-
-int64_t ToInt64Nanoseconds(Duration d) {
- if (time_internal::GetRepHi(d) >= 0 &&
- time_internal::GetRepHi(d) >> 33 == 0) {
- return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
- (time_internal::GetRepLo(d) / kTicksPerNanosecond);
- }
- return d / Nanoseconds(1);
-}
-int64_t ToInt64Microseconds(Duration d) {
- if (time_internal::GetRepHi(d) >= 0 &&
- time_internal::GetRepHi(d) >> 43 == 0) {
- return (time_internal::GetRepHi(d) * 1000 * 1000) +
- (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
- }
- return d / Microseconds(1);
-}
-int64_t ToInt64Milliseconds(Duration d) {
- if (time_internal::GetRepHi(d) >= 0 &&
- time_internal::GetRepHi(d) >> 53 == 0) {
- return (time_internal::GetRepHi(d) * 1000) +
- (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
- }
- return d / Milliseconds(1);
-}
-int64_t ToInt64Seconds(Duration d) {
- int64_t hi = time_internal::GetRepHi(d);
- if (time_internal::IsInfiniteDuration(d)) return hi;
- if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
- return hi;
-}
-int64_t ToInt64Minutes(Duration d) {
- int64_t hi = time_internal::GetRepHi(d);
- if (time_internal::IsInfiniteDuration(d)) return hi;
- if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
- return hi / 60;
-}
-int64_t ToInt64Hours(Duration d) {
- int64_t hi = time_internal::GetRepHi(d);
- if (time_internal::IsInfiniteDuration(d)) return hi;
- if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
- return hi / (60 * 60);
-}
-
double ToDoubleNanoseconds(Duration d) {
return FDivDuration(d, Nanoseconds(1));
}
@@ -718,13 +678,12 @@
int prec;
double pow10;
};
-ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
-ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
-ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
-ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
-ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
-ABSL_CONST_INIT const DisplayUnit kDisplayHour = {"h", -1,
- 0.0}; // prec ignored
+constexpr DisplayUnit kDisplayNano = {"ns", 2, 1e2};
+constexpr DisplayUnit kDisplayMicro = {"us", 5, 1e5};
+constexpr DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
+constexpr DisplayUnit kDisplaySec = {"s", 11, 1e11};
+constexpr DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
+constexpr DisplayUnit kDisplayHour = {"h", -1, 0.0}; // prec ignored
void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
char buf[sizeof("2562047788015216")]; // hours in max duration
@@ -744,8 +703,9 @@
char buf[kBufferSize]; // also large enough to hold integer part
char* ep = buf + sizeof(buf);
double d = 0;
- int64_t frac_part = std::round(std::modf(n, &d) * unit.pow10);
- int64_t int_part = d;
+ int64_t frac_part =
+ static_cast<int64_t>(std::round(std::modf(n, &d) * unit.pow10));
+ int64_t int_part = static_cast<int64_t>(d);
if (int_part != 0 || frac_part != 0) {
char* bp = Format64(ep, 0, int_part); // always < 1000
out->append(bp, static_cast<size_t>(ep - bp));
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 4c801a8..1e3fe67 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -16,14 +16,19 @@
#include <winsock2.h> // for timeval
#endif
+#include "absl/base/config.h"
+
+// For feature testing and determining which headers can be included.
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#include <version>
+#endif
+
#include <array>
#include <cfloat>
#include <chrono> // NOLINT(build/c++11)
-
-#ifdef __cpp_impl_three_way_comparison
+#ifdef __cpp_lib_three_way_comparison
#include <compare>
-#endif // __cpp_impl_three_way_comparison
-
+#endif // __cpp_lib_three_way_comparison
#include <cmath>
#include <cstdint>
#include <ctime>
@@ -31,9 +36,11 @@
#include <limits>
#include <random>
#include <string>
+#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/random/random.h"
#include "absl/strings/str_format.h"
#include "absl/time/time.h"
@@ -69,6 +76,8 @@
}
TEST(Duration, ConstExpr) {
+ static_assert(std::is_trivially_destructible<absl::Duration>::value,
+ "Duration is documented as being trivially destructible");
constexpr absl::Duration d0 = absl::ZeroDuration();
static_assert(d0 == absl::ZeroDuration(), "ZeroDuration()");
constexpr absl::Duration d1 = absl::Seconds(1);
@@ -437,14 +446,14 @@
EXPECT_LT(-inf, inf);
EXPECT_GT(inf, -inf);
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
EXPECT_EQ(inf <=> inf, std::strong_ordering::equal);
EXPECT_EQ(-inf <=> -inf, std::strong_ordering::equal);
EXPECT_EQ(-inf <=> inf, std::strong_ordering::less);
EXPECT_EQ(inf <=> -inf, std::strong_ordering::greater);
EXPECT_EQ(any_dur <=> inf, std::strong_ordering::less);
EXPECT_EQ(any_dur <=> -inf, std::strong_ordering::greater);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
}
TEST(Duration, InfinityAddition) {
@@ -511,18 +520,18 @@
absl::Duration almost_neg_inf = sec_min;
EXPECT_LT(-inf, almost_neg_inf);
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
EXPECT_EQ(-inf <=> almost_neg_inf, std::strong_ordering::less);
EXPECT_EQ(almost_neg_inf <=> -inf, std::strong_ordering::greater);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
almost_neg_inf -= -absl::Nanoseconds(1);
EXPECT_LT(-inf, almost_neg_inf);
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
EXPECT_EQ(-inf <=> almost_neg_inf, std::strong_ordering::less);
EXPECT_EQ(almost_neg_inf <=> -inf, std::strong_ordering::greater);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
// For reference: IEEE 754 behavior
const double dbl_inf = std::numeric_limits<double>::infinity();
@@ -883,7 +892,7 @@
EXPECT_LT(neg_full_range, full_range);
EXPECT_EQ(neg_full_range, -full_range);
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
EXPECT_EQ(range_future <=> absl::InfiniteDuration(),
std::strong_ordering::less);
EXPECT_EQ(range_past <=> -absl::InfiniteDuration(),
@@ -896,7 +905,7 @@
std::strong_ordering::greater);
EXPECT_EQ(neg_full_range <=> full_range, std::strong_ordering::less);
EXPECT_EQ(neg_full_range <=> -full_range, std::strong_ordering::equal);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
}
TEST(Duration, RelationalOperators) {
@@ -920,8 +929,7 @@
#undef TEST_REL_OPS
}
-
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
TEST(Duration, SpaceshipOperators) {
#define TEST_REL_OPS(UNIT) \
@@ -939,7 +947,7 @@
#undef TEST_REL_OPS
}
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
TEST(Duration, Addition) {
#define TEST_ADD_OPS(UNIT) \
@@ -1507,9 +1515,7 @@
}
TEST(Duration, ToDoubleSecondsCheckRandom) {
- std::random_device rd;
- std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()});
- std::mt19937_64 gen(seed);
+ absl::InsecureBitGen gen;
// We want doubles distributed from 1/8ns up to 2^63, where
// as many values are tested from 1ns to 2ns as from 1sec to 2sec,
// so even distribute along a log-scale of those values, and
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index 0b43bb1..da30a0f 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+load("//absl:copts/configure_copts.bzl", "ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_LINKOPTS", "ABSL_TEST_COPTS")
+
package(features = [
"header_modules",
"layering_check",
@@ -28,6 +30,8 @@
hdrs = [
"include/cctz/civil_time.h",
],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
textual_hdrs = ["include/cctz/civil_time_detail.h"],
visibility = ["//visibility:public"],
deps = ["//absl/base:config"],
@@ -57,7 +61,8 @@
"include/cctz/time_zone.h",
"include/cctz/zone_info_source.h",
],
- linkopts = select({
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS + select({
"@platforms//os:osx": ["-Wl,-framework,CoreFoundation"],
"@platforms//os:ios": ["-Wl,-framework,CoreFoundation"],
"//conditions:default": [],
@@ -84,11 +89,13 @@
name = "civil_time_test",
size = "small",
srcs = ["src/civil_time_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":civil_time",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -96,8 +103,9 @@
name = "time_zone_format_test",
size = "small",
srcs = ["src/time_zone_format_test.cc"],
+ copts = ABSL_TEST_COPTS,
data = [":zoneinfo"],
- env = {"TZDIR": "absl/time/internal/cctz/testdata/zoneinfo"},
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_android_arm",
"no_test_android_arm64",
@@ -108,8 +116,8 @@
":civil_time",
":time_zone",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -118,8 +126,9 @@
size = "small",
timeout = "moderate",
srcs = ["src/time_zone_lookup_test.cc"],
+ copts = ABSL_TEST_COPTS,
data = [":zoneinfo"],
- env = {"TZDIR": "absl/time/internal/cctz/testdata/zoneinfo"},
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_android_arm",
"no_test_android_arm64",
@@ -130,8 +139,8 @@
":civil_time",
":time_zone",
"//absl/base:config",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -146,22 +155,24 @@
"src/time_zone_info.h",
"src/tzfile.h",
],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
linkstatic = 1,
tags = ["benchmark"],
deps = [
":civil_time",
":time_zone",
"//absl/base:config",
- "@com_github_google_benchmark//:benchmark_main",
+ "@google_benchmark//:benchmark_main",
],
)
+### examples
+
+### binaries
+
filegroup(
name = "zoneinfo",
srcs = glob(["testdata/zoneinfo/**"]),
visibility = ["//absl/time:__subpackages__"],
)
-
-### examples
-
-### binaries
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h
index b2b0cf6..5b232f5 100644
--- a/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -200,7 +200,7 @@
// version() and description() provide additional information about the
// time zone. The content of each of the returned strings is unspecified,
// however, when the IANA Time Zone Database is the underlying data source
- // the version() string will be in the familar form (e.g, "2018e") or
+ // the version() string will be in the familiar form (e.g, "2018e") or
// empty when unavailable.
//
// Note: These functions are for informational or testing purposes only.
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index 11f9ba6..ba7e149 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -23,7 +23,7 @@
#include "benchmark/benchmark.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
-#include "time_zone_impl.h"
+#include "absl/time/internal/cctz/src/time_zone_impl.h"
namespace {
@@ -199,6 +199,7 @@
"America/Ciudad_Juarez",
"America/Coral_Harbour",
"America/Costa_Rica",
+ "America/Coyhaique",
"America/Creston",
"America/Cuiaba",
"America/Curacao",
@@ -215,7 +216,6 @@
"America/Fort_Nelson",
"America/Fortaleza",
"America/Glace_Bay",
- "America/Godthab",
"America/Goose_Bay",
"America/Grand_Turk",
"America/Grenada",
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index e09654e..ed7f9cb 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "time_zone_fixed.h"
+#include "absl/time/internal/cctz/src/time_zone_fixed.h"
#include <algorithm>
#include <cassert>
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index e7e30a2..0e5f32f 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -46,7 +46,7 @@
#endif
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
-#include "time_zone_if.h"
+#include "absl/time/internal/cctz/src/time_zone_if.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
index 0e65cd9..09f83e8 100644
--- a/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -12,11 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "time_zone_if.h"
+#include "absl/time/internal/cctz/src/time_zone_if.h"
#include "absl/base/config.h"
-#include "time_zone_info.h"
-#include "time_zone_libc.h"
+#include "absl/time/internal/cctz/src/time_zone_info.h"
+#include "absl/time/internal/cctz/src/time_zone_libc.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index aadbb77..5f2f49e 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "time_zone_impl.h"
+#include "absl/time/internal/cctz/src/time_zone_impl.h"
#include <deque>
#include <memory>
@@ -22,7 +22,7 @@
#include <utility>
#include "absl/base/config.h"
-#include "time_zone_fixed.h"
+#include "absl/time/internal/cctz/src/time_zone_fixed.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h
index 8308a3b..da3aec5 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.h
+++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -21,8 +21,8 @@
#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
-#include "time_zone_if.h"
-#include "time_zone_info.h"
+#include "absl/time/internal/cctz/src/time_zone_if.h"
+#include "absl/time/internal/cctz/src/time_zone_info.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index b7178a6..f8484c9 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -30,7 +30,7 @@
// Note that we assume the proleptic Gregorian calendar and 60-second
// minutes throughout.
-#include "time_zone_info.h"
+#include "absl/time/internal/cctz/src/time_zone_info.h"
#include <algorithm>
#include <cassert>
@@ -49,8 +49,8 @@
#include "absl/base/config.h"
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
-#include "time_zone_fixed.h"
-#include "time_zone_posix.h"
+#include "absl/time/internal/cctz/src/time_zone_fixed.h"
+#include "absl/time/internal/cctz/src/time_zone_posix.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h
index 689df6f..efe2f9c 100644
--- a/absl/time/internal/cctz/src/time_zone_info.h
+++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -26,8 +26,8 @@
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
-#include "time_zone_if.h"
-#include "tzfile.h"
+#include "absl/time/internal/cctz/src/time_zone_if.h"
+#include "absl/time/internal/cctz/src/tzfile.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index b509402..362da1a 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -16,7 +16,7 @@
#define _CRT_SECURE_NO_WARNINGS 1
#endif
-#include "time_zone_libc.h"
+#include "absl/time/internal/cctz/src/time_zone_libc.h"
#include <chrono>
#include <ctime>
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h
index ae21073..f1ed5cd 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.h
+++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -19,7 +19,7 @@
#include <string>
#include "absl/base/config.h"
-#include "time_zone_if.h"
+#include "absl/time/internal/cctz/src/time_zone_if.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index 8979174..90b2972 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -33,29 +33,38 @@
#endif
#if defined(_WIN32)
-#include <sdkddkver.h>
-// Include only when the SDK is for Windows 10 (and later), and the binary is
-// targeted for Windows XP and later.
-// Note: The Windows SDK added windows.globalization.h file for Windows 10, but
-// MinGW did not add it until NTDDI_WIN10_NI (SDK version 10.0.22621.0).
-#if ((defined(_WIN32_WINNT_WIN10) && !defined(__MINGW32__)) || \
- (defined(NTDDI_WIN10_NI) && NTDDI_VERSION >= NTDDI_WIN10_NI)) && \
- (_WIN32_WINNT >= _WIN32_WINNT_WINXP)
+// Include only when <icu.h> is available.
+// https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-
+// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255
+#if defined(__has_include)
+#if __has_include(<icu.h>)
#define USE_WIN32_LOCAL_TIME_ZONE
-#include <roapi.h>
-#include <tchar.h>
-#include <wchar.h>
-#include <windows.globalization.h>
#include <windows.h>
-#endif
-#endif
+#pragma push_macro("_WIN32_WINNT")
+#pragma push_macro("NTDDI_VERSION")
+// Minimum _WIN32_WINNT and NTDDI_VERSION to use ucal_getTimeZoneIDForWindowsID
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0A00 // == _WIN32_WINNT_WIN10
+#undef NTDDI_VERSION
+#define NTDDI_VERSION 0x0A000004 // == NTDDI_WIN10_RS3
+#include <icu.h>
+#pragma pop_macro("NTDDI_VERSION")
+#pragma pop_macro("_WIN32_WINNT")
+#include <timezoneapi.h>
+#include <atomic>
+#endif // __has_include(<icu.h>)
+#endif // __has_include
+#endif // _WIN32
+
+#include <array>
+#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <string>
-#include "time_zone_fixed.h"
-#include "time_zone_impl.h"
+#include "absl/time/internal/cctz/src/time_zone_fixed.h"
+#include "absl/time/internal/cctz/src/time_zone_impl.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -64,80 +73,78 @@
namespace {
#if defined(USE_WIN32_LOCAL_TIME_ZONE)
-// Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the
-// local time zone. Returns an empty vector in case of an error.
-std::string win32_local_time_zone(const HMODULE combase) {
- std::string result;
- const auto ro_activate_instance =
- reinterpret_cast<decltype(&RoActivateInstance)>(
- GetProcAddress(combase, "RoActivateInstance"));
- if (!ro_activate_instance) {
- return result;
- }
- const auto windows_create_string_reference =
- reinterpret_cast<decltype(&WindowsCreateStringReference)>(
- GetProcAddress(combase, "WindowsCreateStringReference"));
- if (!windows_create_string_reference) {
- return result;
- }
- const auto windows_delete_string =
- reinterpret_cast<decltype(&WindowsDeleteString)>(
- GetProcAddress(combase, "WindowsDeleteString"));
- if (!windows_delete_string) {
- return result;
- }
- const auto windows_get_string_raw_buffer =
- reinterpret_cast<decltype(&WindowsGetStringRawBuffer)>(
- GetProcAddress(combase, "WindowsGetStringRawBuffer"));
- if (!windows_get_string_raw_buffer) {
- return result;
+// True if we have already failed to load the API.
+static std::atomic_bool g_ucal_getTimeZoneIDForWindowsIDUnavailable;
+static std::atomic<decltype(ucal_getTimeZoneIDForWindowsID)*>
+ g_ucal_getTimeZoneIDForWindowsIDRef;
+
+std::string win32_local_time_zone() {
+ // If we have already failed to load the API, then just give up.
+ if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
+ return "";
}
- // The string returned by WindowsCreateStringReference doesn't need to be
- // deleted.
- HSTRING calendar_class_id;
- HSTRING_HEADER calendar_class_id_header;
- HRESULT hr = windows_create_string_reference(
- RuntimeClass_Windows_Globalization_Calendar,
- sizeof(RuntimeClass_Windows_Globalization_Calendar) / sizeof(wchar_t) - 1,
- &calendar_class_id_header, &calendar_class_id);
- if (FAILED(hr)) {
- return result;
- }
-
- IInspectable* calendar;
- hr = ro_activate_instance(calendar_class_id, &calendar);
- if (FAILED(hr)) {
- return result;
- }
-
- ABI::Windows::Globalization::ITimeZoneOnCalendar* time_zone;
- hr = calendar->QueryInterface(IID_PPV_ARGS(&time_zone));
- if (FAILED(hr)) {
- calendar->Release();
- return result;
- }
-
- HSTRING tz_hstr;
- hr = time_zone->GetTimeZone(&tz_hstr);
- if (SUCCEEDED(hr)) {
- UINT32 wlen;
- const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen);
- if (tz_wstr) {
- const int size =
- WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
- nullptr, 0, nullptr, nullptr);
- result.resize(static_cast<size_t>(size));
- WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
- &result[0], size, nullptr, nullptr);
+ auto ucal_getTimeZoneIDForWindowsIDFunc =
+ g_ucal_getTimeZoneIDForWindowsIDRef.load();
+ if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
+ // If we have already failed to load the API, then just give up.
+ if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
+ return "";
}
- windows_delete_string(tz_hstr);
+
+ const HMODULE icudll =
+ ::LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
+
+ if (icudll == nullptr) {
+ g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
+ return "";
+ }
+
+ ucal_getTimeZoneIDForWindowsIDFunc =
+ reinterpret_cast<decltype(ucal_getTimeZoneIDForWindowsID)*>(
+ ::GetProcAddress(icudll, "ucal_getTimeZoneIDForWindowsID"));
+
+ if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
+ g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
+ return "";
+ }
+ // store-race is not a problem here, because ::GetProcAddress() returns the
+ // same address for the same function in the same DLL.
+ g_ucal_getTimeZoneIDForWindowsIDRef.store(
+ ucal_getTimeZoneIDForWindowsIDFunc);
+
+ // We intentionally do not call ::FreeLibrary() here to avoid frequent DLL
+ // loadings and unloading. As "icu.dll" is a system library, keeping it on
+ // memory is supposed to have no major drawback.
}
- time_zone->Release();
- calendar->Release();
- return result;
+
+ DYNAMIC_TIME_ZONE_INFORMATION info = {};
+ if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) {
+ return "";
+ }
+
+ std::array<UChar, 128> buffer;
+ UErrorCode status = U_ZERO_ERROR;
+ const auto num_chars_in_buffer = ucal_getTimeZoneIDForWindowsIDFunc(
+ reinterpret_cast<const UChar*>(info.TimeZoneKeyName), -1, nullptr,
+ buffer.data(), static_cast<int32_t>(buffer.size()), &status);
+ if (status != U_ZERO_ERROR || num_chars_in_buffer <= 0 ||
+ num_chars_in_buffer > static_cast<int32_t>(buffer.size())) {
+ return "";
+ }
+
+ const int num_bytes_in_utf8 = ::WideCharToMultiByte(
+ CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
+ static_cast<int>(num_chars_in_buffer), nullptr, 0, nullptr, nullptr);
+ std::string local_time_str;
+ local_time_str.resize(static_cast<size_t>(num_bytes_in_utf8));
+ ::WideCharToMultiByte(
+ CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
+ static_cast<int>(num_chars_in_buffer), &local_time_str[0],
+ num_bytes_in_utf8, nullptr, nullptr);
+ return local_time_str;
}
-#endif
+#endif // USE_WIN32_LOCAL_TIME_ZONE
} // namespace
std::string time_zone::name() const { return effective_impl().Name(); }
@@ -255,36 +262,9 @@
}
#endif
#if defined(USE_WIN32_LOCAL_TIME_ZONE)
- // Use the WinRT Calendar class to get the local time zone. This feature is
- // available on Windows 10 and later. The library is dynamically linked to
- // maintain binary compatibility with Windows XP - Windows 7. On Windows 8,
- // The combase.dll API functions are available but the RoActivateInstance
- // call will fail for the Calendar class.
- std::string winrt_tz;
- const HMODULE combase =
- LoadLibraryEx(_T("combase.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
- if (combase) {
- const auto ro_initialize = reinterpret_cast<decltype(&::RoInitialize)>(
- GetProcAddress(combase, "RoInitialize"));
- const auto ro_uninitialize = reinterpret_cast<decltype(&::RoUninitialize)>(
- GetProcAddress(combase, "RoUninitialize"));
- if (ro_initialize && ro_uninitialize) {
- const HRESULT hr = ro_initialize(RO_INIT_MULTITHREADED);
- // RPC_E_CHANGED_MODE means that a previous RoInitialize call specified
- // a different concurrency model. The WinRT runtime is initialized and
- // should work for our purpose here, but we should *not* call
- // RoUninitialize because it's a failure.
- if (SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE) {
- winrt_tz = win32_local_time_zone(combase);
- if (SUCCEEDED(hr)) {
- ro_uninitialize();
- }
- }
- }
- FreeLibrary(combase);
- }
- if (!winrt_tz.empty()) {
- zone = winrt_tz.c_str();
+ std::string win32_tz = win32_local_time_zone();
+ if (!win32_tz.empty()) {
+ zone = win32_tz.c_str();
}
#endif
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 6f7e5cf..e1bea28 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -134,6 +134,7 @@
"America/Ciudad_Juarez",
"America/Coral_Harbour",
"America/Costa_Rica",
+ "America/Coyhaique",
"America/Creston",
"America/Cuiaba",
"America/Curacao",
@@ -150,7 +151,6 @@
"America/Fort_Nelson",
"America/Fortaleza",
"America/Glace_Bay",
- "America/Godthab",
"America/Goose_Bay",
"America/Grand_Turk",
"America/Grenada",
@@ -1330,35 +1330,24 @@
ExpectTime(tp, tz, 1983, 12, 31, 23, 59, 59, -5 * 3600, false, "EST");
}
-TEST(TimeZoneEdgeCase, WET) {
- // Cover some non-existent times within forward transitions.
- const time_zone tz = LoadZone("WET");
+TEST(TimeZoneEdgeCase, EuropeLisbon) {
+ // Cover a non-existent time within a forward transition.
+ const time_zone tz = LoadZone("Europe/Lisbon");
- // Before the first transition.
- auto tp = convert(civil_second(1977, 1, 1, 0, 0, 0), tz);
- ExpectTime(tp, tz, 1977, 1, 1, 0, 0, 0, 0, false, "WET");
-
- // Over the first transition.
- // 228877199 == Sun, 3 Apr 1977 00:59:59 +0000 (WET)
- // 228877200 == Sun, 3 Apr 1977 02:00:00 +0100 (WEST)
- tp = convert(civil_second(1977, 4, 3, 0, 59, 59), tz);
- ExpectTime(tp, tz, 1977, 4, 3, 0, 59, 59, 0, false, "WET");
+ // Over a forward transition.
+ // 354671999 == Sat, 28 Mar 1981 23:59:59 +0000 (WET)
+ // 354672000 == Sun, 29 Mar 1981 01:00:00 +0100 (WEST)
+ auto tp = convert(civil_second(1981, 3, 28, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 1981, 3, 28, 23, 59, 59, 0, false, "WET");
tp += absl::time_internal::cctz::seconds(1);
- ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
+ ExpectTime(tp, tz, 1981, 3, 29, 1, 0, 0, 1 * 3600, true, "WEST");
- // A non-existent time within the first transition.
- time_zone::civil_lookup cl1 = tz.lookup(civil_second(1977, 4, 3, 1, 15, 0));
+ // A non-existent time within the transition.
+ time_zone::civil_lookup cl1 = tz.lookup(civil_second(1981, 3, 29, 0, 15, 0));
EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl1.kind);
- ExpectTime(cl1.pre, tz, 1977, 4, 3, 2, 15, 0, 1 * 3600, true, "WEST");
- ExpectTime(cl1.trans, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
- ExpectTime(cl1.post, tz, 1977, 4, 3, 0, 15, 0, 0 * 3600, false, "WET");
-
- // A non-existent time within the second forward transition.
- time_zone::civil_lookup cl2 = tz.lookup(civil_second(1978, 4, 2, 1, 15, 0));
- EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl2.kind);
- ExpectTime(cl2.pre, tz, 1978, 4, 2, 2, 15, 0, 1 * 3600, true, "WEST");
- ExpectTime(cl2.trans, tz, 1978, 4, 2, 2, 0, 0, 1 * 3600, true, "WEST");
- ExpectTime(cl2.post, tz, 1978, 4, 2, 0, 15, 0, 0 * 3600, false, "WET");
+ ExpectTime(cl1.pre, tz, 1981, 3, 29, 1, 15, 0, 1 * 3600, true, "WEST");
+ ExpectTime(cl1.trans, tz, 1981, 3, 29, 1, 0, 0, 1 * 3600, true, "WEST");
+ ExpectTime(cl1.post, tz, 1981, 3, 28, 23, 15, 0, 0 * 3600, false, "WET");
}
TEST(TimeZoneEdgeCase, FixedOffsets) {
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
index 5cdd09e..efea080 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.cc
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "time_zone_posix.h"
+#include "absl/time/internal/cctz/src/time_zone_posix.h"
#include <cstddef>
#include <cstring>
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h
index 2be3bb8..6281438 100644
--- a/absl/time/internal/cctz/src/tzfile.h
+++ b/absl/time/internal/cctz/src/tzfile.h
@@ -25,7 +25,7 @@
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
-/* See Internet RFC 8536 for more details about the following format. */
+/* See Internet RFC 9636 for more details about the following format. */
/*
** Each file begins with. . .
@@ -75,14 +75,16 @@
** If tzh_version is '2' or greater, the above is followed by a second instance
** of tzhead and a second instance of the data in which each coded transition
** time uses 8 rather than 4 chars,
-** then a POSIX-TZ-environment-variable-style string for use in handling
+** then a POSIX.1-2017 proleptic TZ string for use in handling
** instants after the last transition time stored in the file
** (with nothing between the newlines if there is no POSIX.1-2017
** representation for such instants).
**
-** If tz_version is '3' or greater, the above is extended as follows.
+** If tz_version is '3' or greater, the TZ string can be any POSIX.1-2024
+** proleptic TZ string, which means the above is extended as follows.
** First, the TZ string's hour offset may range from -167
-** through 167 as compared to the POSIX-required 0 through 24.
+** through 167 as compared to the range 0 through 24 required
+** by POSIX.1-2017 and earlier.
** Second, its DST start time may be January 1 at 00:00 and its stop
** time December 31 at 24:00 plus the difference between DST and
** standard time, indicating DST all year.
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index 04fe674..ef468ad 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2024a
+2025b
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
index 651e5cf..581bb0e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
index 6225036..f056047 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
index 48faea2..882400b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
index 640b259..3110cdf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
index 5e0a54f..f65bb1c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ciudad_Juarez b/absl/time/internal/cctz/testdata/zoneinfo/America/Ciudad_Juarez
index f636ee6..5f865ea 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ciudad_Juarez
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ciudad_Juarez
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Coyhaique b/absl/time/internal/cctz/testdata/zoneinfo/America/Coyhaique
new file mode 100644
index 0000000..26354e8
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Coyhaique
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
index 42087af..18d0d14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
index 5c92e29..ba7b147 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
index 97d4d36..5aa6039 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
index e5de113..e5c7d8c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
index 80a415c..1811234 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
index a5822e2..c1e0546 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
index f7e40c0..1dd08b1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
index 42087af..18d0d14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
index 42087af..18d0d14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
index 0a948c2..6f5d3a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
index bb7be9f..22e705c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
index 3c3584e..145bb6f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
index 824acb0..6fd31e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
index e6e2616..cda1c1d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
index cf965c3..21e8457 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET
index 546748d..3197327 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
index d931558..b016880 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET
index 378919e..231bf9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST b/absl/time/internal/cctz/testdata/zoneinfo/EST
index 3ae9691..9154643 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
index 50c95e0..2b6c2ee 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
index f0c70b6..7e9aae7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST
index 160a53e..40e3d49 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/HST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/HST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran
index 824acb0..6fd31e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iran
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iran
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET
index 6f0558c..3197327 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST b/absl/time/internal/cctz/testdata/zoneinfo/MST
index a0953d1..c2bd2f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
index 137867c..09e54e5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
index 42087af..18d0d14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
index 97d4d36..5aa6039 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
index 80a415c..1811234 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
index fde4833..aaf0778 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
index f0c70b6..7e9aae7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Portugal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Portugal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET
index 423c6c2..7e9aae7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/WET
+++ b/absl/time/internal/cctz/testdata/zoneinfo/WET
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index abd9489..36535bd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -124,7 +124,8 @@
CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan
CK -2114-15946 Pacific/Rarotonga
CL -3327-07040 America/Santiago most of Chile
-CL -5309-07055 America/Punta_Arenas Region of Magallanes
+CL -4534-07204 America/Coyhaique Aysén Region
+CL -5309-07055 America/Punta_Arenas Magallanes Region
CL -2709-10926 Pacific/Easter Easter Island
CN +3114+12128 Asia/Shanghai Beijing Time
CN +4348+08735 Asia/Urumqi Xinjiang Time
@@ -183,7 +184,7 @@
IT,SM,VA +4154+01229 Europe/Rome
JM +175805-0764736 America/Jamaica
JO +3157+03556 Asia/Amman
-JP +353916+1394441 Asia/Tokyo
+JP,AU +353916+1394441 Asia/Tokyo Eyre Bird Observatory
KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi
KG +4254+07436 Asia/Bishkek
KI,MH,TV,UM,WF +0125+17300 Pacific/Tarawa Gilberts, Marshalls, Wake
@@ -209,8 +210,7 @@
MH +0905+16720 Pacific/Kwajalein Kwajalein
MM,CC +1647+09610 Asia/Yangon
MN +4755+10653 Asia/Ulaanbaatar most of Mongolia
-MN +4801+09139 Asia/Hovd Bayan-Ölgii, Govi-Altai, Hovd, Uvs, Zavkhan
-MN +4804+11430 Asia/Choibalsan Dornod, Sükhbaatar
+MN +4801+09139 Asia/Hovd Bayan-Ölgii, Hovd, Uvs
MO +221150+1133230 Asia/Macau
MQ +1436-06105 America/Martinique
MT +3554+01431 Europe/Malta
@@ -247,7 +247,7 @@
PF -2308-13457 Pacific/Gambier Gambier Islands
PG,AQ,FM -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas), Chuuk, Yap, Dumont d'Urville
PG -0613+15534 Pacific/Bougainville Bougainville
-PH +1435+12100 Asia/Manila
+PH +143512+1205804 Asia/Manila
PK +2452+06703 Asia/Karachi
PL +5215+02100 Europe/Warsaw
PM +4703-05620 America/Miquelon
@@ -294,7 +294,7 @@
SA,AQ,KW,YE +2438+04643 Asia/Riyadh Syowa
SB,FM -0932+16012 Pacific/Guadalcanal Pohnpei
SD +1536+03232 Africa/Khartoum
-SG,MY +0117+10351 Asia/Singapore peninsular Malaysia
+SG,AQ,MY +0117+10351 Asia/Singapore peninsular Malaysia, Concordia
SR +0550-05510 America/Paramaribo
SS +0451+03137 Africa/Juba
ST +0020+00644 Africa/Sao_Tome
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
index b6f2910..093f0a0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
@@ -5,7 +5,7 @@
# From Paul Eggert (2023-12-18):
# This file contains a table where each row stands for a timezone
# where civil timestamps are predicted to agree from now on.
-# This file is like zone1970.tab (see zone1970.tab's coments),
+# This file is like zone1970.tab (see zone1970.tab's comments),
# but with the following changes:
#
# 1. Each timezone corresponds to a set of clocks that are planned
@@ -97,9 +97,6 @@
# -04/-03 (Chile DST)
XX -3327-07040 America/Santiago most of Chile
#
-# -04/-03 (Paraguay DST)
-XX -2516-05740 America/Asuncion Paraguay
-#
# -04/-03 - AST/ADT (North America DST)
XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda
#
@@ -107,7 +104,7 @@
XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT")
#
# -03
-XX -2332-04637 America/Sao_Paulo eastern South America
+XX -2332-04637 America/Sao_Paulo eastern and southern South America
#
# -03/-02 (North America DST)
XX +4703-05620 America/Miquelon St Pierre & Miquelon
@@ -123,8 +120,6 @@
#
# -01/+00 (EU DST)
XX +3744-02540 Atlantic/Azores Azores
-# -01/+00 (EU DST) until 2024-03-31; then -02/-01 (EU DST)
-XX +7029-02158 America/Scoresbysund Ittoqqortoormiit
#
# +00 - GMT
XX +0519-00402 Africa/Abidjan far western Africa; Iceland ("GMT")
@@ -199,7 +194,7 @@
XX +3431+06912 Asia/Kabul Afghanistan
#
# +05
-XX +4120+06918 Asia/Tashkent Russia; west Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives
+XX +4120+06918 Asia/Tashkent Russia; Kazakhstan; Tajikistan; Turkmenistan; Uzbekistan; Maldives
#
# +05 - PKT
XX +2452+06703 Asia/Karachi Pakistan ("PKT")
@@ -215,8 +210,6 @@
#
# +06
XX +2343+09025 Asia/Dhaka Russia; Kyrgyzstan; Bhutan; Bangladesh; Chagos
-# +06 until 2024-03-01; then +05
-XX +4315+07657 Asia/Almaty Kazakhstan (except western areas)
#
# +06:30
XX +1647+09610 Asia/Yangon Myanmar; Cocos
@@ -228,7 +221,7 @@
XX -0610+10648 Asia/Jakarta Indonesia ("WIB")
#
# +08
-XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore
+XX +0117+10351 Asia/Singapore Russia; Brunei; Malaysia; Singapore; Concordia
#
# +08 - AWST
XX -3157+11551 Australia/Perth Western Australia ("AWST")
@@ -240,7 +233,7 @@
XX +2217+11409 Asia/Hong_Kong Hong Kong ("HKT")
#
# +08 - PHT
-XX +1435+12100 Asia/Manila Philippines ("PHT")
+XX +143512+1205804 Asia/Manila Philippines ("PHT")
#
# +08 - WITA
XX -0507+11924 Asia/Makassar Indonesia ("WITA")
@@ -252,7 +245,7 @@
XX +5203+11328 Asia/Chita Russia; Palau; East Timor
#
# +09 - JST
-XX +353916+1394441 Asia/Tokyo Japan ("JST")
+XX +353916+1394441 Asia/Tokyo Japan ("JST"); Eyre Bird Observatory
#
# +09 - KST
XX +3733+12658 Asia/Seoul Korea ("KST")
diff --git a/absl/time/time.h b/absl/time/time.h
index f133c2d..53bca90 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -74,13 +74,19 @@
// including 'windows.h' so we are picking the lesser of two evils here.
struct timeval;
#endif
+
+#include "absl/base/config.h"
+
+// For feature testing and determining which headers can be included.
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#include <version>
+#endif
+
#include <chrono> // NOLINT(build/c++11)
-
-#ifdef __cpp_impl_three_way_comparison
-#include <compare>
-#endif // __cpp_impl_three_way_comparison
-
#include <cmath>
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
+#endif // __cpp_lib_three_way_comparison
#include <cstdint>
#include <ctime>
#include <limits>
@@ -91,12 +97,16 @@
#include <utility>
#include "absl/base/attributes.h"
-#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+#if defined(__cpp_impl_three_way_comparison) && \
+ defined(__cpp_lib_three_way_comparison)
+#define ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON 1
+#endif
+
namespace absl {
ABSL_NAMESPACE_BEGIN
@@ -138,7 +148,8 @@
// the result of subtracting one `absl::Time` from another. Durations behave
// like unit-safe integers and they support all the natural integer-like
// arithmetic operations. Arithmetic overflows and saturates at +/- infinity.
-// `Duration` should be passed by value rather than const reference.
+// `Duration` is trivially destructible and should be passed by value rather
+// than const reference.
//
// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`,
// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for
@@ -313,12 +324,12 @@
// Relational Operators
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>(
Duration lhs, Duration rhs);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Duration lhs,
Duration rhs);
@@ -609,12 +620,12 @@
//
// absl::Duration d = absl::Milliseconds(1500);
// int64_t isec = absl::ToInt64Seconds(d); // isec == 1
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Nanoseconds(Duration d);
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Microseconds(Duration d);
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Milliseconds(Duration d);
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Seconds(Duration d);
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Minutes(Duration d);
-ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Hours(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Nanoseconds(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Microseconds(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Milliseconds(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Seconds(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Minutes(Duration d);
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Hours(Duration d);
// ToDoubleNanoseconds()
// ToDoubleMicroseconds()
@@ -738,8 +749,9 @@
// are provided for naturally expressing time calculations. Instances are
// created using `absl::Now()` and the `absl::From*()` factory functions that
// accept the gamut of other time representations. Formatting and parsing
-// functions are provided for conversion to and from strings. `absl::Time`
-// should be passed by value rather than const reference.
+// functions are provided for conversion to and from strings. `absl::Time` is
+// trivially destructible and should be passed by value rather than const
+// reference.
//
// `absl::Time` assumes there are 60 seconds in a minute, which means the
// underlying time scales must be "smeared" to eliminate leap seconds.
@@ -853,9 +865,9 @@
friend constexpr Time time_internal::FromUnixDuration(Duration d);
friend constexpr Duration time_internal::ToUnixDuration(Time t);
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
friend constexpr std::strong_ordering operator<=>(Time lhs, Time rhs);
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
friend constexpr bool operator<(Time lhs, Time rhs);
friend constexpr bool operator==(Time lhs, Time rhs);
@@ -868,14 +880,14 @@
};
// Relational Operators
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>(
Time lhs, Time rhs) {
return lhs.rep_ <=> rhs.rep_;
}
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Time lhs, Time rhs) {
return lhs.rep_ < rhs.rep_;
@@ -1752,8 +1764,7 @@
: time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
}
-
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr std::strong_ordering operator<=>(
Duration lhs, Duration rhs) {
@@ -1769,7 +1780,7 @@
: lhs_lo <=> rhs_lo;
}
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Duration lhs,
Duration rhs) {
@@ -1853,6 +1864,61 @@
return time_internal::FromUnixDuration(Seconds(t));
}
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Nanoseconds(Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 33 == 0) {
+ return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
+ (time_internal::GetRepLo(d) / time_internal::kTicksPerNanosecond);
+ } else {
+ return d / Nanoseconds(1);
+ }
+}
+
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Microseconds(
+ Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 43 == 0) {
+ return (time_internal::GetRepHi(d) * 1000 * 1000) +
+ (time_internal::GetRepLo(d) /
+ (time_internal::kTicksPerNanosecond * 1000));
+ } else {
+ return d / Microseconds(1);
+ }
+}
+
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Milliseconds(
+ Duration d) {
+ if (time_internal::GetRepHi(d) >= 0 &&
+ time_internal::GetRepHi(d) >> 53 == 0) {
+ return (time_internal::GetRepHi(d) * 1000) +
+ (time_internal::GetRepLo(d) /
+ (time_internal::kTicksPerNanosecond * 1000 * 1000));
+ } else {
+ return d / Milliseconds(1);
+ }
+}
+
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Seconds(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi;
+}
+
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Minutes(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi / 60;
+}
+
+ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t ToInt64Hours(Duration d) {
+ int64_t hi = time_internal::GetRepHi(d);
+ if (time_internal::IsInfiniteDuration(d)) return hi;
+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
+ return hi / (60 * 60);
+}
+
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 71f54d6..7033326 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -13,30 +13,35 @@
// limitations under the License.
#include "absl/time/time.h"
-
-#include <cstdint>
-#include <ios>
-
#include "absl/time/civil_time.h"
#if defined(_MSC_VER)
#include <winsock2.h> // for timeval
#endif
+#include "absl/base/config.h"
+
+// For feature testing and determining which headers can be included.
+#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+#include <version>
+#endif
+
#include <chrono> // NOLINT(build/c++11)
-
-#ifdef __cpp_impl_three_way_comparison
+#ifdef __cpp_lib_three_way_comparison
#include <compare>
-#endif // __cpp_impl_three_way_comparison
-
+#endif // __cpp_lib_three_way_comparison
+#include <cstdint>
#include <cstring>
#include <ctime>
#include <iomanip>
+#include <ios>
#include <limits>
#include <string>
+#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/hash/hash_testing.h"
#include "absl/numeric/int128.h"
#include "absl/strings/str_format.h"
#include "absl/time/clock.h"
@@ -86,6 +91,8 @@
}
TEST(Time, ConstExpr) {
+ static_assert(std::is_trivially_destructible<absl::Time>::value,
+ "Time is documented as being trivially destructible");
constexpr absl::Time t0 = absl::UnixEpoch();
static_assert(t0 == absl::UnixEpoch(), "UnixEpoch");
constexpr absl::Time t1 = absl::InfiniteFuture();
@@ -213,7 +220,7 @@
static_assert(t1 >= t1, "");
static_assert(t3 >= t1, "");
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
static_assert((t1 <=> t1) == std::strong_ordering::equal, "");
static_assert((t2 <=> t2) == std::strong_ordering::equal, "");
@@ -227,7 +234,7 @@
static_assert((t3 <=> t2) == std::strong_ordering::greater, "");
static_assert((t3 <=> t1) == std::strong_ordering::greater, "");
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
}
TEST(Time, Infinity) {
@@ -239,14 +246,14 @@
static_assert(ipast < ifuture, "");
static_assert(ifuture > ipast, "");
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
static_assert((ifuture <=> ifuture) == std::strong_ordering::equal, "");
static_assert((ipast <=> ipast) == std::strong_ordering::equal, "");
static_assert((ipast <=> ifuture) == std::strong_ordering::less, "");
static_assert((ifuture <=> ipast) == std::strong_ordering::greater, "");
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
// Arithmetic saturates
EXPECT_EQ(ifuture, ifuture + absl::Seconds(1));
@@ -263,14 +270,14 @@
static_assert(t < ifuture, "");
static_assert(t > ipast, "");
-#ifdef __cpp_impl_three_way_comparison
+#ifdef ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
static_assert((t <=> ifuture) == std::strong_ordering::less, "");
static_assert((t <=> ipast) == std::strong_ordering::greater, "");
static_assert((ipast <=> t) == std::strong_ordering::less, "");
static_assert((ifuture <=> t) == std::strong_ordering::greater, "");
-#endif // __cpp_impl_three_way_comparison
+#endif // ABSL_INTERNAL_TIME_HAS_THREE_WAY_COMPARISON
EXPECT_EQ(ifuture, t + absl::InfiniteDuration());
EXPECT_EQ(ipast, t - absl::InfiniteDuration());
@@ -1329,4 +1336,29 @@
EXPECT_EQ(absl::StrFormat("%v", t), absl::FormatTime(t));
}
+TEST(Time, SupportsHash) {
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::UTCTimeZone(),
+ absl::FixedTimeZone(-8 * 60 * 60),
+ absl::UTCTimeZone(),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::Now(),
+ absl::UnixEpoch(),
+ absl::UnixEpoch() + absl::Seconds(60),
+ absl::UnixEpoch() + absl::Minutes(1),
+ absl::InfiniteFuture(),
+ absl::InfinitePast(),
+ }));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ absl::Seconds(1),
+ absl::Seconds(60),
+ absl::Minutes(1),
+ absl::InfiniteDuration(),
+ -absl::InfiniteDuration(),
+ }));
+}
+
} // namespace
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index a86e2c1..0668a2e 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -37,72 +37,15 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":bad_any_cast",
"//absl/base:config",
"//absl/base:core_headers",
- "//absl/base:fast_type_id",
- "//absl/meta:type_traits",
"//absl/utility",
],
)
cc_library(
name = "bad_any_cast",
- hdrs = ["bad_any_cast.h"],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":bad_any_cast_impl",
- "//absl/base:config",
- ],
-)
-
-cc_library(
- name = "bad_any_cast_impl",
- srcs = [
- "bad_any_cast.cc",
- "bad_any_cast.h",
- ],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- visibility = ["//visibility:private"],
- deps = [
- "//absl/base:config",
- "//absl/base:raw_logging_internal",
- ],
-)
-
-cc_test(
- name = "any_test",
- size = "small",
- srcs = [
- "any_test.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":any",
- "//absl/base:config",
- "//absl/base:exception_testing",
- "//absl/container:test_instance_tracker",
- "//absl/log",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "any_exception_safety_test",
- srcs = ["any_exception_safety_test.cc"],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":any",
- "//absl/base:config",
- "//absl/base:exception_safety_testing",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
+ deprecation = "bad_any_cast dependency is empty can be removed",
)
cc_library(
@@ -117,9 +60,11 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/algorithm",
+ "//absl/base:config",
"//absl/base:core_headers",
"//absl/base:nullability",
"//absl/base:throw_delegate",
+ "//absl/hash:weakly_mixed_integer",
"//absl/meta:type_traits",
],
)
@@ -137,105 +82,45 @@
"//absl/base:exception_testing",
"//absl/container:fixed_array",
"//absl/container:inlined_vector",
+ "//absl/hash",
"//absl/hash:hash_testing",
"//absl/meta:type_traits",
"//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
cc_library(
name = "optional",
- srcs = ["internal/optional.h"],
hdrs = ["optional.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":bad_optional_access",
- "//absl/base:base_internal",
"//absl/base:config",
- "//absl/base:core_headers",
- "//absl/base:nullability",
- "//absl/memory",
- "//absl/meta:type_traits",
"//absl/utility",
],
)
cc_library(
name = "bad_optional_access",
- srcs = ["bad_optional_access.cc"],
- hdrs = ["bad_optional_access.h"],
+ deprecation = "bad_optional_access dependency is empty can be removed",
+)
+
+cc_library(
+ name = "variant",
+ hdrs = ["variant.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
- "//absl/base:raw_logging_internal",
+ "//absl/utility",
],
)
cc_library(
name = "bad_variant_access",
- srcs = ["bad_variant_access.cc"],
- hdrs = ["bad_variant_access.h"],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- "//absl/base:config",
- "//absl/base:raw_logging_internal",
- ],
-)
-
-cc_test(
- name = "optional_test",
- size = "small",
- srcs = [
- "optional_test.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":optional",
- "//absl/base:config",
- "//absl/log",
- "//absl/meta:type_traits",
- "//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "optional_exception_safety_test",
- srcs = [
- "optional_exception_safety_test.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":optional",
- "//absl/base:config",
- "//absl/base:exception_safety_testing",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_library(
- name = "variant",
- srcs = ["internal/variant.h"],
- hdrs = ["variant.h"],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":bad_variant_access",
- "//absl/base:base_internal",
- "//absl/base:config",
- "//absl/base:core_headers",
- "//absl/meta:type_traits",
- "//absl/utility",
- ],
+ deprecation = "bad_variant_access dependency is empty can be removed",
)
cc_test(
@@ -246,47 +131,8 @@
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":variant",
- "//absl/base:config",
- "//absl/base:core_headers",
- "//absl/memory",
- "//absl/meta:type_traits",
- "//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_test(
- name = "variant_benchmark",
- srcs = [
- "variant_benchmark.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- tags = ["benchmark"],
- deps = [
- ":variant",
- "//absl/utility",
- "@com_github_google_benchmark//:benchmark_main",
- "@com_google_googletest//:gtest",
- ],
-)
-
-cc_test(
- name = "variant_exception_safety_test",
- size = "small",
- srcs = [
- "variant_exception_safety_test.cc",
- ],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":variant",
- "//absl/base:config",
- "//absl/base:exception_safety_testing",
- "//absl/memory",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
@@ -312,7 +158,7 @@
deps = [
":compare",
"//absl/base",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
+ "@googletest//:gtest",
+ "@googletest//:gtest_main",
],
)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index fed532f..20a7e90 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -21,90 +21,14 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::bad_any_cast
absl::config
absl::core_headers
- absl::fast_type_id
- absl::type_traits
absl::utility
PUBLIC
)
absl_cc_library(
NAME
- bad_any_cast
- HDRS
- "bad_any_cast.h"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- DEPS
- absl::bad_any_cast_impl
- absl::config
- PUBLIC
-)
-
-# Internal-only target, do not depend on directly.
-absl_cc_library(
- NAME
- bad_any_cast_impl
- SRCS
- "bad_any_cast.h"
- "bad_any_cast.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- DEPS
- absl::config
- absl::raw_logging_internal
-)
-
-absl_cc_test(
- NAME
- any_test
- SRCS
- "any_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::any
- absl::config
- absl::exception_testing
- absl::log
- absl::test_instance_tracker
- GTest::gmock_main
-)
-
-absl_cc_test(
- NAME
- any_test_noexceptions
- SRCS
- "any_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::any
- absl::config
- absl::exception_testing
- absl::raw_logging_internal
- absl::test_instance_tracker
- GTest::gmock_main
-)
-
-absl_cc_test(
- NAME
- any_exception_safety_test
- SRCS
- "any_exception_safety_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::any
- absl::config
- absl::exception_safety_testing
- GTest::gmock_main
-)
-
-absl_cc_library(
- NAME
span
HDRS
"span.h"
@@ -114,10 +38,12 @@
${ABSL_DEFAULT_COPTS}
DEPS
absl::algorithm
+ absl::config
absl::core_headers
absl::nullability
absl::throw_delegate
absl::type_traits
+ absl::weakly_mixed_integer
PUBLIC
)
@@ -135,6 +61,7 @@
absl::core_headers
absl::exception_testing
absl::fixed_array
+ absl::hash
absl::inlined_vector
absl::hash_testing
absl::strings
@@ -167,97 +94,23 @@
optional
HDRS
"optional.h"
- SRCS
- "internal/optional.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::bad_optional_access
- absl::base_internal
absl::config
- absl::core_headers
- absl::memory
- absl::nullability
- absl::type_traits
absl::utility
PUBLIC
)
absl_cc_library(
NAME
- bad_optional_access
- HDRS
- "bad_optional_access.h"
- SRCS
- "bad_optional_access.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- DEPS
- absl::config
- absl::raw_logging_internal
- PUBLIC
-)
-
-absl_cc_library(
- NAME
- bad_variant_access
- HDRS
- "bad_variant_access.h"
- SRCS
- "bad_variant_access.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- DEPS
- absl::config
- absl::raw_logging_internal
- PUBLIC
-)
-
-absl_cc_test(
- NAME
- optional_test
- SRCS
- "optional_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::optional
- absl::config
- absl::log
- absl::strings
- absl::type_traits
- GTest::gmock_main
-)
-
-absl_cc_test(
- NAME
- optional_exception_safety_test
- SRCS
- "optional_exception_safety_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::optional
- absl::config
- absl::exception_safety_testing
- GTest::gmock_main
-)
-
-absl_cc_library(
- NAME
variant
HDRS
"variant.h"
- SRCS
- "internal/variant.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::bad_variant_access
- absl::base_internal
absl::config
- absl::core_headers
- absl::type_traits
absl::utility
PUBLIC
)
@@ -271,11 +124,6 @@
${ABSL_TEST_COPTS}
DEPS
absl::variant
- absl::config
- absl::core_headers
- absl::memory
- absl::type_traits
- absl::strings
GTest::gmock_main
)
@@ -306,17 +154,26 @@
GTest::gmock_main
)
-absl_cc_test(
+# Deprecated empty library.
+# Clients should remove this dependency.
+absl_cc_library(
NAME
- variant_exception_safety_test
- SRCS
- "variant_exception_safety_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::variant
- absl::config
- absl::exception_safety_testing
- absl::memory
- GTest::gmock_main
+ bad_any_cast
+ PUBLIC
+)
+
+# Deprecated empty library.
+# Clients should remove this dependency.
+absl_cc_library(
+ NAME
+ bad_optional_access
+ PUBLIC
+)
+
+# Deprecated empty library.
+# Clients should remove this dependency.
+absl_cc_library(
+ NAME
+ bad_variant_access
+ PUBLIC
)
diff --git a/absl/types/any.h b/absl/types/any.h
index 61f071f..c488631 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -17,50 +17,21 @@
// any.h
// -----------------------------------------------------------------------------
//
-// This header file define the `absl::any` type for holding a type-safe value
-// of any type. The 'absl::any` type is useful for providing a way to hold
-// something that is, as yet, unspecified. Such unspecified types
-// traditionally are passed between API boundaries until they are later cast to
-// their "destination" types. To cast to such a destination type, use
-// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it
-// to an explicit type; implicit conversions will throw.
-//
-// Example:
-//
-// auto a = absl::any(65);
-// absl::any_cast<int>(a); // 65
-// absl::any_cast<char>(a); // throws absl::bad_any_cast
-// absl::any_cast<std::string>(a); // throws absl::bad_any_cast
-//
-// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
-// and is designed to be a drop-in replacement for code compliant with C++17.
-//
-// Traditionally, the behavior of casting to a temporary unspecified type has
-// been accomplished with the `void *` paradigm, where the pointer was to some
-// other unspecified type. `absl::any` provides an "owning" version of `void *`
-// that avoids issues of pointer management.
-//
-// Note: just as in the case of `void *`, use of `absl::any` (and its C++17
-// version `std::any`) is a code smell indicating that your API might not be
-// constructed correctly. We have seen that most uses of `any` are unwarranted,
-// and `absl::any`, like `std::any`, is difficult to use properly. Before using
-// this abstraction, make sure that you should not instead be rewriting your
-// code to be more specific.
-//
-// Abseil has also released an `absl::variant` type (a C++11 compatible version
-// of the C++17 `std::variant`), which is generally preferred for use over
-// `absl::any`.
+// Historical note: Abseil once provided an implementation of `absl::any` as a
+// polyfill for `std::any` prior to C++17. Now that C++17 is required,
+// `absl::any` is an alias for `std::any`.
+
#ifndef ABSL_TYPES_ANY_H_
#define ABSL_TYPES_ANY_H_
-#include "absl/base/attributes.h"
-#include "absl/base/config.h"
-#include "absl/utility/utility.h"
-
-#ifdef ABSL_USES_STD_ANY
-
#include <any> // IWYU pragma: export
+#include "absl/base/config.h"
+
+// Include-what-you-use cleanup required for these headers.
+#include "absl/base/attributes.h"
+#include "absl/utility/utility.h"
+
namespace absl {
ABSL_NAMESPACE_BEGIN
using std::any;
@@ -70,450 +41,4 @@
ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_USES_STD_ANY
-
-#include <algorithm>
-#include <cstddef>
-#include <initializer_list>
-#include <memory>
-#include <stdexcept>
-#include <type_traits>
-#include <typeinfo>
-#include <utility>
-
-#include "absl/base/internal/fast_type_id.h"
-#include "absl/meta/type_traits.h"
-#include "absl/types/bad_any_cast.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-class any;
-
-// swap()
-//
-// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are
-// `absl::any` types.
-void swap(any& x, any& y) noexcept;
-
-// make_any()
-//
-// Constructs an `absl::any` of type `T` with the given arguments.
-template <typename T, typename... Args>
-any make_any(Args&&... args);
-
-// Overload of `absl::make_any()` for constructing an `absl::any` type from an
-// initializer list.
-template <typename T, typename U, typename... Args>
-any make_any(std::initializer_list<U> il, Args&&... args);
-
-// any_cast()
-//
-// Statically casts the value of a `const absl::any` type to the given type.
-// This function will throw `absl::bad_any_cast` if the stored value type of the
-// `absl::any` does not match the cast.
-//
-// `any_cast()` can also be used to get a reference to the internal storage iff
-// a reference type is passed as its `ValueType`:
-//
-// Example:
-//
-// absl::any my_any = std::vector<int>();
-// absl::any_cast<std::vector<int>&>(my_any).push_back(42);
-template <typename ValueType>
-ValueType any_cast(const any& operand);
-
-// Overload of `any_cast()` to statically cast the value of a non-const
-// `absl::any` type to the given type. This function will throw
-// `absl::bad_any_cast` if the stored value type of the `absl::any` does not
-// match the cast.
-template <typename ValueType>
-ValueType any_cast(any& operand); // NOLINT(runtime/references)
-
-// Overload of `any_cast()` to statically cast the rvalue of an `absl::any`
-// type. This function will throw `absl::bad_any_cast` if the stored value type
-// of the `absl::any` does not match the cast.
-template <typename ValueType>
-ValueType any_cast(any&& operand);
-
-// Overload of `any_cast()` to statically cast the value of a const pointer
-// `absl::any` type to the given pointer type, or `nullptr` if the stored value
-// type of the `absl::any` does not match the cast.
-template <typename ValueType>
-const ValueType* any_cast(const any* operand) noexcept;
-
-// Overload of `any_cast()` to statically cast the value of a pointer
-// `absl::any` type to the given pointer type, or `nullptr` if the stored value
-// type of the `absl::any` does not match the cast.
-template <typename ValueType>
-ValueType* any_cast(any* operand) noexcept;
-
-// -----------------------------------------------------------------------------
-// absl::any
-// -----------------------------------------------------------------------------
-//
-// An `absl::any` object provides the facility to either store an instance of a
-// type, known as the "contained object", or no value. An `absl::any` is used to
-// store values of types that are unknown at compile time. The `absl::any`
-// object, when containing a value, must contain a value type; storing a
-// reference type is neither desired nor supported.
-//
-// An `absl::any` can only store a type that is copy-constructible; move-only
-// types are not allowed within an `any` object.
-//
-// Example:
-//
-// auto a = absl::any(65); // Literal, copyable
-// auto b = absl::any(std::vector<int>()); // Default-initialized, copyable
-// std::unique_ptr<Foo> my_foo;
-// auto c = absl::any(std::move(my_foo)); // Error, not copy-constructible
-//
-// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this
-// context) to remove const-volatile qualifiers (known as "cv qualifiers"),
-// decay functions to function pointers, etc. We essentially "decay" a given
-// type into its essential type.
-//
-// `absl::any` makes use of decayed types when determining the basic type `T` of
-// the value to store in the any's contained object. In the documentation below,
-// we explicitly denote this by using the phrase "a decayed type of `T`".
-//
-// Example:
-//
-// const int a = 4;
-// absl::any foo(a); // Decay ensures we store an "int", not a "const int&".
-//
-// void my_function() {}
-// absl::any bar(my_function); // Decay ensures we store a function pointer.
-//
-// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction
-// and is designed to be a drop-in replacement for code compliant with C++17.
-class any {
- private:
- template <typename T>
- struct IsInPlaceType;
-
- public:
- // Constructors
-
- // Constructs an empty `absl::any` object (`any::has_value()` will return
- // `false`).
- constexpr any() noexcept;
-
- // Copy constructs an `absl::any` object with a "contained object" of the
- // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
- // `false`.
- any(const any& other)
- : obj_(other.has_value() ? other.obj_->Clone()
- : std::unique_ptr<ObjInterface>()) {}
-
- // Move constructs an `absl::any` object with a "contained object" of the
- // passed type of `other` (or an empty `absl::any` if `other.has_value()` is
- // `false`).
- any(any&& other) noexcept = default;
-
- // Constructs an `absl::any` object with a "contained object" of the decayed
- // type of `T`, which is initialized via `std::forward<T>(value)`.
- //
- // This constructor will not participate in overload resolution if the
- // decayed type of `T` is not copy-constructible.
- template <
- typename T, typename VT = absl::decay_t<T>,
- absl::enable_if_t<!absl::disjunction<
- std::is_same<any, VT>, IsInPlaceType<VT>,
- absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr>
- any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {}
-
- // Constructs an `absl::any` object with a "contained object" of the decayed
- // type of `T`, which is initialized via `std::forward<T>(value)`.
- template <typename T, typename... Args, typename VT = absl::decay_t<T>,
- absl::enable_if_t<absl::conjunction<
- std::is_copy_constructible<VT>,
- std::is_constructible<VT, Args...>>::value>* = nullptr>
- explicit any(in_place_type_t<T> /*tag*/, Args&&... args)
- : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {}
-
- // Constructs an `absl::any` object with a "contained object" of the passed
- // type `VT` as a decayed type of `T`. `VT` is initialized as if
- // direct-non-list-initializing an object of type `VT` with the arguments
- // `initializer_list, std::forward<Args>(args)...`.
- template <
- typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
- absl::enable_if_t<
- absl::conjunction<std::is_copy_constructible<VT>,
- std::is_constructible<VT, std::initializer_list<U>&,
- Args...>>::value>* = nullptr>
- explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist,
- Args&&... args)
- : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {}
-
- // Assignment operators
-
- // Copy assigns an `absl::any` object with a "contained object" of the
- // passed type.
- any& operator=(const any& rhs) {
- any(rhs).swap(*this);
- return *this;
- }
-
- // Move assigns an `absl::any` object with a "contained object" of the
- // passed type. `rhs` is left in a valid but otherwise unspecified state.
- any& operator=(any&& rhs) noexcept {
- any(std::move(rhs)).swap(*this);
- return *this;
- }
-
- // Assigns an `absl::any` object with a "contained object" of the passed type.
- template <typename T, typename VT = absl::decay_t<T>,
- absl::enable_if_t<absl::conjunction<
- absl::negation<std::is_same<VT, any>>,
- std::is_copy_constructible<VT>>::value>* = nullptr>
- any& operator=(T&& rhs) {
- any tmp(in_place_type_t<VT>(), std::forward<T>(rhs));
- tmp.swap(*this);
- return *this;
- }
-
- // Modifiers
-
- // any::emplace()
- //
- // Emplaces a value within an `absl::any` object by calling `any::reset()`,
- // initializing the contained value as if direct-non-list-initializing an
- // object of type `VT` with the arguments `std::forward<Args>(args)...`, and
- // returning a reference to the new contained value.
- //
- // Note: If an exception is thrown during the call to `VT`'s constructor,
- // `*this` does not contain a value, and any previously contained value has
- // been destroyed.
- template <
- typename T, typename... Args, typename VT = absl::decay_t<T>,
- absl::enable_if_t<std::is_copy_constructible<VT>::value &&
- std::is_constructible<VT, Args...>::value>* = nullptr>
- VT& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- reset(); // NOTE: reset() is required here even in the world of exceptions.
- Obj<VT>* const object_ptr =
- new Obj<VT>(in_place, std::forward<Args>(args)...);
- obj_ = std::unique_ptr<ObjInterface>(object_ptr);
- return object_ptr->value;
- }
-
- // Overload of `any::emplace()` to emplace a value within an `absl::any`
- // object by calling `any::reset()`, initializing the contained value as if
- // direct-non-list-initializing an object of type `VT` with the arguments
- // `initializer_list, std::forward<Args>(args)...`, and returning a reference
- // to the new contained value.
- //
- // Note: If an exception is thrown during the call to `VT`'s constructor,
- // `*this` does not contain a value, and any previously contained value has
- // been destroyed. The function shall not participate in overload resolution
- // unless `is_copy_constructible_v<VT>` is `true` and
- // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`.
- template <
- typename T, typename U, typename... Args, typename VT = absl::decay_t<T>,
- absl::enable_if_t<std::is_copy_constructible<VT>::value &&
- std::is_constructible<VT, std::initializer_list<U>&,
- Args...>::value>* = nullptr>
- VT& emplace(std::initializer_list<U> ilist,
- Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- reset(); // NOTE: reset() is required here even in the world of exceptions.
- Obj<VT>* const object_ptr =
- new Obj<VT>(in_place, ilist, std::forward<Args>(args)...);
- obj_ = std::unique_ptr<ObjInterface>(object_ptr);
- return object_ptr->value;
- }
-
- // any::reset()
- //
- // Resets the state of the `absl::any` object, destroying the contained object
- // if present.
- void reset() noexcept { obj_ = nullptr; }
-
- // any::swap()
- //
- // Swaps the passed value and the value of this `absl::any` object.
- void swap(any& other) noexcept { obj_.swap(other.obj_); }
-
- // Observers
-
- // any::has_value()
- //
- // Returns `true` if the `any` object has a contained value, otherwise
- // returns `false`.
- bool has_value() const noexcept { return obj_ != nullptr; }
-
-#ifdef ABSL_INTERNAL_HAS_RTTI
- // Returns: typeid(T) if *this has a contained object of type T, otherwise
- // typeid(void).
- const std::type_info& type() const noexcept {
- if (has_value()) {
- return obj_->Type();
- }
-
- return typeid(void);
- }
-#endif // ABSL_INTERNAL_HAS_RTTI
-
- private:
- // Tagged type-erased abstraction for holding a cloneable object.
- class ObjInterface {
- public:
- virtual ~ObjInterface() = default;
- virtual std::unique_ptr<ObjInterface> Clone() const = 0;
- virtual const void* ObjTypeId() const noexcept = 0;
-#ifdef ABSL_INTERNAL_HAS_RTTI
- virtual const std::type_info& Type() const noexcept = 0;
-#endif // ABSL_INTERNAL_HAS_RTTI
- };
-
- // Hold a value of some queryable type, with an ability to Clone it.
- template <typename T>
- class Obj : public ObjInterface {
- public:
- template <typename... Args>
- explicit Obj(in_place_t /*tag*/, Args&&... args)
- : value(std::forward<Args>(args)...) {}
-
- std::unique_ptr<ObjInterface> Clone() const final {
- return std::unique_ptr<ObjInterface>(new Obj(in_place, value));
- }
-
- const void* ObjTypeId() const noexcept final { return IdForType<T>(); }
-
-#ifdef ABSL_INTERNAL_HAS_RTTI
- const std::type_info& Type() const noexcept final { return typeid(T); }
-#endif // ABSL_INTERNAL_HAS_RTTI
-
- T value;
- };
-
- std::unique_ptr<ObjInterface> CloneObj() const {
- if (!obj_) return nullptr;
- return obj_->Clone();
- }
-
- template <typename T>
- constexpr static const void* IdForType() {
- // Note: This type dance is to make the behavior consistent with typeid.
- using NormalizedType =
- typename std::remove_cv<typename std::remove_reference<T>::type>::type;
-
- return base_internal::FastTypeId<NormalizedType>();
- }
-
- const void* GetObjTypeId() const {
- return obj_ ? obj_->ObjTypeId() : base_internal::FastTypeId<void>();
- }
-
- // `absl::any` nonmember functions //
-
- // Description at the declaration site (top of file).
- template <typename ValueType>
- friend ValueType any_cast(const any& operand);
-
- // Description at the declaration site (top of file).
- template <typename ValueType>
- friend ValueType any_cast(any& operand); // NOLINT(runtime/references)
-
- // Description at the declaration site (top of file).
- template <typename T>
- friend const T* any_cast(const any* operand) noexcept;
-
- // Description at the declaration site (top of file).
- template <typename T>
- friend T* any_cast(any* operand) noexcept;
-
- std::unique_ptr<ObjInterface> obj_;
-};
-
-// -----------------------------------------------------------------------------
-// Implementation Details
-// -----------------------------------------------------------------------------
-
-constexpr any::any() noexcept = default;
-
-template <typename T>
-struct any::IsInPlaceType : std::false_type {};
-
-template <typename T>
-struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {};
-
-inline void swap(any& x, any& y) noexcept { x.swap(y); }
-
-// Description at the declaration site (top of file).
-template <typename T, typename... Args>
-any make_any(Args&&... args) {
- return any(in_place_type_t<T>(), std::forward<Args>(args)...);
-}
-
-// Description at the declaration site (top of file).
-template <typename T, typename U, typename... Args>
-any make_any(std::initializer_list<U> il, Args&&... args) {
- return any(in_place_type_t<T>(), il, std::forward<Args>(args)...);
-}
-
-// Description at the declaration site (top of file).
-template <typename ValueType>
-ValueType any_cast(const any& operand) {
- using U = typename std::remove_cv<
- typename std::remove_reference<ValueType>::type>::type;
- static_assert(std::is_constructible<ValueType, const U&>::value,
- "Invalid ValueType");
- auto* const result = (any_cast<U>)(&operand);
- if (result == nullptr) {
- any_internal::ThrowBadAnyCast();
- }
- return static_cast<ValueType>(*result);
-}
-
-// Description at the declaration site (top of file).
-template <typename ValueType>
-ValueType any_cast(any& operand) { // NOLINT(runtime/references)
- using U = typename std::remove_cv<
- typename std::remove_reference<ValueType>::type>::type;
- static_assert(std::is_constructible<ValueType, U&>::value,
- "Invalid ValueType");
- auto* result = (any_cast<U>)(&operand);
- if (result == nullptr) {
- any_internal::ThrowBadAnyCast();
- }
- return static_cast<ValueType>(*result);
-}
-
-// Description at the declaration site (top of file).
-template <typename ValueType>
-ValueType any_cast(any&& operand) {
- using U = typename std::remove_cv<
- typename std::remove_reference<ValueType>::type>::type;
- static_assert(std::is_constructible<ValueType, U>::value,
- "Invalid ValueType");
- return static_cast<ValueType>(std::move((any_cast<U&>)(operand)));
-}
-
-// Description at the declaration site (top of file).
-template <typename T>
-const T* any_cast(const any* operand) noexcept {
- using U =
- typename std::remove_cv<typename std::remove_reference<T>::type>::type;
- return operand && operand->GetObjTypeId() == any::IdForType<U>()
- ? std::addressof(
- static_cast<const any::Obj<U>*>(operand->obj_.get())->value)
- : nullptr;
-}
-
-// Description at the declaration site (top of file).
-template <typename T>
-T* any_cast(any* operand) noexcept {
- using U =
- typename std::remove_cv<typename std::remove_reference<T>::type>::type;
- return operand && operand->GetObjTypeId() == any::IdForType<U>()
- ? std::addressof(
- static_cast<any::Obj<U>*>(operand->obj_.get())->value)
- : nullptr;
-}
-
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_USES_STD_ANY
-
#endif // ABSL_TYPES_ANY_H_
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc
deleted file mode 100644
index 31c1140..0000000
--- a/absl/types/any_exception_safety_test.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/any.h"
-
-#include "absl/base/config.h"
-
-// This test is a no-op when absl::any is an alias for std::any and when
-// exceptions are not enabled.
-#if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
-
-#include <typeinfo>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "absl/base/internal/exception_safety_testing.h"
-
-using Thrower = testing::ThrowingValue<>;
-using NoThrowMoveThrower =
- testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
-using ThrowerList = std::initializer_list<Thrower>;
-using ThrowerVec = std::vector<Thrower>;
-using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
-using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
-
-namespace {
-
-testing::AssertionResult AnyInvariants(absl::any* a) {
- using testing::AssertionFailure;
- using testing::AssertionSuccess;
-
- if (a->has_value()) {
- if (a->type() == typeid(void)) {
- return AssertionFailure()
- << "A non-empty any should not have type `void`";
- }
- } else {
- if (a->type() != typeid(void)) {
- return AssertionFailure()
- << "An empty any should have type void, but has type "
- << a->type().name();
- }
- }
-
- // Make sure that reset() changes any to a valid state.
- a->reset();
- if (a->has_value()) {
- return AssertionFailure() << "A reset `any` should be valueless";
- }
- if (a->type() != typeid(void)) {
- return AssertionFailure() << "A reset `any` should have type() of `void`, "
- "but instead has type "
- << a->type().name();
- }
- try {
- auto unused = absl::any_cast<Thrower>(*a);
- static_cast<void>(unused);
- return AssertionFailure()
- << "A reset `any` should not be able to be any_cast";
- } catch (const absl::bad_any_cast&) {
- } catch (...) {
- return AssertionFailure()
- << "Unexpected exception thrown from absl::any_cast";
- }
- return AssertionSuccess();
-}
-
-testing::AssertionResult AnyIsEmpty(absl::any* a) {
- if (!a->has_value()) {
- return testing::AssertionSuccess();
- }
- return testing::AssertionFailure()
- << "a should be empty, but instead has value "
- << absl::any_cast<Thrower>(*a).Get();
-}
-
-TEST(AnyExceptionSafety, Ctors) {
- Thrower val(1);
- testing::TestThrowingCtor<absl::any>(val);
-
- Thrower copy(val);
- testing::TestThrowingCtor<absl::any>(copy);
-
- testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
-
- testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(),
- ThrowerList{val});
-
- testing::TestThrowingCtor<absl::any,
- absl::in_place_type_t<ThrowingThrowerVec>,
- ThrowerList, ThrowingAlloc>(
- absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
-}
-
-TEST(AnyExceptionSafety, Assignment) {
- auto original =
- absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor);
- auto any_is_strong = [original](absl::any* ap) {
- return testing::AssertionResult(ap->has_value() &&
- absl::any_cast<Thrower>(original) ==
- absl::any_cast<Thrower>(*ap));
- };
- auto any_strong_tester = testing::MakeExceptionSafetyTester()
- .WithInitialValue(original)
- .WithContracts(AnyInvariants, any_is_strong);
-
- Thrower val(2);
- absl::any any_val(val);
- NoThrowMoveThrower mv_val(2);
-
- auto assign_any = [&any_val](absl::any* ap) { *ap = any_val; };
- auto assign_val = [&val](absl::any* ap) { *ap = val; };
- auto move = [&val](absl::any* ap) { *ap = std::move(val); };
- auto move_movable = [&mv_val](absl::any* ap) { *ap = std::move(mv_val); };
-
- EXPECT_TRUE(any_strong_tester.Test(assign_any));
- EXPECT_TRUE(any_strong_tester.Test(assign_val));
- EXPECT_TRUE(any_strong_tester.Test(move));
- EXPECT_TRUE(any_strong_tester.Test(move_movable));
-
- auto empty_any_is_strong = [](absl::any* ap) {
- return testing::AssertionResult{!ap->has_value()};
- };
- auto strong_empty_any_tester =
- testing::MakeExceptionSafetyTester()
- .WithInitialValue(absl::any{})
- .WithContracts(AnyInvariants, empty_any_is_strong);
-
- EXPECT_TRUE(strong_empty_any_tester.Test(assign_any));
- EXPECT_TRUE(strong_empty_any_tester.Test(assign_val));
- EXPECT_TRUE(strong_empty_any_tester.Test(move));
-}
-
-TEST(AnyExceptionSafety, Emplace) {
- auto initial_val =
- absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor};
- auto one_tester = testing::MakeExceptionSafetyTester()
- .WithInitialValue(initial_val)
- .WithContracts(AnyInvariants, AnyIsEmpty);
-
- auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
- auto emp_throwervec = [](absl::any* ap) {
- std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)};
- ap->emplace<ThrowerVec>(il);
- };
- auto emp_movethrower = [](absl::any* ap) {
- ap->emplace<NoThrowMoveThrower>(2);
- };
-
- EXPECT_TRUE(one_tester.Test(emp_thrower));
- EXPECT_TRUE(one_tester.Test(emp_throwervec));
- EXPECT_TRUE(one_tester.Test(emp_movethrower));
-
- auto empty_tester = one_tester.WithInitialValue(absl::any{});
-
- EXPECT_TRUE(empty_tester.Test(emp_thrower));
- EXPECT_TRUE(empty_tester.Test(emp_throwervec));
-}
-
-} // namespace
-
-#endif // #if !defined(ABSL_USES_STD_ANY) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc
deleted file mode 100644
index 666ea5b..0000000
--- a/absl/types/any_test.cc
+++ /dev/null
@@ -1,778 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/any.h"
-
-// This test is a no-op when absl::any is an alias for std::any.
-#if !defined(ABSL_USES_STD_ANY)
-
-#include <initializer_list>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "absl/base/config.h"
-#include "absl/base/internal/exception_testing.h"
-#include "absl/container/internal/test_instance_tracker.h"
-#include "absl/log/log.h"
-
-namespace {
-using absl::test_internal::CopyableOnlyInstance;
-using absl::test_internal::InstanceTracker;
-
-template <typename T>
-const T& AsConst(const T& t) {
- return t;
-}
-
-struct MoveOnly {
- MoveOnly() = default;
- explicit MoveOnly(int value) : value(value) {}
- MoveOnly(MoveOnly&&) = default;
- MoveOnly& operator=(MoveOnly&&) = default;
-
- int value = 0;
-};
-
-struct CopyOnly {
- CopyOnly() = default;
- explicit CopyOnly(int value) : value(value) {}
- CopyOnly(CopyOnly&&) = delete;
- CopyOnly& operator=(CopyOnly&&) = delete;
- CopyOnly(const CopyOnly&) = default;
- CopyOnly& operator=(const CopyOnly&) = default;
-
- int value = 0;
-};
-
-struct MoveOnlyWithListConstructor {
- MoveOnlyWithListConstructor() = default;
- explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
- int value)
- : value(value) {}
- MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
- MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
- default;
-
- int value = 0;
-};
-
-struct IntMoveOnlyCopyOnly {
- IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/)
- : value(value) {}
-
- int value;
-};
-
-struct ListMoveOnlyCopyOnly {
- ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/,
- CopyOnly /*copy_only*/)
- : values(ilist) {}
-
- std::vector<int> values;
-};
-
-using FunctionType = void();
-void FunctionToEmplace() {}
-
-using ArrayType = int[2];
-using DecayedArray = absl::decay_t<ArrayType>;
-
-TEST(AnyTest, Noexcept) {
- static_assert(std::is_nothrow_default_constructible<absl::any>(), "");
- static_assert(std::is_nothrow_move_constructible<absl::any>(), "");
- static_assert(std::is_nothrow_move_assignable<absl::any>(), "");
- static_assert(noexcept(std::declval<absl::any&>().has_value()), "");
- static_assert(noexcept(std::declval<absl::any&>().type()), "");
- static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), "");
- static_assert(
- noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())),
- "");
-
- using std::swap;
- static_assert(
- noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())),
- "");
-}
-
-TEST(AnyTest, HasValue) {
- absl::any o;
- EXPECT_FALSE(o.has_value());
- o.emplace<int>();
- EXPECT_TRUE(o.has_value());
- o.reset();
- EXPECT_FALSE(o.has_value());
-}
-
-TEST(AnyTest, Type) {
- absl::any o;
- EXPECT_EQ(typeid(void), o.type());
- o.emplace<int>(5);
- EXPECT_EQ(typeid(int), o.type());
- o.emplace<float>(5.f);
- EXPECT_EQ(typeid(float), o.type());
- o.reset();
- EXPECT_EQ(typeid(void), o.type());
-}
-
-TEST(AnyTest, EmptyPointerCast) {
- // pointer-to-unqualified overload
- {
- absl::any o;
- EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
- o.emplace<int>();
- EXPECT_NE(nullptr, absl::any_cast<int>(&o));
- o.reset();
- EXPECT_EQ(nullptr, absl::any_cast<int>(&o));
- }
-
- // pointer-to-const overload
- {
- absl::any o;
- EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
- o.emplace<int>();
- EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o)));
- o.reset();
- EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o)));
- }
-}
-
-TEST(AnyTest, InPlaceConstruction) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(),
- copy_only);
- IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
-}
-
-TEST(AnyTest, InPlaceConstructionVariableTemplate) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type<IntMoveOnlyCopyOnly>, 5, MoveOnly(),
- copy_only);
- auto& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
-}
-
-TEST(AnyTest, InPlaceConstructionWithCV) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5,
- MoveOnly(), copy_only);
- IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
-}
-
-TEST(AnyTest, InPlaceConstructionWithCVVariableTemplate) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type<const volatile IntMoveOnlyCopyOnly>, 5,
- MoveOnly(), copy_only);
- auto& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
-}
-
-TEST(AnyTest, InPlaceConstructionWithFunction) {
- absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace);
- FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o);
- EXPECT_EQ(&FunctionToEmplace, construction_result);
-}
-
-TEST(AnyTest, InPlaceConstructionWithFunctionVariableTemplate) {
- absl::any o(absl::in_place_type<FunctionType>, FunctionToEmplace);
- auto& construction_result = absl::any_cast<FunctionType*&>(o);
- EXPECT_EQ(&FunctionToEmplace, construction_result);
-}
-
-TEST(AnyTest, InPlaceConstructionWithArray) {
- ArrayType ar = {5, 42};
- absl::any o(absl::in_place_type_t<ArrayType>(), ar);
- DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o);
- EXPECT_EQ(&ar[0], construction_result);
-}
-
-TEST(AnyTest, InPlaceConstructionWithArrayVariableTemplate) {
- ArrayType ar = {5, 42};
- absl::any o(absl::in_place_type<ArrayType>, ar);
- auto& construction_result = absl::any_cast<DecayedArray&>(o);
- EXPECT_EQ(&ar[0], construction_result);
-}
-
-TEST(AnyTest, InPlaceConstructionIlist) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4},
- MoveOnly(), copy_only);
- ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-}
-
-TEST(AnyTest, InPlaceConstructionIlistVariableTemplate) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type<ListMoveOnlyCopyOnly>, {1, 2, 3, 4},
- MoveOnly(), copy_only);
- auto& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-}
-
-TEST(AnyTest, InPlaceConstructionIlistWithCV) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(),
- {1, 2, 3, 4}, MoveOnly(), copy_only);
- ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-}
-
-TEST(AnyTest, InPlaceConstructionIlistWithCVVariableTemplate) {
- const CopyOnly copy_only{};
- absl::any o(absl::in_place_type<const volatile ListMoveOnlyCopyOnly>,
- {1, 2, 3, 4}, MoveOnly(), copy_only);
- auto& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-}
-
-TEST(AnyTest, InPlaceNoArgs) {
- absl::any o(absl::in_place_type_t<int>{});
- EXPECT_EQ(0, absl::any_cast<int&>(o));
-}
-
-TEST(AnyTest, InPlaceNoArgsVariableTemplate) {
- absl::any o(absl::in_place_type<int>);
- EXPECT_EQ(0, absl::any_cast<int&>(o));
-}
-
-template <typename Enabler, typename T, typename... Args>
-struct CanEmplaceAnyImpl : std::false_type {};
-
-template <typename T, typename... Args>
-struct CanEmplaceAnyImpl<
- absl::void_t<decltype(
- std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>,
- T, Args...> : std::true_type {};
-
-template <typename T, typename... Args>
-using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>;
-
-TEST(AnyTest, Emplace) {
- const CopyOnly copy_only{};
- absl::any o;
- EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>(
- 5, MoveOnly(), copy_only)),
- IntMoveOnlyCopyOnly&>::value));
- IntMoveOnlyCopyOnly& emplace_result =
- o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
- EXPECT_EQ(5, emplace_result.value);
- IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
- EXPECT_EQ(&emplace_result, &v);
-
- static_assert(!CanEmplaceAny<int, int, int>::value, "");
- static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, "");
-}
-
-TEST(AnyTest, EmplaceWithCV) {
- const CopyOnly copy_only{};
- absl::any o;
- EXPECT_TRUE(
- (std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>(
- 5, MoveOnly(), copy_only)),
- IntMoveOnlyCopyOnly&>::value));
- IntMoveOnlyCopyOnly& emplace_result =
- o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
- EXPECT_EQ(5, emplace_result.value);
- IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(5, v.value);
- EXPECT_EQ(&emplace_result, &v);
-}
-
-TEST(AnyTest, EmplaceWithFunction) {
- absl::any o;
- EXPECT_TRUE(
- (std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)),
- FunctionType*&>::value));
- FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace);
- EXPECT_EQ(&FunctionToEmplace, emplace_result);
-}
-
-TEST(AnyTest, EmplaceWithArray) {
- absl::any o;
- ArrayType ar = {5, 42};
- EXPECT_TRUE(
- (std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value));
- DecayedArray& emplace_result = o.emplace<ArrayType>(ar);
- EXPECT_EQ(&ar[0], emplace_result);
-}
-
-TEST(AnyTest, EmplaceIlist) {
- const CopyOnly copy_only{};
- absl::any o;
- EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>(
- {1, 2, 3, 4}, MoveOnly(), copy_only)),
- ListMoveOnlyCopyOnly&>::value));
- ListMoveOnlyCopyOnly& emplace_result =
- o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only);
- ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(&v, &emplace_result);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-
- static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, "");
- static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor,
- std::initializer_list<int>, int>::value,
- "");
-}
-
-TEST(AnyTest, EmplaceIlistWithCV) {
- const CopyOnly copy_only{};
- absl::any o;
- EXPECT_TRUE(
- (std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>(
- {1, 2, 3, 4}, MoveOnly(), copy_only)),
- ListMoveOnlyCopyOnly&>::value));
- ListMoveOnlyCopyOnly& emplace_result =
- o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(),
- copy_only);
- ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- EXPECT_EQ(&v, &emplace_result);
- std::vector<int> expected_values = {1, 2, 3, 4};
- EXPECT_EQ(expected_values, v.values);
-}
-
-TEST(AnyTest, EmplaceNoArgs) {
- absl::any o;
- o.emplace<int>();
- EXPECT_EQ(0, absl::any_cast<int>(o));
-}
-
-TEST(AnyTest, ConversionConstruction) {
- {
- absl::any o = 5;
- EXPECT_EQ(5, absl::any_cast<int>(o));
- }
-
- {
- const CopyOnly copy_only(5);
- absl::any o = copy_only;
- EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
- }
-
- static_assert(!std::is_convertible<MoveOnly, absl::any>::value, "");
-}
-
-TEST(AnyTest, ConversionAssignment) {
- {
- absl::any o;
- o = 5;
- EXPECT_EQ(5, absl::any_cast<int>(o));
- }
-
- {
- const CopyOnly copy_only(5);
- absl::any o;
- o = copy_only;
- EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value);
- }
-
- static_assert(!std::is_assignable<MoveOnly, absl::any>::value, "");
-}
-
-// Suppress MSVC warnings.
-// 4521: multiple copy constructors specified
-// We wrote multiple of them to test that the correct overloads are selected.
-#ifdef _MSC_VER
-#pragma warning( push )
-#pragma warning( disable : 4521)
-#endif
-
-// Weird type for testing, only used to make sure we "properly" perfect-forward
-// when being placed into an absl::any (use the l-value constructor if given an
-// l-value rather than use the copy constructor).
-struct WeirdConstructor42 {
- explicit WeirdConstructor42(int value) : value(value) {}
-
- // Copy-constructor
- WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {}
-
- // L-value "weird" constructor (used when given an l-value)
- WeirdConstructor42(
- WeirdConstructor42& /*other*/) // NOLINT(runtime/references)
- : value(42) {}
-
- int value;
-};
-#ifdef _MSC_VER
-#pragma warning( pop )
-#endif
-
-TEST(AnyTest, WeirdConversionConstruction) {
- {
- const WeirdConstructor42 source(5);
- absl::any o = source; // Actual copy
- EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
- }
-
- {
- WeirdConstructor42 source(5);
- absl::any o = source; // Weird "conversion"
- EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
- }
-}
-
-TEST(AnyTest, WeirdConversionAssignment) {
- {
- const WeirdConstructor42 source(5);
- absl::any o;
- o = source; // Actual copy
- EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value);
- }
-
- {
- WeirdConstructor42 source(5);
- absl::any o;
- o = source; // Weird "conversion"
- EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value);
- }
-}
-
-struct Value {};
-
-TEST(AnyTest, AnyCastValue) {
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<int>(o));
- EXPECT_EQ(5, absl::any_cast<int>(AsConst(o)));
- static_assert(
- std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, "");
- }
-
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<const int>(o));
- EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
- static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)),
- const Value>::value,
- "");
- }
-}
-
-TEST(AnyTest, AnyCastReference) {
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<int&>(o));
- EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o)));
- static_assert(
- std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, "");
- }
-
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<const int>(o));
- EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o)));
- static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)),
- const Value&>::value,
- "");
- }
-
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o)));
- static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))),
- Value&&>::value,
- "");
- }
-
- {
- absl::any o;
- o.emplace<int>(5);
- EXPECT_EQ(5, absl::any_cast<const int>(std::move(o)));
- static_assert(
- std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))),
- const Value&&>::value,
- "");
- }
-}
-
-TEST(AnyTest, AnyCastPointer) {
- {
- absl::any o;
- EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
- o.emplace<int>(5);
- EXPECT_EQ(nullptr, absl::any_cast<char>(&o));
- o.emplace<char>('a');
- EXPECT_EQ('a', *absl::any_cast<char>(&o));
- static_assert(
- std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, "");
- }
-
- {
- absl::any o;
- EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
- o.emplace<int>(5);
- EXPECT_EQ(nullptr, absl::any_cast<const char>(&o));
- o.emplace<char>('a');
- EXPECT_EQ('a', *absl::any_cast<const char>(&o));
- static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)),
- const Value*>::value,
- "");
- }
-}
-
-TEST(AnyTest, MakeAny) {
- const CopyOnly copy_only{};
- auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only);
- static_assert(std::is_same<decltype(o), absl::any>::value, "");
- EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value);
-}
-
-TEST(AnyTest, MakeAnyIList) {
- const CopyOnly copy_only{};
- auto o =
- absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only);
- static_assert(std::is_same<decltype(o), absl::any>::value, "");
- ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o);
- std::vector<int> expected_values = {1, 2, 3};
- EXPECT_EQ(expected_values, v.values);
-}
-
-// Test the use of copy constructor and operator=
-TEST(AnyTest, Copy) {
- InstanceTracker tracker_raii;
-
- {
- absl::any o(absl::in_place_type<CopyableOnlyInstance>, 123);
- CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
-
- absl::any o2(o);
- const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2);
- EXPECT_EQ(123, f2->value());
- EXPECT_NE(f1, f2);
-
- absl::any o3;
- o3 = o2;
- const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3);
- EXPECT_EQ(123, f3->value());
- EXPECT_NE(f2, f3);
-
- const absl::any o4(4);
- // copy construct from const lvalue ref.
- absl::any o5 = o4;
- EXPECT_EQ(4, absl::any_cast<int>(o4));
- EXPECT_EQ(4, absl::any_cast<int>(o5));
-
- // Copy construct from const rvalue ref.
- absl::any o6 = std::move(o4); // NOLINT
- EXPECT_EQ(4, absl::any_cast<int>(o4));
- EXPECT_EQ(4, absl::any_cast<int>(o6));
- }
-}
-
-TEST(AnyTest, Move) {
- InstanceTracker tracker_raii;
-
- absl::any any1;
- any1.emplace<CopyableOnlyInstance>(5);
-
- // This is a copy, so copy count increases to 1.
- absl::any any2 = any1;
- EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value());
- EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value());
- EXPECT_EQ(1, tracker_raii.copies());
-
- // This isn't a copy, so copy count doesn't increase.
- absl::any any3 = std::move(any2);
- EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value());
- EXPECT_EQ(1, tracker_raii.copies());
-
- absl::any any4;
- any4 = std::move(any3);
- EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value());
- EXPECT_EQ(1, tracker_raii.copies());
-
- absl::any tmp4(4);
- absl::any o4(std::move(tmp4)); // move construct
- EXPECT_EQ(4, absl::any_cast<int>(o4));
- o4 = *&o4; // self assign
- EXPECT_EQ(4, absl::any_cast<int>(o4));
- EXPECT_TRUE(o4.has_value());
-
- absl::any o5;
- absl::any tmp5(5);
- o5 = std::move(tmp5); // move assign
- EXPECT_EQ(5, absl::any_cast<int>(o5));
-}
-
-// Reset the ObjectOwner with an object of a different type
-TEST(AnyTest, Reset) {
- absl::any o;
- o.emplace<int>();
-
- o.reset();
- EXPECT_FALSE(o.has_value());
-
- o.emplace<char>();
- EXPECT_TRUE(o.has_value());
-}
-
-TEST(AnyTest, ConversionConstructionCausesOneCopy) {
- InstanceTracker tracker_raii;
- CopyableOnlyInstance counter(5);
- absl::any o(counter);
- EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value());
- EXPECT_EQ(1, tracker_raii.copies());
-}
-
-//////////////////////////////////
-// Tests for Exception Behavior //
-//////////////////////////////////
-
-#if defined(ABSL_USES_STD_ANY)
-
-// If using a std `any` implementation, we can't check for a specific message.
-#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
- ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
- "")
-
-#else
-
-// If using the absl `any` implementation, we can rely on a specific message.
-#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \
- ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \
- "Bad any cast")
-
-#endif // defined(ABSL_USES_STD_ANY)
-
-TEST(AnyTest, ThrowBadAlloc) {
- {
- absl::any a;
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{}));
-
- // const absl::any operand
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a)));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a)));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a)));
- }
-
- {
- absl::any a(absl::in_place_type<int>);
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(
- absl::any_cast<const float&&>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{}));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{}));
-
- // const absl::any operand
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a)));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a)));
- ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a)));
- }
-}
-
-class BadCopy {};
-
-struct BadCopyable {
- BadCopyable() = default;
- BadCopyable(BadCopyable&&) = default;
- BadCopyable(const BadCopyable&) {
-#ifdef ABSL_HAVE_EXCEPTIONS
- throw BadCopy();
-#else
- LOG(FATAL) << "Bad copy";
-#endif
- }
-};
-
-#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \
- ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy")
-
-// Test the guarantees regarding exceptions in copy/assign.
-TEST(AnyTest, FailedCopy) {
- {
- const BadCopyable bad{};
- ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad});
- }
-
- {
- absl::any src(absl::in_place_type<BadCopyable>);
- ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
- }
-
- {
- BadCopyable bad;
- absl::any target;
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
- }
-
- {
- BadCopyable bad;
- absl::any target(absl::in_place_type<BadCopyable>);
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad);
- EXPECT_TRUE(target.has_value());
- }
-
- {
- absl::any src(absl::in_place_type<BadCopyable>);
- absl::any target;
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
- EXPECT_FALSE(target.has_value());
- }
-
- {
- absl::any src(absl::in_place_type<BadCopyable>);
- absl::any target(absl::in_place_type<BadCopyable>);
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src);
- EXPECT_TRUE(target.has_value());
- }
-}
-
-// Test the guarantees regarding exceptions in emplace.
-TEST(AnyTest, FailedEmplace) {
- BadCopyable bad;
- absl::any target;
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
-}
-
-// GCC and Clang have a bug here.
-// Ine some cases, the exception seems to be thrown at the wrong time, and
-// target may contain a value.
-#ifdef __GNUC__
-TEST(AnyTest, DISABLED_FailedEmplaceInPlace) {
-#else
-TEST(AnyTest, FailedEmplaceInPlace) {
-#endif
- BadCopyable bad;
- absl::any target(absl::in_place_type<int>);
- ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
- EXPECT_FALSE(target.has_value());
-}
-
-} // namespace
-
-#endif // #if !defined(ABSL_USES_STD_ANY)
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc
deleted file mode 100644
index 22558b4..0000000
--- a/absl/types/bad_any_cast.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/bad_any_cast.h"
-
-#ifndef ABSL_USES_STD_ANY
-
-#include <cstdlib>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-bad_any_cast::~bad_any_cast() = default;
-
-const char* bad_any_cast::what() const noexcept { return "Bad any cast"; }
-
-namespace any_internal {
-
-void ThrowBadAnyCast() {
-#ifdef ABSL_HAVE_EXCEPTIONS
- throw bad_any_cast();
-#else
- ABSL_RAW_LOG(FATAL, "Bad any cast");
- std::abort();
-#endif
-}
-
-} // namespace any_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else
-
-// https://github.com/abseil/abseil-cpp/issues/1465
-// CMake builds on Apple platforms error when libraries are empty.
-// Our CMake configuration can avoid this error on header-only libraries,
-// but since this library is conditionally empty, including a single
-// variable is an easy workaround.
-#ifdef __APPLE__
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace types_internal {
-extern const char kAvoidEmptyBadAnyCastLibraryWarning;
-const char kAvoidEmptyBadAnyCastLibraryWarning = 0;
-} // namespace types_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-#endif // __APPLE__
-
-#endif // ABSL_USES_STD_ANY
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
deleted file mode 100644
index 114cef8..0000000
--- a/absl/types/bad_any_cast.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// -----------------------------------------------------------------------------
-// bad_any_cast.h
-// -----------------------------------------------------------------------------
-//
-// This header file defines the `absl::bad_any_cast` type.
-
-#ifndef ABSL_TYPES_BAD_ANY_CAST_H_
-#define ABSL_TYPES_BAD_ANY_CAST_H_
-
-#include <typeinfo>
-
-#include "absl/base/config.h"
-
-#ifdef ABSL_USES_STD_ANY
-
-#include <any>
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-using std::bad_any_cast;
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else // ABSL_USES_STD_ANY
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// -----------------------------------------------------------------------------
-// bad_any_cast
-// -----------------------------------------------------------------------------
-//
-// An `absl::bad_any_cast` type is an exception type that is thrown when
-// failing to successfully cast the return value of an `absl::any` object.
-//
-// Example:
-//
-// auto a = absl::any(65);
-// absl::any_cast<int>(a); // 65
-// try {
-// absl::any_cast<char>(a);
-// } catch(const absl::bad_any_cast& e) {
-// std::cout << "Bad any cast: " << e.what() << '\n';
-// }
-class bad_any_cast : public std::bad_cast {
- public:
- ~bad_any_cast() override;
- const char* what() const noexcept override;
-};
-
-namespace any_internal {
-
-[[noreturn]] void ThrowBadAnyCast();
-
-} // namespace any_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_USES_STD_ANY
-
-#endif // ABSL_TYPES_BAD_ANY_CAST_H_
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc
deleted file mode 100644
index 2552cc8..0000000
--- a/absl/types/bad_optional_access.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/bad_optional_access.h"
-
-#ifndef ABSL_USES_STD_OPTIONAL
-
-#include <cstdlib>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-bad_optional_access::~bad_optional_access() = default;
-
-const char* bad_optional_access::what() const noexcept {
- return "optional has no value";
-}
-
-namespace optional_internal {
-
-void throw_bad_optional_access() {
-#ifdef ABSL_HAVE_EXCEPTIONS
- throw bad_optional_access();
-#else
- ABSL_RAW_LOG(FATAL, "Bad optional access");
- abort();
-#endif
-}
-
-} // namespace optional_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else
-
-// https://github.com/abseil/abseil-cpp/issues/1465
-// CMake builds on Apple platforms error when libraries are empty.
-// Our CMake configuration can avoid this error on header-only libraries,
-// but since this library is conditionally empty, including a single
-// variable is an easy workaround.
-#ifdef __APPLE__
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace types_internal {
-extern const char kAvoidEmptyBadOptionalAccessLibraryWarning;
-const char kAvoidEmptyBadOptionalAccessLibraryWarning = 0;
-} // namespace types_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-#endif // __APPLE__
-
-#endif // ABSL_USES_STD_OPTIONAL
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
deleted file mode 100644
index 049e72a..0000000
--- a/absl/types/bad_optional_access.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// -----------------------------------------------------------------------------
-// bad_optional_access.h
-// -----------------------------------------------------------------------------
-//
-// This header file defines the `absl::bad_optional_access` type.
-
-#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
-#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
-
-#include <stdexcept>
-
-#include "absl/base/config.h"
-
-#ifdef ABSL_USES_STD_OPTIONAL
-
-#include <optional>
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-using std::bad_optional_access;
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else // ABSL_USES_STD_OPTIONAL
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// -----------------------------------------------------------------------------
-// bad_optional_access
-// -----------------------------------------------------------------------------
-//
-// An `absl::bad_optional_access` type is an exception type that is thrown when
-// attempting to access an `absl::optional` object that does not contain a
-// value.
-//
-// Example:
-//
-// absl::optional<int> o;
-//
-// try {
-// int n = o.value();
-// } catch(const absl::bad_optional_access& e) {
-// std::cout << "Bad optional access: " << e.what() << '\n';
-// }
-class bad_optional_access : public std::exception {
- public:
- bad_optional_access() = default;
- ~bad_optional_access() override;
- const char* what() const noexcept override;
-};
-
-namespace optional_internal {
-
-// throw delegator
-[[noreturn]] ABSL_DLL void throw_bad_optional_access();
-
-} // namespace optional_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_USES_STD_OPTIONAL
-
-#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc
deleted file mode 100644
index a76aa80..0000000
--- a/absl/types/bad_variant_access.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/bad_variant_access.h"
-
-#ifndef ABSL_USES_STD_VARIANT
-
-#include <cstdlib>
-#include <stdexcept>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/raw_logging.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-//////////////////////////
-// [variant.bad.access] //
-//////////////////////////
-
-bad_variant_access::~bad_variant_access() = default;
-
-const char* bad_variant_access::what() const noexcept {
- return "Bad variant access";
-}
-
-namespace variant_internal {
-
-void ThrowBadVariantAccess() {
-#ifdef ABSL_HAVE_EXCEPTIONS
- throw bad_variant_access();
-#else
- ABSL_RAW_LOG(FATAL, "Bad variant access");
- abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
-#endif
-}
-
-void Rethrow() {
-#ifdef ABSL_HAVE_EXCEPTIONS
- throw;
-#else
- ABSL_RAW_LOG(FATAL,
- "Internal error in absl::variant implementation. Attempted to "
- "rethrow an exception when building with exceptions disabled.");
- abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn.
-#endif
-}
-
-} // namespace variant_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else
-
-// https://github.com/abseil/abseil-cpp/issues/1465
-// CMake builds on Apple platforms error when libraries are empty.
-// Our CMake configuration can avoid this error on header-only libraries,
-// but since this library is conditionally empty, including a single
-// variable is an easy workaround.
-#ifdef __APPLE__
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace types_internal {
-extern const char kAvoidEmptyBadVariantAccessLibraryWarning;
-const char kAvoidEmptyBadVariantAccessLibraryWarning = 0;
-} // namespace types_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-#endif // __APPLE__
-
-#endif // ABSL_USES_STD_VARIANT
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h
deleted file mode 100644
index 8ab215e..0000000
--- a/absl/types/bad_variant_access.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// -----------------------------------------------------------------------------
-// bad_variant_access.h
-// -----------------------------------------------------------------------------
-//
-// This header file defines the `absl::bad_variant_access` type.
-
-#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_
-#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_
-
-#include <stdexcept>
-
-#include "absl/base/config.h"
-
-#ifdef ABSL_USES_STD_VARIANT
-
-#include <variant>
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-using std::bad_variant_access;
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else // ABSL_USES_STD_VARIANT
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// -----------------------------------------------------------------------------
-// bad_variant_access
-// -----------------------------------------------------------------------------
-//
-// An `absl::bad_variant_access` type is an exception type that is thrown in
-// the following cases:
-//
-// * Calling `absl::get(absl::variant) with an index or type that does not
-// match the currently selected alternative type
-// * Calling `absl::visit on an `absl::variant` that is in the
-// `variant::valueless_by_exception` state.
-//
-// Example:
-//
-// absl::variant<int, std::string> v;
-// v = 1;
-// try {
-// absl::get<std::string>(v);
-// } catch(const absl::bad_variant_access& e) {
-// std::cout << "Bad variant access: " << e.what() << '\n';
-// }
-class bad_variant_access : public std::exception {
- public:
- bad_variant_access() noexcept = default;
- ~bad_variant_access() override;
- const char* what() const noexcept override;
-};
-
-namespace variant_internal {
-
-[[noreturn]] ABSL_DLL void ThrowBadVariantAccess();
-[[noreturn]] ABSL_DLL void Rethrow();
-
-} // namespace variant_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_USES_STD_VARIANT
-
-#endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_
diff --git a/absl/types/internal/optional.h b/absl/types/internal/optional.h
deleted file mode 100644
index 5731a5b..0000000
--- a/absl/types/internal/optional.h
+++ /dev/null
@@ -1,352 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#ifndef ABSL_TYPES_INTERNAL_OPTIONAL_H_
-#define ABSL_TYPES_INTERNAL_OPTIONAL_H_
-
-#include <functional>
-#include <new>
-#include <type_traits>
-#include <utility>
-
-#include "absl/base/internal/inline_variable.h"
-#include "absl/memory/memory.h"
-#include "absl/meta/type_traits.h"
-#include "absl/utility/utility.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// Forward declaration
-template <typename T>
-class optional;
-
-namespace optional_internal {
-
-// This tag type is used as a constructor parameter type for `nullopt_t`.
-struct init_t {
- explicit init_t() = default;
-};
-
-struct empty_struct {};
-
-// This class stores the data in optional<T>.
-// It is specialized based on whether T is trivially destructible.
-// This is the specialization for non trivially destructible type.
-template <typename T, bool unused = std::is_trivially_destructible<T>::value>
-class optional_data_dtor_base {
- struct dummy_type {
- static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
- // Use an array to avoid GCC 6 placement-new warning.
- empty_struct data[sizeof(T) / sizeof(empty_struct)];
- };
-
- protected:
- // Whether there is data or not.
- bool engaged_;
- // Data storage
- union {
- T data_;
- dummy_type dummy_;
- };
-
- void destruct() noexcept {
- if (engaged_) {
- // `data_` must be initialized if `engaged_` is true.
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
- data_.~T();
-#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
-#pragma GCC diagnostic pop
-#endif
- engaged_ = false;
- }
- }
-
- // dummy_ must be initialized for constexpr constructor.
- constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
-
- template <typename... Args>
- constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
- : engaged_(true), data_(std::forward<Args>(args)...) {}
-
- ~optional_data_dtor_base() { destruct(); }
-};
-
-// Specialization for trivially destructible type.
-template <typename T>
-class optional_data_dtor_base<T, true> {
- struct dummy_type {
- static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
- // Use array to avoid GCC 6 placement-new warning.
- empty_struct data[sizeof(T) / sizeof(empty_struct)];
- };
-
- protected:
- // Whether there is data or not.
- bool engaged_;
- // Data storage
- union {
- T data_;
- dummy_type dummy_;
- };
- void destruct() noexcept { engaged_ = false; }
-
- // dummy_ must be initialized for constexpr constructor.
- constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
-
- template <typename... Args>
- constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
- : engaged_(true), data_(std::forward<Args>(args)...) {}
-};
-
-template <typename T>
-class optional_data_base : public optional_data_dtor_base<T> {
- protected:
- using base = optional_data_dtor_base<T>;
- using base::base;
-
- template <typename... Args>
- void construct(Args&&... args) {
- // Use dummy_'s address to work around casting cv-qualified T* to void*.
- ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
- this->engaged_ = true;
- }
-
- template <typename U>
- void assign(U&& u) {
- if (this->engaged_) {
- this->data_ = std::forward<U>(u);
- } else {
- construct(std::forward<U>(u));
- }
- }
-};
-
-// TODO(absl-team): Add another class using
-// std::is_trivially_move_constructible trait when available to match
-// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
-// have trivial move but nontrivial copy.
-// Also, we should be checking is_trivially_copyable here, which is not
-// supported now, so we use is_trivially_* traits instead.
-template <typename T,
- bool unused = absl::is_trivially_copy_constructible<T>::value&&
- absl::is_trivially_copy_assignable<typename std::remove_cv<
- T>::type>::value&& std::is_trivially_destructible<T>::value>
-class optional_data;
-
-// Trivially copyable types
-template <typename T>
-class optional_data<T, true> : public optional_data_base<T> {
- protected:
- using optional_data_base<T>::optional_data_base;
-};
-
-template <typename T>
-class optional_data<T, false> : public optional_data_base<T> {
- protected:
- using optional_data_base<T>::optional_data_base;
-
- optional_data() = default;
-
- optional_data(const optional_data& rhs) : optional_data_base<T>() {
- if (rhs.engaged_) {
- this->construct(rhs.data_);
- }
- }
-
- optional_data(optional_data&& rhs) noexcept(
- absl::default_allocator_is_nothrow::value ||
- std::is_nothrow_move_constructible<T>::value)
- : optional_data_base<T>() {
- if (rhs.engaged_) {
- this->construct(std::move(rhs.data_));
- }
- }
-
- optional_data& operator=(const optional_data& rhs) {
- if (rhs.engaged_) {
- this->assign(rhs.data_);
- } else {
- this->destruct();
- }
- return *this;
- }
-
- optional_data& operator=(optional_data&& rhs) noexcept(
- std::is_nothrow_move_assignable<T>::value&&
- std::is_nothrow_move_constructible<T>::value) {
- if (rhs.engaged_) {
- this->assign(std::move(rhs.data_));
- } else {
- this->destruct();
- }
- return *this;
- }
-};
-
-// Ordered by level of restriction, from low to high.
-// Copyable implies movable.
-enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
-
-// Base class for enabling/disabling copy/move constructor.
-template <copy_traits>
-class optional_ctor_base;
-
-template <>
-class optional_ctor_base<copy_traits::copyable> {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = default;
- optional_ctor_base(optional_ctor_base&&) = default;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-template <>
-class optional_ctor_base<copy_traits::movable> {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = delete;
- optional_ctor_base(optional_ctor_base&&) = default;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-template <>
-class optional_ctor_base<copy_traits::non_movable> {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = delete;
- optional_ctor_base(optional_ctor_base&&) = delete;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
-};
-
-// Base class for enabling/disabling copy/move assignment.
-template <copy_traits>
-class optional_assign_base;
-
-template <>
-class optional_assign_base<copy_traits::copyable> {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = default;
- optional_assign_base& operator=(optional_assign_base&&) = default;
-};
-
-template <>
-class optional_assign_base<copy_traits::movable> {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = delete;
- optional_assign_base& operator=(optional_assign_base&&) = default;
-};
-
-template <>
-class optional_assign_base<copy_traits::non_movable> {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = delete;
- optional_assign_base& operator=(optional_assign_base&&) = delete;
-};
-
-template <typename T>
-struct ctor_copy_traits {
- static constexpr copy_traits traits =
- std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : std::is_move_constructible<T>::value ? copy_traits::movable
- : copy_traits::non_movable;
-};
-
-template <typename T>
-struct assign_copy_traits {
- static constexpr copy_traits traits =
- absl::is_copy_assignable<T>::value && std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : absl::is_move_assignable<T>::value &&
- std::is_move_constructible<T>::value
- ? copy_traits::movable
- : copy_traits::non_movable;
-};
-
-// Whether T is constructible or convertible from optional<U>.
-template <typename T, typename U>
-struct is_constructible_convertible_from_optional
- : std::integral_constant<
- bool, std::is_constructible<T, optional<U>&>::value ||
- std::is_constructible<T, optional<U>&&>::value ||
- std::is_constructible<T, const optional<U>&>::value ||
- std::is_constructible<T, const optional<U>&&>::value ||
- std::is_convertible<optional<U>&, T>::value ||
- std::is_convertible<optional<U>&&, T>::value ||
- std::is_convertible<const optional<U>&, T>::value ||
- std::is_convertible<const optional<U>&&, T>::value> {};
-
-// Whether T is constructible or convertible or assignable from optional<U>.
-template <typename T, typename U>
-struct is_constructible_convertible_assignable_from_optional
- : std::integral_constant<
- bool, is_constructible_convertible_from_optional<T, U>::value ||
- std::is_assignable<T&, optional<U>&>::value ||
- std::is_assignable<T&, optional<U>&&>::value ||
- std::is_assignable<T&, const optional<U>&>::value ||
- std::is_assignable<T&, const optional<U>&&>::value> {};
-
-// Helper function used by [optional.relops], [optional.comp_with_t],
-// for checking whether an expression is convertible to bool.
-bool convertible_to_bool(bool);
-
-// Base class for std::hash<absl::optional<T>>:
-// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
-// compute the hash; Otherwise, it is disabled.
-// Reference N4659 23.14.15 [unord.hash].
-template <typename T, typename = size_t>
-struct optional_hash_base {
- optional_hash_base() = delete;
- optional_hash_base(const optional_hash_base&) = delete;
- optional_hash_base(optional_hash_base&&) = delete;
- optional_hash_base& operator=(const optional_hash_base&) = delete;
- optional_hash_base& operator=(optional_hash_base&&) = delete;
-};
-
-template <typename T>
-struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
- std::declval<absl::remove_const_t<T> >()))> {
- using argument_type = absl::optional<T>;
- using result_type = size_t;
- size_t operator()(const absl::optional<T>& opt) const {
- absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
- if (opt) {
- return std::hash<absl::remove_const_t<T> >()(*opt);
- } else {
- return static_cast<size_t>(0x297814aaad196e6dULL);
- }
- }
-};
-
-} // namespace optional_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/absl/types/internal/span.h b/absl/types/internal/span.h
index ab89ba3..1039f61 100644
--- a/absl/types/internal/span.h
+++ b/absl/types/internal/span.h
@@ -22,6 +22,7 @@
#include <type_traits>
#include "absl/algorithm/algorithm.h"
+#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/meta/type_traits.h"
@@ -86,13 +87,13 @@
typename std::enable_if<!std::is_const<T>::value, int>::type;
template <template <typename> class SpanT, typename T>
-bool EqualImpl(SpanT<T> a, SpanT<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool EqualImpl(SpanT<T> a, SpanT<T> b) {
static_assert(std::is_const<T>::value, "");
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}
template <template <typename> class SpanT, typename T>
-bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool LessThanImpl(SpanT<T> a, SpanT<T> b) {
// We can't use value_type since that is remove_cv_t<T>, so we go the long way
// around.
static_assert(std::is_const<T>::value, "");
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
deleted file mode 100644
index 4cb15f2..0000000
--- a/absl/types/internal/variant.h
+++ /dev/null
@@ -1,1622 +0,0 @@
-// Copyright 2018 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-// Implementation details of absl/types/variant.h, pulled into a
-// separate file to avoid cluttering the top of the API header with
-// implementation details.
-
-#ifndef ABSL_TYPES_INTERNAL_VARIANT_H_
-#define ABSL_TYPES_INTERNAL_VARIANT_H_
-
-#include <cassert>
-#include <cstddef>
-#include <cstdlib>
-#include <memory>
-#include <stdexcept>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-
-#include "absl/base/config.h"
-#include "absl/base/internal/identity.h"
-#include "absl/base/internal/inline_variable.h"
-#include "absl/base/internal/invoke.h"
-#include "absl/base/macros.h"
-#include "absl/base/optimization.h"
-#include "absl/meta/type_traits.h"
-#include "absl/types/bad_variant_access.h"
-#include "absl/utility/utility.h"
-
-#if !defined(ABSL_USES_STD_VARIANT)
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-template <class... Types>
-class variant;
-
-ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
-
-template <class T>
-struct variant_size;
-
-template <std::size_t I, class T>
-struct variant_alternative;
-
-namespace variant_internal {
-
-// NOTE: See specializations below for details.
-template <std::size_t I, class T>
-struct VariantAlternativeSfinae {};
-
-// Requires: I < variant_size_v<T>.
-//
-// Value: The Ith type of Types...
-template <std::size_t I, class T0, class... Tn>
-struct VariantAlternativeSfinae<I, variant<T0, Tn...>>
- : VariantAlternativeSfinae<I - 1, variant<Tn...>> {};
-
-// Value: T0
-template <class T0, class... Ts>
-struct VariantAlternativeSfinae<0, variant<T0, Ts...>> {
- using type = T0;
-};
-
-template <std::size_t I, class T>
-using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type;
-
-// NOTE: Requires T to be a reference type.
-template <class T, class U>
-struct GiveQualsTo;
-
-template <class T, class U>
-struct GiveQualsTo<T&, U> {
- using type = U&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<T&&, U> {
- using type = U&&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<const T&, U> {
- using type = const U&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<const T&&, U> {
- using type = const U&&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<volatile T&, U> {
- using type = volatile U&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<volatile T&&, U> {
- using type = volatile U&&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<volatile const T&, U> {
- using type = volatile const U&;
-};
-
-template <class T, class U>
-struct GiveQualsTo<volatile const T&&, U> {
- using type = volatile const U&&;
-};
-
-template <class T, class U>
-using GiveQualsToT = typename GiveQualsTo<T, U>::type;
-
-// Convenience alias, since size_t integral_constant is used a lot in this file.
-template <std::size_t I>
-using SizeT = std::integral_constant<std::size_t, I>;
-
-using NPos = SizeT<variant_npos>;
-
-template <class Variant, class T, class = void>
-struct IndexOfConstructedType {};
-
-template <std::size_t I, class Variant>
-struct VariantAccessResultImpl;
-
-template <std::size_t I, template <class...> class Variantemplate, class... T>
-struct VariantAccessResultImpl<I, Variantemplate<T...>&> {
- using type = typename absl::variant_alternative<I, variant<T...>>::type&;
-};
-
-template <std::size_t I, template <class...> class Variantemplate, class... T>
-struct VariantAccessResultImpl<I, const Variantemplate<T...>&> {
- using type =
- const typename absl::variant_alternative<I, variant<T...>>::type&;
-};
-
-template <std::size_t I, template <class...> class Variantemplate, class... T>
-struct VariantAccessResultImpl<I, Variantemplate<T...>&&> {
- using type = typename absl::variant_alternative<I, variant<T...>>::type&&;
-};
-
-template <std::size_t I, template <class...> class Variantemplate, class... T>
-struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> {
- using type =
- const typename absl::variant_alternative<I, variant<T...>>::type&&;
-};
-
-template <std::size_t I, class Variant>
-using VariantAccessResult =
- typename VariantAccessResultImpl<I, Variant&&>::type;
-
-// NOTE: This is used instead of std::array to reduce instantiation overhead.
-template <class T, std::size_t Size>
-struct SimpleArray {
- static_assert(Size != 0, "");
- T value[Size];
-};
-
-template <class T>
-struct AccessedType {
- using type = T;
-};
-
-template <class T>
-using AccessedTypeT = typename AccessedType<T>::type;
-
-template <class T, std::size_t Size>
-struct AccessedType<SimpleArray<T, Size>> {
- using type = AccessedTypeT<T>;
-};
-
-template <class T>
-constexpr T AccessSimpleArray(const T& value) {
- return value;
-}
-
-template <class T, std::size_t Size, class... SizeT>
-constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table,
- std::size_t head_index,
- SizeT... tail_indices) {
- return AccessSimpleArray(table.value[head_index], tail_indices...);
-}
-
-// Note: Intentionally is an alias.
-template <class T>
-using AlwaysZero = SizeT<0>;
-
-template <class Op, class... Vs>
-struct VisitIndicesResultImpl {
- using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>;
-};
-
-template <class Op, class... Vs>
-using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type;
-
-template <class ReturnType, class FunctionObject, class EndIndices,
- class BoundIndices>
-struct MakeVisitationMatrix;
-
-template <class ReturnType, class FunctionObject, std::size_t... Indices>
-constexpr ReturnType call_with_indices(FunctionObject&& function) {
- static_assert(
- std::is_same<ReturnType, decltype(std::declval<FunctionObject>()(
- SizeT<Indices>()...))>::value,
- "Not all visitation overloads have the same return type.");
- return std::forward<FunctionObject>(function)(SizeT<Indices>()...);
-}
-
-template <class ReturnType, class FunctionObject, std::size_t... BoundIndices>
-struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
- index_sequence<BoundIndices...>> {
- using ResultType = ReturnType (*)(FunctionObject&&);
- static constexpr ResultType Run() {
- return &call_with_indices<ReturnType, FunctionObject,
- (BoundIndices - 1)...>;
- }
-};
-
-template <typename Is, std::size_t J>
-struct AppendToIndexSequence;
-
-template <typename Is, std::size_t J>
-using AppendToIndexSequenceT = typename AppendToIndexSequence<Is, J>::type;
-
-template <std::size_t... Is, std::size_t J>
-struct AppendToIndexSequence<index_sequence<Is...>, J> {
- using type = index_sequence<Is..., J>;
-};
-
-template <class ReturnType, class FunctionObject, class EndIndices,
- class CurrIndices, class BoundIndices>
-struct MakeVisitationMatrixImpl;
-
-template <class ReturnType, class FunctionObject, class EndIndices,
- std::size_t... CurrIndices, class BoundIndices>
-struct MakeVisitationMatrixImpl<ReturnType, FunctionObject, EndIndices,
- index_sequence<CurrIndices...>, BoundIndices> {
- using ResultType = SimpleArray<
- typename MakeVisitationMatrix<ReturnType, FunctionObject, EndIndices,
- index_sequence<>>::ResultType,
- sizeof...(CurrIndices)>;
-
- static constexpr ResultType Run() {
- return {{MakeVisitationMatrix<
- ReturnType, FunctionObject, EndIndices,
- AppendToIndexSequenceT<BoundIndices, CurrIndices>>::Run()...}};
- }
-};
-
-template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex,
- std::size_t... TailEndIndices, std::size_t... BoundIndices>
-struct MakeVisitationMatrix<ReturnType, FunctionObject,
- index_sequence<HeadEndIndex, TailEndIndices...>,
- index_sequence<BoundIndices...>>
- : MakeVisitationMatrixImpl<ReturnType, FunctionObject,
- index_sequence<TailEndIndices...>,
- absl::make_index_sequence<HeadEndIndex>,
- index_sequence<BoundIndices...>> {};
-
-struct UnreachableSwitchCase {
- template <class Op>
- [[noreturn]] static VisitIndicesResultT<Op, std::size_t> Run(
- Op&& /*ignored*/) {
- ABSL_UNREACHABLE();
- }
-};
-
-template <class Op, std::size_t I>
-struct ReachableSwitchCase {
- static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) {
- return absl::base_internal::invoke(std::forward<Op>(op), SizeT<I>());
- }
-};
-
-// The number 33 is just a guess at a reasonable maximum to our switch. It is
-// not based on any analysis. The reason it is a power of 2 plus 1 instead of a
-// power of 2 is because the number was picked to correspond to a power of 2
-// amount of "normal" alternatives, plus one for the possibility of the user
-// providing "monostate" in addition to the more natural alternatives.
-ABSL_INTERNAL_INLINE_CONSTEXPR(std::size_t, MaxUnrolledVisitCases, 33);
-
-// Note: The default-definition is for unreachable cases.
-template <bool IsReachable>
-struct PickCaseImpl {
- template <class Op, std::size_t I>
- using Apply = UnreachableSwitchCase;
-};
-
-template <>
-struct PickCaseImpl</*IsReachable =*/true> {
- template <class Op, std::size_t I>
- using Apply = ReachableSwitchCase<Op, I>;
-};
-
-// Note: This form of dance with template aliases is to make sure that we
-// instantiate a number of templates proportional to the number of variant
-// alternatives rather than a number of templates proportional to our
-// maximum unrolled amount of visitation cases (aliases are effectively
-// "free" whereas other template instantiations are costly).
-template <class Op, std::size_t I, std::size_t EndIndex>
-using PickCase = typename PickCaseImpl<(I < EndIndex)>::template Apply<Op, I>;
-
-template <class ReturnType>
-[[noreturn]] ReturnType TypedThrowBadVariantAccess() {
- absl::variant_internal::ThrowBadVariantAccess();
-}
-
-// Given N variant sizes, determine the number of cases there would need to be
-// in a single switch-statement that would cover every possibility in the
-// corresponding N-ary visit operation.
-template <std::size_t... NumAlternatives>
-struct NumCasesOfSwitch;
-
-template <std::size_t HeadNumAlternatives, std::size_t... TailNumAlternatives>
-struct NumCasesOfSwitch<HeadNumAlternatives, TailNumAlternatives...> {
- static constexpr std::size_t value =
- (HeadNumAlternatives + 1) *
- NumCasesOfSwitch<TailNumAlternatives...>::value;
-};
-
-template <>
-struct NumCasesOfSwitch<> {
- static constexpr std::size_t value = 1;
-};
-
-// A switch statement optimizes better than the table of function pointers.
-template <std::size_t EndIndex>
-struct VisitIndicesSwitch {
- static_assert(EndIndex <= MaxUnrolledVisitCases,
- "Maximum unrolled switch size exceeded.");
-
- template <class Op>
- static VisitIndicesResultT<Op, std::size_t> Run(Op&& op, std::size_t i) {
- switch (i) {
- case 0:
- return PickCase<Op, 0, EndIndex>::Run(std::forward<Op>(op));
- case 1:
- return PickCase<Op, 1, EndIndex>::Run(std::forward<Op>(op));
- case 2:
- return PickCase<Op, 2, EndIndex>::Run(std::forward<Op>(op));
- case 3:
- return PickCase<Op, 3, EndIndex>::Run(std::forward<Op>(op));
- case 4:
- return PickCase<Op, 4, EndIndex>::Run(std::forward<Op>(op));
- case 5:
- return PickCase<Op, 5, EndIndex>::Run(std::forward<Op>(op));
- case 6:
- return PickCase<Op, 6, EndIndex>::Run(std::forward<Op>(op));
- case 7:
- return PickCase<Op, 7, EndIndex>::Run(std::forward<Op>(op));
- case 8:
- return PickCase<Op, 8, EndIndex>::Run(std::forward<Op>(op));
- case 9:
- return PickCase<Op, 9, EndIndex>::Run(std::forward<Op>(op));
- case 10:
- return PickCase<Op, 10, EndIndex>::Run(std::forward<Op>(op));
- case 11:
- return PickCase<Op, 11, EndIndex>::Run(std::forward<Op>(op));
- case 12:
- return PickCase<Op, 12, EndIndex>::Run(std::forward<Op>(op));
- case 13:
- return PickCase<Op, 13, EndIndex>::Run(std::forward<Op>(op));
- case 14:
- return PickCase<Op, 14, EndIndex>::Run(std::forward<Op>(op));
- case 15:
- return PickCase<Op, 15, EndIndex>::Run(std::forward<Op>(op));
- case 16:
- return PickCase<Op, 16, EndIndex>::Run(std::forward<Op>(op));
- case 17:
- return PickCase<Op, 17, EndIndex>::Run(std::forward<Op>(op));
- case 18:
- return PickCase<Op, 18, EndIndex>::Run(std::forward<Op>(op));
- case 19:
- return PickCase<Op, 19, EndIndex>::Run(std::forward<Op>(op));
- case 20:
- return PickCase<Op, 20, EndIndex>::Run(std::forward<Op>(op));
- case 21:
- return PickCase<Op, 21, EndIndex>::Run(std::forward<Op>(op));
- case 22:
- return PickCase<Op, 22, EndIndex>::Run(std::forward<Op>(op));
- case 23:
- return PickCase<Op, 23, EndIndex>::Run(std::forward<Op>(op));
- case 24:
- return PickCase<Op, 24, EndIndex>::Run(std::forward<Op>(op));
- case 25:
- return PickCase<Op, 25, EndIndex>::Run(std::forward<Op>(op));
- case 26:
- return PickCase<Op, 26, EndIndex>::Run(std::forward<Op>(op));
- case 27:
- return PickCase<Op, 27, EndIndex>::Run(std::forward<Op>(op));
- case 28:
- return PickCase<Op, 28, EndIndex>::Run(std::forward<Op>(op));
- case 29:
- return PickCase<Op, 29, EndIndex>::Run(std::forward<Op>(op));
- case 30:
- return PickCase<Op, 30, EndIndex>::Run(std::forward<Op>(op));
- case 31:
- return PickCase<Op, 31, EndIndex>::Run(std::forward<Op>(op));
- case 32:
- return PickCase<Op, 32, EndIndex>::Run(std::forward<Op>(op));
- default:
- ABSL_ASSERT(i == variant_npos);
- return absl::base_internal::invoke(std::forward<Op>(op), NPos());
- }
- }
-};
-
-template <std::size_t... EndIndices>
-struct VisitIndicesFallback {
- template <class Op, class... SizeT>
- static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) {
- return AccessSimpleArray(
- MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op,
- index_sequence<(EndIndices + 1)...>,
- index_sequence<>>::Run(),
- (indices + 1)...)(std::forward<Op>(op));
- }
-};
-
-// Take an N-dimensional series of indices and convert them into a single index
-// without loss of information. The purpose of this is to be able to convert an
-// N-ary visit operation into a single switch statement.
-template <std::size_t...>
-struct FlattenIndices;
-
-template <std::size_t HeadSize, std::size_t... TailSize>
-struct FlattenIndices<HeadSize, TailSize...> {
- template <class... SizeType>
- static constexpr std::size_t Run(std::size_t head, SizeType... tail) {
- return head + HeadSize * FlattenIndices<TailSize...>::Run(tail...);
- }
-};
-
-template <>
-struct FlattenIndices<> {
- static constexpr std::size_t Run() { return 0; }
-};
-
-// Take a single "flattened" index (flattened by FlattenIndices) and determine
-// the value of the index of one of the logically represented dimensions.
-template <std::size_t I, std::size_t IndexToGet, std::size_t HeadSize,
- std::size_t... TailSize>
-struct UnflattenIndex {
- static constexpr std::size_t value =
- UnflattenIndex<I / HeadSize, IndexToGet - 1, TailSize...>::value;
-};
-
-template <std::size_t I, std::size_t HeadSize, std::size_t... TailSize>
-struct UnflattenIndex<I, 0, HeadSize, TailSize...> {
- static constexpr std::size_t value = (I % HeadSize);
-};
-
-// The backend for converting an N-ary visit operation into a unary visit.
-template <class IndexSequence, std::size_t... EndIndices>
-struct VisitIndicesVariadicImpl;
-
-template <std::size_t... N, std::size_t... EndIndices>
-struct VisitIndicesVariadicImpl<absl::index_sequence<N...>, EndIndices...> {
- // A type that can take an N-ary function object and converts it to a unary
- // function object that takes a single, flattened index, and "unflattens" it
- // into its individual dimensions when forwarding to the wrapped object.
- template <class Op>
- struct FlattenedOp {
- template <std::size_t I>
- VisitIndicesResultT<Op, decltype(EndIndices)...> operator()(
- SizeT<I> /*index*/) && {
- return base_internal::invoke(
- std::forward<Op>(op),
- SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value -
- std::size_t{1}>()...);
- }
-
- Op&& op;
- };
-
- template <class Op, class... SizeType>
- static VisitIndicesResultT<Op, decltype(EndIndices)...> Run(Op&& op,
- SizeType... i) {
- return VisitIndicesSwitch<NumCasesOfSwitch<EndIndices...>::value>::Run(
- FlattenedOp<Op>{std::forward<Op>(op)},
- FlattenIndices<(EndIndices + std::size_t{1})...>::Run(
- (i + std::size_t{1})...));
- }
-};
-
-template <std::size_t... EndIndices>
-struct VisitIndicesVariadic
- : VisitIndicesVariadicImpl<absl::make_index_sequence<sizeof...(EndIndices)>,
- EndIndices...> {};
-
-// This implementation will flatten N-ary visit operations into a single switch
-// statement when the number of cases would be less than our maximum specified
-// switch-statement size.
-// TODO(calabrese)
-// Based on benchmarks, determine whether the function table approach actually
-// does optimize better than a chain of switch statements and possibly update
-// the implementation accordingly. Also consider increasing the maximum switch
-// size.
-template <std::size_t... EndIndices>
-struct VisitIndices
- : absl::conditional_t<(NumCasesOfSwitch<EndIndices...>::value <=
- MaxUnrolledVisitCases),
- VisitIndicesVariadic<EndIndices...>,
- VisitIndicesFallback<EndIndices...>> {};
-
-template <std::size_t EndIndex>
-struct VisitIndices<EndIndex>
- : absl::conditional_t<(EndIndex <= MaxUnrolledVisitCases),
- VisitIndicesSwitch<EndIndex>,
- VisitIndicesFallback<EndIndex>> {};
-
-// Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast`
-// below is returning the address of a temporary or local object.
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4172)
-#endif // _MSC_VER
-
-// TODO(calabrese) std::launder
-// TODO(calabrese) constexpr
-// NOTE: DO NOT REMOVE the `inline` keyword as it is necessary to work around a
-// MSVC bug. See https://github.com/abseil/abseil-cpp/issues/129 for details.
-template <class Self, std::size_t I>
-inline VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) {
- return reinterpret_cast<VariantAccessResult<I, Self>>(self);
-}
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER
-
-template <class T>
-void DeducedDestroy(T& self) { // NOLINT
- self.~T();
-}
-
-// NOTE: This type exists as a single entity for variant and its bases to
-// befriend. It contains helper functionality that manipulates the state of the
-// variant, such as the implementation of things like assignment and emplace
-// operations.
-struct VariantCoreAccess {
- template <class VariantType>
- static typename VariantType::Variant& Derived(VariantType& self) { // NOLINT
- return static_cast<typename VariantType::Variant&>(self);
- }
-
- template <class VariantType>
- static const typename VariantType::Variant& Derived(
- const VariantType& self) { // NOLINT
- return static_cast<const typename VariantType::Variant&>(self);
- }
-
- template <class VariantType>
- static void Destroy(VariantType& self) { // NOLINT
- Derived(self).destroy();
- self.index_ = absl::variant_npos;
- }
-
- template <class Variant>
- static void SetIndex(Variant& self, std::size_t i) { // NOLINT
- self.index_ = i;
- }
-
- template <class Variant>
- static void InitFrom(Variant& self, Variant&& other) { // NOLINT
- VisitIndices<absl::variant_size<Variant>::value>::Run(
- InitFromVisitor<Variant, Variant&&>{&self,
- std::forward<Variant>(other)},
- other.index());
- self.index_ = other.index();
- }
-
- // Access a variant alternative, assuming the index is correct.
- template <std::size_t I, class Variant>
- static VariantAccessResult<I, Variant> Access(Variant&& self) {
- // This cast instead of invocation of AccessUnion with an rvalue is a
- // workaround for msvc. Without this there is a runtime failure when dealing
- // with rvalues.
- // TODO(calabrese) Reduce test case and find a simpler workaround.
- return static_cast<VariantAccessResult<I, Variant>>(
- variant_internal::AccessUnion(self.state_, SizeT<I>()));
- }
-
- // Access a variant alternative, throwing if the index is incorrect.
- template <std::size_t I, class Variant>
- static VariantAccessResult<I, Variant> CheckedAccess(Variant&& self) {
- if (ABSL_PREDICT_FALSE(self.index_ != I)) {
- TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>();
- }
-
- return Access<I>(std::forward<Variant>(self));
- }
-
- // The implementation of the move-assignment operation for a variant.
- template <class VType>
- struct MoveAssignVisitor {
- using DerivedType = typename VType::Variant;
- template <std::size_t NewIndex>
- void operator()(SizeT<NewIndex> /*new_i*/) const {
- if (left->index_ == NewIndex) {
- Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right));
- } else {
- Derived(*left).template emplace<NewIndex>(
- std::move(Access<NewIndex>(*right)));
- }
- }
-
- void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
- Destroy(*left);
- }
-
- VType* left;
- VType* right;
- };
-
- template <class VType>
- static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left,
- VType* other) {
- return {left, other};
- }
-
- // The implementation of the assignment operation for a variant.
- template <class VType>
- struct CopyAssignVisitor {
- using DerivedType = typename VType::Variant;
- template <std::size_t NewIndex>
- void operator()(SizeT<NewIndex> /*new_i*/) const {
- using New =
- typename absl::variant_alternative<NewIndex, DerivedType>::type;
-
- if (left->index_ == NewIndex) {
- Access<NewIndex>(*left) = Access<NewIndex>(*right);
- } else if (std::is_nothrow_copy_constructible<New>::value ||
- !std::is_nothrow_move_constructible<New>::value) {
- Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right));
- } else {
- Derived(*left) = DerivedType(Derived(*right));
- }
- }
-
- void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
- Destroy(*left);
- }
-
- VType* left;
- const VType* right;
- };
-
- template <class VType>
- static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left,
- const VType& other) {
- return {left, &other};
- }
-
- // The implementation of conversion-assignment operations for variant.
- template <class Left, class QualifiedNew>
- struct ConversionAssignVisitor {
- using NewIndex =
- variant_internal::IndexOfConstructedType<Left, QualifiedNew>;
-
- void operator()(SizeT<NewIndex::value> /*old_i*/
- ) const {
- Access<NewIndex::value>(*left) = std::forward<QualifiedNew>(other);
- }
-
- template <std::size_t OldIndex>
- void operator()(SizeT<OldIndex> /*old_i*/
- ) const {
- using New =
- typename absl::variant_alternative<NewIndex::value, Left>::type;
- if (std::is_nothrow_constructible<New, QualifiedNew>::value ||
- !std::is_nothrow_move_constructible<New>::value) {
- left->template emplace<NewIndex::value>(
- std::forward<QualifiedNew>(other));
- } else {
- // the standard says "equivalent to
- // operator=(variant(std::forward<T>(t)))", but we use `emplace` here
- // because the variant's move assignment operator could be deleted.
- left->template emplace<NewIndex::value>(
- New(std::forward<QualifiedNew>(other)));
- }
- }
-
- Left* left;
- QualifiedNew&& other;
- };
-
- template <class Left, class QualifiedNew>
- static ConversionAssignVisitor<Left, QualifiedNew>
- MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) {
- return {left, std::forward<QualifiedNew>(qual)};
- }
-
- // Backend for operations for `emplace()` which destructs `*self` then
- // construct a new alternative with `Args...`.
- template <std::size_t NewIndex, class Self, class... Args>
- static typename absl::variant_alternative<NewIndex, Self>::type& Replace(
- Self* self, Args&&... args) {
- Destroy(*self);
- using New = typename absl::variant_alternative<NewIndex, Self>::type;
- New* const result = ::new (static_cast<void*>(&self->state_))
- New(std::forward<Args>(args)...);
- self->index_ = NewIndex;
- return *result;
- }
-
- template <class LeftVariant, class QualifiedRightVariant>
- struct InitFromVisitor {
- template <std::size_t NewIndex>
- void operator()(SizeT<NewIndex> /*new_i*/) const {
- using Alternative =
- typename variant_alternative<NewIndex, LeftVariant>::type;
- ::new (static_cast<void*>(&left->state_)) Alternative(
- Access<NewIndex>(std::forward<QualifiedRightVariant>(right)));
- }
-
- void operator()(SizeT<absl::variant_npos> /*new_i*/) const {
- // This space intentionally left blank.
- }
- LeftVariant* left;
- QualifiedRightVariant&& right;
- };
-};
-
-template <class Expected, class... T>
-struct IndexOfImpl;
-
-template <class Expected>
-struct IndexOfImpl<Expected> {
- using IndexFromEnd = SizeT<0>;
- using MatchedIndexFromEnd = IndexFromEnd;
- using MultipleMatches = std::false_type;
-};
-
-template <class Expected, class Head, class... Tail>
-struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> {
- using IndexFromEnd =
- SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
-};
-
-template <class Expected, class... Tail>
-struct IndexOfImpl<Expected, Expected, Tail...>
- : IndexOfImpl<Expected, Tail...> {
- using IndexFromEnd =
- SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>;
- using MatchedIndexFromEnd = IndexFromEnd;
- using MultipleMatches = std::integral_constant<
- bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>;
-};
-
-template <class Expected, class... Types>
-struct IndexOfMeta {
- using Results = IndexOfImpl<Expected, Types...>;
- static_assert(!Results::MultipleMatches::value,
- "Attempted to access a variant by specifying a type that "
- "matches more than one alternative.");
- static_assert(Results::MatchedIndexFromEnd::value != 0,
- "Attempted to access a variant by specifying a type that does "
- "not match any alternative.");
- using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>;
-};
-
-template <class Expected, class... Types>
-using IndexOf = typename IndexOfMeta<Expected, Types...>::type;
-
-template <class Variant, class T, std::size_t CurrIndex>
-struct UnambiguousIndexOfImpl;
-
-// Terminating case encountered once we've checked all of the alternatives
-template <class T, std::size_t CurrIndex>
-struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {};
-
-// Case where T is not Head
-template <class Head, class... Tail, class T, std::size_t CurrIndex>
-struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex>
- : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {};
-
-// Case where T is Head
-template <class Head, class... Tail, std::size_t CurrIndex>
-struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex>
- : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value ==
- sizeof...(Tail)
- ? CurrIndex
- : CurrIndex + sizeof...(Tail) + 1> {};
-
-template <class Variant, class T>
-struct UnambiguousIndexOf;
-
-struct NoMatch {
- struct type {};
-};
-
-template <class... Alts, class T>
-struct UnambiguousIndexOf<variant<Alts...>, T>
- : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value !=
- sizeof...(Alts),
- UnambiguousIndexOfImpl<variant<Alts...>, T, 0>,
- NoMatch>::type::type {};
-
-template <class T, std::size_t /*Dummy*/>
-using UnambiguousTypeOfImpl = T;
-
-template <class Variant, class T>
-using UnambiguousTypeOfT =
- UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>;
-
-template <class H, class... T>
-class VariantStateBase;
-
-// This is an implementation of the "imaginary function" that is described in
-// [variant.ctor]
-// It is used in order to determine which alternative to construct during
-// initialization from some type T.
-template <class Variant, std::size_t I = 0>
-struct ImaginaryFun;
-
-template <std::size_t I>
-struct ImaginaryFun<variant<>, I> {
- static void Run() = delete;
-};
-
-template <class H, class... T, std::size_t I>
-struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
- using ImaginaryFun<variant<T...>, I + 1>::Run;
-
- // NOTE: const& and && are used instead of by-value due to lack of guaranteed
- // move elision of C++17. This may have other minor differences, but tests
- // pass.
- static SizeT<I> Run(const H&, SizeT<I>);
- static SizeT<I> Run(H&&, SizeT<I>);
-};
-
-// The following metafunctions are used in constructor and assignment
-// constraints.
-template <class Self, class T>
-struct IsNeitherSelfNorInPlace : std::true_type {};
-
-template <class Self>
-struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {};
-
-template <class Self, class T>
-struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {};
-
-template <class Self, std::size_t I>
-struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {};
-
-template <class Variant, class T>
-struct IndexOfConstructedType<
- Variant, T,
- void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
- : decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {})) {};
-
-template <std::size_t... Is>
-struct ContainsVariantNPos
- : absl::negation<std::is_same< // NOLINT
- std::integer_sequence<bool, 0 <= Is...>,
- std::integer_sequence<bool, Is != absl::variant_npos...>>> {};
-
-template <class Op, class... QualifiedVariants>
-using RawVisitResult =
- absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
-
-// NOTE: The spec requires that all return-paths yield the same type and is not
-// SFINAE-friendly, so we can deduce the return type by examining the first
-// result. If it's not callable, then we get an error, but are compliant and
-// fast to compile.
-// TODO(calabrese) Possibly rewrite in a way that yields better compile errors
-// at the cost of longer compile-times.
-template <class Op, class... QualifiedVariants>
-struct VisitResultImpl {
- using type =
- absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>;
-};
-
-// Done in two steps intentionally so that we don't cause substitution to fail.
-template <class Op, class... QualifiedVariants>
-using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type;
-
-template <class Op, class... QualifiedVariants>
-struct PerformVisitation {
- using ReturnType = VisitResult<Op, QualifiedVariants...>;
-
- template <std::size_t... Is>
- constexpr ReturnType operator()(SizeT<Is>... indices) const {
- return Run(typename ContainsVariantNPos<Is...>::type{},
- absl::index_sequence_for<QualifiedVariants...>(), indices...);
- }
-
- template <std::size_t... TupIs, std::size_t... Is>
- constexpr ReturnType Run(std::false_type /*has_valueless*/,
- index_sequence<TupIs...>, SizeT<Is>...) const {
- static_assert(
- std::is_same<ReturnType,
- absl::result_of_t<Op(VariantAccessResult<
- Is, QualifiedVariants>...)>>::value,
- "All visitation overloads must have the same return type.");
- return absl::base_internal::invoke(
- std::forward<Op>(op),
- VariantCoreAccess::Access<Is>(
- std::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...);
- }
-
- template <std::size_t... TupIs, std::size_t... Is>
- [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/,
- index_sequence<TupIs...>, SizeT<Is>...) const {
- absl::variant_internal::ThrowBadVariantAccess();
- }
-
- // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations
- // Attempts using lambda variadic captures fail on current GCC.
- std::tuple<QualifiedVariants&&...> variant_tup;
- Op&& op;
-};
-
-template <class... T>
-union Union;
-
-// We want to allow for variant<> to be trivial. For that, we need the default
-// constructor to be trivial, which means we can't define it ourselves.
-// Instead, we use a non-default constructor that takes NoopConstructorTag
-// that doesn't affect the triviality of the types.
-struct NoopConstructorTag {};
-
-template <std::size_t I>
-struct EmplaceTag {};
-
-template <>
-union Union<> {
- constexpr explicit Union(NoopConstructorTag) noexcept {}
-};
-
-// Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined
-// deleted destructor from the `std::is_destructible` check below.
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4624)
-#endif // _MSC_VER
-
-template <class Head, class... Tail>
-union Union<Head, Tail...> {
- using TailUnion = Union<Tail...>;
-
- explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept
- : tail(NoopConstructorTag()) {}
-
- template <class... P>
- explicit constexpr Union(EmplaceTag<0>, P&&... args)
- : head(std::forward<P>(args)...) {}
-
- template <std::size_t I, class... P>
- explicit constexpr Union(EmplaceTag<I>, P&&... args)
- : tail(EmplaceTag<I - 1>{}, std::forward<P>(args)...) {}
-
- Head head;
- TailUnion tail;
-};
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER
-
-// TODO(calabrese) Just contain a Union in this union (certain configs fail).
-template <class... T>
-union DestructibleUnionImpl;
-
-template <>
-union DestructibleUnionImpl<> {
- constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {}
-};
-
-template <class Head, class... Tail>
-union DestructibleUnionImpl<Head, Tail...> {
- using TailUnion = DestructibleUnionImpl<Tail...>;
-
- explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept
- : tail(NoopConstructorTag()) {}
-
- template <class... P>
- explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args)
- : head(std::forward<P>(args)...) {}
-
- template <std::size_t I, class... P>
- explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args)
- : tail(EmplaceTag<I - 1>{}, std::forward<P>(args)...) {}
-
- ~DestructibleUnionImpl() {}
-
- Head head;
- TailUnion tail;
-};
-
-// This union type is destructible even if one or more T are not trivially
-// destructible. In the case that all T are trivially destructible, then so is
-// this resultant type.
-template <class... T>
-using DestructibleUnion =
- absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>,
- DestructibleUnionImpl<T...>>;
-
-// Deepest base, containing the actual union and the discriminator
-template <class H, class... T>
-class VariantStateBase {
- protected:
- using Variant = variant<H, T...>;
-
- template <class LazyH = H,
- class ConstructibleH = absl::enable_if_t<
- std::is_default_constructible<LazyH>::value, LazyH>>
- constexpr VariantStateBase() noexcept(
- std::is_nothrow_default_constructible<ConstructibleH>::value)
- : state_(EmplaceTag<0>()), index_(0) {}
-
- template <std::size_t I, class... P>
- explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args)
- : state_(tag, std::forward<P>(args)...), index_(I) {}
-
- explicit constexpr VariantStateBase(NoopConstructorTag)
- : state_(NoopConstructorTag()), index_(variant_npos) {}
-
- void destroy() {} // Does nothing (shadowed in child if non-trivial)
-
- DestructibleUnion<H, T...> state_;
- std::size_t index_;
-};
-
-using absl::internal::type_identity;
-
-// OverloadSet::Overload() is a unary function which is overloaded to
-// take any of the element types of the variant, by reference-to-const.
-// The return type of the overload on T is type_identity<T>, so that you
-// can statically determine which overload was called.
-//
-// Overload() is not defined, so it can only be called in unevaluated
-// contexts.
-template <typename... Ts>
-struct OverloadSet;
-
-template <typename T, typename... Ts>
-struct OverloadSet<T, Ts...> : OverloadSet<Ts...> {
- using Base = OverloadSet<Ts...>;
- static type_identity<T> Overload(const T&);
- using Base::Overload;
-};
-
-template <>
-struct OverloadSet<> {
- // For any case not handled above.
- static void Overload(...);
-};
-
-template <class T>
-using LessThanResult = decltype(std::declval<T>() < std::declval<T>());
-
-template <class T>
-using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>());
-
-template <class T>
-using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>());
-
-template <class T>
-using GreaterThanOrEqualResult =
- decltype(std::declval<T>() >= std::declval<T>());
-
-template <class T>
-using EqualResult = decltype(std::declval<T>() == std::declval<T>());
-
-template <class T>
-using NotEqualResult = decltype(std::declval<T>() != std::declval<T>());
-
-using type_traits_internal::is_detected_convertible;
-
-template <class... T>
-using RequireAllHaveEqualT = absl::enable_if_t<
- absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value,
- bool>;
-
-template <class... T>
-using RequireAllHaveNotEqualT =
- absl::enable_if_t<absl::conjunction<is_detected_convertible<
- bool, NotEqualResult, T>...>::value,
- bool>;
-
-template <class... T>
-using RequireAllHaveLessThanT =
- absl::enable_if_t<absl::conjunction<is_detected_convertible<
- bool, LessThanResult, T>...>::value,
- bool>;
-
-template <class... T>
-using RequireAllHaveLessThanOrEqualT =
- absl::enable_if_t<absl::conjunction<is_detected_convertible<
- bool, LessThanOrEqualResult, T>...>::value,
- bool>;
-
-template <class... T>
-using RequireAllHaveGreaterThanOrEqualT =
- absl::enable_if_t<absl::conjunction<is_detected_convertible<
- bool, GreaterThanOrEqualResult, T>...>::value,
- bool>;
-
-template <class... T>
-using RequireAllHaveGreaterThanT =
- absl::enable_if_t<absl::conjunction<is_detected_convertible<
- bool, GreaterThanResult, T>...>::value,
- bool>;
-
-// Helper template containing implementations details of variant that can't go
-// in the private section. For convenience, this takes the variant type as a
-// single template parameter.
-template <typename T>
-struct VariantHelper;
-
-template <typename... Ts>
-struct VariantHelper<variant<Ts...>> {
- // Type metafunction which returns the element type selected if
- // OverloadSet::Overload() is well-formed when called with argument type U.
- template <typename U>
- using BestMatch = decltype(variant_internal::OverloadSet<Ts...>::Overload(
- std::declval<U>()));
-
- // Type metafunction which returns true if OverloadSet::Overload() is
- // well-formed when called with argument type U.
- // CanAccept can't be just an alias because there is a MSVC bug on parameter
- // pack expansion involving decltype.
- template <typename U>
- struct CanAccept
- : std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {};
-
- // Type metafunction which returns true if Other is an instantiation of
- // variant, and variants's converting constructor from Other will be
- // well-formed. We will use this to remove constructors that would be
- // ill-formed from the overload set.
- template <typename Other>
- struct CanConvertFrom;
-
- template <typename... Us>
- struct CanConvertFrom<variant<Us...>>
- : public absl::conjunction<CanAccept<Us>...> {};
-};
-
-// A type with nontrivial copy ctor and trivial move ctor.
-struct TrivialMoveOnly {
- TrivialMoveOnly(TrivialMoveOnly&&) = default;
-};
-
-// Trait class to detect whether a type is trivially move constructible.
-// A union's defaulted copy/move constructor is deleted if any variant member's
-// copy/move constructor is nontrivial.
-template <typename T>
-struct IsTriviallyMoveConstructible
- : std::is_move_constructible<Union<T, TrivialMoveOnly>> {};
-
-// To guarantee triviality of all special-member functions that can be trivial,
-// we use a chain of conditional bases for each one.
-// The order of inheritance of bases from child to base are logically:
-//
-// variant
-// VariantCopyAssignBase
-// VariantMoveAssignBase
-// VariantCopyBase
-// VariantMoveBase
-// VariantStateBaseDestructor
-// VariantStateBase
-//
-// Note that there is a separate branch at each base that is dependent on
-// whether or not that corresponding special-member-function can be trivial in
-// the resultant variant type.
-
-template <class... T>
-class VariantStateBaseDestructorNontrivial;
-
-template <class... T>
-class VariantMoveBaseNontrivial;
-
-template <class... T>
-class VariantCopyBaseNontrivial;
-
-template <class... T>
-class VariantMoveAssignBaseNontrivial;
-
-template <class... T>
-class VariantCopyAssignBaseNontrivial;
-
-// Base that is dependent on whether or not the destructor can be trivial.
-template <class... T>
-using VariantStateBaseDestructor =
- absl::conditional_t<std::is_destructible<Union<T...>>::value,
- VariantStateBase<T...>,
- VariantStateBaseDestructorNontrivial<T...>>;
-
-// Base that is dependent on whether or not the move-constructor can be
-// implicitly generated by the compiler (trivial or deleted).
-// Previously we were using `std::is_move_constructible<Union<T...>>` to check
-// whether all Ts have trivial move constructor, but it ran into a GCC bug:
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866
-// So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to
-// work around the bug.
-template <class... T>
-using VariantMoveBase = absl::conditional_t<
- absl::disjunction<
- absl::negation<absl::conjunction<std::is_move_constructible<T>...>>,
- absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value,
- VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>;
-
-// Base that is dependent on whether or not the copy-constructor can be trivial.
-template <class... T>
-using VariantCopyBase = absl::conditional_t<
- absl::disjunction<
- absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>,
- std::is_copy_constructible<Union<T...>>>::value,
- VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>;
-
-// Base that is dependent on whether or not the move-assign can be trivial.
-template <class... T>
-using VariantMoveAssignBase = absl::conditional_t<
- absl::disjunction<
- absl::conjunction<absl::is_move_assignable<Union<T...>>,
- std::is_move_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<std::is_move_constructible<T>...,
- // Note: We're not qualifying this with
- // absl:: because it doesn't compile
- // under MSVC.
- is_move_assignable<T>...>>>::value,
- VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>;
-
-// Base that is dependent on whether or not the copy-assign can be trivial.
-template <class... T>
-using VariantCopyAssignBase = absl::conditional_t<
- absl::disjunction<
- absl::conjunction<absl::is_copy_assignable<Union<T...>>,
- std::is_copy_constructible<Union<T...>>,
- std::is_destructible<Union<T...>>>,
- absl::negation<absl::conjunction<std::is_copy_constructible<T>...,
- // Note: We're not qualifying this with
- // absl:: because it doesn't compile
- // under MSVC.
- is_copy_assignable<T>...>>>::value,
- VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>;
-
-template <class... T>
-using VariantBase = VariantCopyAssignBase<T...>;
-
-template <class... T>
-class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> {
- private:
- using Base = VariantStateBase<T...>;
-
- protected:
- using Base::Base;
-
- VariantStateBaseDestructorNontrivial() = default;
- VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) =
- default;
- VariantStateBaseDestructorNontrivial(
- const VariantStateBaseDestructorNontrivial&) = default;
- VariantStateBaseDestructorNontrivial& operator=(
- VariantStateBaseDestructorNontrivial&&) = default;
- VariantStateBaseDestructorNontrivial& operator=(
- const VariantStateBaseDestructorNontrivial&) = default;
-
- struct Destroyer {
- template <std::size_t I>
- void operator()(SizeT<I> i) const {
- using Alternative =
- typename absl::variant_alternative<I, variant<T...>>::type;
- variant_internal::AccessUnion(self->state_, i).~Alternative();
- }
-
- void operator()(SizeT<absl::variant_npos> /*i*/) const {
- // This space intentionally left blank
- }
-
- VariantStateBaseDestructorNontrivial* self;
- };
-
- void destroy() { VisitIndices<sizeof...(T)>::Run(Destroyer{this}, index_); }
-
- ~VariantStateBaseDestructorNontrivial() { destroy(); }
-
- protected:
- using Base::index_;
- using Base::state_;
-};
-
-template <class... T>
-class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> {
- private:
- using Base = VariantStateBaseDestructor<T...>;
-
- protected:
- using Base::Base;
-
- struct Construct {
- template <std::size_t I>
- void operator()(SizeT<I> i) const {
- using Alternative =
- typename absl::variant_alternative<I, variant<T...>>::type;
- ::new (static_cast<void*>(&self->state_)) Alternative(
- variant_internal::AccessUnion(std::move(other->state_), i));
- }
-
- void operator()(SizeT<absl::variant_npos> /*i*/) const {}
-
- VariantMoveBaseNontrivial* self;
- VariantMoveBaseNontrivial* other;
- };
-
- VariantMoveBaseNontrivial() = default;
- VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept(
- absl::conjunction<std::is_nothrow_move_constructible<T>...>::value)
- : Base(NoopConstructorTag()) {
- VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
- index_ = other.index_;
- }
-
- VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default;
-
- VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default;
- VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) =
- default;
-
- protected:
- using Base::index_;
- using Base::state_;
-};
-
-template <class... T>
-class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> {
- private:
- using Base = VariantMoveBase<T...>;
-
- protected:
- using Base::Base;
-
- VariantCopyBaseNontrivial() = default;
- VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default;
-
- struct Construct {
- template <std::size_t I>
- void operator()(SizeT<I> i) const {
- using Alternative =
- typename absl::variant_alternative<I, variant<T...>>::type;
- ::new (static_cast<void*>(&self->state_))
- Alternative(variant_internal::AccessUnion(other->state_, i));
- }
-
- void operator()(SizeT<absl::variant_npos> /*i*/) const {}
-
- VariantCopyBaseNontrivial* self;
- const VariantCopyBaseNontrivial* other;
- };
-
- VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other)
- : Base(NoopConstructorTag()) {
- VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_);
- index_ = other.index_;
- }
-
- VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default;
- VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) =
- default;
-
- protected:
- using Base::index_;
- using Base::state_;
-};
-
-template <class... T>
-class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> {
- friend struct VariantCoreAccess;
-
- private:
- using Base = VariantCopyBase<T...>;
-
- protected:
- using Base::Base;
-
- VariantMoveAssignBaseNontrivial() = default;
- VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default;
- VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) =
- default;
- VariantMoveAssignBaseNontrivial& operator=(
- VariantMoveAssignBaseNontrivial const&) = default;
-
- VariantMoveAssignBaseNontrivial&
- operator=(VariantMoveAssignBaseNontrivial&& other) noexcept(
- absl::conjunction<std::is_nothrow_move_constructible<T>...,
- std::is_nothrow_move_assignable<T>...>::value) {
- VisitIndices<sizeof...(T)>::Run(
- VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_);
- return *this;
- }
-
- protected:
- using Base::index_;
- using Base::state_;
-};
-
-template <class... T>
-class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> {
- friend struct VariantCoreAccess;
-
- private:
- using Base = VariantMoveAssignBase<T...>;
-
- protected:
- using Base::Base;
-
- VariantCopyAssignBaseNontrivial() = default;
- VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default;
- VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) =
- default;
- VariantCopyAssignBaseNontrivial& operator=(
- VariantCopyAssignBaseNontrivial&&) = default;
-
- VariantCopyAssignBaseNontrivial& operator=(
- const VariantCopyAssignBaseNontrivial& other) {
- VisitIndices<sizeof...(T)>::Run(
- VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_);
- return *this;
- }
-
- protected:
- using Base::index_;
- using Base::state_;
-};
-
-////////////////////////////////////////
-// Visitors for Comparison Operations //
-////////////////////////////////////////
-
-template <class... Types>
-struct EqualsOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return true;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w);
- }
-};
-
-template <class... Types>
-struct NotEqualsOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return false;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w);
- }
-};
-
-template <class... Types>
-struct LessThanOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return false;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w);
- }
-};
-
-template <class... Types>
-struct GreaterThanOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return false;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w);
- }
-};
-
-template <class... Types>
-struct LessThanOrEqualsOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return true;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w);
- }
-};
-
-template <class... Types>
-struct GreaterThanOrEqualsOp {
- const variant<Types...>* v;
- const variant<Types...>* w;
-
- constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const {
- return true;
- }
-
- template <std::size_t I>
- constexpr bool operator()(SizeT<I> /*v_i*/) const {
- return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w);
- }
-};
-
-// Precondition: v.index() == w.index();
-template <class... Types>
-struct SwapSameIndex {
- variant<Types...>* v;
- variant<Types...>* w;
- template <std::size_t I>
- void operator()(SizeT<I>) const {
- type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v),
- VariantCoreAccess::Access<I>(*w));
- }
-
- void operator()(SizeT<variant_npos>) const {}
-};
-
-// TODO(calabrese) do this from a different namespace for proper adl usage
-template <class... Types>
-struct Swap {
- variant<Types...>* v;
- variant<Types...>* w;
-
- void generic_swap() const {
- variant<Types...> tmp(std::move(*w));
- VariantCoreAccess::Destroy(*w);
- VariantCoreAccess::InitFrom(*w, std::move(*v));
- VariantCoreAccess::Destroy(*v);
- VariantCoreAccess::InitFrom(*v, std::move(tmp));
- }
-
- void operator()(SizeT<absl::variant_npos> /*w_i*/) const {
- if (!v->valueless_by_exception()) {
- generic_swap();
- }
- }
-
- template <std::size_t Wi>
- void operator()(SizeT<Wi> /*w_i*/) {
- if (v->index() == Wi) {
- VisitIndices<sizeof...(Types)>::Run(SwapSameIndex<Types...>{v, w}, Wi);
- } else {
- generic_swap();
- }
- }
-};
-
-template <typename Variant, typename = void, typename... Ts>
-struct VariantHashBase {
- VariantHashBase() = delete;
- VariantHashBase(const VariantHashBase&) = delete;
- VariantHashBase(VariantHashBase&&) = delete;
- VariantHashBase& operator=(const VariantHashBase&) = delete;
- VariantHashBase& operator=(VariantHashBase&&) = delete;
-};
-
-struct VariantHashVisitor {
- template <typename T>
- size_t operator()(const T& t) {
- return std::hash<T>{}(t);
- }
-};
-
-template <typename Variant, typename... Ts>
-struct VariantHashBase<Variant,
- absl::enable_if_t<absl::conjunction<
- type_traits_internal::IsHashable<Ts>...>::value>,
- Ts...> {
- using argument_type = Variant;
- using result_type = size_t;
- size_t operator()(const Variant& var) const {
- type_traits_internal::AssertHashEnabled<Ts...>();
- if (var.valueless_by_exception()) {
- return 239799884;
- }
- size_t result = VisitIndices<variant_size<Variant>::value>::Run(
- PerformVisitation<VariantHashVisitor, const Variant&>{
- std::forward_as_tuple(var), VariantHashVisitor{}},
- var.index());
- // Combine the index and the hash result in order to distinguish
- // std::variant<int, int> holding the same value as different alternative.
- return result ^ var.index();
- }
-};
-
-} // namespace variant_internal
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // !defined(ABSL_USES_STD_VARIANT)
-#endif // ABSL_TYPES_INTERNAL_VARIANT_H_
diff --git a/absl/types/optional.h b/absl/types/optional.h
index cf7249c..65bba64 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -16,32 +16,18 @@
// optional.h
// -----------------------------------------------------------------------------
//
-// This header file defines the `absl::optional` type for holding a value which
-// may or may not be present. This type is useful for providing value semantics
-// for operations that may either wish to return or hold "something-or-nothing".
-//
-// Example:
-//
-// // A common way to signal operation failure is to provide an output
-// // parameter and a bool return type:
-// bool AcquireResource(const Input&, Resource * out);
-//
-// // Providing an absl::optional return type provides a cleaner API:
-// absl::optional<Resource> AcquireResource(const Input&);
-//
-// `absl::optional` is a C++11 compatible version of the C++17 `std::optional`
-// abstraction and is designed to be a drop-in replacement for code compliant
-// with C++17.
+// Historical note: Abseil once provided an implementation of `absl::optional`
+// as a polyfill for `std::optional` prior to C++17. Now that C++17 is required,
+// `absl::optional` is an alias for `std::optional`.
+
#ifndef ABSL_TYPES_OPTIONAL_H_
#define ABSL_TYPES_OPTIONAL_H_
-#include "absl/base/config.h" // TODO(calabrese) IWYU removal?
+#include <optional>
+
+#include "absl/base/config.h"
#include "absl/utility/utility.h"
-#ifdef ABSL_USES_STD_OPTIONAL
-
-#include <optional> // IWYU pragma: export
-
namespace absl {
ABSL_NAMESPACE_BEGIN
using std::bad_optional_access;
@@ -52,728 +38,4 @@
ABSL_NAMESPACE_END
} // namespace absl
-#else // ABSL_USES_STD_OPTIONAL
-
-#include <cassert>
-#include <functional>
-#include <initializer_list>
-#include <type_traits>
-#include <utility>
-
-#include "absl/base/attributes.h"
-#include "absl/base/nullability.h"
-#include "absl/base/internal/inline_variable.h"
-#include "absl/meta/type_traits.h"
-#include "absl/types/bad_optional_access.h"
-#include "absl/types/internal/optional.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// nullopt_t
-//
-// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
-// that does not contain a value.
-struct nullopt_t {
- // It must not be default-constructible to avoid ambiguity for opt = {}.
- explicit constexpr nullopt_t(optional_internal::init_t) noexcept {}
-};
-
-// nullopt
-//
-// A tag constant of type `absl::nullopt_t` used to indicate an empty
-// `absl::optional` in certain functions, such as construction or assignment.
-ABSL_INTERNAL_INLINE_CONSTEXPR(nullopt_t, nullopt,
- nullopt_t(optional_internal::init_t()));
-
-// -----------------------------------------------------------------------------
-// absl::optional
-// -----------------------------------------------------------------------------
-//
-// A value of type `absl::optional<T>` holds either a value of `T` or an
-// "empty" value. When it holds a value of `T`, it stores it as a direct
-// sub-object, so `sizeof(optional<T>)` is approximately
-// `sizeof(T) + sizeof(bool)`.
-//
-// This implementation is based on the specification in the latest draft of the
-// C++17 `std::optional` specification as of May 2017, section 20.6.
-//
-// Differences between `absl::optional<T>` and `std::optional<T>` include:
-//
-// * `constexpr` is not used for non-const member functions.
-// (dependency on some differences between C++11 and C++14.)
-// * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We
-// need the inline variable support in C++17 for external linkage.
-// * Throws `absl::bad_optional_access` instead of
-// `std::bad_optional_access`.
-// * `make_optional()` cannot be declared `constexpr` due to the absence of
-// guaranteed copy elision.
-// * The move constructor's `noexcept` specification is stronger, i.e. if the
-// default allocator is non-throwing (via setting
-// `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because
-// we assume
-// a) move constructors should only throw due to allocation failure and
-// b) if T's move constructor allocates, it uses the same allocation
-// function as the default allocator.
-//
-template <typename T>
-class optional : private optional_internal::optional_data<T>,
- private optional_internal::optional_ctor_base<
- optional_internal::ctor_copy_traits<T>::traits>,
- private optional_internal::optional_assign_base<
- optional_internal::assign_copy_traits<T>::traits> {
- using data_base = optional_internal::optional_data<T>;
-
- public:
- typedef T value_type;
-
- // Constructors
-
- // Constructs an `optional` holding an empty value, NOT a default constructed
- // `T`.
- constexpr optional() noexcept = default;
-
- // Constructs an `optional` initialized with `nullopt` to hold an empty value.
- constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit)
-
- // Copy constructor, standard semantics
- optional(const optional&) = default;
-
- // Move constructor, standard semantics
- optional(optional&&) = default;
-
- // Constructs a non-empty `optional` direct-initialized value of type `T` from
- // the arguments `std::forward<Args>(args)...` within the `optional`.
- // (The `in_place_t` is a tag used to indicate that the contained object
- // should be constructed in-place.)
- template <typename InPlaceT, typename... Args,
- absl::enable_if_t<absl::conjunction<
- std::is_same<InPlaceT, in_place_t>,
- std::is_constructible<T, Args&&...> >::value>* = nullptr>
- constexpr explicit optional(InPlaceT, Args&&... args)
- : data_base(in_place_t(), std::forward<Args>(args)...) {}
-
- // Constructs a non-empty `optional` direct-initialized value of type `T` from
- // the arguments of an initializer_list and `std::forward<Args>(args)...`.
- // (The `in_place_t` is a tag used to indicate that the contained object
- // should be constructed in-place.)
- template <typename U, typename... Args,
- typename = typename std::enable_if<std::is_constructible<
- T, std::initializer_list<U>&, Args&&...>::value>::type>
- constexpr explicit optional(in_place_t, std::initializer_list<U> il,
- Args&&... args)
- : data_base(in_place_t(), il, std::forward<Args>(args)...) {}
-
- // Value constructor (implicit)
- template <
- typename U = T,
- typename std::enable_if<
- absl::conjunction<absl::negation<std::is_same<
- in_place_t, typename std::decay<U>::type> >,
- absl::negation<std::is_same<
- optional<T>, typename std::decay<U>::type> >,
- std::is_convertible<U&&, T>,
- std::is_constructible<T, U&&> >::value,
- bool>::type = false>
- constexpr optional(U&& v) : data_base(in_place_t(), std::forward<U>(v)) {}
-
- // Value constructor (explicit)
- template <
- typename U = T,
- typename std::enable_if<
- absl::conjunction<absl::negation<std::is_same<
- in_place_t, typename std::decay<U>::type> >,
- absl::negation<std::is_same<
- optional<T>, typename std::decay<U>::type> >,
- absl::negation<std::is_convertible<U&&, T> >,
- std::is_constructible<T, U&&> >::value,
- bool>::type = false>
- explicit constexpr optional(U&& v)
- : data_base(in_place_t(), std::forward<U>(v)) {}
-
- // Converting copy constructor (implicit)
- template <typename U,
- typename std::enable_if<
- absl::conjunction<
- absl::negation<std::is_same<T, U> >,
- std::is_constructible<T, const U&>,
- absl::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U> >,
- std::is_convertible<const U&, T> >::value,
- bool>::type = false>
- optional(const optional<U>& rhs) {
- if (rhs) {
- this->construct(*rhs);
- }
- }
-
- // Converting copy constructor (explicit)
- template <typename U,
- typename std::enable_if<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>,
- absl::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U>>,
- absl::negation<std::is_convertible<const U&, T>>>::value,
- bool>::type = false>
- explicit optional(const optional<U>& rhs) {
- if (rhs) {
- this->construct(*rhs);
- }
- }
-
- // Converting move constructor (implicit)
- template <typename U,
- typename std::enable_if<
- absl::conjunction<
- absl::negation<std::is_same<T, U> >,
- std::is_constructible<T, U&&>,
- absl::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U> >,
- std::is_convertible<U&&, T> >::value,
- bool>::type = false>
- optional(optional<U>&& rhs) {
- if (rhs) {
- this->construct(std::move(*rhs));
- }
- }
-
- // Converting move constructor (explicit)
- template <
- typename U,
- typename std::enable_if<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
- absl::negation<
- optional_internal::is_constructible_convertible_from_optional<
- T, U>>,
- absl::negation<std::is_convertible<U&&, T>>>::value,
- bool>::type = false>
- explicit optional(optional<U>&& rhs) {
- if (rhs) {
- this->construct(std::move(*rhs));
- }
- }
-
- // Destructor. Trivial if `T` is trivially destructible.
- ~optional() = default;
-
- // Assignment Operators
-
- // Assignment from `nullopt`
- //
- // Example:
- //
- // struct S { int value; };
- // optional<S> opt = absl::nullopt; // Could also use opt = { };
- optional& operator=(nullopt_t) noexcept {
- this->destruct();
- return *this;
- }
-
- // Copy assignment operator, standard semantics
- optional& operator=(const optional& src) = default;
-
- // Move assignment operator, standard semantics
- optional& operator=(optional&& src) = default;
-
- // Value assignment operators
- template <typename U = T,
- int&..., // Workaround an internal compiler error in GCC 5 to 10.
- typename = typename std::enable_if<absl::conjunction<
- absl::negation<
- std::is_same<optional<T>, typename std::decay<U>::type> >,
- absl::negation<absl::conjunction<
- std::is_scalar<T>,
- std::is_same<T, typename std::decay<U>::type> > >,
- std::is_constructible<T, U>,
- std::is_assignable<T&, U> >::value>::type>
- optional& operator=(U&& v) {
- this->assign(std::forward<U>(v));
- return *this;
- }
-
- template <
- typename U,
- int&..., // Workaround an internal compiler error in GCC 5 to 10.
- typename = typename std::enable_if<absl::conjunction<
- absl::negation<std::is_same<T, U> >,
- std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
- absl::negation<
- optional_internal::
- is_constructible_convertible_assignable_from_optional<
- T, U> > >::value>::type>
- optional& operator=(const optional<U>& rhs) {
- if (rhs) {
- this->assign(*rhs);
- } else {
- this->destruct();
- }
- return *this;
- }
-
- template <typename U,
- int&..., // Workaround an internal compiler error in GCC 5 to 10.
- typename = typename std::enable_if<absl::conjunction<
- absl::negation<std::is_same<T, U> >,
- std::is_constructible<T, U>, std::is_assignable<T&, U>,
- absl::negation<
- optional_internal::
- is_constructible_convertible_assignable_from_optional<
- T, U> > >::value>::type>
- optional& operator=(optional<U>&& rhs) {
- if (rhs) {
- this->assign(std::move(*rhs));
- } else {
- this->destruct();
- }
- return *this;
- }
-
- // Modifiers
-
- // optional::reset()
- //
- // Destroys the inner `T` value of an `absl::optional` if one is present.
- ABSL_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); }
-
- // optional::emplace()
- //
- // (Re)constructs the underlying `T` in-place with the given forwarded
- // arguments.
- //
- // Example:
- //
- // optional<Foo> opt;
- // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3)
- //
- // If the optional is non-empty, and the `args` refer to subobjects of the
- // current object, then behaviour is undefined, because the current object
- // will be destructed before the new object is constructed with `args`.
- template <typename... Args,
- typename = typename std::enable_if<
- std::is_constructible<T, Args&&...>::value>::type>
- T& emplace(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- this->destruct();
- this->construct(std::forward<Args>(args)...);
- return reference();
- }
-
- // Emplace reconstruction overload for an initializer list and the given
- // forwarded arguments.
- //
- // Example:
- //
- // struct Foo {
- // Foo(std::initializer_list<int>);
- // };
- //
- // optional<Foo> opt;
- // opt.emplace({1,2,3}); // Constructs Foo({1,2,3})
- template <typename U, typename... Args,
- typename = typename std::enable_if<std::is_constructible<
- T, std::initializer_list<U>&, Args&&...>::value>::type>
- T& emplace(std::initializer_list<U> il,
- Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
- this->destruct();
- this->construct(il, std::forward<Args>(args)...);
- return reference();
- }
-
- // Swaps
-
- // Swap, standard semantics
- void swap(optional& rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value&&
- type_traits_internal::IsNothrowSwappable<T>::value) {
- if (*this) {
- if (rhs) {
- type_traits_internal::Swap(**this, *rhs);
- } else {
- rhs.construct(std::move(**this));
- this->destruct();
- }
- } else {
- if (rhs) {
- this->construct(std::move(*rhs));
- rhs.destruct();
- } else {
- // No effect (swap(disengaged, disengaged)).
- }
- }
- }
-
- // Observers
-
- // optional::operator->()
- //
- // Accesses the underlying `T` value's member `m` of an `optional`. If the
- // `optional` is empty, behavior is undefined.
- //
- // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
- absl::Nonnull<const T*> operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
- ABSL_HARDENING_ASSERT(this->engaged_);
- return std::addressof(this->data_);
- }
- absl::Nonnull<T*> operator->() ABSL_ATTRIBUTE_LIFETIME_BOUND {
- ABSL_HARDENING_ASSERT(this->engaged_);
- return std::addressof(this->data_);
- }
-
- // optional::operator*()
- //
- // Accesses the underlying `T` value of an `optional`. If the `optional` is
- // empty, behavior is undefined.
- constexpr const T& operator*() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return ABSL_HARDENING_ASSERT(this->engaged_), reference();
- }
- T& operator*() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
- ABSL_HARDENING_ASSERT(this->engaged_);
- return reference();
- }
- constexpr const T&& operator*() const&& ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return ABSL_HARDENING_ASSERT(this->engaged_), std::move(reference());
- }
- T&& operator*() && ABSL_ATTRIBUTE_LIFETIME_BOUND {
- ABSL_HARDENING_ASSERT(this->engaged_);
- return std::move(reference());
- }
-
- // optional::operator bool()
- //
- // Returns false if and only if the `optional` is empty.
- //
- // if (opt) {
- // // do something with *opt or opt->;
- // } else {
- // // opt is empty.
- // }
- //
- constexpr explicit operator bool() const noexcept { return this->engaged_; }
-
- // optional::has_value()
- //
- // Determines whether the `optional` contains a value. Returns `false` if and
- // only if `*this` is empty.
- constexpr bool has_value() const noexcept { return this->engaged_; }
-
-// Suppress bogus warning on MSVC: MSVC complains call to reference() after
-// throw_bad_optional_access() is unreachable.
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4702)
-#endif // _MSC_VER
- // optional::value()
- //
- // Returns a reference to an `optional`s underlying value. The constness
- // and lvalue/rvalue-ness of the `optional` is preserved to the view of
- // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional`
- // is empty.
- constexpr const T& value() const& ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference());
- }
- T& value() & ABSL_ATTRIBUTE_LIFETIME_BOUND {
- return static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference());
- }
- T&& value() && ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11)
- return std::move(
- static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference()));
- }
- constexpr const T&& value()
- const&& ABSL_ATTRIBUTE_LIFETIME_BOUND { // NOLINT(build/c++11)
- return std::move(
- static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference()));
- }
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER
-
- // optional::value_or()
- //
- // Returns either the value of `T` or a passed default `v` if the `optional`
- // is empty.
- template <typename U>
- constexpr T value_or(U&& v) const& {
- static_assert(std::is_copy_constructible<value_type>::value,
- "optional<T>::value_or: T must be copy constructible");
- static_assert(std::is_convertible<U&&, value_type>::value,
- "optional<T>::value_or: U must be convertible to T");
- return static_cast<bool>(*this) ? **this
- : static_cast<T>(std::forward<U>(v));
- }
- template <typename U>
- T value_or(U&& v) && { // NOLINT(build/c++11)
- static_assert(std::is_move_constructible<value_type>::value,
- "optional<T>::value_or: T must be move constructible");
- static_assert(std::is_convertible<U&&, value_type>::value,
- "optional<T>::value_or: U must be convertible to T");
- return static_cast<bool>(*this) ? std::move(**this)
- : static_cast<T>(std::forward<U>(v));
- }
-
- private:
- // Private accessors for internal storage viewed as reference to T.
- constexpr const T& reference() const { return this->data_; }
- T& reference() { return this->data_; }
-
- // T constraint checks. You can't have an optional of nullopt_t, in_place_t
- // or a reference.
- static_assert(
- !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
- "optional<nullopt_t> is not allowed.");
- static_assert(
- !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
- "optional<in_place_t> is not allowed.");
- static_assert(!std::is_reference<T>::value,
- "optional<reference> is not allowed.");
-};
-
-// Non-member functions
-
-// swap()
-//
-// Performs a swap between two `absl::optional` objects, using standard
-// semantics.
-template <typename T, typename std::enable_if<
- std::is_move_constructible<T>::value &&
- type_traits_internal::IsSwappable<T>::value,
- bool>::type = false>
-void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
- a.swap(b);
-}
-
-// make_optional()
-//
-// Creates a non-empty `optional<T>` where the type of `T` is deduced. An
-// `absl::optional` can also be explicitly instantiated with
-// `make_optional<T>(v)`.
-//
-// Note: `make_optional()` constructions may be declared `constexpr` for
-// trivially copyable types `T`. Non-trivial types require copy elision
-// support in C++17 for `make_optional` to support `constexpr` on such
-// non-trivial types.
-//
-// Example:
-//
-// constexpr absl::optional<int> opt = absl::make_optional(1);
-// static_assert(opt.value() == 1, "");
-template <typename T>
-constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
- return optional<typename std::decay<T>::type>(std::forward<T>(v));
-}
-
-template <typename T, typename... Args>
-constexpr optional<T> make_optional(Args&&... args) {
- return optional<T>(in_place_t(), std::forward<Args>(args)...);
-}
-
-template <typename T, typename U, typename... Args>
-constexpr optional<T> make_optional(std::initializer_list<U> il,
- Args&&... args) {
- return optional<T>(in_place_t(), il, std::forward<Args>(args)...);
-}
-
-// Relational operators [optional.relops]
-
-// Empty optionals are considered equal to each other and less than non-empty
-// optionals. Supports relations between optional<T> and optional<U>, between
-// optional<T> and U, and between optional<T> and nullopt.
-//
-// Note: We're careful to support T having non-bool relationals.
-
-// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result
-// shall be convertible to bool.
-// The C++17 (N4606) "Returns:" statements are translated into
-// code in an obvious way here, and the original text retained as function docs.
-// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
-// otherwise *x == *y.
-template <typename T, typename U>
-constexpr auto operator==(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
- return static_cast<bool>(x) != static_cast<bool>(y)
- ? false
- : static_cast<bool>(x) == false ? true
- : static_cast<bool>(*x == *y);
-}
-
-// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
-// otherwise *x != *y.
-template <typename T, typename U>
-constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
- return static_cast<bool>(x) != static_cast<bool>(y)
- ? true
- : static_cast<bool>(x) == false ? false
- : static_cast<bool>(*x != *y);
-}
-// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
-template <typename T, typename U>
-constexpr auto operator<(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
- return !y ? false : !x ? true : static_cast<bool>(*x < *y);
-}
-// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
-template <typename T, typename U>
-constexpr auto operator>(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
- return !x ? false : !y ? true : static_cast<bool>(*x > *y);
-}
-// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
-template <typename T, typename U>
-constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
- return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
-}
-// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
-template <typename T, typename U>
-constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
- return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
-}
-
-// Comparison with nullopt [optional.nullops]
-// The C++17 (N4606) "Returns:" statements are used directly here.
-template <typename T>
-constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
- return !x;
-}
-template <typename T>
-constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
- return !x;
-}
-template <typename T>
-constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
- return static_cast<bool>(x);
-}
-template <typename T>
-constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
- return static_cast<bool>(x);
-}
-template <typename T>
-constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
- return false;
-}
-template <typename T>
-constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
- return static_cast<bool>(x);
-}
-template <typename T>
-constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
- return !x;
-}
-template <typename T>
-constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
- return true;
-}
-template <typename T>
-constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
- return static_cast<bool>(x);
-}
-template <typename T>
-constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
- return false;
-}
-template <typename T>
-constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
- return true;
-}
-template <typename T>
-constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
- return !x;
-}
-
-// Comparison with T [optional.comp_with_t]
-
-// Requires: The expression, e.g. "*x == v" shall be well-formed and its result
-// shall be convertible to bool.
-// The C++17 (N4606) "Equivalent to:" statements are used directly here.
-template <typename T, typename U>
-constexpr auto operator==(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x == v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
-}
-template <typename T, typename U>
-constexpr auto operator==(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v == *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
-}
-template <typename T, typename U>
-constexpr auto operator!=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x != v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
-}
-template <typename T, typename U>
-constexpr auto operator!=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v != *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
-}
-template <typename T, typename U>
-constexpr auto operator<(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x < v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
-}
-template <typename T, typename U>
-constexpr auto operator<(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v < *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
-}
-template <typename T, typename U>
-constexpr auto operator<=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
-}
-template <typename T, typename U>
-constexpr auto operator<=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
-}
-template <typename T, typename U>
-constexpr auto operator>(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x > v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
-}
-template <typename T, typename U>
-constexpr auto operator>(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v > *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
-}
-template <typename T, typename U>
-constexpr auto operator>=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
-}
-template <typename T, typename U>
-constexpr auto operator>=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
-}
-
-ABSL_NAMESPACE_END
-} // namespace absl
-
-namespace std {
-
-// std::hash specialization for absl::optional.
-template <typename T>
-struct hash<absl::optional<T> >
- : absl::optional_internal::optional_hash_base<T> {};
-
-} // namespace std
-
-#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
-
-#endif // ABSL_USES_STD_OPTIONAL
-
#endif // ABSL_TYPES_OPTIONAL_H_
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc
deleted file mode 100644
index 8e5fe85..0000000
--- a/absl/types/optional_exception_safety_test.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/optional.h"
-
-#include "absl/base/config.h"
-
-// This test is a no-op when absl::optional is an alias for std::optional and
-// when exceptions are not enabled.
-#if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
-
-#include "gtest/gtest.h"
-#include "absl/base/internal/exception_safety_testing.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-namespace {
-
-using ::testing::AssertionFailure;
-using ::testing::AssertionResult;
-using ::testing::AssertionSuccess;
-using ::testing::MakeExceptionSafetyTester;
-
-using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
-using Optional = absl::optional<Thrower>;
-
-using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
-using MoveOptional = absl::optional<MoveThrower>;
-
-constexpr int kInitialInteger = 5;
-constexpr int kUpdatedInteger = 10;
-
-template <typename OptionalT>
-bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try {
- return (static_cast<void>(optional.value()), false);
-} catch (const absl::bad_optional_access&) {
- return true;
-}
-
-template <typename OptionalT>
-AssertionResult OptionalInvariants(OptionalT* optional_ptr) {
- // Check the current state post-throw for validity
- auto& optional = *optional_ptr;
-
- if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) {
- return AssertionFailure()
- << "Optional with value should not throw bad_optional_access when "
- "accessing the value.";
- }
- if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) {
- return AssertionFailure()
- << "Optional without a value should throw bad_optional_access when "
- "accessing the value.";
- }
-
- // Reset to a known state
- optional.reset();
-
- // Confirm that the known post-reset state is valid
- if (optional.has_value()) {
- return AssertionFailure()
- << "Optional should not contain a value after being reset.";
- }
- if (!ValueThrowsBadOptionalAccess(optional)) {
- return AssertionFailure() << "Optional should throw bad_optional_access "
- "when accessing the value after being reset.";
- }
-
- return AssertionSuccess();
-}
-
-template <typename OptionalT>
-AssertionResult CheckDisengaged(OptionalT* optional_ptr) {
- auto& optional = *optional_ptr;
-
- if (optional.has_value()) {
- return AssertionFailure()
- << "Expected optional to not contain a value but a value was found.";
- }
-
- return AssertionSuccess();
-}
-
-template <typename OptionalT>
-AssertionResult CheckEngaged(OptionalT* optional_ptr) {
- auto& optional = *optional_ptr;
-
- if (!optional.has_value()) {
- return AssertionFailure()
- << "Expected optional to contain a value but no value was found.";
- }
-
- return AssertionSuccess();
-}
-
-TEST(OptionalExceptionSafety, ThrowingConstructors) {
- auto thrower_nonempty = Optional(Thrower(kInitialInteger));
- testing::TestThrowingCtor<Optional>(thrower_nonempty);
-
- auto integer_nonempty = absl::optional<int>(kInitialInteger);
- testing::TestThrowingCtor<Optional>(integer_nonempty);
- testing::TestThrowingCtor<Optional>(std::move(integer_nonempty)); // NOLINT
-
- testing::TestThrowingCtor<Optional>(kInitialInteger);
- using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>;
- testing::TestThrowingCtor<absl::optional<ThrowerVec>>(
- absl::in_place,
- std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()},
- testing::ThrowingAllocator<Thrower>());
-}
-
-TEST(OptionalExceptionSafety, NothrowConstructors) {
- // This constructor is marked noexcept. If it throws, the program will
- // terminate.
- testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger));
-}
-
-TEST(OptionalExceptionSafety, Emplace) {
- // Test the basic guarantee plus test the result of optional::has_value()
- // is false in all cases
- auto disengaged_test = MakeExceptionSafetyTester().WithContracts(
- OptionalInvariants<Optional>, CheckDisengaged<Optional>);
- auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional());
- auto disengaged_test_nonempty =
- disengaged_test.WithInitialValue(Optional(kInitialInteger));
-
- auto emplace_thrower_directly = [](Optional* optional_ptr) {
- optional_ptr->emplace(kUpdatedInteger);
- };
- EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly));
- EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly));
-
- auto emplace_thrower_copy = [](Optional* optional_ptr) {
- auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
- optional_ptr->emplace(thrower);
- };
- EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy));
- EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy));
-}
-
-TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
- // Test the basic guarantee plus test the result of optional::has_value()
- // remains the same
- auto test =
- MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
- auto disengaged_test_empty = test.WithInitialValue(Optional())
- .WithContracts(CheckDisengaged<Optional>);
- auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
- .WithContracts(CheckEngaged<Optional>);
-
- auto swap_empty = [](Optional* optional_ptr) {
- auto empty = Optional();
- optional_ptr->swap(empty);
- };
- EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty));
-
- auto swap_nonempty = [](Optional* optional_ptr) {
- auto nonempty =
- Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
- optional_ptr->swap(nonempty);
- };
- EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty));
- EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty));
-}
-
-TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
- // Tests the nothrow guarantee for optional of T with non-throwing move
- {
- auto empty = MoveOptional();
- auto nonempty = MoveOptional(kInitialInteger);
- EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); }));
- }
- {
- auto nonempty = MoveOptional(kUpdatedInteger);
- auto empty = MoveOptional();
- EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); }));
- }
- {
- auto nonempty_from = MoveOptional(kUpdatedInteger);
- auto nonempty_to = MoveOptional(kInitialInteger);
- EXPECT_TRUE(
- testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); }));
- }
-}
-
-TEST(OptionalExceptionSafety, CopyAssign) {
- // Test the basic guarantee plus test the result of optional::has_value()
- // remains the same
- auto test =
- MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
- auto disengaged_test_empty = test.WithInitialValue(Optional())
- .WithContracts(CheckDisengaged<Optional>);
- auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
- .WithContracts(CheckEngaged<Optional>);
-
- auto copyassign_nonempty = [](Optional* optional_ptr) {
- auto nonempty =
- Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
- *optional_ptr = nonempty;
- };
- EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty));
- EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty));
-
- auto copyassign_thrower = [](Optional* optional_ptr) {
- auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
- *optional_ptr = thrower;
- };
- EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower));
- EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower));
-}
-
-TEST(OptionalExceptionSafety, MoveAssign) {
- // Test the basic guarantee plus test the result of optional::has_value()
- // remains the same
- auto test =
- MakeExceptionSafetyTester().WithContracts(OptionalInvariants<Optional>);
- auto disengaged_test_empty = test.WithInitialValue(Optional())
- .WithContracts(CheckDisengaged<Optional>);
- auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger))
- .WithContracts(CheckEngaged<Optional>);
-
- auto moveassign_empty = [](Optional* optional_ptr) {
- auto empty = Optional();
- *optional_ptr = std::move(empty);
- };
- EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty));
-
- auto moveassign_nonempty = [](Optional* optional_ptr) {
- auto nonempty =
- Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
- *optional_ptr = std::move(nonempty);
- };
- EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty));
- EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty));
-
- auto moveassign_thrower = [](Optional* optional_ptr) {
- auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor);
- *optional_ptr = std::move(thrower);
- };
- EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower));
- EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower));
-}
-
-TEST(OptionalExceptionSafety, NothrowMoveAssign) {
- // Tests the nothrow guarantee for optional of T with non-throwing move
- {
- auto empty = MoveOptional();
- auto nonempty = MoveOptional(kInitialInteger);
- EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); }));
- }
- {
- auto nonempty = MoveOptional(kInitialInteger);
- auto empty = MoveOptional();
- EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); }));
- }
- {
- auto nonempty_from = MoveOptional(kUpdatedInteger);
- auto nonempty_to = MoveOptional(kInitialInteger);
- EXPECT_TRUE(testing::TestNothrowOp(
- [&]() { nonempty_to = std::move(nonempty_from); }));
- }
- {
- auto thrower = MoveThrower(kUpdatedInteger);
- auto empty = MoveOptional();
- EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); }));
- }
- {
- auto thrower = MoveThrower(kUpdatedInteger);
- auto nonempty = MoveOptional(kInitialInteger);
- EXPECT_TRUE(
- testing::TestNothrowOp([&]() { nonempty = std::move(thrower); }));
- }
-}
-
-} // namespace
-
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // #if !defined(ABSL_USES_STD_OPTIONAL) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
deleted file mode 100644
index 115e20c..0000000
--- a/absl/types/optional_test.cc
+++ /dev/null
@@ -1,1615 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/optional.h"
-
-// This test is a no-op when absl::optional is an alias for std::optional.
-#if !defined(ABSL_USES_STD_OPTIONAL)
-
-#include <string>
-#include <type_traits>
-#include <utility>
-
-#include "gtest/gtest.h"
-#include "absl/base/config.h"
-#include "absl/log/log.h"
-#include "absl/meta/type_traits.h"
-#include "absl/strings/string_view.h"
-
-#if defined(__cplusplus) && __cplusplus >= 202002L
-// In C++20, volatile-qualified return types are deprecated.
-#define ABSL_VOLATILE_RETURN_TYPES_DEPRECATED 1
-#endif
-
-// The following types help test an internal compiler error in GCC5 though
-// GCC10. The case OptionalTest.InternalCompilerErrorInGcc5ToGcc10 crashes the
-// compiler without a workaround. This test case should remain at the beginning
-// of the file as the internal compiler error is sensitive to other constructs
-// in this file.
-template <class T, class...>
-using GccIceHelper1 = T;
-template <typename T>
-struct GccIceHelper2 {};
-template <typename T>
-class GccIce {
- template <typename U,
- typename SecondTemplateArgHasToExistForSomeReason = void,
- typename DependentType = void,
- typename = std::is_assignable<GccIceHelper1<T, DependentType>&, U>>
- GccIce& operator=(GccIceHelper2<U> const&) {}
-};
-
-TEST(OptionalTest, InternalCompilerErrorInGcc5ToGcc10) {
- GccIce<int> instantiate_ice_with_same_type_as_optional;
- static_cast<void>(instantiate_ice_with_same_type_as_optional);
- absl::optional<int> val1;
- absl::optional<int> val2;
- val1 = val2;
-}
-
-struct Hashable {};
-
-namespace std {
-template <>
-struct hash<Hashable> {
- size_t operator()(const Hashable&) { return 0; }
-};
-} // namespace std
-
-struct NonHashable {};
-
-namespace {
-
-std::string TypeQuals(std::string&) { return "&"; }
-std::string TypeQuals(std::string&&) { return "&&"; }
-std::string TypeQuals(const std::string&) { return "c&"; }
-std::string TypeQuals(const std::string&&) { return "c&&"; }
-
-struct StructorListener {
- int construct0 = 0;
- int construct1 = 0;
- int construct2 = 0;
- int listinit = 0;
- int copy = 0;
- int move = 0;
- int copy_assign = 0;
- int move_assign = 0;
- int destruct = 0;
- int volatile_copy = 0;
- int volatile_move = 0;
- int volatile_copy_assign = 0;
- int volatile_move_assign = 0;
-};
-
-// Suppress MSVC warnings.
-// 4521: multiple copy constructors specified
-// 4522: multiple assignment operators specified
-// We wrote multiple of them to test that the correct overloads are selected.
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable : 4521)
-#pragma warning(disable : 4522)
-#endif
-struct Listenable {
- static StructorListener* listener;
-
- Listenable() { ++listener->construct0; }
- explicit Listenable(int /*unused*/) { ++listener->construct1; }
- Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; }
- Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; }
- Listenable(const Listenable& /*unused*/) { ++listener->copy; }
- Listenable(const volatile Listenable& /*unused*/) {
- ++listener->volatile_copy;
- }
- Listenable(volatile Listenable&& /*unused*/) { ++listener->volatile_move; }
- Listenable(Listenable&& /*unused*/) { ++listener->move; }
- Listenable& operator=(const Listenable& /*unused*/) {
- ++listener->copy_assign;
- return *this;
- }
- Listenable& operator=(Listenable&& /*unused*/) {
- ++listener->move_assign;
- return *this;
- }
- // use void return type instead of volatile T& to work around GCC warning
- // when the assignment's returned reference is ignored.
- void operator=(const volatile Listenable& /*unused*/) volatile {
- ++listener->volatile_copy_assign;
- }
- void operator=(volatile Listenable&& /*unused*/) volatile {
- ++listener->volatile_move_assign;
- }
- ~Listenable() { ++listener->destruct; }
-};
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-StructorListener* Listenable::listener = nullptr;
-
-struct ConstexprType {
- enum CtorTypes {
- kCtorDefault,
- kCtorInt,
- kCtorInitializerList,
- kCtorConstChar
- };
- constexpr ConstexprType() : x(kCtorDefault) {}
- constexpr explicit ConstexprType(int i) : x(kCtorInt) {}
- constexpr ConstexprType(std::initializer_list<int> il)
- : x(kCtorInitializerList) {}
- constexpr ConstexprType(const char*) // NOLINT(runtime/explicit)
- : x(kCtorConstChar) {}
- int x;
-};
-
-struct Copyable {
- Copyable() {}
- Copyable(const Copyable&) {}
- Copyable& operator=(const Copyable&) { return *this; }
-};
-
-struct MoveableThrow {
- MoveableThrow() {}
- MoveableThrow(MoveableThrow&&) {}
- MoveableThrow& operator=(MoveableThrow&&) { return *this; }
-};
-
-struct MoveableNoThrow {
- MoveableNoThrow() {}
- MoveableNoThrow(MoveableNoThrow&&) noexcept {}
- MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; }
-};
-
-struct NonMovable {
- NonMovable() {}
- NonMovable(const NonMovable&) = delete;
- NonMovable& operator=(const NonMovable&) = delete;
- NonMovable(NonMovable&&) = delete;
- NonMovable& operator=(NonMovable&&) = delete;
-};
-
-struct NoDefault {
- NoDefault() = delete;
- NoDefault(const NoDefault&) {}
- NoDefault& operator=(const NoDefault&) { return *this; }
-};
-
-struct ConvertsFromInPlaceT {
- ConvertsFromInPlaceT(absl::in_place_t) {} // NOLINT
-};
-
-TEST(optionalTest, DefaultConstructor) {
- absl::optional<int> empty;
- EXPECT_FALSE(empty);
- constexpr absl::optional<int> cempty;
- static_assert(!cempty.has_value(), "");
- EXPECT_TRUE(
- std::is_nothrow_default_constructible<absl::optional<int>>::value);
-}
-
-TEST(optionalTest, nulloptConstructor) {
- absl::optional<int> empty(absl::nullopt);
- EXPECT_FALSE(empty);
- constexpr absl::optional<int> cempty{absl::nullopt};
- static_assert(!cempty.has_value(), "");
- EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>,
- absl::nullopt_t>::value));
-}
-
-TEST(optionalTest, CopyConstructor) {
- {
- absl::optional<int> empty, opt42 = 42;
- absl::optional<int> empty_copy(empty);
- EXPECT_FALSE(empty_copy);
- absl::optional<int> opt42_copy(opt42);
- EXPECT_TRUE(opt42_copy);
- EXPECT_EQ(42, *opt42_copy);
- }
- {
- absl::optional<const int> empty, opt42 = 42;
- absl::optional<const int> empty_copy(empty);
- EXPECT_FALSE(empty_copy);
- absl::optional<const int> opt42_copy(opt42);
- EXPECT_TRUE(opt42_copy);
- EXPECT_EQ(42, *opt42_copy);
- }
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- {
- absl::optional<volatile int> empty, opt42 = 42;
- absl::optional<volatile int> empty_copy(empty);
- EXPECT_FALSE(empty_copy);
- absl::optional<volatile int> opt42_copy(opt42);
- EXPECT_TRUE(opt42_copy);
- EXPECT_EQ(42, *opt42_copy);
- }
-#endif
- // test copyablility
- EXPECT_TRUE(std::is_copy_constructible<absl::optional<int>>::value);
- EXPECT_TRUE(std::is_copy_constructible<absl::optional<Copyable>>::value);
- EXPECT_FALSE(
- std::is_copy_constructible<absl::optional<MoveableThrow>>::value);
- EXPECT_FALSE(
- std::is_copy_constructible<absl::optional<MoveableNoThrow>>::value);
- EXPECT_FALSE(std::is_copy_constructible<absl::optional<NonMovable>>::value);
-
- EXPECT_FALSE(
- absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value);
- EXPECT_TRUE(
- absl::is_trivially_copy_constructible<absl::optional<int>>::value);
- EXPECT_TRUE(
- absl::is_trivially_copy_constructible<absl::optional<const int>>::value);
-#if !defined(_MSC_VER) && !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- // See defect report "Trivial copy/move constructor for class with volatile
- // member" at
- // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094
- // A class with non-static data member of volatile-qualified type should still
- // have a trivial copy constructor if the data member is trivial.
- // Also a cv-qualified scalar type should be trivially copyable.
- EXPECT_TRUE(absl::is_trivially_copy_constructible<
- absl::optional<volatile int>>::value);
-#endif // !defined(_MSC_VER) && !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
-
- // constexpr copy constructor for trivially copyable types
- {
- constexpr absl::optional<int> o1;
- constexpr absl::optional<int> o2 = o1;
- static_assert(!o2, "");
- }
- {
- constexpr absl::optional<int> o1 = 42;
- constexpr absl::optional<int> o2 = o1;
- static_assert(o2, "");
- static_assert(*o2 == 42, "");
- }
- {
- struct TrivialCopyable {
- constexpr TrivialCopyable() : x(0) {}
- constexpr explicit TrivialCopyable(int i) : x(i) {}
- int x;
- };
- constexpr absl::optional<TrivialCopyable> o1(42);
- constexpr absl::optional<TrivialCopyable> o2 = o1;
- static_assert(o2, "");
- static_assert((*o2).x == 42, "");
-#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG
- EXPECT_TRUE(absl::is_trivially_copy_constructible<
- absl::optional<TrivialCopyable>>::value);
- EXPECT_TRUE(absl::is_trivially_copy_constructible<
- absl::optional<const TrivialCopyable>>::value);
-#endif
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- EXPECT_FALSE(std::is_copy_constructible<
- absl::optional<volatile TrivialCopyable>>::value);
-#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- }
-}
-
-TEST(optionalTest, MoveConstructor) {
- absl::optional<int> empty, opt42 = 42;
- absl::optional<int> empty_move(std::move(empty));
- EXPECT_FALSE(empty_move);
- absl::optional<int> opt42_move(std::move(opt42));
- EXPECT_TRUE(opt42_move);
- EXPECT_EQ(42, opt42_move);
- // test movability
- EXPECT_TRUE(std::is_move_constructible<absl::optional<int>>::value);
- EXPECT_TRUE(std::is_move_constructible<absl::optional<Copyable>>::value);
- EXPECT_TRUE(std::is_move_constructible<absl::optional<MoveableThrow>>::value);
- EXPECT_TRUE(
- std::is_move_constructible<absl::optional<MoveableNoThrow>>::value);
- EXPECT_FALSE(std::is_move_constructible<absl::optional<NonMovable>>::value);
- // test noexcept
- EXPECT_TRUE(std::is_nothrow_move_constructible<absl::optional<int>>::value);
- EXPECT_EQ(
- absl::default_allocator_is_nothrow::value,
- std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value);
- EXPECT_TRUE(std::is_nothrow_move_constructible<
- absl::optional<MoveableNoThrow>>::value);
-}
-
-TEST(optionalTest, Destructor) {
- struct Trivial {};
-
- struct NonTrivial {
- NonTrivial(const NonTrivial&) {}
- NonTrivial& operator=(const NonTrivial&) { return *this; }
- ~NonTrivial() {}
- };
-
- EXPECT_TRUE(std::is_trivially_destructible<absl::optional<int>>::value);
- EXPECT_TRUE(std::is_trivially_destructible<absl::optional<Trivial>>::value);
- EXPECT_FALSE(
- std::is_trivially_destructible<absl::optional<NonTrivial>>::value);
-}
-
-TEST(optionalTest, InPlaceConstructor) {
- constexpr absl::optional<ConstexprType> opt0{absl::in_place_t()};
- static_assert(opt0, "");
- static_assert((*opt0).x == ConstexprType::kCtorDefault, "");
- constexpr absl::optional<ConstexprType> opt1{absl::in_place_t(), 1};
- static_assert(opt1, "");
- static_assert((*opt1).x == ConstexprType::kCtorInt, "");
- constexpr absl::optional<ConstexprType> opt2{absl::in_place_t(), {1, 2}};
- static_assert(opt2, "");
- static_assert((*opt2).x == ConstexprType::kCtorInitializerList, "");
-
- EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
- absl::in_place_t>::value));
- EXPECT_FALSE((std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
- const absl::in_place_t&>::value));
- EXPECT_TRUE(
- (std::is_constructible<absl::optional<ConvertsFromInPlaceT>,
- absl::in_place_t, absl::in_place_t>::value));
-
- EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>,
- absl::in_place_t>::value));
- EXPECT_FALSE((std::is_constructible<absl::optional<NoDefault>,
- absl::in_place_t&&>::value));
-}
-
-// template<U=T> optional(U&&);
-TEST(optionalTest, ValueConstructor) {
- constexpr absl::optional<int> opt0(0);
- static_assert(opt0, "");
- static_assert(*opt0 == 0, "");
- EXPECT_TRUE((std::is_convertible<int, absl::optional<int>>::value));
- // Copy initialization ( = "abc") won't work due to optional(optional&&)
- // is not constexpr. Use list initialization instead. This invokes
- // absl::optional<ConstexprType>::absl::optional<U>(U&&), with U = const char
- // (&) [4], which direct-initializes the ConstexprType value held by the
- // optional via ConstexprType::ConstexprType(const char*).
- constexpr absl::optional<ConstexprType> opt1 = {"abc"};
- static_assert(opt1, "");
- static_assert(ConstexprType::kCtorConstChar == (*opt1).x, "");
- EXPECT_TRUE(
- (std::is_convertible<const char*, absl::optional<ConstexprType>>::value));
- // direct initialization
- constexpr absl::optional<ConstexprType> opt2{2};
- static_assert(opt2, "");
- static_assert(ConstexprType::kCtorInt == (*opt2).x, "");
- EXPECT_FALSE(
- (std::is_convertible<int, absl::optional<ConstexprType>>::value));
-
- // this invokes absl::optional<int>::optional(int&&)
- // NOTE: this has different behavior than assignment, e.g.
- // "opt3 = {};" clears the optional rather than setting the value to 0
- // According to C++17 standard N4659 [over.ics.list] 16.3.3.1.5, (9.2)- "if
- // the initializer list has no elements, the implicit conversion is the
- // identity conversion", so `optional(int&&)` should be a better match than
- // `optional(optional&&)` which is a user-defined conversion.
- // Note: GCC 7 has a bug with this overload selection when compiled with
- // `-std=c++17`.
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7 && \
- __cplusplus == 201703L
-#define ABSL_GCC7_OVER_ICS_LIST_BUG 1
-#endif
-#ifndef ABSL_GCC7_OVER_ICS_LIST_BUG
- constexpr absl::optional<int> opt3({});
- static_assert(opt3, "");
- static_assert(*opt3 == 0, "");
-#endif
-
- // this invokes the move constructor with a default constructed optional
- // because non-template function is a better match than template function.
- absl::optional<ConstexprType> opt4({});
- EXPECT_FALSE(opt4);
-}
-
-struct Implicit {};
-
-struct Explicit {};
-
-struct Convert {
- Convert(const Implicit&) // NOLINT(runtime/explicit)
- : implicit(true), move(false) {}
- Convert(Implicit&&) // NOLINT(runtime/explicit)
- : implicit(true), move(true) {}
- explicit Convert(const Explicit&) : implicit(false), move(false) {}
- explicit Convert(Explicit&&) : implicit(false), move(true) {}
-
- bool implicit;
- bool move;
-};
-
-struct ConvertFromOptional {
- ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit)
- : implicit(true), move(false), from_optional(false) {}
- ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit)
- : implicit(true), move(true), from_optional(false) {}
- ConvertFromOptional(
- const absl::optional<Implicit>&) // NOLINT(runtime/explicit)
- : implicit(true), move(false), from_optional(true) {}
- ConvertFromOptional(absl::optional<Implicit>&&) // NOLINT(runtime/explicit)
- : implicit(true), move(true), from_optional(true) {}
- explicit ConvertFromOptional(const Explicit&)
- : implicit(false), move(false), from_optional(false) {}
- explicit ConvertFromOptional(Explicit&&)
- : implicit(false), move(true), from_optional(false) {}
- explicit ConvertFromOptional(const absl::optional<Explicit>&)
- : implicit(false), move(false), from_optional(true) {}
- explicit ConvertFromOptional(absl::optional<Explicit>&&)
- : implicit(false), move(true), from_optional(true) {}
-
- bool implicit;
- bool move;
- bool from_optional;
-};
-
-TEST(optionalTest, ConvertingConstructor) {
- absl::optional<Implicit> i_empty;
- absl::optional<Implicit> i(absl::in_place);
- absl::optional<Explicit> e_empty;
- absl::optional<Explicit> e(absl::in_place);
- {
- // implicitly constructing absl::optional<Convert> from
- // absl::optional<Implicit>
- absl::optional<Convert> empty = i_empty;
- EXPECT_FALSE(empty);
- absl::optional<Convert> opt_copy = i;
- EXPECT_TRUE(opt_copy);
- EXPECT_TRUE(opt_copy->implicit);
- EXPECT_FALSE(opt_copy->move);
- absl::optional<Convert> opt_move = absl::optional<Implicit>(absl::in_place);
- EXPECT_TRUE(opt_move);
- EXPECT_TRUE(opt_move->implicit);
- EXPECT_TRUE(opt_move->move);
- }
- {
- // explicitly constructing absl::optional<Convert> from
- // absl::optional<Explicit>
- absl::optional<Convert> empty(e_empty);
- EXPECT_FALSE(empty);
- absl::optional<Convert> opt_copy(e);
- EXPECT_TRUE(opt_copy);
- EXPECT_FALSE(opt_copy->implicit);
- EXPECT_FALSE(opt_copy->move);
- EXPECT_FALSE((std::is_convertible<const absl::optional<Explicit>&,
- absl::optional<Convert>>::value));
- absl::optional<Convert> opt_move{absl::optional<Explicit>(absl::in_place)};
- EXPECT_TRUE(opt_move);
- EXPECT_FALSE(opt_move->implicit);
- EXPECT_TRUE(opt_move->move);
- EXPECT_FALSE((std::is_convertible<absl::optional<Explicit>&&,
- absl::optional<Convert>>::value));
- }
- {
- // implicitly constructing absl::optional<ConvertFromOptional> from
- // absl::optional<Implicit> via
- // ConvertFromOptional(absl::optional<Implicit>&&) check that
- // ConvertFromOptional(Implicit&&) is NOT called
- static_assert(
- std::is_convertible<absl::optional<Implicit>,
- absl::optional<ConvertFromOptional>>::value,
- "");
- absl::optional<ConvertFromOptional> opt0 = i_empty;
- EXPECT_TRUE(opt0);
- EXPECT_TRUE(opt0->implicit);
- EXPECT_FALSE(opt0->move);
- EXPECT_TRUE(opt0->from_optional);
- absl::optional<ConvertFromOptional> opt1 = absl::optional<Implicit>();
- EXPECT_TRUE(opt1);
- EXPECT_TRUE(opt1->implicit);
- EXPECT_TRUE(opt1->move);
- EXPECT_TRUE(opt1->from_optional);
- }
- {
- // implicitly constructing absl::optional<ConvertFromOptional> from
- // absl::optional<Explicit> via
- // ConvertFromOptional(absl::optional<Explicit>&&) check that
- // ConvertFromOptional(Explicit&&) is NOT called
- absl::optional<ConvertFromOptional> opt0(e_empty);
- EXPECT_TRUE(opt0);
- EXPECT_FALSE(opt0->implicit);
- EXPECT_FALSE(opt0->move);
- EXPECT_TRUE(opt0->from_optional);
- EXPECT_FALSE(
- (std::is_convertible<const absl::optional<Explicit>&,
- absl::optional<ConvertFromOptional>>::value));
- absl::optional<ConvertFromOptional> opt1{absl::optional<Explicit>()};
- EXPECT_TRUE(opt1);
- EXPECT_FALSE(opt1->implicit);
- EXPECT_TRUE(opt1->move);
- EXPECT_TRUE(opt1->from_optional);
- EXPECT_FALSE(
- (std::is_convertible<absl::optional<Explicit>&&,
- absl::optional<ConvertFromOptional>>::value));
- }
-}
-
-TEST(optionalTest, StructorBasic) {
- StructorListener listener;
- Listenable::listener = &listener;
- {
- absl::optional<Listenable> empty;
- EXPECT_FALSE(empty);
- absl::optional<Listenable> opt0(absl::in_place);
- EXPECT_TRUE(opt0);
- absl::optional<Listenable> opt1(absl::in_place, 1);
- EXPECT_TRUE(opt1);
- absl::optional<Listenable> opt2(absl::in_place, 1, 2);
- EXPECT_TRUE(opt2);
- }
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.construct1);
- EXPECT_EQ(1, listener.construct2);
- EXPECT_EQ(3, listener.destruct);
-}
-
-TEST(optionalTest, CopyMoveStructor) {
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> original(absl::in_place);
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(0, listener.copy);
- EXPECT_EQ(0, listener.move);
- absl::optional<Listenable> copy(original);
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.copy);
- EXPECT_EQ(0, listener.move);
- absl::optional<Listenable> move(std::move(original));
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.copy);
- EXPECT_EQ(1, listener.move);
-}
-
-TEST(optionalTest, ListInit) {
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> listinit1(absl::in_place, {1});
- absl::optional<Listenable> listinit2(absl::in_place, {1, 2});
- EXPECT_EQ(2, listener.listinit);
-}
-
-TEST(optionalTest, AssignFromNullopt) {
- absl::optional<int> opt(1);
- opt = absl::nullopt;
- EXPECT_FALSE(opt);
-
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> opt1(absl::in_place);
- opt1 = absl::nullopt;
- EXPECT_FALSE(opt1);
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.destruct);
-
- EXPECT_TRUE((
- std::is_nothrow_assignable<absl::optional<int>, absl::nullopt_t>::value));
- EXPECT_TRUE((std::is_nothrow_assignable<absl::optional<Listenable>,
- absl::nullopt_t>::value));
-}
-
-TEST(optionalTest, CopyAssignment) {
- const absl::optional<int> empty, opt1 = 1, opt2 = 2;
- absl::optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty;
-
- EXPECT_FALSE(empty_to_opt1);
- empty_to_opt1 = empty;
- EXPECT_FALSE(empty_to_opt1);
- empty_to_opt1 = opt1;
- EXPECT_TRUE(empty_to_opt1);
- EXPECT_EQ(1, empty_to_opt1.value());
-
- EXPECT_FALSE(opt1_to_opt2);
- opt1_to_opt2 = opt1;
- EXPECT_TRUE(opt1_to_opt2);
- EXPECT_EQ(1, opt1_to_opt2.value());
- opt1_to_opt2 = opt2;
- EXPECT_TRUE(opt1_to_opt2);
- EXPECT_EQ(2, opt1_to_opt2.value());
-
- EXPECT_FALSE(opt2_to_empty);
- opt2_to_empty = opt2;
- EXPECT_TRUE(opt2_to_empty);
- EXPECT_EQ(2, opt2_to_empty.value());
- opt2_to_empty = empty;
- EXPECT_FALSE(opt2_to_empty);
-
- EXPECT_FALSE(absl::is_copy_assignable<absl::optional<const int>>::value);
- EXPECT_TRUE(absl::is_copy_assignable<absl::optional<Copyable>>::value);
- EXPECT_FALSE(absl::is_copy_assignable<absl::optional<MoveableThrow>>::value);
- EXPECT_FALSE(
- absl::is_copy_assignable<absl::optional<MoveableNoThrow>>::value);
- EXPECT_FALSE(absl::is_copy_assignable<absl::optional<NonMovable>>::value);
-
- EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value);
- EXPECT_TRUE(absl::is_trivially_copy_assignable<volatile int>::value);
-
- struct Trivial {
- int i;
- };
- struct NonTrivial {
- NonTrivial& operator=(const NonTrivial&) { return *this; }
- int i;
- };
-
- EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value);
- EXPECT_FALSE(absl::is_copy_assignable<const Trivial>::value);
- EXPECT_FALSE(absl::is_copy_assignable<volatile Trivial>::value);
- EXPECT_TRUE(absl::is_copy_assignable<NonTrivial>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value);
-
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- {
- StructorListener listener;
- Listenable::listener = &listener;
-
- absl::optional<volatile Listenable> empty, set(absl::in_place);
- EXPECT_EQ(1, listener.construct0);
- absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
- set_to_empty(absl::in_place), set_to_set(absl::in_place);
- EXPECT_EQ(3, listener.construct0);
- empty_to_empty = empty; // no effect
- empty_to_set = set; // copy construct
- set_to_empty = empty; // destruct
- set_to_set = set; // copy assign
- EXPECT_EQ(1, listener.volatile_copy);
- EXPECT_EQ(0, listener.volatile_move);
- EXPECT_EQ(1, listener.destruct);
- EXPECT_EQ(1, listener.volatile_copy_assign);
- }
-#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
-}
-
-TEST(optionalTest, MoveAssignment) {
- {
- StructorListener listener;
- Listenable::listener = &listener;
-
- absl::optional<Listenable> empty1, empty2, set1(absl::in_place),
- set2(absl::in_place);
- EXPECT_EQ(2, listener.construct0);
- absl::optional<Listenable> empty_to_empty, empty_to_set,
- set_to_empty(absl::in_place), set_to_set(absl::in_place);
- EXPECT_EQ(4, listener.construct0);
- empty_to_empty = std::move(empty1);
- empty_to_set = std::move(set1);
- set_to_empty = std::move(empty2);
- set_to_set = std::move(set2);
- EXPECT_EQ(0, listener.copy);
- EXPECT_EQ(1, listener.move);
- EXPECT_EQ(1, listener.destruct);
- EXPECT_EQ(1, listener.move_assign);
- }
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- {
- StructorListener listener;
- Listenable::listener = &listener;
-
- absl::optional<volatile Listenable> empty1, empty2, set1(absl::in_place),
- set2(absl::in_place);
- EXPECT_EQ(2, listener.construct0);
- absl::optional<volatile Listenable> empty_to_empty, empty_to_set,
- set_to_empty(absl::in_place), set_to_set(absl::in_place);
- EXPECT_EQ(4, listener.construct0);
- empty_to_empty = std::move(empty1); // no effect
- empty_to_set = std::move(set1); // move construct
- set_to_empty = std::move(empty2); // destruct
- set_to_set = std::move(set2); // move assign
- EXPECT_EQ(0, listener.volatile_copy);
- EXPECT_EQ(1, listener.volatile_move);
- EXPECT_EQ(1, listener.destruct);
- EXPECT_EQ(1, listener.volatile_move_assign);
- }
-#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- EXPECT_FALSE(absl::is_move_assignable<absl::optional<const int>>::value);
- EXPECT_TRUE(absl::is_move_assignable<absl::optional<Copyable>>::value);
- EXPECT_TRUE(absl::is_move_assignable<absl::optional<MoveableThrow>>::value);
- EXPECT_TRUE(absl::is_move_assignable<absl::optional<MoveableNoThrow>>::value);
- EXPECT_FALSE(absl::is_move_assignable<absl::optional<NonMovable>>::value);
-
- EXPECT_FALSE(
- std::is_nothrow_move_assignable<absl::optional<MoveableThrow>>::value);
- EXPECT_TRUE(
- std::is_nothrow_move_assignable<absl::optional<MoveableNoThrow>>::value);
-}
-
-struct NoConvertToOptional {
- // disable implicit conversion from const NoConvertToOptional&
- // to absl::optional<NoConvertToOptional>.
- NoConvertToOptional(const NoConvertToOptional&) = delete;
-};
-
-struct CopyConvert {
- CopyConvert(const NoConvertToOptional&);
- CopyConvert& operator=(const CopyConvert&) = delete;
- CopyConvert& operator=(const NoConvertToOptional&);
-};
-
-struct CopyConvertFromOptional {
- CopyConvertFromOptional(const NoConvertToOptional&);
- CopyConvertFromOptional(const absl::optional<NoConvertToOptional>&);
- CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete;
- CopyConvertFromOptional& operator=(const NoConvertToOptional&);
- CopyConvertFromOptional& operator=(
- const absl::optional<NoConvertToOptional>&);
-};
-
-struct MoveConvert {
- MoveConvert(NoConvertToOptional&&);
- MoveConvert& operator=(const MoveConvert&) = delete;
- MoveConvert& operator=(NoConvertToOptional&&);
-};
-
-struct MoveConvertFromOptional {
- MoveConvertFromOptional(NoConvertToOptional&&);
- MoveConvertFromOptional(absl::optional<NoConvertToOptional>&&);
- MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete;
- MoveConvertFromOptional& operator=(NoConvertToOptional&&);
- MoveConvertFromOptional& operator=(absl::optional<NoConvertToOptional>&&);
-};
-
-// template <typename U = T> absl::optional<T>& operator=(U&& v);
-TEST(optionalTest, ValueAssignment) {
- absl::optional<int> opt;
- EXPECT_FALSE(opt);
- opt = 42;
- EXPECT_TRUE(opt);
- EXPECT_EQ(42, opt.value());
- opt = absl::nullopt;
- EXPECT_FALSE(opt);
- opt = 42;
- EXPECT_TRUE(opt);
- EXPECT_EQ(42, opt.value());
- opt = 43;
- EXPECT_TRUE(opt);
- EXPECT_EQ(43, opt.value());
- opt = {}; // this should clear optional
- EXPECT_FALSE(opt);
-
- opt = {44};
- EXPECT_TRUE(opt);
- EXPECT_EQ(44, opt.value());
-
- // U = const NoConvertToOptional&
- EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvert>&,
- const NoConvertToOptional&>::value));
- // U = const absl::optional<NoConvertToOptional>&
- EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvertFromOptional>&,
- const NoConvertToOptional&>::value));
- // U = const NoConvertToOptional& triggers SFINAE because
- // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
- EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvert>&,
- const NoConvertToOptional&>::value));
- // U = NoConvertToOptional
- EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvert>&,
- NoConvertToOptional&&>::value));
- // U = const NoConvertToOptional& triggers SFINAE because
- // std::is_constructible_v<MoveConvertFromOptional, const
- // NoConvertToOptional&> is false
- EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
- const NoConvertToOptional&>::value));
- // U = NoConvertToOptional
- EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvertFromOptional>&,
- NoConvertToOptional&&>::value));
- // U = const absl::optional<NoConvertToOptional>&
- EXPECT_TRUE(
- (std::is_assignable<absl::optional<CopyConvertFromOptional>&,
- const absl::optional<NoConvertToOptional>&>::value));
- // U = absl::optional<NoConvertToOptional>
- EXPECT_TRUE(
- (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
- absl::optional<NoConvertToOptional>&&>::value));
-}
-
-// template <typename U> absl::optional<T>& operator=(const absl::optional<U>&
-// rhs); template <typename U> absl::optional<T>& operator=(absl::optional<U>&&
-// rhs);
-TEST(optionalTest, ConvertingAssignment) {
- absl::optional<int> opt_i;
- absl::optional<char> opt_c('c');
- opt_i = opt_c;
- EXPECT_TRUE(opt_i);
- EXPECT_EQ(*opt_c, *opt_i);
- opt_i = absl::optional<char>();
- EXPECT_FALSE(opt_i);
- opt_i = absl::optional<char>('d');
- EXPECT_TRUE(opt_i);
- EXPECT_EQ('d', *opt_i);
-
- absl::optional<std::string> opt_str;
- absl::optional<const char*> opt_cstr("abc");
- opt_str = opt_cstr;
- EXPECT_TRUE(opt_str);
- EXPECT_EQ(std::string("abc"), *opt_str);
- opt_str = absl::optional<const char*>();
- EXPECT_FALSE(opt_str);
- opt_str = absl::optional<const char*>("def");
- EXPECT_TRUE(opt_str);
- EXPECT_EQ(std::string("def"), *opt_str);
-
- // operator=(const absl::optional<U>&) with U = NoConvertToOptional
- EXPECT_TRUE(
- (std::is_assignable<absl::optional<CopyConvert>,
- const absl::optional<NoConvertToOptional>&>::value));
- // operator=(const absl::optional<U>&) with U = NoConvertToOptional
- // triggers SFINAE because
- // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false
- EXPECT_FALSE(
- (std::is_assignable<absl::optional<MoveConvert>&,
- const absl::optional<NoConvertToOptional>&>::value));
- // operator=(absl::optional<U>&&) with U = NoConvertToOptional
- EXPECT_TRUE(
- (std::is_assignable<absl::optional<MoveConvert>&,
- absl::optional<NoConvertToOptional>&&>::value));
- // operator=(const absl::optional<U>&) with U = NoConvertToOptional triggers
- // SFINAE because std::is_constructible_v<MoveConvertFromOptional, const
- // NoConvertToOptional&> is false. operator=(U&&) with U = const
- // absl::optional<NoConverToOptional>& triggers SFINAE because
- // std::is_constructible<MoveConvertFromOptional,
- // absl::optional<NoConvertToOptional>&&> is true.
- EXPECT_FALSE(
- (std::is_assignable<absl::optional<MoveConvertFromOptional>&,
- const absl::optional<NoConvertToOptional>&>::value));
-}
-
-TEST(optionalTest, ResetAndHasValue) {
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> opt;
- EXPECT_FALSE(opt);
- EXPECT_FALSE(opt.has_value());
- opt.emplace();
- EXPECT_TRUE(opt);
- EXPECT_TRUE(opt.has_value());
- opt.reset();
- EXPECT_FALSE(opt);
- EXPECT_FALSE(opt.has_value());
- EXPECT_EQ(1, listener.destruct);
- opt.reset();
- EXPECT_FALSE(opt);
- EXPECT_FALSE(opt.has_value());
-
- constexpr absl::optional<int> empty;
- static_assert(!empty.has_value(), "");
- constexpr absl::optional<int> nonempty(1);
- static_assert(nonempty.has_value(), "");
-}
-
-TEST(optionalTest, Emplace) {
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> opt;
- EXPECT_FALSE(opt);
- opt.emplace(1);
- EXPECT_TRUE(opt);
- opt.emplace(1, 2);
- EXPECT_EQ(1, listener.construct1);
- EXPECT_EQ(1, listener.construct2);
- EXPECT_EQ(1, listener.destruct);
-
- absl::optional<std::string> o;
- EXPECT_TRUE((std::is_same<std::string&, decltype(o.emplace("abc"))>::value));
- std::string& ref = o.emplace("abc");
- EXPECT_EQ(&ref, &o.value());
-}
-
-TEST(optionalTest, ListEmplace) {
- StructorListener listener;
- Listenable::listener = &listener;
- absl::optional<Listenable> opt;
- EXPECT_FALSE(opt);
- opt.emplace({1});
- EXPECT_TRUE(opt);
- opt.emplace({1, 2});
- EXPECT_EQ(2, listener.listinit);
- EXPECT_EQ(1, listener.destruct);
-
- absl::optional<Listenable> o;
- EXPECT_TRUE((std::is_same<Listenable&, decltype(o.emplace({1}))>::value));
- Listenable& ref = o.emplace({1});
- EXPECT_EQ(&ref, &o.value());
-}
-
-TEST(optionalTest, Swap) {
- absl::optional<int> opt_empty, opt1 = 1, opt2 = 2;
- EXPECT_FALSE(opt_empty);
- EXPECT_TRUE(opt1);
- EXPECT_EQ(1, opt1.value());
- EXPECT_TRUE(opt2);
- EXPECT_EQ(2, opt2.value());
- swap(opt_empty, opt1);
- EXPECT_FALSE(opt1);
- EXPECT_TRUE(opt_empty);
- EXPECT_EQ(1, opt_empty.value());
- EXPECT_TRUE(opt2);
- EXPECT_EQ(2, opt2.value());
- swap(opt_empty, opt1);
- EXPECT_FALSE(opt_empty);
- EXPECT_TRUE(opt1);
- EXPECT_EQ(1, opt1.value());
- EXPECT_TRUE(opt2);
- EXPECT_EQ(2, opt2.value());
- swap(opt1, opt2);
- EXPECT_FALSE(opt_empty);
- EXPECT_TRUE(opt1);
- EXPECT_EQ(2, opt1.value());
- EXPECT_TRUE(opt2);
- EXPECT_EQ(1, opt2.value());
-
- EXPECT_TRUE(noexcept(opt1.swap(opt2)));
- EXPECT_TRUE(noexcept(swap(opt1, opt2)));
-}
-
-template <int v>
-struct DeletedOpAddr {
- int value = v;
- constexpr DeletedOpAddr() = default;
- constexpr const DeletedOpAddr<v>* operator&() const = delete; // NOLINT
- DeletedOpAddr<v>* operator&() = delete; // NOLINT
-};
-
-// The static_assert featuring a constexpr call to operator->() is commented out
-// to document the fact that the current implementation of absl::optional<T>
-// expects such usecases to be malformed and not compile.
-TEST(optionalTest, OperatorAddr) {
- constexpr int v = -1;
- { // constexpr
- constexpr absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
- static_assert(opt.has_value(), "");
- // static_assert(opt->value == v, "");
- static_assert((*opt).value == v, "");
- }
- { // non-constexpr
- const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{});
- EXPECT_TRUE(opt.has_value());
- EXPECT_TRUE(opt->value == v);
- EXPECT_TRUE((*opt).value == v);
- }
-}
-
-TEST(optionalTest, PointerStuff) {
- absl::optional<std::string> opt(absl::in_place, "foo");
- EXPECT_EQ("foo", *opt);
- const auto& opt_const = opt;
- EXPECT_EQ("foo", *opt_const);
- EXPECT_EQ(opt->size(), 3u);
- EXPECT_EQ(opt_const->size(), 3u);
-
- constexpr absl::optional<ConstexprType> opt1(1);
- static_assert((*opt1).x == ConstexprType::kCtorInt, "");
-}
-
-TEST(optionalTest, Value) {
- using O = absl::optional<std::string>;
- using CO = const absl::optional<std::string>;
- using OC = absl::optional<const std::string>;
- O lvalue(absl::in_place, "lvalue");
- CO clvalue(absl::in_place, "clvalue");
- OC lvalue_c(absl::in_place, "lvalue_c");
- EXPECT_EQ("lvalue", lvalue.value());
- EXPECT_EQ("clvalue", clvalue.value());
- EXPECT_EQ("lvalue_c", lvalue_c.value());
- EXPECT_EQ("xvalue", O(absl::in_place, "xvalue").value());
- EXPECT_EQ("xvalue_c", OC(absl::in_place, "xvalue_c").value());
- EXPECT_EQ("cxvalue", CO(absl::in_place, "cxvalue").value());
- EXPECT_EQ("&", TypeQuals(lvalue.value()));
- EXPECT_EQ("c&", TypeQuals(clvalue.value()));
- EXPECT_EQ("c&", TypeQuals(lvalue_c.value()));
- EXPECT_EQ("&&", TypeQuals(O(absl::in_place, "xvalue").value()));
- EXPECT_EQ("c&&", TypeQuals(CO(absl::in_place, "cxvalue").value()));
- EXPECT_EQ("c&&", TypeQuals(OC(absl::in_place, "xvalue_c").value()));
-
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- // test on volatile type
- using OV = absl::optional<volatile int>;
- OV lvalue_v(absl::in_place, 42);
- EXPECT_EQ(42, lvalue_v.value());
- EXPECT_EQ(42, OV(42).value());
- EXPECT_TRUE((std::is_same<volatile int&, decltype(lvalue_v.value())>::value));
- EXPECT_TRUE((std::is_same<volatile int&&, decltype(OV(42).value())>::value));
-#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
-
- // test exception throw on value()
- absl::optional<int> empty;
-#ifdef ABSL_HAVE_EXCEPTIONS
- EXPECT_THROW((void)empty.value(), absl::bad_optional_access);
-#else
- EXPECT_DEATH_IF_SUPPORTED((void)empty.value(), "Bad optional access");
-#endif
-
- // test constexpr value()
- constexpr absl::optional<int> o1(1);
- static_assert(1 == o1.value(), ""); // const &
-#ifndef _MSC_VER
- using COI = const absl::optional<int>;
- static_assert(2 == COI(2).value(), ""); // const &&
-#endif
-}
-
-TEST(optionalTest, DerefOperator) {
- using O = absl::optional<std::string>;
- using CO = const absl::optional<std::string>;
- using OC = absl::optional<const std::string>;
- O lvalue(absl::in_place, "lvalue");
- CO clvalue(absl::in_place, "clvalue");
- OC lvalue_c(absl::in_place, "lvalue_c");
- EXPECT_EQ("lvalue", *lvalue);
- EXPECT_EQ("clvalue", *clvalue);
- EXPECT_EQ("lvalue_c", *lvalue_c);
- EXPECT_EQ("xvalue", *O(absl::in_place, "xvalue"));
- EXPECT_EQ("xvalue_c", *OC(absl::in_place, "xvalue_c"));
- EXPECT_EQ("cxvalue", *CO(absl::in_place, "cxvalue"));
- EXPECT_EQ("&", TypeQuals(*lvalue));
- EXPECT_EQ("c&", TypeQuals(*clvalue));
- EXPECT_EQ("&&", TypeQuals(*O(absl::in_place, "xvalue")));
- EXPECT_EQ("c&&", TypeQuals(*CO(absl::in_place, "cxvalue")));
- EXPECT_EQ("c&&", TypeQuals(*OC(absl::in_place, "xvalue_c")));
-
-#if !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
- // test on volatile type
- using OV = absl::optional<volatile int>;
- OV lvalue_v(absl::in_place, 42);
- EXPECT_EQ(42, *lvalue_v);
- EXPECT_EQ(42, *OV(42));
- EXPECT_TRUE((std::is_same<volatile int&, decltype(*lvalue_v)>::value));
- EXPECT_TRUE((std::is_same<volatile int&&, decltype(*OV(42))>::value));
-#endif // !defined(ABSL_VOLATILE_RETURN_TYPES_DEPRECATED)
-
- constexpr absl::optional<int> opt1(1);
- static_assert(*opt1 == 1, "");
-#if !defined(_MSC_VER) && !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG)
- using COI = const absl::optional<int>;
- static_assert(*COI(2) == 2, "");
-#endif
-}
-
-TEST(optionalTest, ValueOr) {
- absl::optional<double> opt_empty, opt_set = 1.2;
- EXPECT_EQ(42.0, opt_empty.value_or(42));
- EXPECT_EQ(1.2, opt_set.value_or(42));
- EXPECT_EQ(42.0, absl::optional<double>().value_or(42));
- EXPECT_EQ(1.2, absl::optional<double>(1.2).value_or(42));
-
- constexpr absl::optional<double> copt_empty, copt_set = {1.2};
- static_assert(42.0 == copt_empty.value_or(42), "");
- static_assert(1.2 == copt_set.value_or(42), "");
- using COD = const absl::optional<double>;
- static_assert(42.0 == COD().value_or(42), "");
- static_assert(1.2 == COD(1.2).value_or(42), "");
-}
-
-// make_optional cannot be constexpr until C++17
-TEST(optionalTest, make_optional) {
- auto opt_int = absl::make_optional(42);
- EXPECT_TRUE((std::is_same<decltype(opt_int), absl::optional<int>>::value));
- EXPECT_EQ(42, opt_int);
-
- StructorListener listener;
- Listenable::listener = &listener;
-
- absl::optional<Listenable> opt0 = absl::make_optional<Listenable>();
- EXPECT_EQ(1, listener.construct0);
- absl::optional<Listenable> opt1 = absl::make_optional<Listenable>(1);
- EXPECT_EQ(1, listener.construct1);
- absl::optional<Listenable> opt2 = absl::make_optional<Listenable>(1, 2);
- EXPECT_EQ(1, listener.construct2);
- absl::optional<Listenable> opt3 = absl::make_optional<Listenable>({1});
- absl::optional<Listenable> opt4 = absl::make_optional<Listenable>({1, 2});
- EXPECT_EQ(2, listener.listinit);
-
- // Constexpr tests on trivially copyable types
- // optional<T> has trivial copy/move ctors when T is trivially copyable.
- // For nontrivial types with constexpr constructors, we need copy elision in
- // C++17 for make_optional to be constexpr.
- {
- constexpr absl::optional<int> c_opt = absl::make_optional(42);
- static_assert(c_opt.value() == 42, "");
- }
- {
- struct TrivialCopyable {
- constexpr TrivialCopyable() : x(0) {}
- constexpr explicit TrivialCopyable(int i) : x(i) {}
- int x;
- };
-
- constexpr TrivialCopyable v;
- constexpr absl::optional<TrivialCopyable> c_opt0 = absl::make_optional(v);
- static_assert((*c_opt0).x == 0, "");
- constexpr absl::optional<TrivialCopyable> c_opt1 =
- absl::make_optional<TrivialCopyable>();
- static_assert((*c_opt1).x == 0, "");
- constexpr absl::optional<TrivialCopyable> c_opt2 =
- absl::make_optional<TrivialCopyable>(42);
- static_assert((*c_opt2).x == 42, "");
- }
-}
-
-template <typename T, typename U>
-void optionalTest_Comparisons_EXPECT_LESS(T x, U y) {
- EXPECT_FALSE(x == y);
- EXPECT_TRUE(x != y);
- EXPECT_TRUE(x < y);
- EXPECT_FALSE(x > y);
- EXPECT_TRUE(x <= y);
- EXPECT_FALSE(x >= y);
-}
-
-template <typename T, typename U>
-void optionalTest_Comparisons_EXPECT_SAME(T x, U y) {
- EXPECT_TRUE(x == y);
- EXPECT_FALSE(x != y);
- EXPECT_FALSE(x < y);
- EXPECT_FALSE(x > y);
- EXPECT_TRUE(x <= y);
- EXPECT_TRUE(x >= y);
-}
-
-template <typename T, typename U>
-void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) {
- EXPECT_FALSE(x == y);
- EXPECT_TRUE(x != y);
- EXPECT_FALSE(x < y);
- EXPECT_TRUE(x > y);
- EXPECT_FALSE(x <= y);
- EXPECT_TRUE(x >= y);
-}
-
-template <typename T, typename U, typename V>
-void TestComparisons() {
- absl::optional<T> ae, a2{2}, a4{4};
- absl::optional<U> be, b2{2}, b4{4};
- V v3 = 3;
-
- // LHS: absl::nullopt, ae, a2, v3, a4
- // RHS: absl::nullopt, be, b2, v3, b4
-
- // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,absl::nullopt);
- optionalTest_Comparisons_EXPECT_SAME(absl::nullopt, be);
- optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b2);
- // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,v3);
- optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b4);
-
- optionalTest_Comparisons_EXPECT_SAME(ae, absl::nullopt);
- optionalTest_Comparisons_EXPECT_SAME(ae, be);
- optionalTest_Comparisons_EXPECT_LESS(ae, b2);
- optionalTest_Comparisons_EXPECT_LESS(ae, v3);
- optionalTest_Comparisons_EXPECT_LESS(ae, b4);
-
- optionalTest_Comparisons_EXPECT_GREATER(a2, absl::nullopt);
- optionalTest_Comparisons_EXPECT_GREATER(a2, be);
- optionalTest_Comparisons_EXPECT_SAME(a2, b2);
- optionalTest_Comparisons_EXPECT_LESS(a2, v3);
- optionalTest_Comparisons_EXPECT_LESS(a2, b4);
-
- // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(v3,absl::nullopt);
- optionalTest_Comparisons_EXPECT_GREATER(v3, be);
- optionalTest_Comparisons_EXPECT_GREATER(v3, b2);
- optionalTest_Comparisons_EXPECT_SAME(v3, v3);
- optionalTest_Comparisons_EXPECT_LESS(v3, b4);
-
- optionalTest_Comparisons_EXPECT_GREATER(a4, absl::nullopt);
- optionalTest_Comparisons_EXPECT_GREATER(a4, be);
- optionalTest_Comparisons_EXPECT_GREATER(a4, b2);
- optionalTest_Comparisons_EXPECT_GREATER(a4, v3);
- optionalTest_Comparisons_EXPECT_SAME(a4, b4);
-}
-
-struct Int1 {
- Int1() = default;
- Int1(int i) : i(i) {} // NOLINT(runtime/explicit)
- int i;
-};
-
-struct Int2 {
- Int2() = default;
- Int2(int i) : i(i) {} // NOLINT(runtime/explicit)
- int i;
-};
-
-// comparison between Int1 and Int2
-constexpr bool operator==(const Int1& lhs, const Int2& rhs) {
- return lhs.i == rhs.i;
-}
-constexpr bool operator!=(const Int1& lhs, const Int2& rhs) {
- return !(lhs == rhs);
-}
-constexpr bool operator<(const Int1& lhs, const Int2& rhs) {
- return lhs.i < rhs.i;
-}
-constexpr bool operator<=(const Int1& lhs, const Int2& rhs) {
- return lhs < rhs || lhs == rhs;
-}
-constexpr bool operator>(const Int1& lhs, const Int2& rhs) {
- return !(lhs <= rhs);
-}
-constexpr bool operator>=(const Int1& lhs, const Int2& rhs) {
- return !(lhs < rhs);
-}
-
-TEST(optionalTest, Comparisons) {
- TestComparisons<int, int, int>();
- TestComparisons<const int, int, int>();
- TestComparisons<Int1, int, int>();
- TestComparisons<int, Int2, int>();
- TestComparisons<Int1, Int2, int>();
-
- // compare absl::optional<std::string> with const char*
- absl::optional<std::string> opt_str = "abc";
- const char* cstr = "abc";
- EXPECT_TRUE(opt_str == cstr);
- // compare absl::optional<std::string> with absl::optional<const char*>
- absl::optional<const char*> opt_cstr = cstr;
- EXPECT_TRUE(opt_str == opt_cstr);
- // compare absl::optional<std::string> with absl::optional<absl::string_view>
- absl::optional<absl::string_view> e1;
- absl::optional<std::string> e2;
- EXPECT_TRUE(e1 == e2);
-}
-
-TEST(optionalTest, SwapRegression) {
- StructorListener listener;
- Listenable::listener = &listener;
-
- {
- absl::optional<Listenable> a;
- absl::optional<Listenable> b(absl::in_place);
- a.swap(b);
- }
-
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.move);
- EXPECT_EQ(2, listener.destruct);
-
- {
- absl::optional<Listenable> a(absl::in_place);
- absl::optional<Listenable> b;
- a.swap(b);
- }
-
- EXPECT_EQ(2, listener.construct0);
- EXPECT_EQ(2, listener.move);
- EXPECT_EQ(4, listener.destruct);
-}
-
-TEST(optionalTest, BigStringLeakCheck) {
- constexpr size_t n = 1 << 16;
-
- using OS = absl::optional<std::string>;
-
- OS a;
- OS b = absl::nullopt;
- OS c = std::string(n, 'c');
- std::string sd(n, 'd');
- OS d = sd;
- OS e(absl::in_place, n, 'e');
- OS f;
- f.emplace(n, 'f');
-
- OS ca(a);
- OS cb(b);
- OS cc(c);
- OS cd(d);
- OS ce(e);
-
- OS oa;
- OS ob = absl::nullopt;
- OS oc = std::string(n, 'c');
- std::string sod(n, 'd');
- OS od = sod;
- OS oe(absl::in_place, n, 'e');
- OS of;
- of.emplace(n, 'f');
-
- OS ma(std::move(oa));
- OS mb(std::move(ob));
- OS mc(std::move(oc));
- OS md(std::move(od));
- OS me(std::move(oe));
- OS mf(std::move(of));
-
- OS aa1;
- OS ab1 = absl::nullopt;
- OS ac1 = std::string(n, 'c');
- std::string sad1(n, 'd');
- OS ad1 = sad1;
- OS ae1(absl::in_place, n, 'e');
- OS af1;
- af1.emplace(n, 'f');
-
- OS aa2;
- OS ab2 = absl::nullopt;
- OS ac2 = std::string(n, 'c');
- std::string sad2(n, 'd');
- OS ad2 = sad2;
- OS ae2(absl::in_place, n, 'e');
- OS af2;
- af2.emplace(n, 'f');
-
- aa1 = af2;
- ab1 = ae2;
- ac1 = ad2;
- ad1 = ac2;
- ae1 = ab2;
- af1 = aa2;
-
- OS aa3;
- OS ab3 = absl::nullopt;
- OS ac3 = std::string(n, 'c');
- std::string sad3(n, 'd');
- OS ad3 = sad3;
- OS ae3(absl::in_place, n, 'e');
- OS af3;
- af3.emplace(n, 'f');
-
- aa3 = absl::nullopt;
- ab3 = absl::nullopt;
- ac3 = absl::nullopt;
- ad3 = absl::nullopt;
- ae3 = absl::nullopt;
- af3 = absl::nullopt;
-
- OS aa4;
- OS ab4 = absl::nullopt;
- OS ac4 = std::string(n, 'c');
- std::string sad4(n, 'd');
- OS ad4 = sad4;
- OS ae4(absl::in_place, n, 'e');
- OS af4;
- af4.emplace(n, 'f');
-
- aa4 = OS(absl::in_place, n, 'a');
- ab4 = OS(absl::in_place, n, 'b');
- ac4 = OS(absl::in_place, n, 'c');
- ad4 = OS(absl::in_place, n, 'd');
- ae4 = OS(absl::in_place, n, 'e');
- af4 = OS(absl::in_place, n, 'f');
-
- OS aa5;
- OS ab5 = absl::nullopt;
- OS ac5 = std::string(n, 'c');
- std::string sad5(n, 'd');
- OS ad5 = sad5;
- OS ae5(absl::in_place, n, 'e');
- OS af5;
- af5.emplace(n, 'f');
-
- std::string saa5(n, 'a');
- std::string sab5(n, 'a');
- std::string sac5(n, 'a');
- std::string sad52(n, 'a');
- std::string sae5(n, 'a');
- std::string saf5(n, 'a');
-
- aa5 = saa5;
- ab5 = sab5;
- ac5 = sac5;
- ad5 = sad52;
- ae5 = sae5;
- af5 = saf5;
-
- OS aa6;
- OS ab6 = absl::nullopt;
- OS ac6 = std::string(n, 'c');
- std::string sad6(n, 'd');
- OS ad6 = sad6;
- OS ae6(absl::in_place, n, 'e');
- OS af6;
- af6.emplace(n, 'f');
-
- aa6 = std::string(n, 'a');
- ab6 = std::string(n, 'b');
- ac6 = std::string(n, 'c');
- ad6 = std::string(n, 'd');
- ae6 = std::string(n, 'e');
- af6 = std::string(n, 'f');
-
- OS aa7;
- OS ab7 = absl::nullopt;
- OS ac7 = std::string(n, 'c');
- std::string sad7(n, 'd');
- OS ad7 = sad7;
- OS ae7(absl::in_place, n, 'e');
- OS af7;
- af7.emplace(n, 'f');
-
- aa7.emplace(n, 'A');
- ab7.emplace(n, 'B');
- ac7.emplace(n, 'C');
- ad7.emplace(n, 'D');
- ae7.emplace(n, 'E');
- af7.emplace(n, 'F');
-}
-
-TEST(optionalTest, MoveAssignRegression) {
- StructorListener listener;
- Listenable::listener = &listener;
-
- {
- absl::optional<Listenable> a;
- Listenable b;
- a = std::move(b);
- }
-
- EXPECT_EQ(1, listener.construct0);
- EXPECT_EQ(1, listener.move);
- EXPECT_EQ(2, listener.destruct);
-}
-
-TEST(optionalTest, ValueType) {
- EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value));
- EXPECT_TRUE((std::is_same<absl::optional<std::string>::value_type,
- std::string>::value));
- EXPECT_FALSE(
- (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value));
-}
-
-template <typename T>
-struct is_hash_enabled_for {
- template <typename U, typename = decltype(std::hash<U>()(std::declval<U>()))>
- static std::true_type test(int);
-
- template <typename U>
- static std::false_type test(...);
-
- static constexpr bool value = decltype(test<T>(0))::value;
-};
-
-TEST(optionalTest, Hash) {
- std::hash<absl::optional<int>> hash;
- std::set<size_t> hashcodes;
- hashcodes.insert(hash(absl::nullopt));
- for (int i = 0; i < 100; ++i) {
- hashcodes.insert(hash(i));
- }
- EXPECT_GT(hashcodes.size(), 90u);
-
- static_assert(is_hash_enabled_for<absl::optional<int>>::value, "");
- static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
- static_assert(
- absl::type_traits_internal::IsHashable<absl::optional<int>>::value, "");
- static_assert(
- absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value,
- "");
- absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>();
- absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>();
-
-#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
- static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, "");
- static_assert(!absl::type_traits_internal::IsHashable<
- absl::optional<NonHashable>>::value,
- "");
-#endif
-
- // libstdc++ std::optional is missing remove_const_t, i.e. it's using
- // std::hash<T> rather than std::hash<std::remove_const_t<T>>.
- // Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82262
-#ifndef __GLIBCXX__
- static_assert(is_hash_enabled_for<absl::optional<const int>>::value, "");
- static_assert(is_hash_enabled_for<absl::optional<const Hashable>>::value, "");
- std::hash<absl::optional<const int>> c_hash;
- for (int i = 0; i < 100; ++i) {
- EXPECT_EQ(hash(i), c_hash(i));
- }
-#endif
-}
-
-struct MoveMeNoThrow {
- MoveMeNoThrow() : x(0) {}
- [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) {
- LOG(FATAL) << "Should not be called.";
- }
- MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {}
- int x;
-};
-
-struct MoveMeThrow {
- MoveMeThrow() : x(0) {}
- MoveMeThrow(const MoveMeThrow& other) : x(other.x) {}
- MoveMeThrow(MoveMeThrow&& other) : x(other.x) {}
- int x;
-};
-
-TEST(optionalTest, NoExcept) {
- static_assert(
- std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value,
- "");
- static_assert(absl::default_allocator_is_nothrow::value ==
- std::is_nothrow_move_constructible<
- absl::optional<MoveMeThrow>>::value,
- "");
- std::vector<absl::optional<MoveMeNoThrow>> v;
- for (int i = 0; i < 10; ++i) v.emplace_back();
-}
-
-struct AnyLike {
- AnyLike(AnyLike&&) = default;
- AnyLike(const AnyLike&) = default;
-
- template <typename ValueType,
- typename T = typename std::decay<ValueType>::type,
- typename std::enable_if<
- !absl::disjunction<
- std::is_same<AnyLike, T>,
- absl::negation<std::is_copy_constructible<T>>>::value,
- int>::type = 0>
- AnyLike(ValueType&&) {} // NOLINT(runtime/explicit)
-
- AnyLike& operator=(AnyLike&&) = default;
- AnyLike& operator=(const AnyLike&) = default;
-
- template <typename ValueType,
- typename T = typename std::decay<ValueType>::type>
- typename std::enable_if<
- absl::conjunction<absl::negation<std::is_same<AnyLike, T>>,
- std::is_copy_constructible<T>>::value,
- AnyLike&>::type
- operator=(ValueType&& /* rhs */) {
- return *this;
- }
-};
-
-TEST(optionalTest, ConstructionConstraints) {
- EXPECT_TRUE((std::is_constructible<AnyLike, absl::optional<AnyLike>>::value));
-
- EXPECT_TRUE(
- (std::is_constructible<AnyLike, const absl::optional<AnyLike>&>::value));
-
- EXPECT_TRUE((std::is_constructible<absl::optional<AnyLike>, AnyLike>::value));
- EXPECT_TRUE(
- (std::is_constructible<absl::optional<AnyLike>, const AnyLike&>::value));
-
- EXPECT_TRUE((std::is_convertible<absl::optional<AnyLike>, AnyLike>::value));
-
- EXPECT_TRUE(
- (std::is_convertible<const absl::optional<AnyLike>&, AnyLike>::value));
-
- EXPECT_TRUE((std::is_convertible<AnyLike, absl::optional<AnyLike>>::value));
- EXPECT_TRUE(
- (std::is_convertible<const AnyLike&, absl::optional<AnyLike>>::value));
-
- EXPECT_TRUE(std::is_move_constructible<absl::optional<AnyLike>>::value);
- EXPECT_TRUE(std::is_copy_constructible<absl::optional<AnyLike>>::value);
-}
-
-TEST(optionalTest, AssignmentConstraints) {
- EXPECT_TRUE((std::is_assignable<AnyLike&, absl::optional<AnyLike>>::value));
- EXPECT_TRUE(
- (std::is_assignable<AnyLike&, const absl::optional<AnyLike>&>::value));
- EXPECT_TRUE((std::is_assignable<absl::optional<AnyLike>&, AnyLike>::value));
- EXPECT_TRUE(
- (std::is_assignable<absl::optional<AnyLike>&, const AnyLike&>::value));
- EXPECT_TRUE(std::is_move_assignable<absl::optional<AnyLike>>::value);
- EXPECT_TRUE(absl::is_copy_assignable<absl::optional<AnyLike>>::value);
-}
-
-#if !defined(__EMSCRIPTEN__)
-struct NestedClassBug {
- struct Inner {
- bool dummy = false;
- };
- absl::optional<Inner> value;
-};
-
-TEST(optionalTest, InPlaceTSFINAEBug) {
- NestedClassBug b;
- ((void)b);
- using Inner = NestedClassBug::Inner;
-
- EXPECT_TRUE((std::is_default_constructible<Inner>::value));
- EXPECT_TRUE((std::is_constructible<Inner>::value));
- EXPECT_TRUE(
- (std::is_constructible<absl::optional<Inner>, absl::in_place_t>::value));
-
- absl::optional<Inner> o(absl::in_place);
- EXPECT_TRUE(o.has_value());
- o.emplace();
- EXPECT_TRUE(o.has_value());
-}
-#endif // !defined(__EMSCRIPTEN__)
-
-} // namespace
-
-#endif // #if !defined(ABSL_USES_STD_OPTIONAL)
diff --git a/absl/types/span.h b/absl/types/span.h
index a0f8027..0e46ee6 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -61,17 +61,53 @@
#include <utility>
#include "absl/base/attributes.h"
+#include "absl/base/config.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/nullability.h"
#include "absl/base/optimization.h"
-#include "absl/base/port.h" // TODO(strel): remove this include
+#include "absl/base/port.h" // TODO(strel): remove this include
+#include "absl/hash/internal/weakly_mixed_integer.h"
#include "absl/meta/type_traits.h"
#include "absl/types/internal/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
+template <typename T>
+class Span;
+
+ABSL_NAMESPACE_END
+} // namespace absl
+
+// Android local modification: some security tests use "#define private public"
+// to access private implementation details. libc++'s <ranges> is currently not
+// compatible with that.
+#if !defined(private)
+
+// If std::ranges is available, mark Span as satisfying the `view` and
+// `borrowed_range` concepts, just like std::span.
+#if !defined(__has_include)
+#define __has_include(header) 0
+#endif
+#if __has_include(<version>)
+#include <version> // NOLINT(misc-include-cleaner)
+#endif
+#if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 201911L
+#include <ranges> // NOLINT(build/c++20)
+template <typename T>
+ // NOLINTNEXTLINE(build/c++20)
+inline constexpr bool std::ranges::enable_view<absl::Span<T>> = true;
+template <typename T>
+ // NOLINTNEXTLINE(build/c++20)
+inline constexpr bool std::ranges::enable_borrowed_range<absl::Span<T>> = true;
+#endif
+
+#endif // !defined(private)
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
//------------------------------------------------------------------------------
// Span
//------------------------------------------------------------------------------
@@ -151,7 +187,7 @@
// int* my_array = new int[10];
// MyRoutine(absl::Span<const int>(my_array, 10));
template <typename T>
-class ABSL_INTERNAL_ATTRIBUTE_VIEW Span {
+class ABSL_ATTRIBUTE_VIEW Span {
private:
// Used to determine whether a Span can be constructed from a container of
// type C.
@@ -173,10 +209,11 @@
public:
using element_type = T;
using value_type = absl::remove_cv_t<T>;
- // TODO(b/316099902) - pointer should be Nullable<T*>, but this makes it hard
- // to recognize foreach loops as safe.
- using pointer = T*;
- using const_pointer = const T*;
+ // TODO(b/316099902) - pointer should be absl_nullable, but this makes it hard
+ // to recognize foreach loops as safe. absl_nullability_unknown is currently
+ // used to suppress -Wnullability-completeness warnings.
+ using pointer = T* absl_nullability_unknown;
+ using const_pointer = const T* absl_nullability_unknown;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
@@ -187,15 +224,18 @@
using difference_type = ptrdiff_t;
using absl_internal_is_view = std::true_type;
+ // NOLINTNEXTLINE
static const size_type npos = ~(size_type(0));
constexpr Span() noexcept : Span(nullptr, 0) {}
- constexpr Span(pointer array, size_type length) noexcept
+ constexpr Span(pointer array ABSL_ATTRIBUTE_LIFETIME_BOUND,
+ size_type length) noexcept
: ptr_(array), len_(length) {}
// Implicit conversion constructors
template <size_t N>
- constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
+ constexpr Span(T( // NOLINT(google-explicit-constructor)
+ &a ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) noexcept
: Span(a, N) {}
// Explicit reference constructor for a mutable `Span<T>` type. Can be
@@ -212,9 +252,8 @@
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfValueIsConst<V>,
typename = span_internal::EnableIfNotIsView<V>>
- constexpr Span(
- const V& v
- ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept // NOLINT(runtime/explicit)
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ constexpr Span(const V& v ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
: Span(span_internal::GetData(v), v.size()) {}
// Overloads of the above two functions that are only enabled for view types.
@@ -229,7 +268,7 @@
template <typename V, typename = EnableIfConvertibleFrom<V>,
typename = EnableIfValueIsConst<V>,
span_internal::EnableIfIsView<V> = 0>
- constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit)
+ constexpr Span(const V& v) noexcept // NOLINT(google-explicit-constructor)
: Span(span_internal::GetData(v), v.size()) {}
// Implicit constructor from an initializer list, making it possible to pass a
@@ -300,7 +339,8 @@
//
// Returns a reference to the i'th element of this span.
constexpr reference operator[](size_type i) const noexcept {
- return ABSL_HARDENING_ASSERT(i < size()), ptr_[i];
+ ABSL_HARDENING_ASSERT(i < size());
+ return ptr_[i];
}
// Span::at()
@@ -319,7 +359,8 @@
// Returns a reference to the first element of this span. The span must not
// be empty.
constexpr reference front() const noexcept {
- return ABSL_HARDENING_ASSERT(size() > 0), *data();
+ ABSL_HARDENING_ASSERT(size() > 0);
+ return *data();
}
// Span::back()
@@ -327,7 +368,8 @@
// Returns a reference to the last element of this span. The span must not
// be empty.
constexpr reference back() const noexcept {
- return ABSL_HARDENING_ASSERT(size() > 0), *(data() + size() - 1);
+ ABSL_HARDENING_ASSERT(size() > 0);
+ return *(data() + size() - 1);
}
// Span::begin()
@@ -465,7 +507,7 @@
template <typename H>
friend H AbslHashValue(H h, Span v) {
return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
- v.size());
+ hash_internal::WeaklyMixedInteger{v.size()});
}
private:
@@ -492,157 +534,165 @@
// operator==
template <typename T>
-bool operator==(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
-bool operator==(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<const T> a,
+ Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
-bool operator==(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a,
+ Span<const T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator==(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(const U& a, Span<T> b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator==(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator==(Span<T> a, const U& b) {
return span_internal::EqualImpl<Span, const T>(a, b);
}
// operator!=
template <typename T>
-bool operator!=(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, Span<T> b) {
return !(a == b);
}
template <typename T>
-bool operator!=(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<const T> a,
+ Span<T> b) {
return !(a == b);
}
template <typename T>
-bool operator!=(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a,
+ Span<const T> b) {
return !(a == b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator!=(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(const U& a, Span<T> b) {
return !(a == b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator!=(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator!=(Span<T> a, const U& b) {
return !(a == b);
}
// operator<
template <typename T>
-bool operator<(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
-bool operator<(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<const T> a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
-bool operator<(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, Span<const T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator<(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(const U& a, Span<T> b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator<(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<(Span<T> a, const U& b) {
return span_internal::LessThanImpl<Span, const T>(a, b);
}
// operator>
template <typename T>
-bool operator>(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<T> b) {
return b < a;
}
template <typename T>
-bool operator>(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<const T> a, Span<T> b) {
return b < a;
}
template <typename T>
-bool operator>(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, Span<const T> b) {
return b < a;
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator>(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(const U& a, Span<T> b) {
return b < a;
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator>(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>(Span<T> a, const U& b) {
return b < a;
}
// operator<=
template <typename T>
-bool operator<=(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, Span<T> b) {
return !(b < a);
}
template <typename T>
-bool operator<=(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<const T> a,
+ Span<T> b) {
return !(b < a);
}
template <typename T>
-bool operator<=(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a,
+ Span<const T> b) {
return !(b < a);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator<=(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(const U& a, Span<T> b) {
return !(b < a);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator<=(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator<=(Span<T> a, const U& b) {
return !(b < a);
}
// operator>=
template <typename T>
-bool operator>=(Span<T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, Span<T> b) {
return !(a < b);
}
template <typename T>
-bool operator>=(Span<const T> a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<const T> a,
+ Span<T> b) {
return !(a < b);
}
template <typename T>
-bool operator>=(Span<T> a, Span<const T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a,
+ Span<const T> b) {
return !(a < b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator>=(const U& a, Span<T> b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(const U& a, Span<T> b) {
return !(a < b);
}
template <
typename T, typename U,
typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
-bool operator>=(Span<T> a, const U& b) {
+ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 bool operator>=(Span<T> a, const U& b) {
return !(a < b);
}
@@ -683,14 +733,14 @@
// }
//
template <int&... ExplicitArgumentBarrier, typename T>
-constexpr Span<T> MakeSpan(absl::Nullable<T*> ptr, size_t size) noexcept {
+constexpr Span<T> MakeSpan(T* absl_nullable ptr, size_t size) noexcept {
return Span<T>(ptr, size);
}
template <int&... ExplicitArgumentBarrier, typename T>
-Span<T> MakeSpan(absl::Nullable<T*> begin, absl::Nullable<T*> end) noexcept {
- return ABSL_HARDENING_ASSERT(begin <= end),
- Span<T>(begin, static_cast<size_t>(end - begin));
+Span<T> MakeSpan(T* absl_nullable begin, T* absl_nullable end) noexcept {
+ ABSL_HARDENING_ASSERT(begin <= end);
+ return Span<T>(begin, static_cast<size_t>(end - begin));
}
template <int&... ExplicitArgumentBarrier, typename C>
@@ -729,15 +779,16 @@
// ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
//
template <int&... ExplicitArgumentBarrier, typename T>
-constexpr Span<const T> MakeConstSpan(absl::Nullable<T*> ptr,
+constexpr Span<const T> MakeConstSpan(T* absl_nullable ptr,
size_t size) noexcept {
return Span<const T>(ptr, size);
}
template <int&... ExplicitArgumentBarrier, typename T>
-Span<const T> MakeConstSpan(absl::Nullable<T*> begin,
- absl::Nullable<T*> end) noexcept {
- return ABSL_HARDENING_ASSERT(begin <= end), Span<const T>(begin, end - begin);
+Span<const T> MakeConstSpan(T* absl_nullable begin,
+ T* absl_nullable end) noexcept {
+ ABSL_HARDENING_ASSERT(begin <= end);
+ return Span<const T>(begin, end - begin);
}
template <int&... ExplicitArgumentBarrier, typename C>
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index e24144d..6700b81 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -30,6 +30,7 @@
#include "absl/base/options.h"
#include "absl/container/fixed_array.h"
#include "absl/container/inlined_vector.h"
+#include "absl/hash/hash.h"
#include "absl/hash/hash_testing.h"
#include "absl/meta/type_traits.h"
#include "absl/strings/str_cat.h"
@@ -787,9 +788,9 @@
template <int i>
struct ConstexprTester {};
-#define ABSL_TEST_CONSTEXPR(expr) \
- do { \
- ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \
+#define ABSL_TEST_CONSTEXPR(expr) \
+ do { \
+ ABSL_ATTRIBUTE_UNUSED ConstexprTester<(static_cast<void>(expr), 1)> t; \
} while (0)
struct ContainerWithConstexprMethods {
@@ -826,6 +827,41 @@
ABSL_TEST_CONSTEXPR(span[0]);
}
+#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
+ ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
+TEST(ConstIntSpan, ConstexprRelOpsTest) {
+ static constexpr int lhs_data[] = {1, 2, 3};
+ static constexpr int rhs_data[] = {1, 2, 3};
+
+ constexpr absl::Span<const int> lhs = absl::MakeConstSpan(lhs_data, 3);
+ constexpr absl::Span<const int> rhs = absl::MakeConstSpan(rhs_data, 3);
+
+ ABSL_TEST_CONSTEXPR(lhs_data == rhs);
+ ABSL_TEST_CONSTEXPR(lhs_data != rhs);
+ ABSL_TEST_CONSTEXPR(lhs_data < rhs);
+ ABSL_TEST_CONSTEXPR(lhs_data <= rhs);
+ ABSL_TEST_CONSTEXPR(lhs_data > rhs);
+ ABSL_TEST_CONSTEXPR(lhs_data >= rhs);
+
+ ABSL_TEST_CONSTEXPR(lhs == rhs);
+ ABSL_TEST_CONSTEXPR(lhs != rhs);
+ ABSL_TEST_CONSTEXPR(lhs < rhs);
+ ABSL_TEST_CONSTEXPR(lhs <= rhs);
+ ABSL_TEST_CONSTEXPR(lhs > rhs);
+ ABSL_TEST_CONSTEXPR(lhs >= rhs);
+
+ ABSL_TEST_CONSTEXPR(lhs == rhs_data);
+ ABSL_TEST_CONSTEXPR(lhs != rhs_data);
+ ABSL_TEST_CONSTEXPR(lhs < rhs_data);
+ ABSL_TEST_CONSTEXPR(lhs <= rhs_data);
+ ABSL_TEST_CONSTEXPR(lhs > rhs_data);
+ ABSL_TEST_CONSTEXPR(lhs >= rhs_data);
+}
+
+#endif // defined(ABSL_INTERNAL_CPLUSPLUS_LANG) &&
+ // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
+
struct BigStruct {
char bytes[10000];
};
@@ -850,4 +886,16 @@
T(array + 1, 2), T(array + 2, 2)}));
}
+// std::vector is implicitly convertible to absl::Span.
+// There are real life cases where clients rely on this consistency in order to
+// implement heterogeneous lookup.
+TEST(Span, HashConsistentWithVectorLike) {
+ EXPECT_EQ(absl::HashOf(absl::Span<const int>({1, 2, 3})),
+ absl::HashOf(std::vector<int>{1, 2, 3}));
+ EXPECT_EQ(absl::HashOf(absl::Span<const int>({1, 2, 3})),
+ absl::HashOf(absl::InlinedVector<int, 2>{1, 2, 3}));
+ EXPECT_EQ(absl::HashOf(absl::Span<const int>({1, 2, 3})),
+ absl::HashOf(absl::FixedArray<int>{1, 2, 3}));
+}
+
} // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 56a7e05..6b36645 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -16,39 +16,18 @@
// variant.h
// -----------------------------------------------------------------------------
//
-// This header file defines an `absl::variant` type for holding a type-safe
-// value of some prescribed set of types (noted as alternative types), and
-// associated functions for managing variants.
-//
-// The `absl::variant` type is a form of type-safe union. An `absl::variant`
-// should always hold a value of one of its alternative types (except in the
-// "valueless by exception state" -- see below). A default-constructed
-// `absl::variant` will hold the value of its first alternative type, provided
-// it is default-constructible.
-//
-// In exceptional cases due to error, an `absl::variant` can hold no
-// value (known as a "valueless by exception" state), though this is not the
-// norm.
-//
-// As with `absl::optional`, an `absl::variant` -- when it holds a value --
-// allocates a value of that type directly within the `variant` itself; it
-// cannot hold a reference, array, or the type `void`; it can, however, hold a
-// pointer to externally managed memory.
-//
-// `absl::variant` is a C++11 compatible version of the C++17 `std::variant`
-// abstraction and is designed to be a drop-in replacement for code compliant
-// with C++17.
+// Historical note: Abseil once provided an implementation of `absl::variant`
+// as a polyfill for `std::variant` prior to C++17. Now that C++17 is required,
+// `absl::variant` is an alias for `std::variant`.
#ifndef ABSL_TYPES_VARIANT_H_
#define ABSL_TYPES_VARIANT_H_
+#include <variant>
+
#include "absl/base/config.h"
#include "absl/utility/utility.h"
-#ifdef ABSL_USES_STD_VARIANT
-
-#include <variant> // IWYU pragma: export
-
namespace absl {
ABSL_NAMESPACE_BEGIN
using std::bad_variant_access;
@@ -63,765 +42,8 @@
using std::variant_size;
using std::variant_size_v;
using std::visit;
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#else // ABSL_USES_STD_VARIANT
-
-#include <functional>
-#include <new>
-#include <type_traits>
-#include <utility>
-
-#include "absl/base/macros.h"
-#include "absl/base/port.h"
-#include "absl/meta/type_traits.h"
-#include "absl/types/internal/variant.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-// -----------------------------------------------------------------------------
-// absl::variant
-// -----------------------------------------------------------------------------
-//
-// An `absl::variant` type is a form of type-safe union. An `absl::variant` --
-// except in exceptional cases -- always holds a value of one of its alternative
-// types.
-//
-// Example:
-//
-// // Construct a variant that holds either an integer or a std::string and
-// // assign it to a std::string.
-// absl::variant<int, std::string> v = std::string("abc");
-//
-// // A default-constructed variant will hold a value-initialized value of
-// // the first alternative type.
-// auto a = absl::variant<int, std::string>(); // Holds an int of value '0'.
-//
-// // variants are assignable.
-//
-// // copy assignment
-// auto v1 = absl::variant<int, std::string>("abc");
-// auto v2 = absl::variant<int, std::string>(10);
-// v2 = v1; // copy assign
-//
-// // move assignment
-// auto v1 = absl::variant<int, std::string>("abc");
-// v1 = absl::variant<int, std::string>(10);
-//
-// // assignment through type conversion
-// a = 128; // variant contains int
-// a = "128"; // variant contains std::string
-//
-// An `absl::variant` holding a value of one of its alternative types `T` holds
-// an allocation of `T` directly within the variant itself. An `absl::variant`
-// is not allowed to allocate additional storage, such as dynamic memory, to
-// allocate the contained value. The contained value shall be allocated in a
-// region of the variant storage suitably aligned for all alternative types.
-template <typename... Ts>
-class variant;
-
-// swap()
-//
-// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)`
-// where `v` and `w` are `absl::variant` types.
-//
-// Note that this function requires all alternative types to be both swappable
-// and move-constructible, because any two variants may refer to either the same
-// type (in which case, they will be swapped) or to two different types (in
-// which case the values will need to be moved).
-//
-template <
- typename... Ts,
- absl::enable_if_t<
- absl::conjunction<std::is_move_constructible<Ts>...,
- type_traits_internal::IsSwappable<Ts>...>::value,
- int> = 0>
-void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) {
- v.swap(w);
-}
-
-// variant_size
-//
-// Returns the number of alternative types available for a given `absl::variant`
-// type as a compile-time constant expression. As this is a class template, it
-// is not generally useful for accessing the number of alternative types of
-// any given `absl::variant` instance.
-//
-// Example:
-//
-// auto a = absl::variant<int, std::string>;
-// constexpr int num_types =
-// absl::variant_size<absl::variant<int, std::string>>();
-//
-// // You can also use the member constant `value`.
-// constexpr int num_types =
-// absl::variant_size<absl::variant<int, std::string>>::value;
-//
-// // `absl::variant_size` is more valuable for use in generic code:
-// template <typename Variant>
-// constexpr bool IsVariantMultivalue() {
-// return absl::variant_size<Variant>() > 1;
-// }
-//
-// Note that the set of cv-qualified specializations of `variant_size` are
-// provided to ensure that those specializations compile (especially when passed
-// within template logic).
-template <class T>
-struct variant_size;
-
-template <class... Ts>
-struct variant_size<variant<Ts...>>
- : std::integral_constant<std::size_t, sizeof...(Ts)> {};
-
-// Specialization of `variant_size` for const qualified variants.
-template <class T>
-struct variant_size<const T> : variant_size<T>::type {};
-
-// Specialization of `variant_size` for volatile qualified variants.
-template <class T>
-struct variant_size<volatile T> : variant_size<T>::type {};
-
-// Specialization of `variant_size` for const volatile qualified variants.
-template <class T>
-struct variant_size<const volatile T> : variant_size<T>::type {};
-
-// variant_alternative
-//
-// Returns the alternative type for a given `absl::variant` at the passed
-// index value as a compile-time constant expression. As this is a class
-// template resulting in a type, it is not useful for access of the run-time
-// value of any given `absl::variant` variable.
-//
-// Example:
-//
-// // The type of the 0th alternative is "int".
-// using alternative_type_0
-// = absl::variant_alternative<0, absl::variant<int, std::string>>::type;
-//
-// static_assert(std::is_same<alternative_type_0, int>::value, "");
-//
-// // `absl::variant_alternative` is more valuable for use in generic code:
-// template <typename Variant>
-// constexpr bool IsFirstElementTrivial() {
-// return std::is_trivial_v<variant_alternative<0, Variant>::type>;
-// }
-//
-// Note that the set of cv-qualified specializations of `variant_alternative`
-// are provided to ensure that those specializations compile (especially when
-// passed within template logic).
-template <std::size_t I, class T>
-struct variant_alternative;
-
-template <std::size_t I, class... Types>
-struct variant_alternative<I, variant<Types...>> {
- using type =
- variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>;
-};
-
-// Specialization of `variant_alternative` for const qualified variants.
-template <std::size_t I, class T>
-struct variant_alternative<I, const T> {
- using type = const typename variant_alternative<I, T>::type;
-};
-
-// Specialization of `variant_alternative` for volatile qualified variants.
-template <std::size_t I, class T>
-struct variant_alternative<I, volatile T> {
- using type = volatile typename variant_alternative<I, T>::type;
-};
-
-// Specialization of `variant_alternative` for const volatile qualified
-// variants.
-template <std::size_t I, class T>
-struct variant_alternative<I, const volatile T> {
- using type = const volatile typename variant_alternative<I, T>::type;
-};
-
-// Template type alias for variant_alternative<I, T>::type.
-//
-// Example:
-//
-// using alternative_type_0
-// = absl::variant_alternative_t<0, absl::variant<int, std::string>>;
-// static_assert(std::is_same<alternative_type_0, int>::value, "");
-template <std::size_t I, class T>
-using variant_alternative_t = typename variant_alternative<I, T>::type;
-
-// holds_alternative()
-//
-// Checks whether the given variant currently holds a given alternative type,
-// returning `true` if so.
-//
-// Example:
-//
-// absl::variant<int, std::string> foo = 42;
-// if (absl::holds_alternative<int>(foo)) {
-// std::cout << "The variant holds an integer";
-// }
-template <class T, class... Types>
-constexpr bool holds_alternative(const variant<Types...>& v) noexcept {
- static_assert(
- variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T,
- 0>::value != sizeof...(Types),
- "The type T must occur exactly once in Types...");
- return v.index() ==
- variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value;
-}
-
-// get()
-//
-// Returns a reference to the value currently within a given variant, using
-// either a unique alternative type amongst the variant's set of alternative
-// types, or the variant's index value. Attempting to get a variant's value
-// using a type that is not unique within the variant's set of alternative types
-// is a compile-time error. If the index of the alternative being specified is
-// different from the index of the alternative that is currently stored, throws
-// `absl::bad_variant_access`.
-//
-// Example:
-//
-// auto a = absl::variant<int, std::string>;
-//
-// // Get the value by type (if unique).
-// int i = absl::get<int>(a);
-//
-// auto b = absl::variant<int, int>;
-//
-// // Getting the value by a type that is not unique is ill-formed.
-// int j = absl::get<int>(b); // Compile Error!
-//
-// // Getting value by index not ambiguous and allowed.
-// int k = absl::get<1>(b);
-
-// Overload for getting a variant's lvalue by type.
-template <class T, class... Types>
-constexpr T& get(variant<Types...>& v) { // NOLINT
- return variant_internal::VariantCoreAccess::CheckedAccess<
- variant_internal::IndexOf<T, Types...>::value>(v);
-}
-
-// Overload for getting a variant's rvalue by type.
-template <class T, class... Types>
-constexpr T&& get(variant<Types...>&& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<
- variant_internal::IndexOf<T, Types...>::value>(std::move(v));
-}
-
-// Overload for getting a variant's const lvalue by type.
-template <class T, class... Types>
-constexpr const T& get(const variant<Types...>& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<
- variant_internal::IndexOf<T, Types...>::value>(v);
-}
-
-// Overload for getting a variant's const rvalue by type.
-template <class T, class... Types>
-constexpr const T&& get(const variant<Types...>&& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<
- variant_internal::IndexOf<T, Types...>::value>(std::move(v));
-}
-
-// Overload for getting a variant's lvalue by index.
-template <std::size_t I, class... Types>
-constexpr variant_alternative_t<I, variant<Types...>>& get(
- variant<Types...>& v) { // NOLINT
- return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
-}
-
-// Overload for getting a variant's rvalue by index.
-template <std::size_t I, class... Types>
-constexpr variant_alternative_t<I, variant<Types...>>&& get(
- variant<Types...>&& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<I>(std::move(v));
-}
-
-// Overload for getting a variant's const lvalue by index.
-template <std::size_t I, class... Types>
-constexpr const variant_alternative_t<I, variant<Types...>>& get(
- const variant<Types...>& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<I>(v);
-}
-
-// Overload for getting a variant's const rvalue by index.
-template <std::size_t I, class... Types>
-constexpr const variant_alternative_t<I, variant<Types...>>&& get(
- const variant<Types...>&& v) {
- return variant_internal::VariantCoreAccess::CheckedAccess<I>(std::move(v));
-}
-
-// get_if()
-//
-// Returns a pointer to the value currently stored within a given variant, if
-// present, using either a unique alternative type amongst the variant's set of
-// alternative types, or the variant's index value. If such a value does not
-// exist, returns `nullptr`.
-//
-// As with `get`, attempting to get a variant's value using a type that is not
-// unique within the variant's set of alternative types is a compile-time error.
-
-// Overload for getting a pointer to the value stored in the given variant by
-// index.
-template <std::size_t I, class... Types>
-constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>>
-get_if(variant<Types...>* v) noexcept {
- return (v != nullptr && v->index() == I)
- ? std::addressof(
- variant_internal::VariantCoreAccess::Access<I>(*v))
- : nullptr;
-}
-
-// Overload for getting a pointer to the const value stored in the given
-// variant by index.
-template <std::size_t I, class... Types>
-constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>>
-get_if(const variant<Types...>* v) noexcept {
- return (v != nullptr && v->index() == I)
- ? std::addressof(
- variant_internal::VariantCoreAccess::Access<I>(*v))
- : nullptr;
-}
-
-// Overload for getting a pointer to the value stored in the given variant by
-// type.
-template <class T, class... Types>
-constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept {
- return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
-}
-
-// Overload for getting a pointer to the const value stored in the given variant
-// by type.
-template <class T, class... Types>
-constexpr absl::add_pointer_t<const T> get_if(
- const variant<Types...>* v) noexcept {
- return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v);
-}
-
-// visit()
-//
-// Calls a provided functor on a given set of variants. `absl::visit()` is
-// commonly used to conditionally inspect the state of a given variant (or set
-// of variants).
-//
-// The functor must return the same type when called with any of the variants'
-// alternatives.
-//
-// Example:
-//
-// // Define a visitor functor
-// struct GetVariant {
-// template<typename T>
-// void operator()(const T& i) const {
-// std::cout << "The variant's value is: " << i;
-// }
-// };
-//
-// // Declare our variant, and call `absl::visit()` on it.
-// // Note that `GetVariant()` returns void in either case.
-// absl::variant<int, std::string> foo = std::string("foo");
-// GetVariant visitor;
-// absl::visit(visitor, foo); // Prints `The variant's value is: foo'
-template <typename Visitor, typename... Variants>
-variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis,
- Variants&&... vars) {
- return variant_internal::
- VisitIndices<variant_size<absl::decay_t<Variants> >::value...>::Run(
- variant_internal::PerformVisitation<Visitor, Variants...>{
- std::forward_as_tuple(std::forward<Variants>(vars)...),
- std::forward<Visitor>(vis)},
- vars.index()...);
-}
-
-// monostate
-//
-// The monostate class serves as a first alternative type for a variant for
-// which the first variant type is otherwise not default-constructible.
-struct monostate {};
-
-// `absl::monostate` Relational Operators
-
-constexpr bool operator<(monostate, monostate) noexcept { return false; }
-constexpr bool operator>(monostate, monostate) noexcept { return false; }
-constexpr bool operator<=(monostate, monostate) noexcept { return true; }
-constexpr bool operator>=(monostate, monostate) noexcept { return true; }
-constexpr bool operator==(monostate, monostate) noexcept { return true; }
-constexpr bool operator!=(monostate, monostate) noexcept { return false; }
-
-
-//------------------------------------------------------------------------------
-// `absl::variant` Template Definition
-//------------------------------------------------------------------------------
-template <typename T0, typename... Tn>
-class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
- static_assert(absl::conjunction<std::is_object<T0>,
- std::is_object<Tn>...>::value,
- "Attempted to instantiate a variant containing a non-object "
- "type.");
- // Intentionally not qualifying `negation` with `absl::` to work around a bug
- // in MSVC 2015 with inline namespace and variadic template.
- static_assert(absl::conjunction<negation<std::is_array<T0> >,
- negation<std::is_array<Tn> >...>::value,
- "Attempted to instantiate a variant containing an array type.");
- static_assert(absl::conjunction<std::is_nothrow_destructible<T0>,
- std::is_nothrow_destructible<Tn>...>::value,
- "Attempted to instantiate a variant containing a non-nothrow "
- "destructible type.");
-
- friend struct variant_internal::VariantCoreAccess;
-
- private:
- using Base = variant_internal::VariantBase<T0, Tn...>;
-
- public:
- // Constructors
-
- // Constructs a variant holding a default-initialized value of the first
- // alternative type.
- constexpr variant() /*noexcept(see 111above)*/ = default;
-
- // Copy constructor, standard semantics
- variant(const variant& other) = default;
-
- // Move constructor, standard semantics
- variant(variant&& other) /*noexcept(see above)*/ = default;
-
- // Constructs a variant of an alternative type specified by overload
- // resolution of the provided forwarding arguments through
- // direct-initialization.
- //
- // Note: If the selected constructor is a constexpr constructor, this
- // constructor shall be a constexpr constructor.
- //
- // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
- // has been voted passed the design phase in the C++ standard meeting in Mar
- // 2018. It will be implemented and integrated into `absl::variant`.
- template <
- class T,
- std::size_t I = std::enable_if<
- variant_internal::IsNeitherSelfNorInPlace<variant,
- absl::decay_t<T> >::value,
- variant_internal::IndexOfConstructedType<variant, T> >::type::value,
- class Tj = absl::variant_alternative_t<I, variant>,
- absl::enable_if_t<std::is_constructible<Tj, T>::value>* = nullptr>
- constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value)
- : Base(variant_internal::EmplaceTag<I>(), std::forward<T>(t)) {}
-
- // Constructs a variant of an alternative type from the arguments through
- // direct-initialization.
- //
- // Note: If the selected constructor is a constexpr constructor, this
- // constructor shall be a constexpr constructor.
- template <class T, class... Args,
- typename std::enable_if<std::is_constructible<
- variant_internal::UnambiguousTypeOfT<variant, T>,
- Args...>::value>::type* = nullptr>
- constexpr explicit variant(in_place_type_t<T>, Args&&... args)
- : Base(variant_internal::EmplaceTag<
- variant_internal::UnambiguousIndexOf<variant, T>::value>(),
- std::forward<Args>(args)...) {}
-
- // Constructs a variant of an alternative type from an initializer list
- // and other arguments through direct-initialization.
- //
- // Note: If the selected constructor is a constexpr constructor, this
- // constructor shall be a constexpr constructor.
- template <class T, class U, class... Args,
- typename std::enable_if<std::is_constructible<
- variant_internal::UnambiguousTypeOfT<variant, T>,
- std::initializer_list<U>&, Args...>::value>::type* = nullptr>
- constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il,
- Args&&... args)
- : Base(variant_internal::EmplaceTag<
- variant_internal::UnambiguousIndexOf<variant, T>::value>(),
- il, std::forward<Args>(args)...) {}
-
- // Constructs a variant of an alternative type from a provided index,
- // through value-initialization using the provided forwarded arguments.
- template <std::size_t I, class... Args,
- typename std::enable_if<std::is_constructible<
- variant_internal::VariantAlternativeSfinaeT<I, variant>,
- Args...>::value>::type* = nullptr>
- constexpr explicit variant(in_place_index_t<I>, Args&&... args)
- : Base(variant_internal::EmplaceTag<I>(), std::forward<Args>(args)...) {}
-
- // Constructs a variant of an alternative type from a provided index,
- // through value-initialization of an initializer list and the provided
- // forwarded arguments.
- template <std::size_t I, class U, class... Args,
- typename std::enable_if<std::is_constructible<
- variant_internal::VariantAlternativeSfinaeT<I, variant>,
- std::initializer_list<U>&, Args...>::value>::type* = nullptr>
- constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il,
- Args&&... args)
- : Base(variant_internal::EmplaceTag<I>(), il,
- std::forward<Args>(args)...) {}
-
- // Destructors
-
- // Destroys the variant's currently contained value, provided that
- // `absl::valueless_by_exception()` is false.
- ~variant() = default;
-
- // Assignment Operators
-
- // Copy assignment operator
- variant& operator=(const variant& other) = default;
-
- // Move assignment operator
- variant& operator=(variant&& other) /*noexcept(see above)*/ = default;
-
- // Converting assignment operator
- //
- // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html
- // has been voted passed the design phase in the C++ standard meeting in Mar
- // 2018. It will be implemented and integrated into `absl::variant`.
- template <
- class T,
- std::size_t I = std::enable_if<
- !std::is_same<absl::decay_t<T>, variant>::value,
- variant_internal::IndexOfConstructedType<variant, T>>::type::value,
- class Tj = absl::variant_alternative_t<I, variant>,
- typename std::enable_if<std::is_assignable<Tj&, T>::value &&
- std::is_constructible<Tj, T>::value>::type* =
- nullptr>
- variant& operator=(T&& t) noexcept(
- std::is_nothrow_assignable<Tj&, T>::value&&
- std::is_nothrow_constructible<Tj, T>::value) {
- variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
- variant_internal::VariantCoreAccess::MakeConversionAssignVisitor(
- this, std::forward<T>(t)),
- index());
-
- return *this;
- }
-
-
- // emplace() Functions
-
- // Constructs a value of the given alternative type T within the variant. The
- // existing value of the variant is destroyed first (provided that
- // `absl::valueless_by_exception()` is false). Requires that T is unambiguous
- // in the variant.
- //
- // Example:
- //
- // absl::variant<std::vector<int>, int, std::string> v;
- // v.emplace<int>(99);
- // v.emplace<std::string>("abc");
- template <
- class T, class... Args,
- typename std::enable_if<std::is_constructible<
- absl::variant_alternative_t<
- variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
- Args...>::value>::type* = nullptr>
- T& emplace(Args&&... args) {
- return variant_internal::VariantCoreAccess::Replace<
- variant_internal::UnambiguousIndexOf<variant, T>::value>(
- this, std::forward<Args>(args)...);
- }
-
- // Constructs a value of the given alternative type T within the variant using
- // an initializer list. The existing value of the variant is destroyed first
- // (provided that `absl::valueless_by_exception()` is false). Requires that T
- // is unambiguous in the variant.
- //
- // Example:
- //
- // absl::variant<std::vector<int>, int, std::string> v;
- // v.emplace<std::vector<int>>({0, 1, 2});
- template <
- class T, class U, class... Args,
- typename std::enable_if<std::is_constructible<
- absl::variant_alternative_t<
- variant_internal::UnambiguousIndexOf<variant, T>::value, variant>,
- std::initializer_list<U>&, Args...>::value>::type* = nullptr>
- T& emplace(std::initializer_list<U> il, Args&&... args) {
- return variant_internal::VariantCoreAccess::Replace<
- variant_internal::UnambiguousIndexOf<variant, T>::value>(
- this, il, std::forward<Args>(args)...);
- }
-
- // Destroys the current value of the variant (provided that
- // `absl::valueless_by_exception()` is false) and constructs a new value at
- // the given index.
- //
- // Example:
- //
- // absl::variant<std::vector<int>, int, int> v;
- // v.emplace<1>(99);
- // v.emplace<2>(98);
- // v.emplace<int>(99); // Won't compile. 'int' isn't a unique type.
- template <std::size_t I, class... Args,
- typename std::enable_if<
- std::is_constructible<absl::variant_alternative_t<I, variant>,
- Args...>::value>::type* = nullptr>
- absl::variant_alternative_t<I, variant>& emplace(Args&&... args) {
- return variant_internal::VariantCoreAccess::Replace<I>(
- this, std::forward<Args>(args)...);
- }
-
- // Destroys the current value of the variant (provided that
- // `absl::valueless_by_exception()` is false) and constructs a new value at
- // the given index using an initializer list and the provided arguments.
- //
- // Example:
- //
- // absl::variant<std::vector<int>, int, int> v;
- // v.emplace<0>({0, 1, 2});
- template <std::size_t I, class U, class... Args,
- typename std::enable_if<std::is_constructible<
- absl::variant_alternative_t<I, variant>,
- std::initializer_list<U>&, Args...>::value>::type* = nullptr>
- absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il,
- Args&&... args) {
- return variant_internal::VariantCoreAccess::Replace<I>(
- this, il, std::forward<Args>(args)...);
- }
-
- // variant::valueless_by_exception()
- //
- // Returns false if and only if the variant currently holds a valid value.
- constexpr bool valueless_by_exception() const noexcept {
- return this->index_ == absl::variant_npos;
- }
-
- // variant::index()
- //
- // Returns the index value of the variant's currently selected alternative
- // type.
- constexpr std::size_t index() const noexcept { return this->index_; }
-
- // variant::swap()
- //
- // Swaps the values of two variant objects.
- //
- void swap(variant& rhs) noexcept(
- absl::conjunction<
- std::is_nothrow_move_constructible<T0>,
- std::is_nothrow_move_constructible<Tn>...,
- type_traits_internal::IsNothrowSwappable<T0>,
- type_traits_internal::IsNothrowSwappable<Tn>...>::value) {
- return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run(
- variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index());
- }
-};
-
-// We need a valid declaration of variant<> for SFINAE and overload resolution
-// to work properly above, but we don't need a full declaration since this type
-// will never be constructed. This declaration, though incomplete, suffices.
-template <>
-class variant<>;
-
-//------------------------------------------------------------------------------
-// Relational Operators
-//------------------------------------------------------------------------------
-//
-// If neither operand is in the `variant::valueless_by_exception` state:
-//
-// * If the index of both variants is the same, the relational operator
-// returns the result of the corresponding relational operator for the
-// corresponding alternative type.
-// * If the index of both variants is not the same, the relational operator
-// returns the result of that operation applied to the value of the left
-// operand's index and the value of the right operand's index.
-// * If at least one operand is in the valueless_by_exception state:
-// - A variant in the valueless_by_exception state is only considered equal
-// to another variant in the valueless_by_exception state.
-// - If exactly one operand is in the valueless_by_exception state, the
-// variant in the valueless_by_exception state is less than the variant
-// that is not in the valueless_by_exception state.
-//
-// Note: The value 1 is added to each index in the relational comparisons such
-// that the index corresponding to the valueless_by_exception state wraps around
-// to 0 (the lowest value for the index type), and the remaining indices stay in
-// the same relative order.
-
-// Equal-to operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==(
- const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() == b.index()) &&
- variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::EqualsOp<Types...>{&a, &b}, a.index());
-}
-
-// Not equal operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=(
- const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() != b.index()) ||
- variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index());
-}
-
-// Less-than operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<(
- const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() != b.index())
- ? (a.index() + 1) < (b.index() + 1)
- : variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::LessThanOp<Types...>{&a, &b}, a.index());
-}
-
-// Greater-than operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>(
- const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() != b.index())
- ? (a.index() + 1) > (b.index() + 1)
- : variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::GreaterThanOp<Types...>{&a, &b},
- a.index());
-}
-
-// Less-than or equal-to operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=(
- const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() != b.index())
- ? (a.index() + 1) < (b.index() + 1)
- : variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::LessThanOrEqualsOp<Types...>{&a, &b},
- a.index());
-}
-
-// Greater-than or equal-to operator
-template <typename... Types>
-constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...>
-operator>=(const variant<Types...>& a, const variant<Types...>& b) {
- return (a.index() != b.index())
- ? (a.index() + 1) > (b.index() + 1)
- : variant_internal::VisitIndices<sizeof...(Types)>::Run(
- variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b},
- a.index());
-}
-
-ABSL_NAMESPACE_END
-} // namespace absl
-
-namespace std {
-
-// hash()
-template <> // NOLINT
-struct hash<absl::monostate> {
- std::size_t operator()(absl::monostate) const { return 0; }
-};
-
-template <class... T> // NOLINT
-struct hash<absl::variant<T...>>
- : absl::variant_internal::VariantHashBase<absl::variant<T...>, void,
- absl::remove_const_t<T>...> {};
-
-} // namespace std
-
-#endif // ABSL_USES_STD_VARIANT
-namespace absl {
-ABSL_NAMESPACE_BEGIN
namespace variant_internal {
-
// Helper visitor for converting a variant<Ts...>` into another type (mostly
// variant) that can be constructed from any type.
template <typename To>
@@ -831,7 +53,6 @@
return To(std::forward<T>(v));
}
};
-
} // namespace variant_internal
// ConvertVariantTo()
diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc
deleted file mode 100644
index 350b175..0000000
--- a/absl/types/variant_benchmark.cc
+++ /dev/null
@@ -1,222 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Unit tests for the variant template. The 'is' and 'IsEmpty' methods
-// of variant are not explicitly tested because they are used repeatedly
-// in building other tests. All other public variant methods should have
-// explicit tests.
-
-#include "absl/types/variant.h"
-
-#include <cstddef>
-#include <cstdlib>
-#include <string>
-#include <tuple>
-
-#include "benchmark/benchmark.h"
-#include "absl/utility/utility.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace {
-
-template <std::size_t I>
-struct VariantAlternative {
- char member;
-};
-
-template <class Indices>
-struct VariantOfAlternativesImpl;
-
-template <std::size_t... Indices>
-struct VariantOfAlternativesImpl<absl::index_sequence<Indices...>> {
- using type = absl::variant<VariantAlternative<Indices>...>;
-};
-
-template <std::size_t NumAlternatives>
-using VariantOfAlternatives = typename VariantOfAlternativesImpl<
- absl::make_index_sequence<NumAlternatives>>::type;
-
-struct Empty {};
-
-template <class... T>
-void Ignore(T...) noexcept {}
-
-template <class T>
-Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept {
- benchmark::DoNotOptimize(arg);
- return {};
-}
-
-struct VisitorApplier {
- struct Visitor {
- template <class... T>
- void operator()(T&&... args) const noexcept {
- Ignore(DoNotOptimizeAndReturnEmpty(args)...);
- }
- };
-
- template <class... Vars>
- void operator()(const Vars&... vars) const noexcept {
- absl::visit(Visitor(), vars...);
- }
-};
-
-template <std::size_t NumIndices, std::size_t CurrIndex = NumIndices - 1>
-struct MakeWithIndex {
- using Variant = VariantOfAlternatives<NumIndices>;
-
- static Variant Run(std::size_t index) {
- return index == CurrIndex
- ? Variant(absl::in_place_index_t<CurrIndex>())
- : MakeWithIndex<NumIndices, CurrIndex - 1>::Run(index);
- }
-};
-
-template <std::size_t NumIndices>
-struct MakeWithIndex<NumIndices, 0> {
- using Variant = VariantOfAlternatives<NumIndices>;
-
- static Variant Run(std::size_t /*index*/) { return Variant(); }
-};
-
-template <std::size_t NumIndices, class Dimensions>
-struct MakeVariantTuple;
-
-template <class T, std::size_t /*I*/>
-using always_t = T;
-
-template <std::size_t NumIndices>
-VariantOfAlternatives<NumIndices> MakeVariant(std::size_t dimension,
- std::size_t index) {
- return dimension == 0
- ? MakeWithIndex<NumIndices>::Run(index % NumIndices)
- : MakeVariant<NumIndices>(dimension - 1, index / NumIndices);
-}
-
-template <std::size_t NumIndices, std::size_t... Dimensions>
-struct MakeVariantTuple<NumIndices, absl::index_sequence<Dimensions...>> {
- using VariantTuple =
- std::tuple<always_t<VariantOfAlternatives<NumIndices>, Dimensions>...>;
-
- static VariantTuple Run(int index) {
- return std::make_tuple(MakeVariant<NumIndices>(Dimensions, index)...);
- }
-};
-
-constexpr std::size_t integral_pow(std::size_t base, std::size_t power) {
- return power == 0 ? 1 : base * integral_pow(base, power - 1);
-}
-
-template <std::size_t End, std::size_t I = 0>
-struct VisitTestBody {
- template <class Vars, class State>
- static bool Run(Vars& vars, State& state) {
- if (state.KeepRunning()) {
- absl::apply(VisitorApplier(), vars[I]);
- return VisitTestBody<End, I + 1>::Run(vars, state);
- }
- return false;
- }
-};
-
-template <std::size_t End>
-struct VisitTestBody<End, End> {
- template <class Vars, class State>
- static bool Run(Vars& /*vars*/, State& /*state*/) {
- return true;
- }
-};
-
-// Visit operations where branch prediction is likely to give a boost.
-template <std::size_t NumIndices, std::size_t NumDimensions = 1>
-void BM_RedundantVisit(benchmark::State& state) {
- auto vars =
- MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>::
- Run(static_cast<std::size_t>(state.range(0)));
-
- for (auto _ : state) { // NOLINT
- benchmark::DoNotOptimize(vars);
- absl::apply(VisitorApplier(), vars);
- }
-}
-
-// Visit operations where branch prediction is unlikely to give a boost.
-template <std::size_t NumIndices, std::size_t NumDimensions = 1>
-void BM_Visit(benchmark::State& state) {
- constexpr std::size_t num_possibilities =
- integral_pow(NumIndices, NumDimensions);
-
- using VariantTupleMaker =
- MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>;
- using Tuple = typename VariantTupleMaker::VariantTuple;
-
- Tuple vars[num_possibilities];
- for (std::size_t i = 0; i < num_possibilities; ++i)
- vars[i] = VariantTupleMaker::Run(i);
-
- while (VisitTestBody<num_possibilities>::Run(vars, state)) {
- }
-}
-
-// Visitation
-// Each visit is on a different variant with a different active alternative)
-
-// Unary visit
-BENCHMARK_TEMPLATE(BM_Visit, 1);
-BENCHMARK_TEMPLATE(BM_Visit, 2);
-BENCHMARK_TEMPLATE(BM_Visit, 3);
-BENCHMARK_TEMPLATE(BM_Visit, 4);
-BENCHMARK_TEMPLATE(BM_Visit, 5);
-BENCHMARK_TEMPLATE(BM_Visit, 6);
-BENCHMARK_TEMPLATE(BM_Visit, 7);
-BENCHMARK_TEMPLATE(BM_Visit, 8);
-BENCHMARK_TEMPLATE(BM_Visit, 16);
-BENCHMARK_TEMPLATE(BM_Visit, 32);
-BENCHMARK_TEMPLATE(BM_Visit, 64);
-
-// Binary visit
-BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
-BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
-BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
-BENCHMARK_TEMPLATE(BM_Visit, 4, 2);
-BENCHMARK_TEMPLATE(BM_Visit, 5, 2);
-
-// Ternary visit
-BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
-BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
-BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
-
-// Quaternary visit
-BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
-BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
-
-// Redundant Visitation
-// Each visit consistently has the same alternative active
-
-// Unary visit
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0);
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1);
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7);
-
-// Binary visit
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0);
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2)
- ->DenseRange(0, integral_pow(2, 2) - 1);
-BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2)
- ->DenseRange(0, integral_pow(4, 2) - 1);
-
-} // namespace
-ABSL_NAMESPACE_END
-} // namespace absl
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
deleted file mode 100644
index 439c6e1..0000000
--- a/absl/types/variant_exception_safety_test.cc
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright 2017 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/types/variant.h"
-
-#include "absl/base/config.h"
-
-// This test is a no-op when absl::variant is an alias for std::variant and when
-// exceptions are not enabled.
-#if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
-
-#include <iostream>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/base/internal/exception_safety_testing.h"
-#include "absl/memory/memory.h"
-
-// See comment in absl/base/config.h
-#if !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace {
-
-using ::testing::MakeExceptionSafetyTester;
-using ::testing::strong_guarantee;
-using ::testing::TestNothrowOp;
-using ::testing::TestThrowingCtor;
-
-using Thrower = testing::ThrowingValue<>;
-using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
-using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
-using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
-using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
-using ThrowingVariant =
- absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
-
-struct ConversionException {};
-
-template <class T>
-struct ExceptionOnConversion {
- operator T() const { // NOLINT
- throw ConversionException();
- }
-};
-
-// Forces a variant into the valueless by exception state.
-void ToValuelessByException(ThrowingVariant& v) { // NOLINT
- try {
- v.emplace<Thrower>();
- v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
- } catch (const ConversionException&) {
- // This space intentionally left blank.
- }
-}
-
-// Check that variant is still in a usable state after an exception is thrown.
-testing::AssertionResult VariantInvariants(ThrowingVariant* v) {
- using testing::AssertionFailure;
- using testing::AssertionSuccess;
-
- // Try using the active alternative
- if (absl::holds_alternative<Thrower>(*v)) {
- auto& t = absl::get<Thrower>(*v);
- t = Thrower{-100};
- if (t.Get() != -100) {
- return AssertionFailure() << "Thrower should be assigned -100";
- }
- } else if (absl::holds_alternative<ThrowerVec>(*v)) {
- auto& tv = absl::get<ThrowerVec>(*v);
- tv.clear();
- tv.emplace_back(-100);
- if (tv.size() != 1 || tv[0].Get() != -100) {
- return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
- }
- } else if (absl::holds_alternative<CopyNothrow>(*v)) {
- auto& t = absl::get<CopyNothrow>(*v);
- t = CopyNothrow{-100};
- if (t.Get() != -100) {
- return AssertionFailure() << "CopyNothrow should be assigned -100";
- }
- } else if (absl::holds_alternative<MoveNothrow>(*v)) {
- auto& t = absl::get<MoveNothrow>(*v);
- t = MoveNothrow{-100};
- if (t.Get() != -100) {
- return AssertionFailure() << "MoveNothrow should be assigned -100";
- }
- }
-
- // Try making variant valueless_by_exception
- if (!v->valueless_by_exception()) ToValuelessByException(*v);
- if (!v->valueless_by_exception()) {
- return AssertionFailure() << "Variant should be valueless_by_exception";
- }
- try {
- auto unused = absl::get<Thrower>(*v);
- static_cast<void>(unused);
- return AssertionFailure() << "Variant should not contain Thrower";
- } catch (const absl::bad_variant_access&) {
- } catch (...) {
- return AssertionFailure() << "Unexpected exception throw from absl::get";
- }
-
- // Try using the variant
- v->emplace<Thrower>(100);
- if (!absl::holds_alternative<Thrower>(*v) ||
- absl::get<Thrower>(*v) != Thrower(100)) {
- return AssertionFailure() << "Variant should contain Thrower(100)";
- }
- v->emplace<ThrowerVec>({Thrower(100)});
- if (!absl::holds_alternative<ThrowerVec>(*v) ||
- absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
- return AssertionFailure()
- << "Variant should contain ThrowerVec{Thrower(100)}";
- }
- return AssertionSuccess();
-}
-
-template <typename... Args>
-Thrower ExpectedThrower(Args&&... args) {
- return Thrower(42, args...);
-}
-
-ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
-ThrowingVariant ValuelessByException() {
- ThrowingVariant v;
- ToValuelessByException(v);
- return v;
-}
-ThrowingVariant WithThrower() { return Thrower(39); }
-ThrowingVariant WithThrowerVec() {
- return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
-}
-ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
-ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
-
-TEST(VariantExceptionSafetyTest, DefaultConstructor) {
- TestThrowingCtor<ThrowingVariant>();
-}
-
-TEST(VariantExceptionSafetyTest, CopyConstructor) {
- {
- ThrowingVariant v(ExpectedThrower());
- TestThrowingCtor<ThrowingVariant>(v);
- }
- {
- ThrowingVariant v(ExpectedThrowerVec());
- TestThrowingCtor<ThrowingVariant>(v);
- }
- {
- ThrowingVariant v(ValuelessByException());
- TestThrowingCtor<ThrowingVariant>(v);
- }
-}
-
-TEST(VariantExceptionSafetyTest, MoveConstructor) {
- {
- ThrowingVariant v(ExpectedThrower());
- TestThrowingCtor<ThrowingVariant>(std::move(v));
- }
- {
- ThrowingVariant v(ExpectedThrowerVec());
- TestThrowingCtor<ThrowingVariant>(std::move(v));
- }
- {
- ThrowingVariant v(ValuelessByException());
- TestThrowingCtor<ThrowingVariant>(std::move(v));
- }
-}
-
-TEST(VariantExceptionSafetyTest, ValueConstructor) {
- TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
- TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
- TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
- ExpectedThrower());
- TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
- ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
- TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
- ExpectedThrower());
- TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
- ExpectedThrowerVec());
-}
-
-TEST(VariantExceptionSafetyTest, CopyAssign) {
- // variant& operator=(const variant& rhs);
- // Let j be rhs.index()
- {
- // - neither *this nor rhs holds a value
- const ThrowingVariant rhs = ValuelessByException();
- ThrowingVariant lhs = ValuelessByException();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
- }
- {
- // - *this holds a value but rhs does not
- const ThrowingVariant rhs = ValuelessByException();
- ThrowingVariant lhs = WithThrower();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
- }
- // - index() == j
- {
- const ThrowingVariant rhs(ExpectedThrower());
- auto tester =
- MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
- EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
- EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
- }
- {
- const ThrowingVariant rhs(ExpectedThrowerVec());
- auto tester =
- MakeExceptionSafetyTester()
- .WithInitialValue(WithThrowerVec())
- .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
- EXPECT_TRUE(tester.WithContracts(VariantInvariants).Test());
- EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
- }
- // libstdc++ std::variant has bugs on copy assignment regarding exception
- // safety.
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
- // index() != j
- // if is_nothrow_copy_constructible_v<Tj> or
- // !is_nothrow_move_constructible<Tj> is true, equivalent to
- // emplace<j>(get<j>(rhs))
- {
- // is_nothrow_copy_constructible_v<Tj> == true
- // should not throw because emplace() invokes Tj's copy ctor
- // which should not throw.
- const ThrowingVariant rhs(CopyNothrow{});
- ThrowingVariant lhs = WithThrower();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
- }
- {
- // is_nothrow_copy_constructible<Tj> == false &&
- // is_nothrow_move_constructible<Tj> == false
- // should provide basic guarantee because emplace() invokes Tj's copy ctor
- // which may throw.
- const ThrowingVariant rhs(ExpectedThrower());
- auto tester =
- MakeExceptionSafetyTester()
- .WithInitialValue(WithCopyNoThrow())
- .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
- EXPECT_TRUE(tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return lhs->valueless_by_exception();
- })
- .Test());
- EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
- }
-#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
- {
- // is_nothrow_copy_constructible_v<Tj> == false &&
- // is_nothrow_move_constructible_v<Tj> == true
- // should provide strong guarantee because it is equivalent to
- // operator=(variant(rhs)) which creates a temporary then invoke the move
- // ctor which shouldn't throw.
- const ThrowingVariant rhs(MoveNothrow{});
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithContracts(VariantInvariants, strong_guarantee)
- .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
- }
-}
-
-TEST(VariantExceptionSafetyTest, MoveAssign) {
- // variant& operator=(variant&& rhs);
- // Let j be rhs.index()
- {
- // - neither *this nor rhs holds a value
- ThrowingVariant rhs = ValuelessByException();
- ThrowingVariant lhs = ValuelessByException();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
- }
- {
- // - *this holds a value but rhs does not
- ThrowingVariant rhs = ValuelessByException();
- ThrowingVariant lhs = WithThrower();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
- }
- {
- // - index() == j
- // assign get<j>(std::move(rhs)) to the value contained in *this.
- // If an exception is thrown during call to Tj's move assignment, the state
- // of the contained value is as defined by the exception safety guarantee of
- // Tj's move assignment; index() will be j.
- ThrowingVariant rhs(ExpectedThrower());
- size_t j = rhs.index();
- // Since Thrower's move assignment has basic guarantee, so should variant's.
- auto tester = MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithOperation([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- *lhs = std::move(copy);
- });
- EXPECT_TRUE(tester
- .WithContracts(
- VariantInvariants,
- [&](ThrowingVariant* lhs) { return lhs->index() == j; })
- .Test());
- EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
- }
- {
- // libstdc++ introduced a regression between 2018-09-25 and 2019-01-06.
- // The fix is targeted for gcc-9.
- // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7
- // https://gcc.gnu.org/viewcvs/gcc?view=revision&revision=267614
-#if !(defined(ABSL_USES_STD_VARIANT) && \
- defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
- // - otherwise (index() != j), equivalent to
- // emplace<j>(get<j>(std::move(rhs)))
- // - If an exception is thrown during the call to Tj's move construction
- // (with j being rhs.index()), the variant will hold no value.
- ThrowingVariant rhs(CopyNothrow{});
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return lhs->valueless_by_exception();
- })
- .Test([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- *lhs = std::move(copy);
- }));
-#endif // !(defined(ABSL_USES_STD_VARIANT) &&
- // defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
- }
-}
-
-TEST(VariantExceptionSafetyTest, ValueAssign) {
- // template<class T> variant& operator=(T&& t);
- // Let Tj be the type that is selected by overload resolution to be assigned.
- {
- // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
- // *this. If an exception is thrown during the assignment of
- // std::forward<T>(t) to the value contained in *this, the state of the
- // contained value and t are as defined by the exception safety guarantee of
- // the assignment expression; valueless_by_exception() will be false.
- // Since Thrower's copy/move assignment has basic guarantee, so should
- // variant's.
- Thrower rhs = ExpectedThrower();
- // copy assign
- auto copy_tester =
- MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
- EXPECT_TRUE(copy_tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return !lhs->valueless_by_exception();
- })
- .Test());
- EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
- // move assign
- auto move_tester = MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithOperation([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- *lhs = std::move(copy);
- });
- EXPECT_TRUE(move_tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return !lhs->valueless_by_exception();
- })
- .Test());
-
- EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
- }
- // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
- // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
- // emplace<j>(std::forward<T>(t)).
- // We simplify the test by letting T = `const Tj&` or `Tj&&`, so we can reuse
- // the CopyNothrow and MoveNothrow types.
-
- // if is_nothrow_constructible_v<Tj, T>
- // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
- // invokes the copy/move constructor and it should not throw.
- {
- const CopyNothrow rhs;
- ThrowingVariant lhs = WithThrower();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
- }
- {
- MoveNothrow rhs;
- ThrowingVariant lhs = WithThrower();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
- }
- // if is_nothrow_constructible_v<Tj, T> == false &&
- // is_nothrow_move_constructible<Tj> == false
- // emplace() invokes the copy/move constructor which may throw so it should
- // provide basic guarantee and variant object might not hold a value.
- {
- Thrower rhs = ExpectedThrower();
- // copy
- auto copy_tester =
- MakeExceptionSafetyTester()
- .WithInitialValue(WithCopyNoThrow())
- .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
- EXPECT_TRUE(copy_tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return lhs->valueless_by_exception();
- })
- .Test());
- EXPECT_FALSE(copy_tester.WithContracts(strong_guarantee).Test());
- // move
- auto move_tester = MakeExceptionSafetyTester()
- .WithInitialValue(WithCopyNoThrow())
- .WithOperation([](ThrowingVariant* lhs) {
- *lhs = ExpectedThrower(testing::nothrow_ctor);
- });
- EXPECT_TRUE(move_tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* lhs) {
- return lhs->valueless_by_exception();
- })
- .Test());
- EXPECT_FALSE(move_tester.WithContracts(strong_guarantee).Test());
- }
- // Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
- // is_nothrow_move_constructible<Tj> == true),
- // equivalent to operator=(variant(std::forward<T>(t)))
- // This should have strong guarantee because it creates a temporary variant
- // and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
- // libstdc++ std::variant has bugs on conversion assignment regarding
- // exception safety.
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
- {
- MoveNothrow rhs;
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithContracts(VariantInvariants, strong_guarantee)
- .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
- }
-#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-}
-
-TEST(VariantExceptionSafetyTest, Emplace) {
- // If an exception during the initialization of the contained value, the
- // variant might not hold a value. The standard requires emplace() to provide
- // only basic guarantee.
- {
- Thrower args = ExpectedThrower();
- auto tester = MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithOperation([&args](ThrowingVariant* v) {
- v->emplace<Thrower>(args);
- });
- EXPECT_TRUE(tester
- .WithContracts(VariantInvariants,
- [](ThrowingVariant* v) {
- return v->valueless_by_exception();
- })
- .Test());
- EXPECT_FALSE(tester.WithContracts(strong_guarantee).Test());
- }
-}
-
-TEST(VariantExceptionSafetyTest, Swap) {
- // if both are valueless_by_exception(), no effect
- {
- ThrowingVariant rhs = ValuelessByException();
- ThrowingVariant lhs = ValuelessByException();
- EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
- }
- // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
- // where i is index().
- {
- ThrowingVariant rhs = ExpectedThrower();
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithThrower())
- .WithContracts(VariantInvariants)
- .Test([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- lhs->swap(copy);
- }));
- }
- // Otherwise, exchanges the value of rhs and *this. The exception safety
- // involves variant in moved-from state which is not specified in the
- // standard, and since swap is 3-step it's impossible for it to provide a
- // overall strong guarantee. So, we are only checking basic guarantee here.
- {
- ThrowingVariant rhs = ExpectedThrower();
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithCopyNoThrow())
- .WithContracts(VariantInvariants)
- .Test([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- lhs->swap(copy);
- }));
- }
- {
- ThrowingVariant rhs = ExpectedThrower();
- EXPECT_TRUE(MakeExceptionSafetyTester()
- .WithInitialValue(WithCopyNoThrow())
- .WithContracts(VariantInvariants)
- .Test([&](ThrowingVariant* lhs) {
- auto copy = rhs;
- copy.swap(*lhs);
- }));
- }
-}
-
-} // namespace
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-
-#endif // #if !defined(ABSL_USES_STD_VARIANT) && defined(ABSL_HAVE_EXCEPTIONS)
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index 91b142c..4d7b025 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -12,2255 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// Unit tests for the variant template. The 'is' and 'IsEmpty' methods
-// of variant are not explicitly tested because they are used repeatedly
-// in building other tests. All other public variant methods should have
-// explicit tests.
-
#include "absl/types/variant.h"
-// This test is a no-op when absl::variant is an alias for std::variant.
-#if !defined(ABSL_USES_STD_VARIANT)
-
-#include <algorithm>
-#include <cstddef>
-#include <functional>
-#include <initializer_list>
#include <memory>
-#include <ostream>
-#include <queue>
-#include <type_traits>
-#include <unordered_set>
-#include <utility>
-#include <vector>
+#include <string>
+#include <variant>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include "absl/base/config.h"
-#include "absl/base/port.h"
-#include "absl/memory/memory.h"
-#include "absl/meta/type_traits.h"
-#include "absl/strings/string_view.h"
-
-#ifdef ABSL_HAVE_EXCEPTIONS
-
-#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
- EXPECT_THROW(expr, exception_t)
-
-#else
-
-#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \
- EXPECT_DEATH_IF_SUPPORTED(expr, text)
-
-#endif // ABSL_HAVE_EXCEPTIONS
-
-#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \
- ABSL_VARIANT_TEST_EXPECT_FAIL((void)(__VA_ARGS__), absl::bad_variant_access, \
- "Bad variant access")
-
-struct Hashable {};
-
-namespace std {
-template <>
-struct hash<Hashable> {
- size_t operator()(const Hashable&);
-};
-} // namespace std
-
-struct NonHashable {};
namespace absl {
-ABSL_NAMESPACE_BEGIN
namespace {
using ::testing::DoubleEq;
using ::testing::Pointee;
using ::testing::VariantWith;
-struct MoveCanThrow {
- MoveCanThrow() : v(0) {}
- MoveCanThrow(int v) : v(v) {} // NOLINT(runtime/explicit)
- MoveCanThrow(const MoveCanThrow& other) : v(other.v) {}
- MoveCanThrow& operator=(const MoveCanThrow& /*other*/) { return *this; }
- int v;
-};
-
-bool operator==(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v == rhs.v; }
-bool operator!=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v != rhs.v; }
-bool operator<(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v < rhs.v; }
-bool operator<=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v <= rhs.v; }
-bool operator>=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v >= rhs.v; }
-bool operator>(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v > rhs.v; }
-
-// This helper class allows us to determine if it was swapped with std::swap()
-// or with its friend swap() function.
-struct SpecialSwap {
- explicit SpecialSwap(int i) : i(i) {}
- friend void swap(SpecialSwap& a, SpecialSwap& b) {
- a.special_swap = b.special_swap = true;
- std::swap(a.i, b.i);
- }
- bool operator==(SpecialSwap other) const { return i == other.i; }
- int i;
- bool special_swap = false;
-};
-
-struct MoveOnlyWithListConstructor {
- MoveOnlyWithListConstructor() = default;
- explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/,
- int value)
- : value(value) {}
- MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default;
- MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) =
- default;
-
- int value = 0;
-};
-
-#ifdef ABSL_HAVE_EXCEPTIONS
-
-struct ConversionException {};
-
-template <class T>
-struct ExceptionOnConversion {
- operator T() const { // NOLINT(runtime/explicit)
- throw ConversionException();
- }
-};
-
-// Forces a variant into the valueless by exception state.
-template <class H, class... T>
-void ToValuelessByException(absl::variant<H, T...>& v) { // NOLINT
- try {
- v.template emplace<0>(ExceptionOnConversion<H>());
- } catch (ConversionException& /*e*/) {
- // This space intentionally left blank.
- }
-}
-
-#endif // ABSL_HAVE_EXCEPTIONS
-
-// An indexed sequence of distinct structures holding a single
-// value of type T
-template<typename T, size_t N>
-struct ValueHolder {
- explicit ValueHolder(const T& x) : value(x) {}
- typedef T value_type;
- value_type value;
- static const size_t kIndex = N;
-};
-template<typename T, size_t N>
-const size_t ValueHolder<T, N>::kIndex;
-
-// The following three functions make ValueHolder compatible with
-// EXPECT_EQ and EXPECT_NE
-template<typename T, size_t N>
-inline bool operator==(const ValueHolder<T, N>& left,
- const ValueHolder<T, N>& right) {
- return left.value == right.value;
-}
-
-template<typename T, size_t N>
-inline bool operator!=(const ValueHolder<T, N>& left,
- const ValueHolder<T, N>& right) {
- return left.value != right.value;
-}
-
-template<typename T, size_t N>
-inline std::ostream& operator<<(
- std::ostream& stream, const ValueHolder<T, N>& object) {
- return stream << object.value;
-}
-
-// Makes a variant holding twelve uniquely typed T wrappers.
-template<typename T>
-struct VariantFactory {
- typedef variant<ValueHolder<T, 1>, ValueHolder<T, 2>, ValueHolder<T, 3>,
- ValueHolder<T, 4>>
- Type;
-};
-
-// A typelist in 1:1 with VariantFactory, to use type driven unit tests.
-typedef ::testing::Types<ValueHolder<size_t, 1>, ValueHolder<size_t, 2>,
- ValueHolder<size_t, 3>,
- ValueHolder<size_t, 4>> VariantTypes;
-
-// Increments the provided counter pointer in the destructor
-struct IncrementInDtor {
- explicit IncrementInDtor(int* counter) : counter(counter) {}
- ~IncrementInDtor() { *counter += 1; }
- int* counter;
-};
-
-struct IncrementInDtorCopyCanThrow {
- explicit IncrementInDtorCopyCanThrow(int* counter) : counter(counter) {}
- IncrementInDtorCopyCanThrow(IncrementInDtorCopyCanThrow&& other) noexcept =
- default;
- IncrementInDtorCopyCanThrow(const IncrementInDtorCopyCanThrow& other)
- : counter(other.counter) {}
- IncrementInDtorCopyCanThrow& operator=(
- IncrementInDtorCopyCanThrow&&) noexcept = default;
- IncrementInDtorCopyCanThrow& operator=(
- IncrementInDtorCopyCanThrow const& other) {
- counter = other.counter;
- return *this;
- }
- ~IncrementInDtorCopyCanThrow() { *counter += 1; }
- int* counter;
-};
-
-// This is defined so operator== for ValueHolder<IncrementInDtor> will
-// return true if two IncrementInDtor objects increment the same
-// counter
-inline bool operator==(const IncrementInDtor& left,
- const IncrementInDtor& right) {
- return left.counter == right.counter;
-}
-
-// This is defined so EXPECT_EQ can work with IncrementInDtor
-inline std::ostream& operator<<(
- std::ostream& stream, const IncrementInDtor& object) {
- return stream << object.counter;
-}
-
-// A class that can be copied, but not assigned.
-class CopyNoAssign {
- public:
- explicit CopyNoAssign(int value) : foo(value) {}
- CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {}
- int foo;
- private:
- const CopyNoAssign& operator=(const CopyNoAssign&);
-};
-
-// A class that can neither be copied nor assigned. We provide
-// overloads for the constructor with up to four parameters so we can
-// test the overloads of variant::emplace.
-class NonCopyable {
- public:
- NonCopyable()
- : value(0) {}
- explicit NonCopyable(int value1)
- : value(value1) {}
-
- NonCopyable(int value1, int value2)
- : value(value1 + value2) {}
-
- NonCopyable(int value1, int value2, int value3)
- : value(value1 + value2 + value3) {}
-
- NonCopyable(int value1, int value2, int value3, int value4)
- : value(value1 + value2 + value3 + value4) {}
- NonCopyable(const NonCopyable&) = delete;
- NonCopyable& operator=(const NonCopyable&) = delete;
- int value;
-};
-
-// A typed test and typed test case over the VariantTypes typelist,
-// from which we derive a number of tests that will execute for one of
-// each type.
-template <typename T>
-class VariantTypesTest : public ::testing::Test {};
-TYPED_TEST_SUITE(VariantTypesTest, VariantTypes);
-
-////////////////////
-// [variant.ctor] //
-////////////////////
-
-struct NonNoexceptDefaultConstructible {
- NonNoexceptDefaultConstructible() {}
- int value = 5;
-};
-
-struct NonDefaultConstructible {
- NonDefaultConstructible() = delete;
-};
-
-TEST(VariantTest, TestDefaultConstructor) {
- {
- using X = variant<int>;
- constexpr variant<int> x{};
- ASSERT_FALSE(x.valueless_by_exception());
- ASSERT_EQ(0u, x.index());
- EXPECT_EQ(0, absl::get<0>(x));
- EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
- }
-
- {
- using X = variant<NonNoexceptDefaultConstructible>;
- X x{};
- ASSERT_FALSE(x.valueless_by_exception());
- ASSERT_EQ(0u, x.index());
- EXPECT_EQ(5, absl::get<0>(x).value);
- EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
- }
-
- {
- using X = variant<int, NonNoexceptDefaultConstructible>;
- X x{};
- ASSERT_FALSE(x.valueless_by_exception());
- ASSERT_EQ(0u, x.index());
- EXPECT_EQ(0, absl::get<0>(x));
- EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value);
- }
-
- {
- using X = variant<NonNoexceptDefaultConstructible, int>;
- X x{};
- ASSERT_FALSE(x.valueless_by_exception());
- ASSERT_EQ(0u, x.index());
- EXPECT_EQ(5, absl::get<0>(x).value);
- EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value);
- }
- EXPECT_FALSE(
- std::is_default_constructible<variant<NonDefaultConstructible>>::value);
- EXPECT_FALSE((std::is_default_constructible<
- variant<NonDefaultConstructible, int>>::value));
- EXPECT_TRUE((std::is_default_constructible<
- variant<int, NonDefaultConstructible>>::value));
-}
-
-// Test that for each slot, copy constructing a variant with that type
-// produces a sensible object that correctly reports its type, and
-// that copies the provided value.
-TYPED_TEST(VariantTypesTest, TestCopyCtor) {
- typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- using value_type2 = absl::variant_alternative_t<1, Variant>;
- using value_type3 = absl::variant_alternative_t<2, Variant>;
- using value_type4 = absl::variant_alternative_t<3, Variant>;
- const TypeParam value(TypeParam::kIndex);
- Variant original(value);
- Variant copied(original);
- EXPECT_TRUE(absl::holds_alternative<value_type1>(copied) ||
- TypeParam::kIndex != 1);
- EXPECT_TRUE(absl::holds_alternative<value_type2>(copied) ||
- TypeParam::kIndex != 2);
- EXPECT_TRUE(absl::holds_alternative<value_type3>(copied) ||
- TypeParam::kIndex != 3);
- EXPECT_TRUE(absl::holds_alternative<value_type4>(copied) ||
- TypeParam::kIndex != 4);
- EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
- absl::get_if<value_type1>(&copied)) ||
- TypeParam::kIndex == 1);
- EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
- absl::get_if<value_type2>(&copied)) ||
- TypeParam::kIndex == 2);
- EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
- absl::get_if<value_type3>(&copied)) ||
- TypeParam::kIndex == 3);
- EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
- absl::get_if<value_type4>(&copied)) ||
- TypeParam::kIndex == 4);
- EXPECT_TRUE((absl::get_if<value_type1>(&original) ==
- absl::get_if<value_type1>(&copied)) ||
- TypeParam::kIndex == 1);
- EXPECT_TRUE((absl::get_if<value_type2>(&original) ==
- absl::get_if<value_type2>(&copied)) ||
- TypeParam::kIndex == 2);
- EXPECT_TRUE((absl::get_if<value_type3>(&original) ==
- absl::get_if<value_type3>(&copied)) ||
- TypeParam::kIndex == 3);
- EXPECT_TRUE((absl::get_if<value_type4>(&original) ==
- absl::get_if<value_type4>(&copied)) ||
- TypeParam::kIndex == 4);
- const TypeParam* ovalptr = absl::get_if<TypeParam>(&original);
- const TypeParam* cvalptr = absl::get_if<TypeParam>(&copied);
- ASSERT_TRUE(ovalptr != nullptr);
- ASSERT_TRUE(cvalptr != nullptr);
- EXPECT_EQ(*ovalptr, *cvalptr);
- TypeParam* mutable_ovalptr = absl::get_if<TypeParam>(&original);
- TypeParam* mutable_cvalptr = absl::get_if<TypeParam>(&copied);
- ASSERT_TRUE(mutable_ovalptr != nullptr);
- ASSERT_TRUE(mutable_cvalptr != nullptr);
- EXPECT_EQ(*mutable_ovalptr, *mutable_cvalptr);
-}
-
-template <class>
-struct MoveOnly {
- MoveOnly() = default;
- explicit MoveOnly(int value) : value(value) {}
- MoveOnly(MoveOnly&&) = default;
- MoveOnly& operator=(MoveOnly&&) = default;
- int value = 5;
-};
-
-TEST(VariantTest, TestMoveConstruct) {
- using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>;
-
- V v(in_place_index<1>, 10);
- V v2 = std::move(v);
- EXPECT_EQ(10, absl::get<1>(v2).value);
-}
-
-// Used internally to emulate missing triviality traits for tests.
-template <class T>
-union SingleUnion {
- T member;
-};
-
-// NOTE: These don't work with types that can't be union members.
-// They are just for testing.
-template <class T>
-struct is_trivially_move_constructible
- : std::is_move_constructible<SingleUnion<T>>::type {};
-
-template <class T>
-struct is_trivially_move_assignable
- : absl::is_move_assignable<SingleUnion<T>>::type {};
-
-TEST(VariantTest, NothrowMoveConstructible) {
- // Verify that variant is nothrow move constructible iff its template
- // arguments are.
- using U = std::unique_ptr<int>;
- struct E {
- E(E&&) {}
- };
- static_assert(std::is_nothrow_move_constructible<variant<U>>::value, "");
- static_assert(std::is_nothrow_move_constructible<variant<U, int>>::value, "");
- static_assert(!std::is_nothrow_move_constructible<variant<U, E>>::value, "");
-}
-
-// Test that for each slot, constructing a variant with that type
-// produces a sensible object that correctly reports its type, and
-// that copies the provided value.
-TYPED_TEST(VariantTypesTest, TestValueCtor) {
- typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- using value_type2 = absl::variant_alternative_t<1, Variant>;
- using value_type3 = absl::variant_alternative_t<2, Variant>;
- using value_type4 = absl::variant_alternative_t<3, Variant>;
- const TypeParam value(TypeParam::kIndex);
- Variant v(value);
- EXPECT_TRUE(absl::holds_alternative<value_type1>(v) ||
- TypeParam::kIndex != 1);
- EXPECT_TRUE(absl::holds_alternative<value_type2>(v) ||
- TypeParam::kIndex != 2);
- EXPECT_TRUE(absl::holds_alternative<value_type3>(v) ||
- TypeParam::kIndex != 3);
- EXPECT_TRUE(absl::holds_alternative<value_type4>(v) ||
- TypeParam::kIndex != 4);
- EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
- TypeParam::kIndex != 1);
- EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
- TypeParam::kIndex != 2);
- EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
- TypeParam::kIndex != 3);
- EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
- TypeParam::kIndex != 4);
- EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) ||
- TypeParam::kIndex != 1);
- EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) ||
- TypeParam::kIndex != 2);
- EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) ||
- TypeParam::kIndex != 3);
- EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) ||
- TypeParam::kIndex != 4);
- const TypeParam* valptr = absl::get_if<TypeParam>(&v);
- ASSERT_TRUE(nullptr != valptr);
- EXPECT_EQ(value.value, valptr->value);
- const TypeParam* mutable_valptr = absl::get_if<TypeParam>(&v);
- ASSERT_TRUE(nullptr != mutable_valptr);
- EXPECT_EQ(value.value, mutable_valptr->value);
-}
-
-TEST(VariantTest, AmbiguousValueConstructor) {
- EXPECT_FALSE((std::is_convertible<int, absl::variant<int, int>>::value));
- EXPECT_FALSE((std::is_constructible<absl::variant<int, int>, int>::value));
-}
-
-TEST(VariantTest, InPlaceType) {
- using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
-
- Var v1(in_place_type_t<int>(), 7);
- ASSERT_TRUE(absl::holds_alternative<int>(v1));
- EXPECT_EQ(7, absl::get<int>(v1));
-
- Var v2(in_place_type_t<std::string>(), "ABC");
- ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
- EXPECT_EQ("ABC", absl::get<std::string>(v2));
-
- Var v3(in_place_type_t<std::string>(), "ABC", 2u);
- ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
- EXPECT_EQ("AB", absl::get<std::string>(v3));
-
- Var v4(in_place_type_t<NonCopyable>{});
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4));
-
- Var v5(in_place_type_t<std::vector<int>>(), {1, 2, 3});
- ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
- EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
-}
-
-TEST(VariantTest, InPlaceTypeVariableTemplate) {
- using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
-
- Var v1(in_place_type<int>, 7);
- ASSERT_TRUE(absl::holds_alternative<int>(v1));
- EXPECT_EQ(7, absl::get<int>(v1));
-
- Var v2(in_place_type<std::string>, "ABC");
- ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
- EXPECT_EQ("ABC", absl::get<std::string>(v2));
-
- Var v3(in_place_type<std::string>, "ABC", 2u);
- ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
- EXPECT_EQ("AB", absl::get<std::string>(v3));
-
- Var v4(in_place_type<NonCopyable>);
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4));
-
- Var v5(in_place_type<std::vector<int>>, {1, 2, 3});
- ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
- EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
-}
-
-TEST(VariantTest, InPlaceTypeInitializerList) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
-}
-
-TEST(VariantTest, InPlaceTypeInitializerListVariabletemplate) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(in_place_type<MoveOnlyWithListConstructor>, {1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
-}
-
-TEST(VariantTest, InPlaceIndex) {
- using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
-
- Var v1(in_place_index_t<0>(), 7);
- ASSERT_TRUE(absl::holds_alternative<int>(v1));
- EXPECT_EQ(7, absl::get<int>(v1));
-
- Var v2(in_place_index_t<1>(), "ABC");
- ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
- EXPECT_EQ("ABC", absl::get<std::string>(v2));
-
- Var v3(in_place_index_t<1>(), "ABC", 2u);
- ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
- EXPECT_EQ("AB", absl::get<std::string>(v3));
-
- Var v4(in_place_index_t<2>{});
- EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4));
-
- // Verify that a variant with only non-copyables can still be constructed.
- EXPECT_TRUE(absl::holds_alternative<NonCopyable>(
- variant<NonCopyable>(in_place_index_t<0>{})));
-
- Var v5(in_place_index_t<3>(), {1, 2, 3});
- ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
- EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
-}
-
-TEST(VariantTest, InPlaceIndexVariableTemplate) {
- using Var = variant<int, std::string, NonCopyable, std::vector<int>>;
-
- Var v1(in_place_index<0>, 7);
- ASSERT_TRUE(absl::holds_alternative<int>(v1));
- EXPECT_EQ(7, absl::get<int>(v1));
-
- Var v2(in_place_index<1>, "ABC");
- ASSERT_TRUE(absl::holds_alternative<std::string>(v2));
- EXPECT_EQ("ABC", absl::get<std::string>(v2));
-
- Var v3(in_place_index<1>, "ABC", 2u);
- ASSERT_TRUE(absl::holds_alternative<std::string>(v3));
- EXPECT_EQ("AB", absl::get<std::string>(v3));
-
- Var v4(in_place_index<2>);
- EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4));
-
- // Verify that a variant with only non-copyables can still be constructed.
- EXPECT_TRUE(absl::holds_alternative<NonCopyable>(
- variant<NonCopyable>(in_place_index<0>)));
-
- Var v5(in_place_index<3>, {1, 2, 3});
- ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5));
- EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3));
-}
-
-TEST(VariantTest, InPlaceIndexInitializerList) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
-}
-
-TEST(VariantTest, InPlaceIndexInitializerListVariableTemplate) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(in_place_index<3>, {1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
-}
-
-////////////////////
-// [variant.dtor] //
-////////////////////
-
-// Make sure that the destructor destroys the contained value
-TEST(VariantTest, TestDtor) {
- typedef VariantFactory<IncrementInDtor>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- using value_type2 = absl::variant_alternative_t<1, Variant>;
- using value_type3 = absl::variant_alternative_t<2, Variant>;
- using value_type4 = absl::variant_alternative_t<3, Variant>;
- int counter = 0;
- IncrementInDtor counter_adjuster(&counter);
- EXPECT_EQ(0, counter);
-
- value_type1 value1(counter_adjuster);
- { Variant object(value1); }
- EXPECT_EQ(1, counter);
-
- value_type2 value2(counter_adjuster);
- { Variant object(value2); }
- EXPECT_EQ(2, counter);
-
- value_type3 value3(counter_adjuster);
- { Variant object(value3); }
- EXPECT_EQ(3, counter);
-
- value_type4 value4(counter_adjuster);
- { Variant object(value4); }
- EXPECT_EQ(4, counter);
-}
-
-#ifdef ABSL_HAVE_EXCEPTIONS
-
-// See comment in absl/base/config.h
-#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
-TEST(VariantTest, DISABLED_TestDtorValuelessByException)
-#else
-// Test destruction when in the valueless_by_exception state.
-TEST(VariantTest, TestDtorValuelessByException)
-#endif
-{
- int counter = 0;
- IncrementInDtor counter_adjuster(&counter);
-
- {
- using Variant = VariantFactory<IncrementInDtor>::Type;
-
- Variant v(in_place_index<0>, counter_adjuster);
- EXPECT_EQ(0, counter);
-
- ToValuelessByException(v);
- ASSERT_TRUE(v.valueless_by_exception());
- EXPECT_EQ(1, counter);
- }
- EXPECT_EQ(1, counter);
-}
-
-#endif // ABSL_HAVE_EXCEPTIONS
-
-//////////////////////
-// [variant.assign] //
-//////////////////////
-
-// Test that self-assignment doesn't destroy the current value
-TEST(VariantTest, TestSelfAssignment) {
- typedef VariantFactory<IncrementInDtor>::Type Variant;
- int counter = 0;
- IncrementInDtor counter_adjuster(&counter);
- absl::variant_alternative_t<0, Variant> value(counter_adjuster);
- Variant object(value);
- object.operator=(object);
- EXPECT_EQ(0, counter);
-
- // A string long enough that it's likely to defeat any inline representation
- // optimization.
- const std::string long_str(128, 'a');
-
- std::string foo = long_str;
- foo = *&foo;
- EXPECT_EQ(long_str, foo);
-
- variant<int, std::string> so = long_str;
- ASSERT_EQ(1u, so.index());
- EXPECT_EQ(long_str, absl::get<1>(so));
- so = *&so;
-
- ASSERT_EQ(1u, so.index());
- EXPECT_EQ(long_str, absl::get<1>(so));
-}
-
-// Test that assigning a variant<..., T, ...> to a variant<..., T, ...> produces
-// a variant<..., T, ...> with the correct value.
-TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValueSameTypes) {
- typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
- const TypeParam value(TypeParam::kIndex);
- const Variant source(value);
- Variant target(TypeParam(value.value + 1));
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
- ASSERT_NE(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
- target = source;
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
- EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
-}
-
-// Test that assisnging a variant<..., T, ...> to a variant<1, ...>
-// produces a variant<..., T, ...> with the correct value.
-TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingSourceType) {
- typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- const TypeParam value(TypeParam::kIndex);
- const Variant source(value);
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(source));
- Variant target(value_type1(1));
- ASSERT_TRUE(absl::holds_alternative<value_type1>(target));
- target = source;
- EXPECT_TRUE(absl::holds_alternative<TypeParam>(source));
- EXPECT_TRUE(absl::holds_alternative<TypeParam>(target));
- EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target));
-}
-
-// Test that assigning a variant<1, ...> to a variant<..., T, ...>
-// produces a variant<1, ...> with the correct value.
-TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingTargetType) {
- typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- const Variant source(value_type1(1));
- ASSERT_TRUE(absl::holds_alternative<value_type1>(source));
- const TypeParam value(TypeParam::kIndex);
- Variant target(value);
- ASSERT_TRUE(absl::holds_alternative<TypeParam>(target));
- target = source;
- EXPECT_TRUE(absl::holds_alternative<value_type1>(target));
- EXPECT_TRUE(absl::holds_alternative<value_type1>(source));
- EXPECT_EQ(absl::get<value_type1>(source), absl::get<value_type1>(target));
-}
-
-// Test that operator=<T> works, that assigning a new value destroys
-// the old and that assigning the new value again does not redestroy
-// the old
-TEST(VariantTest, TestAssign) {
- typedef VariantFactory<IncrementInDtor>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- using value_type2 = absl::variant_alternative_t<1, Variant>;
- using value_type3 = absl::variant_alternative_t<2, Variant>;
- using value_type4 = absl::variant_alternative_t<3, Variant>;
-
- const int kSize = 4;
- int counter[kSize];
- std::unique_ptr<IncrementInDtor> counter_adjustor[kSize];
- for (int i = 0; i != kSize; i++) {
- counter[i] = 0;
- counter_adjustor[i] = absl::make_unique<IncrementInDtor>(&counter[i]);
- }
-
- value_type1 v1(*counter_adjustor[0]);
- value_type2 v2(*counter_adjustor[1]);
- value_type3 v3(*counter_adjustor[2]);
- value_type4 v4(*counter_adjustor[3]);
-
- // Test that reassignment causes destruction of old value
- {
- Variant object(v1);
- object = v2;
- object = v3;
- object = v4;
- object = v1;
- }
-
- EXPECT_EQ(2, counter[0]);
- EXPECT_EQ(1, counter[1]);
- EXPECT_EQ(1, counter[2]);
- EXPECT_EQ(1, counter[3]);
-
- std::fill(std::begin(counter), std::end(counter), 0);
-
- // Test that self-assignment does not cause destruction of old value
- {
- Variant object(v1);
- object.operator=(object);
- EXPECT_EQ(0, counter[0]);
- }
- {
- Variant object(v2);
- object.operator=(object);
- EXPECT_EQ(0, counter[1]);
- }
- {
- Variant object(v3);
- object.operator=(object);
- EXPECT_EQ(0, counter[2]);
- }
- {
- Variant object(v4);
- object.operator=(object);
- EXPECT_EQ(0, counter[3]);
- }
-
- EXPECT_EQ(1, counter[0]);
- EXPECT_EQ(1, counter[1]);
- EXPECT_EQ(1, counter[2]);
- EXPECT_EQ(1, counter[3]);
-}
-
-// This tests that we perform a backup if the copy-assign can throw but the move
-// cannot throw.
-TEST(VariantTest, TestBackupAssign) {
- typedef VariantFactory<IncrementInDtorCopyCanThrow>::Type Variant;
- using value_type1 = absl::variant_alternative_t<0, Variant>;
- using value_type2 = absl::variant_alternative_t<1, Variant>;
- using value_type3 = absl::variant_alternative_t<2, Variant>;
- using value_type4 = absl::variant_alternative_t<3, Variant>;
-
- const int kSize = 4;
- int counter[kSize];
- std::unique_ptr<IncrementInDtorCopyCanThrow> counter_adjustor[kSize];
- for (int i = 0; i != kSize; i++) {
- counter[i] = 0;
- counter_adjustor[i].reset(new IncrementInDtorCopyCanThrow(&counter[i]));
- }
-
- value_type1 v1(*counter_adjustor[0]);
- value_type2 v2(*counter_adjustor[1]);
- value_type3 v3(*counter_adjustor[2]);
- value_type4 v4(*counter_adjustor[3]);
-
- // Test that reassignment causes destruction of old value
- {
- Variant object(v1);
- object = v2;
- object = v3;
- object = v4;
- object = v1;
- }
-
- // libstdc++ doesn't pass this test
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
- EXPECT_EQ(3, counter[0]);
- EXPECT_EQ(2, counter[1]);
- EXPECT_EQ(2, counter[2]);
- EXPECT_EQ(2, counter[3]);
-#endif
-
- std::fill(std::begin(counter), std::end(counter), 0);
-
- // Test that self-assignment does not cause destruction of old value
- {
- Variant object(v1);
- object.operator=(object);
- EXPECT_EQ(0, counter[0]);
- }
- {
- Variant object(v2);
- object.operator=(object);
- EXPECT_EQ(0, counter[1]);
- }
- {
- Variant object(v3);
- object.operator=(object);
- EXPECT_EQ(0, counter[2]);
- }
- {
- Variant object(v4);
- object.operator=(object);
- EXPECT_EQ(0, counter[3]);
- }
-
- EXPECT_EQ(1, counter[0]);
- EXPECT_EQ(1, counter[1]);
- EXPECT_EQ(1, counter[2]);
- EXPECT_EQ(1, counter[3]);
-}
-
-///////////////////
-// [variant.mod] //
-///////////////////
-
-TEST(VariantTest, TestEmplaceBasic) {
- using Variant = variant<int, char>;
-
- Variant v(absl::in_place_index<0>, 0);
-
- {
- char& emplace_result = v.emplace<char>();
- ASSERT_TRUE(absl::holds_alternative<char>(v));
- EXPECT_EQ(absl::get<char>(v), 0);
- EXPECT_EQ(&emplace_result, &absl::get<char>(v));
- }
-
- // Make sure that another emplace does zero-initialization
- absl::get<char>(v) = 'a';
- v.emplace<char>('b');
- ASSERT_TRUE(absl::holds_alternative<char>(v));
- EXPECT_EQ(absl::get<char>(v), 'b');
-
- {
- int& emplace_result = v.emplace<int>();
- EXPECT_TRUE(absl::holds_alternative<int>(v));
- EXPECT_EQ(absl::get<int>(v), 0);
- EXPECT_EQ(&emplace_result, &absl::get<int>(v));
- }
-}
-
-TEST(VariantTest, TestEmplaceInitializerList) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(absl::in_place_index<0>, 555);
- MoveOnlyWithListConstructor& emplace_result =
- v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
- EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
-}
-
-TEST(VariantTest, TestEmplaceIndex) {
- using Variant = variant<int, char>;
-
- Variant v(absl::in_place_index<0>, 555);
-
- {
- char& emplace_result = v.emplace<1>();
- ASSERT_TRUE(absl::holds_alternative<char>(v));
- EXPECT_EQ(absl::get<char>(v), 0);
- EXPECT_EQ(&emplace_result, &absl::get<char>(v));
- }
-
- // Make sure that another emplace does zero-initialization
- absl::get<char>(v) = 'a';
- v.emplace<1>('b');
- ASSERT_TRUE(absl::holds_alternative<char>(v));
- EXPECT_EQ(absl::get<char>(v), 'b');
-
- {
- int& emplace_result = v.emplace<0>();
- EXPECT_TRUE(absl::holds_alternative<int>(v));
- EXPECT_EQ(absl::get<int>(v), 0);
- EXPECT_EQ(&emplace_result, &absl::get<int>(v));
- }
-}
-
-TEST(VariantTest, TestEmplaceIndexInitializerList) {
- using Var =
- variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
-
- Var v1(absl::in_place_index<0>, 555);
- MoveOnlyWithListConstructor& emplace_result =
- v1.emplace<3>({1, 2, 3, 4, 5}, 6);
- ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1));
- EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value);
- EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1));
-}
-
-//////////////////////
-// [variant.status] //
-//////////////////////
-
-TEST(VariantTest, Index) {
- using Var = variant<int, std::string, double>;
-
- Var v = 1;
- EXPECT_EQ(0u, v.index());
- v = "str";
- EXPECT_EQ(1u, v.index());
- v = 0.;
- EXPECT_EQ(2u, v.index());
-
- Var v2 = v;
- EXPECT_EQ(2u, v2.index());
- v2.emplace<int>(3);
- EXPECT_EQ(0u, v2.index());
-}
-
-TEST(VariantTest, NotValuelessByException) {
- using Var = variant<int, std::string, double>;
-
- Var v = 1;
- EXPECT_FALSE(v.valueless_by_exception());
- v = "str";
- EXPECT_FALSE(v.valueless_by_exception());
- v = 0.;
- EXPECT_FALSE(v.valueless_by_exception());
-
- Var v2 = v;
- EXPECT_FALSE(v.valueless_by_exception());
- v2.emplace<int>(3);
- EXPECT_FALSE(v.valueless_by_exception());
-}
-
-#ifdef ABSL_HAVE_EXCEPTIONS
-
-TEST(VariantTest, IndexValuelessByException) {
- using Var = variant<MoveCanThrow, std::string, double>;
-
- Var v(absl::in_place_index<0>);
- EXPECT_EQ(0u, v.index());
- ToValuelessByException(v);
- EXPECT_EQ(absl::variant_npos, v.index());
- v = "str";
- EXPECT_EQ(1u, v.index());
-}
-
-TEST(VariantTest, ValuelessByException) {
- using Var = variant<MoveCanThrow, std::string, double>;
-
- Var v(absl::in_place_index<0>);
- EXPECT_FALSE(v.valueless_by_exception());
- ToValuelessByException(v);
- EXPECT_TRUE(v.valueless_by_exception());
- v = "str";
- EXPECT_FALSE(v.valueless_by_exception());
-}
-
-#endif // ABSL_HAVE_EXCEPTIONS
-
-////////////////////
-// [variant.swap] //
-////////////////////
-
-TEST(VariantTest, MemberSwap) {
- SpecialSwap v1(3);
- SpecialSwap v2(7);
-
- variant<SpecialSwap> a = v1, b = v2;
-
- EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
- EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
-
- a.swap(b);
- EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
- EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
- EXPECT_TRUE(absl::get<SpecialSwap>(a).special_swap);
-
- using V = variant<MoveCanThrow, std::string, int>;
- int i = 33;
- std::string s = "abc";
- {
- // lhs and rhs holds different alternative
- V lhs(i), rhs(s);
- lhs.swap(rhs);
- EXPECT_THAT(lhs, VariantWith<std::string>(s));
- EXPECT_THAT(rhs, VariantWith<int>(i));
- }
-#ifdef ABSL_HAVE_EXCEPTIONS
- V valueless(in_place_index<0>);
- ToValuelessByException(valueless);
- {
- // lhs is valueless
- V lhs(valueless), rhs(i);
- lhs.swap(rhs);
- EXPECT_THAT(lhs, VariantWith<int>(i));
- EXPECT_TRUE(rhs.valueless_by_exception());
- }
- {
- // rhs is valueless
- V lhs(s), rhs(valueless);
- lhs.swap(rhs);
- EXPECT_THAT(rhs, VariantWith<std::string>(s));
- EXPECT_TRUE(lhs.valueless_by_exception());
- }
- {
- // both are valueless
- V lhs(valueless), rhs(valueless);
- lhs.swap(rhs);
- EXPECT_TRUE(lhs.valueless_by_exception());
- EXPECT_TRUE(rhs.valueless_by_exception());
- }
-#endif // ABSL_HAVE_EXCEPTIONS
-}
-
-//////////////////////
-// [variant.helper] //
-//////////////////////
-
-TEST(VariantTest, VariantSize) {
- {
- using Size1Variant = absl::variant<int>;
- EXPECT_EQ(1u, absl::variant_size<Size1Variant>::value);
- EXPECT_EQ(1u, absl::variant_size<const Size1Variant>::value);
- EXPECT_EQ(1u, absl::variant_size<volatile Size1Variant>::value);
- EXPECT_EQ(1u, absl::variant_size<const volatile Size1Variant>::value);
- }
-
- {
- using Size3Variant = absl::variant<int, float, int>;
- EXPECT_EQ(3u, absl::variant_size<Size3Variant>::value);
- EXPECT_EQ(3u, absl::variant_size<const Size3Variant>::value);
- EXPECT_EQ(3u, absl::variant_size<volatile Size3Variant>::value);
- EXPECT_EQ(3u, absl::variant_size<const volatile Size3Variant>::value);
- }
-}
-
-TEST(VariantTest, VariantAlternative) {
- {
- using V = absl::variant<float, int, const char*>;
- EXPECT_TRUE(
- (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
- EXPECT_TRUE((std::is_same<const float,
- absl::variant_alternative_t<0, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<volatile float,
- absl::variant_alternative_t<0, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const volatile float,
- absl::variant_alternative_t<0, const volatile V>>::value));
-
- EXPECT_TRUE((std::is_same<int, absl::variant_alternative_t<1, V>>::value));
- EXPECT_TRUE((std::is_same<const int,
- absl::variant_alternative_t<1, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<volatile int,
- absl::variant_alternative_t<1, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const volatile int,
- absl::variant_alternative_t<1, const volatile V>>::value));
-
- EXPECT_TRUE(
- (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
- EXPECT_TRUE((std::is_same<const char* const,
- absl::variant_alternative_t<2, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<const char* volatile,
- absl::variant_alternative_t<2, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const char* const volatile,
- absl::variant_alternative_t<2, const volatile V>>::value));
- }
-
- {
- using V = absl::variant<float, volatile int, const char*>;
- EXPECT_TRUE(
- (std::is_same<float, absl::variant_alternative_t<0, V>>::value));
- EXPECT_TRUE((std::is_same<const float,
- absl::variant_alternative_t<0, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<volatile float,
- absl::variant_alternative_t<0, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const volatile float,
- absl::variant_alternative_t<0, const volatile V>>::value));
-
- EXPECT_TRUE(
- (std::is_same<volatile int, absl::variant_alternative_t<1, V>>::value));
- EXPECT_TRUE((std::is_same<const volatile int,
- absl::variant_alternative_t<1, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<volatile int,
- absl::variant_alternative_t<1, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const volatile int,
- absl::variant_alternative_t<1, const volatile V>>::value));
-
- EXPECT_TRUE(
- (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value));
- EXPECT_TRUE((std::is_same<const char* const,
- absl::variant_alternative_t<2, const V>>::value));
- EXPECT_TRUE(
- (std::is_same<const char* volatile,
- absl::variant_alternative_t<2, volatile V>>::value));
- EXPECT_TRUE((
- std::is_same<const char* const volatile,
- absl::variant_alternative_t<2, const volatile V>>::value));
- }
-}
-
-///////////////////
-// [variant.get] //
-///////////////////
-
-TEST(VariantTest, HoldsAlternative) {
- using Var = variant<int, std::string, double>;
-
- Var v = 1;
- EXPECT_TRUE(absl::holds_alternative<int>(v));
- EXPECT_FALSE(absl::holds_alternative<std::string>(v));
- EXPECT_FALSE(absl::holds_alternative<double>(v));
- v = "str";
- EXPECT_FALSE(absl::holds_alternative<int>(v));
- EXPECT_TRUE(absl::holds_alternative<std::string>(v));
- EXPECT_FALSE(absl::holds_alternative<double>(v));
- v = 0.;
- EXPECT_FALSE(absl::holds_alternative<int>(v));
- EXPECT_FALSE(absl::holds_alternative<std::string>(v));
- EXPECT_TRUE(absl::holds_alternative<double>(v));
-
- Var v2 = v;
- EXPECT_FALSE(absl::holds_alternative<int>(v2));
- EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
- EXPECT_TRUE(absl::holds_alternative<double>(v2));
- v2.emplace<int>(3);
- EXPECT_TRUE(absl::holds_alternative<int>(v2));
- EXPECT_FALSE(absl::holds_alternative<std::string>(v2));
- EXPECT_FALSE(absl::holds_alternative<double>(v2));
-}
-
-TEST(VariantTest, GetIndex) {
- using Var = variant<int, std::string, double, int>;
-
- {
- Var v(absl::in_place_index<0>, 0);
-
- using LValueGetType = decltype(absl::get<0>(v));
- using RValueGetType = decltype(absl::get<0>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
- EXPECT_EQ(absl::get<0>(v), 0);
- EXPECT_EQ(absl::get<0>(std::move(v)), 0);
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<0>(const_v));
- using ConstRValueGetType = decltype(absl::get<0>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
- EXPECT_EQ(absl::get<0>(const_v), 0);
- EXPECT_EQ(absl::get<0>(std::move(const_v)), 0);
- }
-
- {
- Var v = std::string("Hello");
-
- using LValueGetType = decltype(absl::get<1>(v));
- using RValueGetType = decltype(absl::get<1>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
- EXPECT_EQ(absl::get<1>(v), "Hello");
- EXPECT_EQ(absl::get<1>(std::move(v)), "Hello");
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<1>(const_v));
- using ConstRValueGetType = decltype(absl::get<1>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
- EXPECT_EQ(absl::get<1>(const_v), "Hello");
- EXPECT_EQ(absl::get<1>(std::move(const_v)), "Hello");
- }
-
- {
- Var v = 2.0;
-
- using LValueGetType = decltype(absl::get<2>(v));
- using RValueGetType = decltype(absl::get<2>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
- EXPECT_EQ(absl::get<2>(v), 2.);
- EXPECT_EQ(absl::get<2>(std::move(v)), 2.);
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<2>(const_v));
- using ConstRValueGetType = decltype(absl::get<2>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
- EXPECT_EQ(absl::get<2>(const_v), 2.);
- EXPECT_EQ(absl::get<2>(std::move(const_v)), 2.);
- }
-
- {
- Var v(absl::in_place_index<0>, 0);
- v.emplace<3>(1);
-
- using LValueGetType = decltype(absl::get<3>(v));
- using RValueGetType = decltype(absl::get<3>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
- EXPECT_EQ(absl::get<3>(v), 1);
- EXPECT_EQ(absl::get<3>(std::move(v)), 1);
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<3>(const_v));
- using ConstRValueGetType = decltype(absl::get<3>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
- EXPECT_EQ(absl::get<3>(const_v), 1);
- EXPECT_EQ(absl::get<3>(std::move(const_v)), 1); // NOLINT
- }
-}
-
-TEST(VariantTest, BadGetIndex) {
- using Var = variant<int, std::string, double>;
-
- {
- Var v = 1;
-
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(std::move(v)));
-
- const Var& const_v = v;
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(const_v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<1>(std::move(const_v))); // NOLINT
- }
-
- {
- Var v = std::string("Hello");
-
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(std::move(v)));
-
- const Var& const_v = v;
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(const_v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<0>(std::move(const_v))); // NOLINT
- }
-}
-
-TEST(VariantTest, GetType) {
- using Var = variant<int, std::string, double>;
-
- {
- Var v = 1;
-
- using LValueGetType = decltype(absl::get<int>(v));
- using RValueGetType = decltype(absl::get<int>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, int&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value));
- EXPECT_EQ(absl::get<int>(v), 1);
- EXPECT_EQ(absl::get<int>(std::move(v)), 1);
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<int>(const_v));
- using ConstRValueGetType = decltype(absl::get<int>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value));
- EXPECT_EQ(absl::get<int>(const_v), 1);
- EXPECT_EQ(absl::get<int>(std::move(const_v)), 1);
- }
-
- {
- Var v = std::string("Hello");
-
- using LValueGetType = decltype(absl::get<1>(v));
- using RValueGetType = decltype(absl::get<1>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value));
- EXPECT_EQ(absl::get<std::string>(v), "Hello");
- EXPECT_EQ(absl::get<std::string>(std::move(v)), "Hello");
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<1>(const_v));
- using ConstRValueGetType = decltype(absl::get<1>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value));
- EXPECT_EQ(absl::get<std::string>(const_v), "Hello");
- EXPECT_EQ(absl::get<std::string>(std::move(const_v)), "Hello");
- }
-
- {
- Var v = 2.0;
-
- using LValueGetType = decltype(absl::get<2>(v));
- using RValueGetType = decltype(absl::get<2>(std::move(v)));
-
- EXPECT_TRUE((std::is_same<LValueGetType, double&>::value));
- EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value));
- EXPECT_EQ(absl::get<double>(v), 2.);
- EXPECT_EQ(absl::get<double>(std::move(v)), 2.);
-
- const Var& const_v = v;
- using ConstLValueGetType = decltype(absl::get<2>(const_v));
- using ConstRValueGetType = decltype(absl::get<2>(std::move(const_v)));
- EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value));
- EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value));
- EXPECT_EQ(absl::get<double>(const_v), 2.);
- EXPECT_EQ(absl::get<double>(std::move(const_v)), 2.);
- }
-}
-
-TEST(VariantTest, BadGetType) {
- using Var = variant<int, std::string, double>;
-
- {
- Var v = 1;
-
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<std::string>(std::move(v)));
-
- const Var& const_v = v;
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<std::string>(const_v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<std::string>(std::move(const_v))); // NOLINT
- }
-
- {
- Var v = std::string("Hello");
-
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(std::move(v)));
-
- const Var& const_v = v;
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(const_v));
- ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
- absl::get<int>(std::move(const_v))); // NOLINT
- }
-}
-
-TEST(VariantTest, GetIfIndex) {
- using Var = variant<int, std::string, double, int>;
-
- {
- Var v(absl::in_place_index<0>, 0);
- EXPECT_TRUE(noexcept(absl::get_if<0>(&v)));
-
- {
- auto* elem = absl::get_if<0>(&v);
- EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 0);
- {
- auto* bad_elem = absl::get_if<1>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- }
-
- const Var& const_v = v;
- EXPECT_TRUE(noexcept(absl::get_if<0>(&const_v)));
-
- {
- auto* elem = absl::get_if<0>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 0);
- {
- auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE(
- (std::is_same<decltype(bad_elem), const std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&const_v);
- EXPECT_EQ(bad_elem, nullptr);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- }
- }
- }
-
- {
- Var v = std::string("Hello");
- EXPECT_TRUE(noexcept(absl::get_if<1>(&v)));
-
- {
- auto* elem = absl::get_if<1>(&v);
- EXPECT_TRUE((std::is_same<decltype(elem), std::string*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, "Hello");
- {
- auto* bad_elem = absl::get_if<0>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- }
-
- const Var& const_v = v;
- EXPECT_TRUE(noexcept(absl::get_if<1>(&const_v)));
-
- {
- auto* elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(elem), const std::string*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, "Hello");
- {
- auto* bad_elem = absl::get_if<0>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&const_v);
- EXPECT_EQ(bad_elem, nullptr);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- }
- }
- }
-
- {
- Var v = 2.0;
- EXPECT_TRUE(noexcept(absl::get_if<2>(&v)));
-
- {
- auto* elem = absl::get_if<2>(&v);
- EXPECT_TRUE((std::is_same<decltype(elem), double*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 2.0);
- {
- auto* bad_elem = absl::get_if<0>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<1>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- }
-
- const Var& const_v = v;
- EXPECT_TRUE(noexcept(absl::get_if<2>(&const_v)));
-
- {
- auto* elem = absl::get_if<2>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(elem), const double*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 2.0);
- {
- auto* bad_elem = absl::get_if<0>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE(
- (std::is_same<decltype(bad_elem), const std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<3>(&const_v);
- EXPECT_EQ(bad_elem, nullptr);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- }
- }
- }
-
- {
- Var v(absl::in_place_index<0>, 0);
- v.emplace<3>(1);
- EXPECT_TRUE(noexcept(absl::get_if<3>(&v)));
-
- {
- auto* elem = absl::get_if<3>(&v);
- EXPECT_TRUE((std::is_same<decltype(elem), int*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 1);
- {
- auto* bad_elem = absl::get_if<0>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<1>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- }
-
- const Var& const_v = v;
- EXPECT_TRUE(noexcept(absl::get_if<3>(&const_v)));
-
- {
- auto* elem = absl::get_if<3>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value));
- ASSERT_NE(elem, nullptr);
- EXPECT_EQ(*elem, 1);
- {
- auto* bad_elem = absl::get_if<0>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE(
- (std::is_same<decltype(bad_elem), const std::string*>::value));
- EXPECT_EQ(bad_elem, nullptr);
- }
- {
- auto* bad_elem = absl::get_if<2>(&const_v);
- EXPECT_EQ(bad_elem, nullptr);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value));
- }
- }
- }
-}
-
-//////////////////////
-// [variant.relops] //
-//////////////////////
-
-TEST(VariantTest, OperatorEquals) {
- variant<int, std::string> a(1), b(1);
- EXPECT_TRUE(a == b);
- EXPECT_TRUE(b == a);
- EXPECT_FALSE(a != b);
- EXPECT_FALSE(b != a);
-
- b = "str";
- EXPECT_FALSE(a == b);
- EXPECT_FALSE(b == a);
- EXPECT_TRUE(a != b);
- EXPECT_TRUE(b != a);
-
- b = 0;
- EXPECT_FALSE(a == b);
- EXPECT_FALSE(b == a);
- EXPECT_TRUE(a != b);
- EXPECT_TRUE(b != a);
-
- a = b = "foo";
- EXPECT_TRUE(a == b);
- EXPECT_TRUE(b == a);
- EXPECT_FALSE(a != b);
- EXPECT_FALSE(b != a);
-
- a = "bar";
- EXPECT_FALSE(a == b);
- EXPECT_FALSE(b == a);
- EXPECT_TRUE(a != b);
- EXPECT_TRUE(b != a);
-}
-
-TEST(VariantTest, OperatorRelational) {
- variant<int, std::string> a(1), b(1);
- EXPECT_FALSE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_FALSE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_TRUE(b <= a);
- EXPECT_TRUE(a >= b);
- EXPECT_TRUE(b >= a);
-
- b = "str";
- EXPECT_TRUE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_TRUE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_FALSE(b <= a);
- EXPECT_FALSE(a >= b);
- EXPECT_TRUE(b >= a);
-
- b = 0;
- EXPECT_FALSE(a < b);
- EXPECT_TRUE(b < a);
- EXPECT_TRUE(a > b);
- EXPECT_FALSE(b > a);
- EXPECT_FALSE(a <= b);
- EXPECT_TRUE(b <= a);
- EXPECT_TRUE(a >= b);
- EXPECT_FALSE(b >= a);
-
- a = b = "foo";
- EXPECT_FALSE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_FALSE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_TRUE(b <= a);
- EXPECT_TRUE(a >= b);
- EXPECT_TRUE(b >= a);
-
- a = "bar";
- EXPECT_TRUE(a < b);
- EXPECT_FALSE(b < a);
- EXPECT_FALSE(a > b);
- EXPECT_TRUE(b > a);
- EXPECT_TRUE(a <= b);
- EXPECT_FALSE(b <= a);
- EXPECT_FALSE(a >= b);
- EXPECT_TRUE(b >= a);
-}
-
-#ifdef ABSL_HAVE_EXCEPTIONS
-
-TEST(VariantTest, ValuelessOperatorEquals) {
- variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
- valueless(absl::in_place_index<0>),
- other_valueless(absl::in_place_index<0>);
- ToValuelessByException(valueless);
- ToValuelessByException(other_valueless);
-
- EXPECT_TRUE(valueless == other_valueless);
- EXPECT_TRUE(other_valueless == valueless);
- EXPECT_FALSE(valueless == int_v);
- EXPECT_FALSE(valueless == string_v);
- EXPECT_FALSE(int_v == valueless);
- EXPECT_FALSE(string_v == valueless);
-
- EXPECT_FALSE(valueless != other_valueless);
- EXPECT_FALSE(other_valueless != valueless);
- EXPECT_TRUE(valueless != int_v);
- EXPECT_TRUE(valueless != string_v);
- EXPECT_TRUE(int_v != valueless);
- EXPECT_TRUE(string_v != valueless);
-}
-
-TEST(VariantTest, ValuelessOperatorRelational) {
- variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
- valueless(absl::in_place_index<0>),
- other_valueless(absl::in_place_index<0>);
- ToValuelessByException(valueless);
- ToValuelessByException(other_valueless);
-
- EXPECT_FALSE(valueless < other_valueless);
- EXPECT_FALSE(other_valueless < valueless);
- EXPECT_TRUE(valueless < int_v);
- EXPECT_TRUE(valueless < string_v);
- EXPECT_FALSE(int_v < valueless);
- EXPECT_FALSE(string_v < valueless);
-
- EXPECT_TRUE(valueless <= other_valueless);
- EXPECT_TRUE(other_valueless <= valueless);
- EXPECT_TRUE(valueless <= int_v);
- EXPECT_TRUE(valueless <= string_v);
- EXPECT_FALSE(int_v <= valueless);
- EXPECT_FALSE(string_v <= valueless);
-
- EXPECT_TRUE(valueless >= other_valueless);
- EXPECT_TRUE(other_valueless >= valueless);
- EXPECT_FALSE(valueless >= int_v);
- EXPECT_FALSE(valueless >= string_v);
- EXPECT_TRUE(int_v >= valueless);
- EXPECT_TRUE(string_v >= valueless);
-
- EXPECT_FALSE(valueless > other_valueless);
- EXPECT_FALSE(other_valueless > valueless);
- EXPECT_FALSE(valueless > int_v);
- EXPECT_FALSE(valueless > string_v);
- EXPECT_TRUE(int_v > valueless);
- EXPECT_TRUE(string_v > valueless);
-}
-
-#endif
-
-/////////////////////
-// [variant.visit] //
-/////////////////////
-
-template <typename T>
-struct ConvertTo {
- template <typename U>
- T operator()(const U& u) const {
- return u;
- }
-};
-
-TEST(VariantTest, VisitSimple) {
- variant<std::string, const char*> v = "A";
-
- std::string str = absl::visit(ConvertTo<std::string>{}, v);
- EXPECT_EQ("A", str);
-
- v = std::string("B");
-
- absl::string_view piece = absl::visit(ConvertTo<absl::string_view>{}, v);
- EXPECT_EQ("B", piece);
-
- struct StrLen {
- size_t operator()(const char* s) const { return strlen(s); }
- size_t operator()(const std::string& s) const { return s.size(); }
- };
-
- v = "SomeStr";
- EXPECT_EQ(7u, absl::visit(StrLen{}, v));
- v = std::string("VeryLargeThisTime");
- EXPECT_EQ(17u, absl::visit(StrLen{}, v));
-}
-
-TEST(VariantTest, VisitRValue) {
- variant<std::string> v = std::string("X");
- struct Visitor {
- bool operator()(const std::string&) const { return false; }
- bool operator()(std::string&&) const { return true; } // NOLINT
-
- int operator()(const std::string&, const std::string&) const { return 0; }
- int operator()(const std::string&, std::string&&) const {
- return 1;
- } // NOLINT
- int operator()(std::string&&, const std::string&) const {
- return 2;
- } // NOLINT
- int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT
- };
- EXPECT_FALSE(absl::visit(Visitor{}, v));
- EXPECT_TRUE(absl::visit(Visitor{}, std::move(v)));
-
- // Also test the variadic overload.
- EXPECT_EQ(0, absl::visit(Visitor{}, v, v));
- EXPECT_EQ(1, absl::visit(Visitor{}, v, std::move(v)));
- EXPECT_EQ(2, absl::visit(Visitor{}, std::move(v), v));
- EXPECT_EQ(3, absl::visit(Visitor{}, std::move(v), std::move(v)));
-}
-
-TEST(VariantTest, VisitRValueVisitor) {
- variant<std::string> v = std::string("X");
- struct Visitor {
- bool operator()(const std::string&) const& { return false; }
- bool operator()(const std::string&) && { return true; }
- };
- Visitor visitor;
- EXPECT_FALSE(absl::visit(visitor, v));
- EXPECT_TRUE(absl::visit(Visitor{}, v));
-}
-
-TEST(VariantTest, VisitResultTypeDifferent) {
- variant<std::string> v = std::string("X");
- struct LValue_LValue {};
- struct RValue_LValue {};
- struct LValue_RValue {};
- struct RValue_RValue {};
- struct Visitor {
- LValue_LValue operator()(const std::string&) const& { return {}; }
- RValue_LValue operator()(std::string&&) const& { return {}; } // NOLINT
- LValue_RValue operator()(const std::string&) && { return {}; }
- RValue_RValue operator()(std::string&&) && { return {}; } // NOLINT
- } visitor;
-
- EXPECT_TRUE(
- (std::is_same<LValue_LValue, decltype(absl::visit(visitor, v))>::value));
- EXPECT_TRUE(
- (std::is_same<RValue_LValue,
- decltype(absl::visit(visitor, std::move(v)))>::value));
- EXPECT_TRUE((
- std::is_same<LValue_RValue, decltype(absl::visit(Visitor{}, v))>::value));
- EXPECT_TRUE(
- (std::is_same<RValue_RValue,
- decltype(absl::visit(Visitor{}, std::move(v)))>::value));
-}
-
-TEST(VariantTest, VisitVariadic) {
- using A = variant<int, std::string>;
- using B = variant<std::unique_ptr<int>, absl::string_view>;
-
- struct Visitor {
- std::pair<int, int> operator()(int a, std::unique_ptr<int> b) const {
- return {a, *b};
- }
- std::pair<int, int> operator()(absl::string_view a,
- std::unique_ptr<int> b) const {
- return {static_cast<int>(a.size()), static_cast<int>(*b)};
- }
- std::pair<int, int> operator()(int a, absl::string_view b) const {
- return {a, static_cast<int>(b.size())};
- }
- std::pair<int, int> operator()(absl::string_view a,
- absl::string_view b) const {
- return {static_cast<int>(a.size()), static_cast<int>(b.size())};
- }
- };
-
- EXPECT_THAT(absl::visit(Visitor(), A(1), B(std::unique_ptr<int>(new int(7)))),
- ::testing::Pair(1, 7));
- EXPECT_THAT(absl::visit(Visitor(), A(1), B(absl::string_view("ABC"))),
- ::testing::Pair(1, 3));
- EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
- B(std::unique_ptr<int>(new int(7)))),
- ::testing::Pair(5, 7));
- EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
- B(absl::string_view("ABC"))),
- ::testing::Pair(5, 3));
-}
-
-TEST(VariantTest, VisitNoArgs) {
- EXPECT_EQ(5, absl::visit([] { return 5; }));
-}
-
-struct ConstFunctor {
- int operator()(int a, int b) const { return a - b; }
-};
-
-struct MutableFunctor {
- int operator()(int a, int b) { return a - b; }
-};
-
-struct Class {
- int Method(int a, int b) { return a - b; }
- int ConstMethod(int a, int b) const { return a - b; }
-
- int member;
-};
-
-TEST(VariantTest, VisitReferenceWrapper) {
- ConstFunctor cf;
- MutableFunctor mf;
- absl::variant<int> three = 3;
- absl::variant<int> two = 2;
-
- EXPECT_EQ(1, absl::visit(std::cref(cf), three, two));
- EXPECT_EQ(1, absl::visit(std::ref(cf), three, two));
- EXPECT_EQ(1, absl::visit(std::ref(mf), three, two));
-}
-
-// libstdc++ std::variant doesn't support the INVOKE semantics.
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-TEST(VariantTest, VisitMemberFunction) {
- absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>());
- absl::variant<std::unique_ptr<const Class>> cp(
- absl::make_unique<const Class>());
- absl::variant<int> three = 3;
- absl::variant<int> two = 2;
-
- EXPECT_EQ(1, absl::visit(&Class::Method, p, three, two));
- EXPECT_EQ(1, absl::visit(&Class::ConstMethod, p, three, two));
- EXPECT_EQ(1, absl::visit(&Class::ConstMethod, cp, three, two));
-}
-
-TEST(VariantTest, VisitDataMember) {
- absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>(Class{42}));
- absl::variant<std::unique_ptr<const Class>> cp(
- absl::make_unique<const Class>(Class{42}));
- EXPECT_EQ(42, absl::visit(&Class::member, p));
-
- absl::visit(&Class::member, p) = 5;
- EXPECT_EQ(5, absl::visit(&Class::member, p));
-
- EXPECT_EQ(42, absl::visit(&Class::member, cp));
-}
-#endif // !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-
-/////////////////////////
-// [variant.monostate] //
-/////////////////////////
-
-TEST(VariantTest, MonostateBasic) {
- absl::monostate mono;
- (void)mono;
-
- // TODO(mattcalabrese) Expose move triviality metafunctions in absl.
- EXPECT_TRUE(absl::is_trivially_default_constructible<absl::monostate>::value);
- EXPECT_TRUE(is_trivially_move_constructible<absl::monostate>::value);
- EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::monostate>::value);
- EXPECT_TRUE(is_trivially_move_assignable<absl::monostate>::value);
- EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::monostate>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<absl::monostate>::value);
-}
-
-TEST(VariantTest, VariantMonostateDefaultConstruction) {
- absl::variant<absl::monostate, NonDefaultConstructible> var;
- EXPECT_EQ(var.index(), 0u);
-}
-
-////////////////////////////////
-// [variant.monostate.relops] //
-////////////////////////////////
-
-TEST(VariantTest, MonostateComparisons) {
- absl::monostate lhs, rhs;
-
- EXPECT_EQ(lhs, lhs);
- EXPECT_EQ(lhs, rhs);
-
- EXPECT_FALSE(lhs != lhs);
- EXPECT_FALSE(lhs != rhs);
- EXPECT_FALSE(lhs < lhs);
- EXPECT_FALSE(lhs < rhs);
- EXPECT_FALSE(lhs > lhs);
- EXPECT_FALSE(lhs > rhs);
-
- EXPECT_LE(lhs, lhs);
- EXPECT_LE(lhs, rhs);
- EXPECT_GE(lhs, lhs);
- EXPECT_GE(lhs, rhs);
-
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() ==
- std::declval<absl::monostate>()));
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() !=
- std::declval<absl::monostate>()));
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <
- std::declval<absl::monostate>()));
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >
- std::declval<absl::monostate>()));
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <=
- std::declval<absl::monostate>()));
- EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >=
- std::declval<absl::monostate>()));
-}
-
-///////////////////////
-// [variant.specalg] //
-///////////////////////
-
-TEST(VariantTest, NonmemberSwap) {
- using std::swap;
-
- SpecialSwap v1(3);
- SpecialSwap v2(7);
-
- variant<SpecialSwap> a = v1, b = v2;
-
- EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
- EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
-
- std::swap(a, b);
- EXPECT_THAT(a, VariantWith<SpecialSwap>(v2));
- EXPECT_THAT(b, VariantWith<SpecialSwap>(v1));
-#ifndef ABSL_USES_STD_VARIANT
- EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap);
-#endif
-
- swap(a, b);
- EXPECT_THAT(a, VariantWith<SpecialSwap>(v1));
- EXPECT_THAT(b, VariantWith<SpecialSwap>(v2));
- EXPECT_TRUE(absl::get<SpecialSwap>(b).special_swap);
-}
-
-//////////////////////////
-// [variant.bad.access] //
-//////////////////////////
-
-TEST(VariantTest, BadAccess) {
- EXPECT_TRUE(noexcept(absl::bad_variant_access()));
- absl::bad_variant_access exception_obj;
- std::exception* base = &exception_obj;
- (void)base;
-}
-
-////////////////////
-// [variant.hash] //
-////////////////////
-
-TEST(VariantTest, MonostateHash) {
- absl::monostate mono, other_mono;
- std::hash<absl::monostate> const hasher{};
- static_assert(std::is_same<decltype(hasher(mono)), std::size_t>::value, "");
- EXPECT_EQ(hasher(mono), hasher(other_mono));
-}
-
-TEST(VariantTest, Hash) {
- static_assert(type_traits_internal::IsHashable<variant<int>>::value, "");
- static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, "");
- static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value,
- "");
-
-#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
- static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value,
- "");
- static_assert(
- !type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value,
- "");
-#endif
-
-// MSVC std::hash<std::variant> does not use the index, thus produce the same
-// result on the same value as different alternative.
-#if !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT))
- {
- // same value as different alternative
- variant<int, int> v0(in_place_index<0>, 42);
- variant<int, int> v1(in_place_index<1>, 42);
- std::hash<variant<int, int>> hash;
- EXPECT_NE(hash(v0), hash(v1));
- }
-#endif // !(defined(_MSC_VER) && defined(ABSL_USES_STD_VARIANT))
-
- {
- std::hash<variant<int>> hash;
- std::set<size_t> hashcodes;
- for (int i = 0; i < 100; ++i) {
- hashcodes.insert(hash(i));
- }
- EXPECT_GT(hashcodes.size(), 90u);
-
- // test const-qualified
- static_assert(type_traits_internal::IsHashable<variant<const int>>::value,
- "");
- static_assert(
- type_traits_internal::IsHashable<variant<const Hashable>>::value, "");
- std::hash<absl::variant<const int>> c_hash;
- for (int i = 0; i < 100; ++i) {
- EXPECT_EQ(hash(i), c_hash(i));
- }
- }
-}
-
-////////////////////////////////////////
-// Miscellaneous and deprecated tests //
-////////////////////////////////////////
-
-// Test that a set requiring a basic type conversion works correctly
-#if !defined(ABSL_USES_STD_VARIANT)
-TEST(VariantTest, TestConvertingSet) {
- typedef variant<double> Variant;
- Variant v(1.0);
- const int two = 2;
- v = two;
- EXPECT_TRUE(absl::holds_alternative<double>(v));
- ASSERT_TRUE(nullptr != absl::get_if<double>(&v));
- EXPECT_DOUBLE_EQ(2, absl::get<double>(v));
-}
-#endif // ABSL_USES_STD_VARIANT
-
-// Test that a vector of variants behaves reasonably.
-TEST(VariantTest, Container) {
- typedef variant<int, float> Variant;
-
- // Creation of vector should work
- std::vector<Variant> vec;
- vec.push_back(Variant(10));
- vec.push_back(Variant(20.0f));
-
- // Vector resizing should work if we supply a value for new slots
- vec.resize(10, Variant(0));
-}
-
-// Test that a variant with a non-copyable type can be constructed and
-// manipulated to some degree.
-TEST(VariantTest, TestVariantWithNonCopyableType) {
- typedef variant<int, NonCopyable> Variant;
- const int kValue = 1;
- Variant v(kValue);
- ASSERT_TRUE(absl::holds_alternative<int>(v));
- EXPECT_EQ(kValue, absl::get<int>(v));
-}
-
-// Test that a variant with a non-copyable type can be transformed to
-// the non-copyable type with a call to `emplace` for different numbers
-// of arguments. We do not need to test this for each of T1 ... T8
-// because `emplace` does not overload on T1 ... to T8, so if this
-// works for any one of T1 ... T8, then it works for all of them. We
-// do need to test that it works with varying numbers of parameters
-// though.
-TEST(VariantTest, TestEmplace) {
- typedef variant<int, NonCopyable> Variant;
- const int kValue = 1;
- Variant v(kValue);
- ASSERT_TRUE(absl::holds_alternative<int>(v));
- EXPECT_EQ(kValue, absl::get<int>(v));
-
- // emplace with zero arguments, then back to 'int'
- v.emplace<NonCopyable>();
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(0, absl::get<NonCopyable>(v).value);
- v = kValue;
- ASSERT_TRUE(absl::holds_alternative<int>(v));
-
- // emplace with one argument:
- v.emplace<NonCopyable>(1);
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(1, absl::get<NonCopyable>(v).value);
- v = kValue;
- ASSERT_TRUE(absl::holds_alternative<int>(v));
-
- // emplace with two arguments:
- v.emplace<NonCopyable>(1, 2);
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(3, absl::get<NonCopyable>(v).value);
- v = kValue;
- ASSERT_TRUE(absl::holds_alternative<int>(v));
-
- // emplace with three arguments
- v.emplace<NonCopyable>(1, 2, 3);
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(6, absl::get<NonCopyable>(v).value);
- v = kValue;
- ASSERT_TRUE(absl::holds_alternative<int>(v));
-
- // emplace with four arguments
- v.emplace<NonCopyable>(1, 2, 3, 4);
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(10, absl::get<NonCopyable>(v).value);
- v = kValue;
- ASSERT_TRUE(absl::holds_alternative<int>(v));
-}
-
-TEST(VariantTest, TestEmplaceDestroysCurrentValue) {
- typedef variant<int, IncrementInDtor, NonCopyable> Variant;
- int counter = 0;
- Variant v(0);
- ASSERT_TRUE(absl::holds_alternative<int>(v));
- v.emplace<IncrementInDtor>(&counter);
- ASSERT_TRUE(absl::holds_alternative<IncrementInDtor>(v));
- ASSERT_EQ(0, counter);
- v.emplace<NonCopyable>();
- ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v));
- EXPECT_EQ(1, counter);
-}
-
-TEST(VariantTest, TestMoveSemantics) {
- typedef variant<std::unique_ptr<int>, std::unique_ptr<std::string>> Variant;
-
- // Construct a variant by moving from an element value.
- Variant v(absl::WrapUnique(new int(10)));
- EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
-
- // Construct a variant by moving from another variant.
- Variant v2(std::move(v));
- ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v2));
- ASSERT_NE(nullptr, absl::get<std::unique_ptr<int>>(v2));
- EXPECT_EQ(10, *absl::get<std::unique_ptr<int>>(v2));
-
- // Moving from a variant object leaves it holding moved-from value of the
- // same element type.
- EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v));
- ASSERT_NE(nullptr, absl::get_if<std::unique_ptr<int>>(&v));
- EXPECT_EQ(nullptr, absl::get<std::unique_ptr<int>>(v));
-
- // Assign a variant from an element value by move.
- v = absl::make_unique<std::string>("foo");
- ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
- EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v));
-
- // Move-assign a variant.
- v2 = std::move(v);
- ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v2));
- EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v2));
- EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v));
-}
-
-variant<int, std::string> PassThrough(const variant<int, std::string>& arg) {
- return arg;
-}
-
-TEST(VariantTest, TestImplicitConversion) {
- EXPECT_TRUE(absl::holds_alternative<int>(PassThrough(0)));
-
- // We still need the explicit cast for std::string, because C++ won't apply
- // two user-defined implicit conversions in a row.
- EXPECT_TRUE(
- absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
-}
-
struct Convertible2;
struct Convertible1 {
Convertible1() {}
@@ -2281,116 +48,41 @@
};
TEST(VariantTest, TestRvalueConversion) {
-#if !defined(ABSL_USES_STD_VARIANT)
- variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(
- variant<std::string, int>(0)));
- ASSERT_TRUE(absl::holds_alternative<double>(var));
- EXPECT_EQ(0.0, absl::get<double>(var));
+ std::variant<Convertible1, Convertible2> v(
+ ConvertVariantTo<std::variant<Convertible1, Convertible2>>(
+ (std::variant<Convertible2, Convertible1>(Convertible1()))));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(v));
- var = ConvertVariantTo<variant<double, std::string>>(
- variant<const char*, float>("foo"));
- ASSERT_TRUE(absl::holds_alternative<std::string>(var));
- EXPECT_EQ("foo", absl::get<std::string>(var));
-
- variant<double> singleton(
- ConvertVariantTo<variant<double>>(variant<int, float>(42)));
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_EQ(42.0, absl::get<double>(singleton));
-
- singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
-
- singleton = ConvertVariantTo<variant<double>>(variant<int>(0));
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_EQ(0.0, absl::get<double>(singleton));
-
- variant<int32_t, uint32_t> variant2(
- ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
- ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
- EXPECT_EQ(42, absl::get<int32_t>(variant2));
-
- variant2 =
- ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42u));
- ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
- EXPECT_EQ(42u, absl::get<uint32_t>(variant2));
-#endif // !ABSL_USES_STD_VARIANT
-
- variant<Convertible1, Convertible2> variant3(
- ConvertVariantTo<variant<Convertible1, Convertible2>>(
- (variant<Convertible2, Convertible1>(Convertible1()))));
- ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
-
- variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
- variant<Convertible2, Convertible1>(Convertible2()));
- ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+ v = ConvertVariantTo<std::variant<Convertible1, Convertible2>>(
+ std::variant<Convertible2, Convertible1>(Convertible2()));
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(v));
}
TEST(VariantTest, TestLvalueConversion) {
-#if !defined(ABSL_USES_STD_VARIANT)
- variant<std::string, int> source1 = 0;
- variant<double, std::string> destination(
- ConvertVariantTo<variant<double, std::string>>(source1));
- ASSERT_TRUE(absl::holds_alternative<double>(destination));
- EXPECT_EQ(0.0, absl::get<double>(destination));
+ std::variant<Convertible2, Convertible1> source((Convertible1()));
+ std::variant<Convertible1, Convertible2> v(
+ ConvertVariantTo<std::variant<Convertible1, Convertible2>>(source));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(v));
- variant<const char*, float> source2 = "foo";
- destination = ConvertVariantTo<variant<double, std::string>>(source2);
- ASSERT_TRUE(absl::holds_alternative<std::string>(destination));
- EXPECT_EQ("foo", absl::get<std::string>(destination));
-
- variant<int, float> source3(42);
- variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_EQ(42.0, absl::get<double>(singleton));
-
- source3 = 3.14f;
- singleton = ConvertVariantTo<variant<double>>(source3);
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
-
- variant<int> source4(0);
- singleton = ConvertVariantTo<variant<double>>(source4);
- ASSERT_TRUE(absl::holds_alternative<double>(singleton));
- EXPECT_EQ(0.0, absl::get<double>(singleton));
-
- variant<int32_t> source5(42);
- variant<int32_t, uint32_t> variant2(
- ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
- ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
- EXPECT_EQ(42, absl::get<int32_t>(variant2));
-
- variant<uint32_t> source6(42u);
- variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
- ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
- EXPECT_EQ(42u, absl::get<uint32_t>(variant2));
-#endif
-
- variant<Convertible2, Convertible1> source7((Convertible1()));
- variant<Convertible1, Convertible2> variant3(
- ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
- ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
-
- source7 = Convertible2();
- variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
- ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+ source = Convertible2();
+ v = ConvertVariantTo<std::variant<Convertible1, Convertible2>>(source);
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(v));
}
TEST(VariantTest, TestMoveConversion) {
- using Variant =
- variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+ using Variant = std::variant<std::unique_ptr<const int>,
+ std::unique_ptr<const std::string>>;
using OtherVariant =
- variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ std::variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
- ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)}));
+ ConvertVariantTo<Variant>(OtherVariant{std::make_unique<int>(0)}));
ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const int>>(var));
ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr);
EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var));
var = ConvertVariantTo<Variant>(
- OtherVariant(absl::make_unique<std::string>("foo")));
+ OtherVariant(std::make_unique<std::string>("foo")));
ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var));
EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var));
}
@@ -2399,10 +91,10 @@
// We use shared_ptr here because it's both copyable and movable, and
// a moved-from shared_ptr is guaranteed to be null, so we can detect
// whether moving or copying has occurred.
- using Variant =
- variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>;
+ using Variant = std::variant<std::shared_ptr<const int>,
+ std::shared_ptr<const std::string>>;
using OtherVariant =
- variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
+ std::variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
Variant v1(std::make_shared<const int>(0));
@@ -2430,289 +122,43 @@
}
TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
-#if !defined(ABSL_USES_STD_VARIANT)
- variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(
- variant<std::string, int>(3)));
- EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0));
+ variant<Convertible1, Convertible2> v(
+ ConvertVariantTo<std::variant<Convertible1, Convertible2>>(
+ (std::variant<Convertible2, Convertible1>(Convertible1()))));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(v));
- var = ConvertVariantTo<variant<double, std::string>>(
- variant<const char*, float>("foo"));
- EXPECT_THAT(absl::get_if<std::string>(&var), Pointee(std::string("foo")));
-
- variant<double> singleton(
- ConvertVariantTo<variant<double>>(variant<int, float>(42)));
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
-
- singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f));
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
-
- singleton = ConvertVariantTo<variant<double>>(variant<int>(3));
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
-
- variant<int32_t, uint32_t> variant2(
- ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
- EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
-
- variant2 =
- ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42u));
- EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42u));
-#endif
-
- variant<Convertible1, Convertible2> variant3(
- ConvertVariantTo<variant<Convertible1, Convertible2>>(
- (variant<Convertible2, Convertible1>(Convertible1()))));
- ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
-
- variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(
- variant<Convertible2, Convertible1>(Convertible2()));
- ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+ v = ConvertVariantTo<std::variant<Convertible1, Convertible2>>(
+ std::variant<Convertible2, Convertible1>(Convertible2()));
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(v));
}
TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
-#if !defined(ABSL_USES_STD_VARIANT)
- variant<std::string, int> source1 = 3;
- variant<double, std::string> destination(
- ConvertVariantTo<variant<double, std::string>>(source1));
- EXPECT_THAT(absl::get_if<double>(&destination), Pointee(3.0));
+ variant<Convertible2, Convertible1> source((Convertible1()));
+ variant<Convertible1, Convertible2> v(
+ ConvertVariantTo<std::variant<Convertible1, Convertible2>>(source));
+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(v));
- variant<const char*, float> source2 = "foo";
- destination = ConvertVariantTo<variant<double, std::string>>(source2);
- EXPECT_THAT(absl::get_if<std::string>(&destination),
- Pointee(std::string("foo")));
-
- variant<int, float> source3(42);
- variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0));
-
- source3 = 3.14f;
- singleton = ConvertVariantTo<variant<double>>(source3);
- EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton)));
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f)));
-
- variant<int> source4(3);
- singleton = ConvertVariantTo<variant<double>>(source4);
- EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0));
-
- variant<int32_t> source5(42);
- variant<int32_t, uint32_t> variant2(
- ConvertVariantTo<variant<int32_t, uint32_t>>(source5));
- EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
-
- variant<uint32_t> source6(42u);
- variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
- EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42u));
-#endif // !ABSL_USES_STD_VARIANT
-
- variant<Convertible2, Convertible1> source7((Convertible1()));
- variant<Convertible1, Convertible2> variant3(
- ConvertVariantTo<variant<Convertible1, Convertible2>>(source7));
- ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3));
-
- source7 = Convertible2();
- variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7);
- ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3));
+ source = Convertible2();
+ v = ConvertVariantTo<std::variant<Convertible1, Convertible2>>(source);
+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(v));
}
TEST(VariantTest, TestMoveConversionViaConvertVariantTo) {
- using Variant =
- variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
+ using Variant = std::variant<std::unique_ptr<const int>,
+ std::unique_ptr<const std::string>>;
using OtherVariant =
- variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ std::variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
- ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)}));
+ ConvertVariantTo<Variant>(OtherVariant{std::make_unique<int>(3)}));
EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var),
Pointee(Pointee(3)));
var = ConvertVariantTo<Variant>(
- OtherVariant(absl::make_unique<std::string>("foo")));
+ OtherVariant(std::make_unique<std::string>("foo")));
EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var),
Pointee(Pointee(std::string("foo"))));
}
-// If all alternatives are trivially copy/move constructible, variant should
-// also be trivially copy/move constructible. This is not required by the
-// standard and we know that libstdc++ variant doesn't have this feature.
-// For more details see the paper:
-// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html
-#if !(defined(ABSL_USES_STD_VARIANT) && defined(__GLIBCXX__))
-#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1
-#endif
-
-TEST(VariantTest, TestCopyAndMoveTypeTraits) {
- EXPECT_TRUE(std::is_copy_constructible<variant<std::string>>::value);
- EXPECT_TRUE(absl::is_copy_assignable<variant<std::string>>::value);
- EXPECT_TRUE(std::is_move_constructible<variant<std::string>>::value);
- EXPECT_TRUE(absl::is_move_assignable<variant<std::string>>::value);
- EXPECT_TRUE(std::is_move_constructible<variant<std::unique_ptr<int>>>::value);
- EXPECT_TRUE(absl::is_move_assignable<variant<std::unique_ptr<int>>>::value);
- EXPECT_FALSE(
- std::is_copy_constructible<variant<std::unique_ptr<int>>>::value);
- EXPECT_FALSE(absl::is_copy_assignable<variant<std::unique_ptr<int>>>::value);
-
- EXPECT_FALSE(
- absl::is_trivially_copy_constructible<variant<std::string>>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<variant<std::string>>::value);
-#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
- EXPECT_TRUE(absl::is_trivially_copy_constructible<variant<int>>::value);
- EXPECT_TRUE(absl::is_trivially_copy_assignable<variant<int>>::value);
- EXPECT_TRUE(is_trivially_move_constructible<variant<int>>::value);
- EXPECT_TRUE(is_trivially_move_assignable<variant<int>>::value);
-#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
-}
-
-TEST(VariantTest, TestVectorOfMoveonlyVariant) {
- // Verify that variant<MoveonlyType> works correctly as a std::vector element.
- std::vector<variant<std::unique_ptr<int>, std::string>> vec;
- vec.push_back(absl::make_unique<int>(42));
- vec.emplace_back("Hello");
- vec.reserve(3);
- auto another_vec = std::move(vec);
- // As a sanity check, verify vector contents.
- ASSERT_EQ(2u, another_vec.size());
- EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0]));
- EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1]));
-}
-
-TEST(VariantTest, NestedVariant) {
-#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
- static_assert(absl::is_trivially_copy_constructible<variant<int>>(), "");
- static_assert(absl::is_trivially_copy_assignable<variant<int>>(), "");
- static_assert(is_trivially_move_constructible<variant<int>>(), "");
- static_assert(is_trivially_move_assignable<variant<int>>(), "");
-
- static_assert(absl::is_trivially_copy_constructible<variant<variant<int>>>(),
- "");
- static_assert(absl::is_trivially_copy_assignable<variant<variant<int>>>(),
- "");
- static_assert(is_trivially_move_constructible<variant<variant<int>>>(), "");
- static_assert(is_trivially_move_assignable<variant<variant<int>>>(), "");
-#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
-
- variant<int> x(42);
- variant<variant<int>> y(x);
- variant<variant<int>> z(y);
- EXPECT_TRUE(absl::holds_alternative<variant<int>>(z));
- EXPECT_EQ(x, absl::get<variant<int>>(z));
-}
-
-struct TriviallyDestructible {
- TriviallyDestructible(TriviallyDestructible&&) {}
- TriviallyDestructible(const TriviallyDestructible&) {}
- TriviallyDestructible& operator=(TriviallyDestructible&&) { return *this; }
- TriviallyDestructible& operator=(const TriviallyDestructible&) {
- return *this;
- }
-};
-
-struct TriviallyMovable {
- TriviallyMovable(TriviallyMovable&&) = default;
- TriviallyMovable(TriviallyMovable const&) {}
- TriviallyMovable& operator=(const TriviallyMovable&) { return *this; }
-};
-
-struct TriviallyCopyable {
- TriviallyCopyable(const TriviallyCopyable&) = default;
- TriviallyCopyable& operator=(const TriviallyCopyable&) { return *this; }
-};
-
-struct TriviallyMoveAssignable {
- TriviallyMoveAssignable(TriviallyMoveAssignable&&) = default;
- TriviallyMoveAssignable(const TriviallyMoveAssignable&) {}
- TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default;
- TriviallyMoveAssignable& operator=(const TriviallyMoveAssignable&) {
- return *this;
- }
-};
-
-struct TriviallyCopyAssignable {};
-
-#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
-TEST(VariantTest, TestTriviality) {
- {
- using TrivDestVar = absl::variant<TriviallyDestructible>;
-
- EXPECT_FALSE(is_trivially_move_constructible<TrivDestVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivDestVar>::value);
- EXPECT_FALSE(is_trivially_move_assignable<TrivDestVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivDestVar>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<TrivDestVar>::value);
- }
-
- {
- using TrivMoveVar = absl::variant<TriviallyMovable>;
-
- EXPECT_TRUE(is_trivially_move_constructible<TrivMoveVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivMoveVar>::value);
- EXPECT_FALSE(is_trivially_move_assignable<TrivMoveVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveVar>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveVar>::value);
- }
-
- {
- using TrivCopyVar = absl::variant<TriviallyCopyable>;
-
- EXPECT_TRUE(is_trivially_move_constructible<TrivCopyVar>::value);
- EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivCopyVar>::value);
- EXPECT_FALSE(is_trivially_move_assignable<TrivCopyVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivCopyVar>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyVar>::value);
- }
-
- {
- using TrivMoveAssignVar = absl::variant<TriviallyMoveAssignable>;
-
- EXPECT_TRUE(is_trivially_move_constructible<TrivMoveAssignVar>::value);
- EXPECT_FALSE(
- absl::is_trivially_copy_constructible<TrivMoveAssignVar>::value);
- EXPECT_TRUE(is_trivially_move_assignable<TrivMoveAssignVar>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveAssignVar>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveAssignVar>::value);
- }
-
- {
- using TrivCopyAssignVar = absl::variant<TriviallyCopyAssignable>;
-
- EXPECT_TRUE(is_trivially_move_constructible<TrivCopyAssignVar>::value);
- EXPECT_TRUE(
- absl::is_trivially_copy_constructible<TrivCopyAssignVar>::value);
- EXPECT_TRUE(is_trivially_move_assignable<TrivCopyAssignVar>::value);
- EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivCopyAssignVar>::value);
- EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyAssignVar>::value);
- }
-}
-#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY
-
-// To verify that absl::variant correctly use the nontrivial move ctor of its
-// member rather than use the trivial copy constructor.
-TEST(VariantTest, MoveCtorBug) {
- // To simulate std::tuple in libstdc++.
- struct TrivialCopyNontrivialMove {
- TrivialCopyNontrivialMove() = default;
- TrivialCopyNontrivialMove(const TrivialCopyNontrivialMove&) = default;
- TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) { called = true; }
- bool called = false;
- };
- {
- using V = absl::variant<TrivialCopyNontrivialMove, int>;
- V v1(absl::in_place_index<0>);
- // this should invoke the move ctor, rather than the trivial copy ctor.
- V v2(std::move(v1));
- EXPECT_TRUE(absl::get<0>(v2).called);
- }
- {
- // this case failed to compile before our fix due to a GCC bug.
- using V = absl::variant<int, TrivialCopyNontrivialMove>;
- V v1(absl::in_place_index<1>);
- // this should invoke the move ctor, rather than the trivial copy ctor.
- V v2(std::move(v1));
- EXPECT_TRUE(absl::get<1>(v2).called);
- }
-}
-
} // namespace
-ABSL_NAMESPACE_END
} // namespace absl
-
-#endif // #if !defined(ABSL_USES_STD_VARIANT)
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
index 1c01fc1..773f949 100644
--- a/absl/utility/BUILD.bazel
+++ b/absl/utility/BUILD.bazel
@@ -18,7 +18,6 @@
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_DEFAULT_LINKOPTS",
- "ABSL_TEST_COPTS",
)
package(
@@ -40,47 +39,7 @@
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- "//absl/base:base_internal",
"//absl/base:config",
"//absl/meta:type_traits",
],
)
-
-cc_test(
- name = "utility_test",
- srcs = ["utility_test.cc"],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":utility",
- "//absl/base:core_headers",
- "//absl/memory",
- "//absl/strings",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
-
-cc_library(
- name = "if_constexpr",
- hdrs = [
- "internal/if_constexpr.h",
- ],
- copts = ABSL_DEFAULT_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- "//absl/base:config",
- ],
-)
-
-cc_test(
- name = "if_constexpr_test",
- srcs = ["internal/if_constexpr_test.cc"],
- copts = ABSL_TEST_COPTS,
- linkopts = ABSL_DEFAULT_LINKOPTS,
- deps = [
- ":if_constexpr",
- "@com_google_googletest//:gtest",
- "@com_google_googletest//:gtest_main",
- ],
-)
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt
index 27ee0de..8ac87bc 100644
--- a/absl/utility/CMakeLists.txt
+++ b/absl/utility/CMakeLists.txt
@@ -22,47 +22,7 @@
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
- absl::base_internal
absl::config
absl::type_traits
PUBLIC
)
-
-absl_cc_test(
- NAME
- utility_test
- SRCS
- "utility_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::utility
- absl::core_headers
- absl::memory
- absl::strings
- GTest::gmock_main
-)
-
-absl_cc_library(
- NAME
- if_constexpr
- HDRS
- "internal/if_constexpr.h"
- COPTS
- ${ABSL_DEFAULT_COPTS}
- DEPS
- absl::config
- PUBLIC
-)
-
-absl_cc_test(
- NAME
- if_constexpr_test
- SRCS
- "internal/if_constexpr_test.cc"
- COPTS
- ${ABSL_TEST_COPTS}
- DEPS
- absl::if_constexpr
- GTest::gmock_main
-)
diff --git a/absl/utility/internal/if_constexpr.h b/absl/utility/internal/if_constexpr.h
deleted file mode 100644
index 7a26311..0000000
--- a/absl/utility/internal/if_constexpr.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2023 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The IfConstexpr and IfConstexprElse utilities in this file are meant to be
-// used to emulate `if constexpr` in pre-C++17 mode in library implementation.
-// The motivation is to allow for avoiding complex SFINAE.
-//
-// The functions passed in must depend on the type(s) of the object(s) that
-// require SFINAE. For example:
-// template<typename T>
-// int MaybeFoo(T& t) {
-// if constexpr (HasFoo<T>::value) return t.foo();
-// return 0;
-// }
-//
-// can be written in pre-C++17 as:
-//
-// template<typename T>
-// int MaybeFoo(T& t) {
-// int i = 0;
-// absl::utility_internal::IfConstexpr<HasFoo<T>::value>(
-// [&](const auto& fooer) { i = fooer.foo(); }, t);
-// return i;
-// }
-
-#ifndef ABSL_UTILITY_INTERNAL_IF_CONSTEXPR_H_
-#define ABSL_UTILITY_INTERNAL_IF_CONSTEXPR_H_
-
-#include <tuple>
-#include <utility>
-
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-
-namespace utility_internal {
-
-template <bool condition, typename TrueFunc, typename FalseFunc,
- typename... Args>
-auto IfConstexprElse(TrueFunc&& true_func, FalseFunc&& false_func,
- Args&&... args) {
- return std::get<condition>(std::forward_as_tuple(
- std::forward<FalseFunc>(false_func), std::forward<TrueFunc>(true_func)))(
- std::forward<Args>(args)...);
-}
-
-template <bool condition, typename Func, typename... Args>
-void IfConstexpr(Func&& func, Args&&... args) {
- IfConstexprElse<condition>(std::forward<Func>(func), [](auto&&...){},
- std::forward<Args>(args)...);
-}
-
-} // namespace utility_internal
-
-ABSL_NAMESPACE_END
-} // namespace absl
-
-#endif // ABSL_UTILITY_INTERNAL_IF_CONSTEXPR_H_
diff --git a/absl/utility/internal/if_constexpr_test.cc b/absl/utility/internal/if_constexpr_test.cc
deleted file mode 100644
index d1ee723..0000000
--- a/absl/utility/internal/if_constexpr_test.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2023 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/utility/internal/if_constexpr.h"
-
-#include <utility>
-
-#include "gtest/gtest.h"
-
-namespace {
-
-struct Empty {};
-struct HasFoo {
- int foo() const { return 1; }
-};
-
-TEST(IfConstexpr, Basic) {
- int i = 0;
- absl::utility_internal::IfConstexpr<false>(
- [&](const auto& t) { i = t.foo(); }, Empty{});
- EXPECT_EQ(i, 0);
-
- absl::utility_internal::IfConstexpr<false>(
- [&](const auto& t) { i = t.foo(); }, HasFoo{});
- EXPECT_EQ(i, 0);
-
- absl::utility_internal::IfConstexpr<true>(
- [&](const auto& t) { i = t.foo(); }, HasFoo{});
- EXPECT_EQ(i, 1);
-}
-
-TEST(IfConstexprElse, Basic) {
- EXPECT_EQ(absl::utility_internal::IfConstexprElse<false>(
- [&](const auto& t) { return t.foo(); }, [&](const auto&) { return 2; },
- Empty{}), 2);
-
- EXPECT_EQ(absl::utility_internal::IfConstexprElse<false>(
- [&](const auto& t) { return t.foo(); }, [&](const auto&) { return 2; },
- HasFoo{}), 2);
-
- EXPECT_EQ(absl::utility_internal::IfConstexprElse<true>(
- [&](const auto& t) { return t.foo(); }, [&](const auto&) { return 2; },
- HasFoo{}), 1);
-}
-
-struct HasFooRValue {
- int foo() && { return 1; }
-};
-struct RValueFunc {
- void operator()(HasFooRValue&& t) && { *i = std::move(t).foo(); }
-
- int* i = nullptr;
-};
-
-TEST(IfConstexpr, RValues) {
- int i = 0;
- RValueFunc func = {&i};
- absl::utility_internal::IfConstexpr<false>(
- std::move(func), HasFooRValue{});
- EXPECT_EQ(i, 0);
-
- func = RValueFunc{&i};
- absl::utility_internal::IfConstexpr<true>(
- std::move(func), HasFooRValue{});
- EXPECT_EQ(i, 1);
-}
-
-} // namespace
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index ebbb49b..4637b03 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -11,25 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
-// This header file contains C++14 versions of standard <utility> header
-// abstractions available within C++17, and are designed to be drop-in
-// replacement for code compliant with C++14 and C++17.
-//
-// The following abstractions are defined:
-//
-// * apply<Functor, Tuple> == std::apply<Functor, Tuple>
-// * exchange<T> == std::exchange<T>
-// * make_from_tuple<T> == std::make_from_tuple<T>
-//
-// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
-// and `in_place_index_t`, as well as the constant `in_place`, and
-// `constexpr` `std::move()` and `std::forward()` implementations in C++11.
-//
-// References:
-//
-// https://en.cppreference.com/w/cpp/utility/apply
-// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html
#ifndef ABSL_UTILITY_UTILITY_H_
#define ABSL_UTILITY_UTILITY_H_
@@ -40,8 +21,8 @@
#include <utility>
#include "absl/base/config.h"
-#include "absl/base/internal/inline_variable.h"
-#include "absl/base/internal/invoke.h"
+
+// TODO(b/290784225): Include what you use cleanup required.
#include "absl/meta/type_traits.h"
namespace absl {
@@ -51,179 +32,23 @@
// abstractions for platforms that had not yet provided them. Those
// platforms are no longer supported. New code should simply use the
// the ones from std directly.
+using std::apply;
using std::exchange;
using std::forward;
+using std::in_place;
+using std::in_place_index;
+using std::in_place_index_t;
+using std::in_place_t;
+using std::in_place_type;
+using std::in_place_type_t;
using std::index_sequence;
using std::index_sequence_for;
using std::integer_sequence;
+using std::make_from_tuple;
using std::make_index_sequence;
using std::make_integer_sequence;
using std::move;
-namespace utility_internal {
-
-template <typename T>
-struct InPlaceTypeTag {
- explicit InPlaceTypeTag() = delete;
- InPlaceTypeTag(const InPlaceTypeTag&) = delete;
- InPlaceTypeTag& operator=(const InPlaceTypeTag&) = delete;
-};
-
-template <size_t I>
-struct InPlaceIndexTag {
- explicit InPlaceIndexTag() = delete;
- InPlaceIndexTag(const InPlaceIndexTag&) = delete;
- InPlaceIndexTag& operator=(const InPlaceIndexTag&) = delete;
-};
-
-} // namespace utility_internal
-
-// Tag types
-
-#ifdef ABSL_USES_STD_OPTIONAL
-
-using std::in_place_t;
-using std::in_place;
-
-#else // ABSL_USES_STD_OPTIONAL
-
-// in_place_t
-//
-// Tag type used to specify in-place construction, such as with
-// `absl::optional`, designed to be a drop-in replacement for C++17's
-// `std::in_place_t`.
-struct in_place_t {};
-
-ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
-
-#endif // ABSL_USES_STD_OPTIONAL
-
-#if defined(ABSL_USES_STD_ANY) || defined(ABSL_USES_STD_VARIANT)
-using std::in_place_type;
-using std::in_place_type_t;
-#else
-
-// in_place_type_t
-//
-// Tag type used for in-place construction when the type to construct needs to
-// be specified, such as with `absl::any`, designed to be a drop-in replacement
-// for C++17's `std::in_place_type_t`.
-template <typename T>
-using in_place_type_t = void (*)(utility_internal::InPlaceTypeTag<T>);
-
-template <typename T>
-void in_place_type(utility_internal::InPlaceTypeTag<T>) {}
-#endif // ABSL_USES_STD_ANY || ABSL_USES_STD_VARIANT
-
-#ifdef ABSL_USES_STD_VARIANT
-using std::in_place_index;
-using std::in_place_index_t;
-#else
-
-// in_place_index_t
-//
-// Tag type used for in-place construction when the type to construct needs to
-// be specified, such as with `absl::any`, designed to be a drop-in replacement
-// for C++17's `std::in_place_index_t`.
-template <size_t I>
-using in_place_index_t = void (*)(utility_internal::InPlaceIndexTag<I>);
-
-template <size_t I>
-void in_place_index(utility_internal::InPlaceIndexTag<I>) {}
-#endif // ABSL_USES_STD_VARIANT
-
-namespace utility_internal {
-// Helper method for expanding tuple into a called method.
-template <typename Functor, typename Tuple, std::size_t... Indexes>
-auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
- -> decltype(absl::base_internal::invoke(
- absl::forward<Functor>(functor),
- std::get<Indexes>(absl::forward<Tuple>(t))...)) {
- return absl::base_internal::invoke(
- absl::forward<Functor>(functor),
- std::get<Indexes>(absl::forward<Tuple>(t))...);
-}
-
-} // namespace utility_internal
-
-// apply
-//
-// Invokes a Callable using elements of a tuple as its arguments.
-// Each element of the tuple corresponds to an argument of the call (in order).
-// Both the Callable argument and the tuple argument are perfect-forwarded.
-// For member-function Callables, the first tuple element acts as the `this`
-// pointer. `absl::apply` is designed to be a drop-in replacement for C++17's
-// `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`.
-//
-// Example:
-//
-// class Foo {
-// public:
-// void Bar(int);
-// };
-// void user_function1(int, std::string);
-// void user_function2(std::unique_ptr<Foo>);
-// auto user_lambda = [](int, int) {};
-//
-// int main()
-// {
-// std::tuple<int, std::string> tuple1(42, "bar");
-// // Invokes the first user function on int, std::string.
-// absl::apply(&user_function1, tuple1);
-//
-// std::tuple<std::unique_ptr<Foo>> tuple2(absl::make_unique<Foo>());
-// // Invokes the user function that takes ownership of the unique
-// // pointer.
-// absl::apply(&user_function2, std::move(tuple2));
-//
-// auto foo = absl::make_unique<Foo>();
-// std::tuple<Foo*, int> tuple3(foo.get(), 42);
-// // Invokes the method Bar on foo with one argument, 42.
-// absl::apply(&Foo::Bar, tuple3);
-//
-// std::tuple<int, int> tuple4(8, 9);
-// // Invokes a lambda.
-// absl::apply(user_lambda, tuple4);
-// }
-template <typename Functor, typename Tuple>
-auto apply(Functor&& functor, Tuple&& t)
- -> decltype(utility_internal::apply_helper(
- absl::forward<Functor>(functor), absl::forward<Tuple>(t),
- absl::make_index_sequence<std::tuple_size<
- typename std::remove_reference<Tuple>::type>::value>{})) {
- return utility_internal::apply_helper(
- absl::forward<Functor>(functor), absl::forward<Tuple>(t),
- absl::make_index_sequence<std::tuple_size<
- typename std::remove_reference<Tuple>::type>::value>{});
-}
-
-namespace utility_internal {
-template <typename T, typename Tuple, size_t... I>
-T make_from_tuple_impl(Tuple&& tup, absl::index_sequence<I...>) {
- return T(std::get<I>(std::forward<Tuple>(tup))...);
-}
-} // namespace utility_internal
-
-// make_from_tuple
-//
-// Given the template parameter type `T` and a tuple of arguments
-// `std::tuple(arg0, arg1, ..., argN)` constructs an object of type `T` as if by
-// calling `T(arg0, arg1, ..., argN)`.
-//
-// Example:
-//
-// std::tuple<const char*, size_t> args("hello world", 5);
-// auto s = absl::make_from_tuple<std::string>(args);
-// assert(s == "hello");
-//
-template <typename T, typename Tuple>
-constexpr T make_from_tuple(Tuple&& tup) {
- return utility_internal::make_from_tuple_impl<T>(
- std::forward<Tuple>(tup),
- absl::make_index_sequence<
- std::tuple_size<absl::decay_t<Tuple>>::value>{});
-}
-
ABSL_NAMESPACE_END
} // namespace absl
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc
deleted file mode 100644
index c540b22..0000000
--- a/absl/utility/utility_test.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2022 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "absl/utility/utility.h"
-
-#include <memory>
-#include <sstream>
-#include <string>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/base/attributes.h"
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-
-namespace {
-
-using ::testing::ElementsAre;
-using ::testing::Pointee;
-using ::testing::StaticAssertTypeEq;
-
-
-int Function(int a, int b) { return a - b; }
-
-int Sink(std::unique_ptr<int> p) { return *p; }
-
-std::unique_ptr<int> Factory(int n) { return absl::make_unique<int>(n); }
-
-void NoOp() {}
-
-struct ConstFunctor {
- int operator()(int a, int b) const { return a - b; }
-};
-
-struct MutableFunctor {
- int operator()(int a, int b) { return a - b; }
-};
-
-struct EphemeralFunctor {
- EphemeralFunctor() {}
- EphemeralFunctor(const EphemeralFunctor&) {}
- EphemeralFunctor(EphemeralFunctor&&) {}
- int operator()(int a, int b) && { return a - b; }
-};
-
-struct OverloadedFunctor {
- OverloadedFunctor() {}
- OverloadedFunctor(const OverloadedFunctor&) {}
- OverloadedFunctor(OverloadedFunctor&&) {}
- template <typename... Args>
- std::string operator()(const Args&... args) & {
- return absl::StrCat("&", args...);
- }
- template <typename... Args>
- std::string operator()(const Args&... args) const& {
- return absl::StrCat("const&", args...);
- }
- template <typename... Args>
- std::string operator()(const Args&... args) && {
- return absl::StrCat("&&", args...);
- }
-};
-
-struct Class {
- int Method(int a, int b) { return a - b; }
- int ConstMethod(int a, int b) const { return a - b; }
-
- int member;
-};
-
-struct FlipFlop {
- int ConstMethod() const { return member; }
- FlipFlop operator*() const { return {-member}; }
-
- int member;
-};
-
-TEST(ApplyTest, Function) {
- EXPECT_EQ(1, absl::apply(Function, std::make_tuple(3, 2)));
- EXPECT_EQ(1, absl::apply(&Function, std::make_tuple(3, 2)));
-}
-
-TEST(ApplyTest, NonCopyableArgument) {
- EXPECT_EQ(42, absl::apply(Sink, std::make_tuple(absl::make_unique<int>(42))));
-}
-
-TEST(ApplyTest, NonCopyableResult) {
- EXPECT_THAT(absl::apply(Factory, std::make_tuple(42)), Pointee(42));
-}
-
-TEST(ApplyTest, VoidResult) { absl::apply(NoOp, std::tuple<>()); }
-
-TEST(ApplyTest, ConstFunctor) {
- EXPECT_EQ(1, absl::apply(ConstFunctor(), std::make_tuple(3, 2)));
-}
-
-TEST(ApplyTest, MutableFunctor) {
- MutableFunctor f;
- EXPECT_EQ(1, absl::apply(f, std::make_tuple(3, 2)));
- EXPECT_EQ(1, absl::apply(MutableFunctor(), std::make_tuple(3, 2)));
-}
-TEST(ApplyTest, EphemeralFunctor) {
- EphemeralFunctor f;
- EXPECT_EQ(1, absl::apply(std::move(f), std::make_tuple(3, 2)));
- EXPECT_EQ(1, absl::apply(EphemeralFunctor(), std::make_tuple(3, 2)));
-}
-TEST(ApplyTest, OverloadedFunctor) {
- OverloadedFunctor f;
- const OverloadedFunctor& cf = f;
-
- EXPECT_EQ("&", absl::apply(f, std::tuple<>{}));
- EXPECT_EQ("& 42", absl::apply(f, std::make_tuple(" 42")));
-
- EXPECT_EQ("const&", absl::apply(cf, std::tuple<>{}));
- EXPECT_EQ("const& 42", absl::apply(cf, std::make_tuple(" 42")));
-
- EXPECT_EQ("&&", absl::apply(std::move(f), std::tuple<>{}));
- OverloadedFunctor f2;
- EXPECT_EQ("&& 42", absl::apply(std::move(f2), std::make_tuple(" 42")));
-}
-
-TEST(ApplyTest, ReferenceWrapper) {
- ConstFunctor cf;
- MutableFunctor mf;
- EXPECT_EQ(1, absl::apply(std::cref(cf), std::make_tuple(3, 2)));
- EXPECT_EQ(1, absl::apply(std::ref(cf), std::make_tuple(3, 2)));
- EXPECT_EQ(1, absl::apply(std::ref(mf), std::make_tuple(3, 2)));
-}
-
-TEST(ApplyTest, MemberFunction) {
- std::unique_ptr<Class> p(new Class);
- std::unique_ptr<const Class> cp(new Class);
- EXPECT_EQ(
- 1, absl::apply(&Class::Method,
- std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::Method,
- std::tuple<Class*, int, int>(p.get(), 3, 2)));
- EXPECT_EQ(
- 1, absl::apply(&Class::Method, std::tuple<Class&, int, int>(*p, 3, 2)));
-
- EXPECT_EQ(
- 1, absl::apply(&Class::ConstMethod,
- std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::tuple<Class*, int, int>(p.get(), 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::tuple<Class&, int, int>(*p, 3, 2)));
-
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::tuple<std::unique_ptr<const Class>&, int, int>(
- cp, 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::tuple<const Class*, int, int>(cp.get(), 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::tuple<const Class&, int, int>(*cp, 3, 2)));
-
- EXPECT_EQ(1, absl::apply(&Class::Method,
- std::make_tuple(absl::make_unique<Class>(), 3, 2)));
- EXPECT_EQ(1, absl::apply(&Class::ConstMethod,
- std::make_tuple(absl::make_unique<Class>(), 3, 2)));
- EXPECT_EQ(
- 1, absl::apply(&Class::ConstMethod,
- std::make_tuple(absl::make_unique<const Class>(), 3, 2)));
-}
-
-TEST(ApplyTest, DataMember) {
- std::unique_ptr<Class> p(new Class{42});
- std::unique_ptr<const Class> cp(new Class{42});
- EXPECT_EQ(
- 42, absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p)));
- EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class&>(*p)));
- EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class*>(p.get())));
-
- absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p)) = 42;
- absl::apply(&Class::member, std::tuple<Class*>(p.get())) = 42;
- absl::apply(&Class::member, std::tuple<Class&>(*p)) = 42;
-
- EXPECT_EQ(42, absl::apply(&Class::member,
- std::tuple<std::unique_ptr<const Class>&>(cp)));
- EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<const Class&>(*cp)));
- EXPECT_EQ(42,
- absl::apply(&Class::member, std::tuple<const Class*>(cp.get())));
-}
-
-TEST(ApplyTest, FlipFlop) {
- FlipFlop obj = {42};
- // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
- // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
- EXPECT_EQ(42, absl::apply(&FlipFlop::ConstMethod, std::make_tuple(obj)));
- EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj)));
-}
-
-TEST(MakeFromTupleTest, String) {
- EXPECT_EQ(
- absl::make_from_tuple<std::string>(std::make_tuple("hello world", 5)),
- "hello");
-}
-
-TEST(MakeFromTupleTest, MoveOnlyParameter) {
- struct S {
- S(std::unique_ptr<int> n, std::unique_ptr<int> m) : value(*n + *m) {}
- int value = 0;
- };
- auto tup =
- std::make_tuple(absl::make_unique<int>(3), absl::make_unique<int>(4));
- auto s = absl::make_from_tuple<S>(std::move(tup));
- EXPECT_EQ(s.value, 7);
-}
-
-TEST(MakeFromTupleTest, NoParameters) {
- struct S {
- S() : value(1) {}
- int value = 2;
- };
- EXPECT_EQ(absl::make_from_tuple<S>(std::make_tuple()).value, 1);
-}
-
-TEST(MakeFromTupleTest, Pair) {
- EXPECT_EQ(
- (absl::make_from_tuple<std::pair<bool, int>>(std::make_tuple(true, 17))),
- std::make_pair(true, 17));
-}
-
-} // namespace
diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh
index c8a5b85..484230c 100644
--- a/ci/cmake_common.sh
+++ b/ci/cmake_common.sh
@@ -13,7 +13,7 @@
# limitations under the License.
# The commit of GoogleTest to be used in the CMake tests in this directory.
-# Keep this in sync with the commit in the WORKSPACE file.
-readonly ABSL_GOOGLETEST_VERSION="1.15.2"
+# Keep this in sync with the commit in the MODULE.bazel file.
+readonly ABSL_GOOGLETEST_VERSION="1.17.0"
readonly ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
diff --git a/ci/linux_arm_clang-latest_libcxx_bazel.sh b/ci/linux_arm_clang-latest_libcxx_bazel.sh
index 13f4ad1..631a8bd 100755
--- a/ci/linux_arm_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_arm_clang-latest_libcxx_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17 c++20"
+ STD="c++17 c++20"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -69,26 +69,25 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
- -e BAZEL_LINKOPTS="-L/opt/llvm/clang/lib/aarch64-unknown-linux-gnu:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/clang/lib/aarch64-unknown-linux-gnu" \
- -e CPLUS_INCLUDE_PATH="/opt/llvm/clang/include/aarch64-unknown-linux-gnu/c++/v1:/opt/llvm/clang/include/c++/v1" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
- /bin/sh -c "
+ /bin/bash --login -c "
cp -r /abseil-cpp-ro/* /abseil-cpp/
if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
fi
/usr/local/bin/bazel test ... \
+ --action_env=CC=clang-19 \
--compilation_mode=\"${compilation_mode}\" \
--copt=\"${exceptions_mode}\" \
--copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
--copt=-Werror \
+ --cxxopt=-std=${std} \
+ --cxxopt=-stdlib=libc++ \
--define=\"absl=1\" \
- --enable_bzlmod=true \
--features=external_include_paths \
--keep_going \
+ --linkopt=-stdlib=libc++ \
--show_timestamps \
--test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
--test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index 3153fae..cfc5510 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17 c++20"
+ STD="c++17 c++20 c++23"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -59,6 +59,9 @@
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
+# https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
+readonly UBSAN_CHECKS="float-divide-by-zero,nullability,undefined"
+
for std in ${STD}; do
for compilation_mode in ${COMPILATION_MODE}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
@@ -68,35 +71,35 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
- -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
- -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
+ /bin/bash --login -c "
/usr/local/bin/bazel test ... \
- --compilation_mode="${compilation_mode}" \
- --copt="${exceptions_mode}" \
- --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
- --copt="-fsanitize=address" \
- --copt="-fsanitize=float-divide-by-zero" \
- --copt="-fsanitize=nullability" \
- --copt="-fsanitize=undefined" \
- --copt="-fno-sanitize-blacklist" \
+ --action_env=\"CC=/opt/llvm/clang/bin/clang\" \
+ --action_env=\"BAZEL_CXXOPTS=-std=${std}:-nostdinc++\" \
+ --action_env=\"BAZEL_LINKOPTS=-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib\" \
+ --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1\" \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
+ --copt=\"-fsanitize=address\" \
+ --copt=\"-fsanitize=${UBSAN_CHECKS}\" \
+ --copt=\"-fno-sanitize-recover=${UBSAN_CHECKS}\" \
+ --copt=\"-fno-sanitize-blacklist\" \
--copt=-Werror \
--enable_bzlmod=true \
--features=external_include_paths \
--keep_going \
- --linkopt="-fsanitize=address" \
- --linkopt="-fsanitize-link-c++-runtime" \
+ --linkopt=\"-fsanitize=address\" \
+ --linkopt=\"-fsanitize-link-c++-runtime\" \
--show_timestamps \
- --test_env="ASAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
- --test_env="UBSAN_OPTIONS=print_stacktrace=1" \
- --test_env="UBSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \
+ --test_env=\"ASAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
+ --test_env=\"UBSAN_OPTIONS=print_stacktrace=1\" \
+ --test_env=\"UBSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \
--test_output=errors \
- --test_tag_filters="-benchmark,-noasan" \
- ${BAZEL_EXTRA_ARGS:-}
+ --test_tag_filters=\"-benchmark,-noasan\" \
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
index 4f3eba4..5c51d15 100755
--- a/ci/linux_clang-latest_libcxx_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17 c++20"
+ STD="c++17 c++20 c++23"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -69,18 +69,18 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
- -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib" \
- -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx/include/c++/v1" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
- /bin/sh -c "
+ /bin/bash --login -c "
cp -r /abseil-cpp-ro/* /abseil-cpp/
if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
fi
/usr/local/bin/bazel test ... \
+ --action_env=CC=/opt/llvm/clang/bin/clang \
+ --action_env=BAZEL_CXXOPTS=-std=${std}:-nostdinc++ \
+ --action_env=BAZEL_LINKOPTS=-L/opt/llvm/libcxx/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx/lib \
+ --action_env=CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1 \
--compilation_mode=\"${compilation_mode}\" \
--copt=\"${exceptions_mode}\" \
--copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
index 06f4c2e..c9ea22d 100755
--- a/ci/linux_clang-latest_libcxx_tsan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17 c++20"
+ STD="c++17 c++20 c++23"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -68,30 +68,31 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_CXXOPTS="-std=${std}:-nostdinc++" \
- -e BAZEL_LINKOPTS="-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib" \
- -e CPLUS_INCLUDE_PATH="/opt/llvm/libcxx-tsan/include/c++/v1" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
+ /bin/bash --login -c "
/usr/local/bin/bazel test ... \
- --build_tag_filters="-notsan" \
- --compilation_mode="${compilation_mode}" \
- --copt="${exceptions_mode}" \
- --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
- --copt="-fsanitize=thread" \
- --copt="-fno-sanitize-blacklist" \
+ --action_env=\"CC=/opt/llvm/clang/bin/clang\" \
+ --action_env=\"BAZEL_CXXOPTS=-std=${std}:-nostdinc++\" \
+ --action_env=\"BAZEL_LINKOPTS=-L/opt/llvm/libcxx-tsan/lib:-lc++:-lc++abi:-lm:-Wl,-rpath=/opt/llvm/libcxx-tsan/lib\" \
+ --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx-tsan/include/c++/v1\" \
+ --build_tag_filters=\"-notsan\" \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
+ --copt=\"-fsanitize=thread\" \
+ --copt=\"-fno-sanitize-blacklist\" \
--copt=-Werror \
--enable_bzlmod=true \
--features=external_include_paths \
--keep_going \
- --linkopt="-fsanitize=thread" \
+ --linkopt=\"-fsanitize=thread\" \
--show_timestamps \
- --test_env="TSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
+ --test_env=\"TSAN_SYMBOLIZER_PATH=/opt/llvm/clang/bin/llvm-symbolizer\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
--test_output=errors \
- --test_tag_filters="-benchmark,-notsan" \
- ${BAZEL_EXTRA_ARGS:-}
+ --test_tag_filters=\"-benchmark,-notsan\" \
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
index d499e13..a1620e0 100755
--- a/ci/linux_clang-latest_libstdcxx_bazel.sh
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17"
+ STD="c++17 c++20 c++23"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -68,28 +68,29 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/opt/llvm/clang/bin/clang" \
- -e BAZEL_CXXOPTS="-std=${std}" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
+ /bin/bash --login -c "
/usr/local/bin/bazel test ... \
- --compilation_mode="${compilation_mode}" \
- --copt="--gcc-toolchain=/usr/local" \
- --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
- --copt="${exceptions_mode}" \
- --copt="-march=haswell" \
+ --action_env=\"CC=/opt/llvm/clang/bin/clang\" \
+ --action_env=\"BAZEL_CXXOPTS=-std=${std}\" \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"--gcc-toolchain=/usr/local\" \
+ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=\"-march=haswell\" \
--copt=-Werror \
- --define="absl=1" \
+ --define=\"absl=1\" \
--enable_bzlmod=true \
--features=external_include_paths \
--keep_going \
- --linkopt="--gcc-toolchain=/usr/local" \
+ --linkopt=\"--gcc-toolchain=/usr/local\" \
--show_timestamps \
- --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
+ --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
--test_output=errors \
--test_tag_filters=-benchmark \
- ${BAZEL_EXTRA_ARGS:-}
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/ci/linux_docker_containers.sh b/ci/linux_docker_containers.sh
index fefef92..0f45471 100644
--- a/ci/linux_docker_containers.sh
+++ b/ci/linux_docker_containers.sh
@@ -16,7 +16,7 @@
# Test scripts should source this file to get the identifiers.
readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20230612"
-readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20240523"
-readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20231219"
-readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20240523"
-readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20240717"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
+readonly LINUX_ARM_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_arm_hybrid-latest:20250430"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
+readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"
diff --git a/ci/linux_gcc-floor_libstdcxx_bazel.sh b/ci/linux_gcc-floor_libstdcxx_bazel.sh
index b2d8c1d..b683b60 100755
--- a/ci/linux_gcc-floor_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-floor_libstdcxx_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14"
+ STD="c++17"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_http_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -68,26 +68,25 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/usr/local/bin/gcc" \
- -e BAZEL_CXXOPTS="-std=${std}" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
+ /bin/bash --login -c "
/usr/local/bin/bazel test ... \
- --compilation_mode="${compilation_mode}" \
- --copt="${exceptions_mode}" \
- --copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
+ --action_env=\"CC=/usr/local/bin/gcc\" \
+ --action_env=\"BAZEL_CXXOPTS=-std=${std}\" \
+ --compilation_mode=\"${compilation_mode}\" \
+ --copt=\"${exceptions_mode}\" \
+ --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
--copt=-Werror \
- --define="absl=1" \
- --distdir="/bazel-distdir" \
- --enable_bzlmod=false \
+ --define=\"absl=1\" \
--features=external_include_paths \
--keep_going \
--show_timestamps \
- --test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" \
- --test_env="TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo" \
+ --test_env=\"GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1\" \
+ --test_env=\"TZDIR=/abseil-cpp/absl/time/internal/cctz/testdata/zoneinfo\" \
--test_output=errors \
--test_tag_filters=-benchmark \
- ${BAZEL_EXTRA_ARGS:-}
+ ${BAZEL_EXTRA_ARGS:-}"
done
done
done
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
index 8f77346..b092c1d 100755
--- a/ci/linux_gcc-latest_libstdcxx_bazel.sh
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -25,7 +25,7 @@
fi
if [[ -z ${STD:-} ]]; then
- STD="c++14 c++17 c++20"
+ STD="c++17 c++20 c++23"
fi
if [[ -z ${COMPILATION_MODE:-} ]]; then
@@ -51,12 +51,12 @@
BAZEL_EXTRA_ARGS="--remote_cache=https://storage.googleapis.com/absl-bazel-remote-cache/${container_key} --google_credentials=/keystore/73103_absl-bazel-remote-cache ${BAZEL_EXTRA_ARGS:-}"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
- BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+# See https://bazel.build/external/vendor and the Dockerfile for
+# an explaination of how this works.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/abseil-cpp_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
+ BAZEL_EXTRA_ARGS="--vendor_dir=/abseil-cpp_vendor ${BAZEL_EXTRA_ARGS:-}"
fi
for std in ${STD}; do
@@ -69,16 +69,16 @@
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \
- -e CC="/usr/local/bin/gcc" \
- -e BAZEL_CXXOPTS="-std=${std}" \
${DOCKER_EXTRA_ARGS:-} \
${DOCKER_CONTAINER} \
- /bin/sh -c "
+ /bin/bash --login -c "
cp -r /abseil-cpp-ro/* /abseil-cpp/
if [ -n \"${ALTERNATE_OPTIONS:-}\" ]; then
cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
fi
/usr/local/bin/bazel test ... \
+ --action_env=CC=/usr/local/bin/gcc \
+ --action_env=BAZEL_CXXOPTS=-std=${std} \
--compilation_mode=\"${compilation_mode}\" \
--copt=\"${exceptions_mode}\" \
--copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index 243901c..d75209b 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -23,7 +23,7 @@
source "${ABSEIL_ROOT}/ci/cmake_common.sh"
if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
- ABSL_CMAKE_CXX_STANDARDS="14 17 20"
+ ABSL_CMAKE_CXX_STANDARDS="17 20"
fi
if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index f19954f..7cf25f7 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -23,7 +23,7 @@
source "${ABSEIL_ROOT}/ci/cmake_common.sh"
if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
- ABSL_CMAKE_CXX_STANDARDS="14 17"
+ ABSL_CMAKE_CXX_STANDARDS="17"
fi
if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh
index bb8fb4b..b05cfac 100755
--- a/ci/macos_xcode_bazel.sh
+++ b/ci/macos_xcode_bazel.sh
@@ -19,12 +19,15 @@
set -euox pipefail
+# Use Xcode 16.0
+sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
+
if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
fi
# If we are running on Kokoro, check for a versioned Bazel binary.
-KOKORO_GFILE_BAZEL_BIN="bazel-7.0.0-darwin-x86_64"
+KOKORO_GFILE_BAZEL_BIN="bazel-8.2.1-darwin-x86_64"
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
chmod +x ${BAZEL_BIN}
@@ -32,11 +35,10 @@
BAZEL_BIN="bazel"
fi
-# Avoid depending on external sites like GitHub by checking --distdir for
-# external dependencies first.
-# https://docs.bazel.build/versions/master/guide.html#distdir
-if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
- BAZEL_EXTRA_ARGS="--distdir=${KOKORO_GFILE_DIR}/distdir ${BAZEL_EXTRA_ARGS:-}"
+# Use Bazel Vendor mode to reduce reliance on external dependencies.
+if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" ]]; then
+ tar -xf "${KOKORO_GFILE_DIR}/distdir/abseil-cpp_vendor.tar.gz" -C "${TMP}/"
+ BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/abseil-cpp_vendor\" ${BAZEL_EXTRA_ARGS:-}"
fi
# Print the compiler and Bazel versions.
@@ -52,10 +54,13 @@
cp ${ALTERNATE_OPTIONS:-} absl/base/options.h || exit 1
fi
+# Avoid using the system version of google-benchmark.
+brew uninstall google-benchmark
+
${BAZEL_BIN} test ... \
--copt="-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1" \
--copt="-Werror" \
- --cxxopt="-std=c++14" \
+ --cxxopt="-std=c++17" \
--enable_bzlmod=true \
--features=external_include_paths \
--keep_going \
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index eba2fb5..6811b87 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -16,6 +16,12 @@
set -euox pipefail
+# Use Xcode 16.0
+sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
+
+export CMAKE_BUILD_PARALLEL_LEVEL=$(sysctl -n hw.ncpu)
+export CTEST_PARALLEL_LEVEL=$(sysctl -n hw.ncpu)
+
if [[ -z ${ABSEIL_ROOT:-} ]]; then
ABSEIL_ROOT="$(dirname ${0})/.."
fi
@@ -53,7 +59,7 @@
-DBUILD_SHARED_LIBS=${build_shared} \
-DABSL_BUILD_TESTING=ON \
-DCMAKE_BUILD_TYPE=${compilation_mode} \
- -DCMAKE_CXX_STANDARD=14 \
+ -DCMAKE_CXX_STANDARD=17 \
-DCMAKE_MODULE_LINKER_FLAGS="-Wl,--no-undefined" \
-DABSL_BUILD_MONOLITHIC_SHARED_LIBS=${monolithic_shared} \
-DABSL_GOOGLETEST_DOWNLOAD_URL="${ABSL_GOOGLETEST_DOWNLOAD_URL}"
diff --git a/ci/windows_clangcl_bazel.bat b/ci/windows_clangcl_bazel.bat
index b031c30..26fd5af 100755
--- a/ci/windows_clangcl_bazel.bat
+++ b/ci/windows_clangcl_bazel.bat
@@ -21,10 +21,18 @@
CD %~dp0\..
if %errorlevel% neq 0 EXIT /B 1
-:: Set the standard version, [c++14|c++17|c++20|c++latest]
+:: Use Bazel Vendor mode to reduce reliance on external dependencies.
+IF EXIST "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" (
+ tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" -C c:\
+ SET VENDOR_FLAG=--vendor_dir=c:\abseil-cpp_vendor
+) ELSE (
+ SET VENDOR_FLAG=
+)
+
+:: Set the standard version, [c++17|c++20|c++latest]
:: https://msdn.microsoft.com/en-us/library/mt490614.aspx
-:: The default is c++14 if not set on command line.
-IF "%STD%"=="" SET STD=c++14
+:: The default is c++17 if not set on command line.
+IF "%STD%"=="" SET STD=c++17
:: Set the compilation_mode (fastbuild|opt|dbg)
:: https://docs.bazel.build/versions/master/user-manual.html#flag--compilation_mode
@@ -39,7 +47,7 @@
:: /google/data/rw/teams/absl/kokoro/windows.
::
:: TODO(absl-team): Remove -Wno-microsoft-cast
-%KOKORO_GFILE_DIR%\bazel-7.0.0-windows-x86_64.exe ^
+%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe ^
test ... ^
--compilation_mode=%COMPILATION_MODE% ^
--compiler=clang-cl ^
@@ -47,7 +55,6 @@
--copt=-Wno-microsoft-cast ^
--cxxopt=/std:%STD% ^
--define=absl=1 ^
- --distdir=%KOKORO_GFILE_DIR%\distdir ^
--enable_bzlmod=true ^
--extra_execution_platforms=//:x64_windows-clang-cl ^
--extra_toolchains=@local_config_cc//:cc-toolchain-x64_windows-clang-cl ^
@@ -55,7 +62,8 @@
--test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^
--test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^
--test_output=errors ^
- --test_tag_filters=-benchmark
+ --test_tag_filters=-benchmark ^
+ %VENDOR_FLAG%
if %errorlevel% neq 0 EXIT /B 1
EXIT /B 0
diff --git a/ci/windows_msvc_bazel.bat b/ci/windows_msvc_bazel.bat
index e2acf5f..bbb57b4 100755
--- a/ci/windows_msvc_bazel.bat
+++ b/ci/windows_msvc_bazel.bat
@@ -18,10 +18,18 @@
CD %~dp0\..
if %errorlevel% neq 0 EXIT /B 1
-:: Set the standard version, [c++14|c++latest]
+:: Use Bazel Vendor mode to reduce reliance on external dependencies.
+IF EXIST "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" (
+ tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\abseil-cpp_vendor.tar.gz" -C c:\
+ SET VENDOR_FLAG=--vendor_dir=c:\abseil-cpp_vendor
+) ELSE (
+ SET VENDOR_FLAG=
+)
+
+:: Set the standard version, [c++17|c++latest]
:: https://msdn.microsoft.com/en-us/library/mt490614.aspx
-:: The default is c++14 if not set on command line.
-IF "%STD%"=="" SET STD=c++14
+:: The default is c++17 if not set on command line.
+IF "%STD%"=="" SET STD=c++17
:: Set the compilation_mode (fastbuild|opt|dbg)
:: https://docs.bazel.build/versions/master/user-manual.html#flag--compilation_mode
@@ -34,19 +42,19 @@
:: To upgrade Bazel, first download a new binary from
:: https://github.com/bazelbuild/bazel/releases and copy it to
:: /google/data/rw/teams/absl/kokoro/windows.
-%KOKORO_GFILE_DIR%\bazel-7.0.0-windows-x86_64.exe ^
+"%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe" ^
test ... ^
--compilation_mode=%COMPILATION_MODE% ^
--copt=/WX ^
--copt=/std:%STD% ^
--define=absl=1 ^
- --distdir=%KOKORO_GFILE_DIR%\distdir ^
--enable_bzlmod=true ^
--keep_going ^
--test_env="GTEST_INSTALL_FAILURE_SIGNAL_HANDLER=1" ^
--test_env=TZDIR="%CD%\absl\time\internal\cctz\testdata\zoneinfo" ^
--test_output=errors ^
- --test_tag_filters=-benchmark
+ --test_tag_filters=-benchmark ^
+ %VENDOR_FLAG%
if %errorlevel% neq 0 EXIT /B 1
EXIT /B 0
diff --git a/ci/windows_msvc_cmake.bat b/ci/windows_msvc_cmake.bat
index c9aee78..62cdb70 100755
--- a/ci/windows_msvc_cmake.bat
+++ b/ci/windows_msvc_cmake.bat
@@ -16,7 +16,7 @@
:: The version of GoogleTest to be used in the CMake tests in this directory.
:: Keep this in sync with the version in the WORKSPACE file.
-SET ABSL_GOOGLETEST_VERSION=1.15.2
+SET ABSL_GOOGLETEST_VERSION=1.17.0
SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
:: Replace '\' with '/' in Windows paths for CMake.
diff --git a/generate_bp.py b/generate_bp.py
new file mode 100755
index 0000000..6797ba4
--- /dev/null
+++ b/generate_bp.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python3
+import argparse
+import json
+import subprocess
+import sys
+import os
+
+root_libs = [
+ '//absl/algorithm:algorithm',
+ '//absl/cleanup:cleanup',
+ '//absl/container:btree',
+ '//absl/container:flat_hash_map',
+ '//absl/container:flat_hash_set',
+ '//absl/container:node_hash_map',
+ '//absl/container:node_hash_set',
+ '//absl/debugging:failure_signal_handler',
+ '//absl/flags:flag',
+ '//absl/flags:parse',
+ '//absl/functional:bind_front',
+ '//absl/log:absl_check',
+ '//absl/log:absl_log',
+ '//absl/log:check',
+ '//absl/log:die_if_null',
+ '//absl/log:initialize',
+ '//absl/log:log',
+ '//absl/log:scoped_mock_log',
+ '//absl/random:bit_gen_ref',
+ '//absl/random:random',
+ '//absl/status:statusor',
+ '//absl/strings:strings',
+ '//absl/synchronization:synchronization',
+]
+ignored_deps = set([
+ '@googletest//:gtest'
+])
+
+# Convert names like //foo/bar:baz to foo_bar_baz.
+# If the last segment of the path and the target names are the same,
+# the target name will be dropped, as per bazel convention.
+# eg: //foo/bar:bar -> foo_bar
+def bazel_name_to_bp_name(name):
+ parts = name[name.rfind('/')+1:].split(':')
+ if len(parts) == 2 and parts[0] == parts[1]:
+ name = name.removesuffix(':'+parts[1])
+ name = name[2:].replace('/', '_').replace(':', '_')
+ return name
+
+def main():
+ query = subprocess.check_output(['bazel', 'query', '--output=streamed_jsonproto', 'kind(cc_library, //...)'], text=True)
+ query = query.split('\n')
+
+ # API level 29 is required native ELF TLS support, see bionic/android-changes-for-ndk-developers.md
+ # We need it because absl/strings/internal/cordz_functions.h defines a thread_local global variable.
+ # If we compile with API lower than 29, it won't link correctly with code compiled with API >= 29
+ bp = '''
+ // This Android.bp file was autogenerated by external/absel-cpp/generate_bp.py
+ // DO NOT EDIT
+
+ package {
+ default_applicable_licenses: ["libabsl_license"],
+ default_visibility: ["//visibility:private"],
+ }
+
+ license {
+ name: "libabsl_license",
+ visibility: [":__subpackages__"],
+ license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+ license_text: ["LICENSE"],
+ }
+
+ cc_defaults {
+ name: "absl_defaults",
+ host_supported: true,
+ product_available: true,
+ ramdisk_available: true,
+ recovery_available: true,
+ vendor_available: true,
+ vendor_ramdisk_available: true,
+ sdk_version: "29",
+ min_sdk_version: "apex_inherit",
+ stl: "libc++",
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+ target: {
+ windows: {
+ enabled: true,
+ cflags: ["-Wno-unknown-pragmas"],
+ },
+ },
+ }
+
+ cc_defaults {
+ name: "absl_notls_defaults",
+ defaults_visibility: ["//external/protobuf:__subpackages__"],
+ host_supported: true,
+ ramdisk_available: true,
+ recovery_available: true,
+ vendor_ramdisk_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.runtime",
+ ],
+ cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
+ }
+
+ cc_defaults {
+ name: "absl_test_defaults",
+ host_supported: true,
+ product_available: true,
+ vendor_available: true,
+ stl: "libc++",
+ }
+
+ cc_defaults {
+ name: "absl_notls_test_defaults",
+ host_supported: true,
+ stl: "libc++",
+ cflags: ["-DANDROID_DISABLE_TLS_FOR_LINKER=1"],
+ }
+ '''
+
+ libs_graph = {}
+ libs = {}
+ alwayslink_libs = {}
+ public_libs = {}
+
+ for q in query:
+ if not q.strip():
+ continue
+ q = json.loads(q)
+ name = q['rule']['name']
+ libs[name] = q
+ libs_graph[name] = []
+ for attr in q['rule']['attribute']:
+ if attr['name'] == 'deps':
+ libs_graph[name] = attr.get('stringListValue', [])
+ if attr['name'] == 'alwayslink':
+ if attr.get('booleanValue', False):
+ alwayslink_libs[name] = True
+ if attr['name'] == 'visibility':
+ if "//visibility:public" in attr['stringListValue']:
+ public_libs[name] = True
+
+ queue = [l for l in root_libs]
+ processed = set(ignored_deps)
+
+ while queue:
+ name = queue.pop()
+ if name in processed:
+ continue
+ processed.add(name)
+ lib = libs[name]
+
+ bp_mod_name = bazel_name_to_bp_name(name)
+
+ deps = []
+ srcs = []
+ hdrs = []
+ testonly = False
+ for attr in lib['rule']['attribute']:
+ if attr['name'] == 'deps':
+ deps = attr.get('stringListValue', [])
+ if attr['name'] == 'srcs':
+ srcs = attr.get('stringListValue', [])
+ if attr['name'] == 'hdrs':
+ hdrs.extend(attr.get('stringListValue', []))
+ if attr['name'] == 'textual_hdrs':
+ hdrs.extend(attr.get('stringListValue', []))
+ if attr['name'] == 'testonly':
+ testonly = attr.get('booleanValue', False)
+
+ hdrs = list(sorted(set(hdrs)))
+
+ srcs = [h[2:].replace(':', '/') for h in srcs]
+ hdrs = [h[2:].replace(':', '/') for h in hdrs]
+
+ # In bazel, you can put headers in the srcs field to mean "private" headers that are not
+ # re-exported. Soong doesn't allow .h files in srcs, or .inc files anywhere. So make this
+ # a little easier for soong by moving all headers to the actual headers property, which
+ # will cause some internal headers to be exported but at least this is still better than
+ # exporting the whole absl folder. The .inc files are also copied to the generated header
+ # directories because sometimes headers #include the .inc files.
+ hdrs.extend([h for h in srcs if h.endswith('.h') or h.endswith('.inc')])
+ srcs = [s for s in srcs if not s.endswith('.h') and not s.endswith('.inc')]
+
+ for dep in deps:
+ if dep in alwayslink_libs:
+ # We are actually using whole_static_libs for everything now, so in theory this
+ # error isn't necessary. But we want to use regular static_libs. We only use
+ # whole_static_libs because soong doesn't re-export static_lib dependencies.
+ # (b/123002125#comment3)
+ sys.exit(f'{name} depends on {dep}, which is alwayslink=1. alwayslink isn\'t supported by this script. (would need to use whole_static_libs instead of static_libs)')
+
+ generated_hdrs_attr = ""
+ if hdrs:
+ header_files_for_bp = ['"' + h + '"' for h in hdrs]
+ # We add an extra my_include_dir/ to not get duplication location errors, as both in and
+ # out are exactly the same paths
+ header_files_for_out = ['"my_include_dir/' + h + '"' for h in hdrs]
+ bp += f'''
+ genrule {{
+ name: "{bp_mod_name}_hdrs",
+ srcs: [
+ {',\n'.join(header_files_for_bp)}
+ ],
+ out: [
+ {',\n'.join(header_files_for_out)}
+ ],
+ export_include_dirs: ["my_include_dir"],
+ cmd: "mkdir -p $(genDir)/my_include_dir $(genDir)/temp && " +
+ "cp --parents $(in) $(genDir)/temp && " +
+ // delete empty folders automatically created by soong
+ "rm -rf $(genDir)/my_include_dir/* && " +
+ "mv $(genDir)/temp/external/abseil-cpp/absl $(genDir)/my_include_dir/ && " +
+ "rm -rf $(genDir)/temp"
+ }}
+ '''
+ generated_hdrs_attr = f'generated_headers: ["{bp_mod_name}_hdrs"],\n'
+ generated_hdrs_attr += f'export_generated_headers: ["{bp_mod_name}_hdrs"],\n'
+
+ module_type = 'cc_library_static'
+ defaults_module = 'absl_defaults'
+ notls_defaults_module = 'absl_notls_defaults'
+ bp_deps = [bazel_name_to_bp_name(d) for d in deps if d not in ignored_deps]
+ extra_attributes = ''
+
+ # Special handling for test-only libraries.
+ if testonly:
+ module_type = 'cc_test_library'
+ defaults_module = 'absl_test_defaults'
+ notls_defaults_module = 'absl_notls_test_defaults'
+ extra_attributes = '''
+ static_libs: ["libgmock", "libgtest"],
+ shared: {
+ enabled: false,
+ },
+ '''
+
+ # Hardcode the addition of liblog to log_sink_set. log_sink_set uses a select() in bazel
+ # to add the liblog dep only on android.
+ if name == "//absl/log/internal:log_sink_set":
+ extra_attributes = '''
+ target: {
+ android: {
+ shared_libs: ["liblog"],
+ },
+ },
+ '''
+
+ visibility_prop = ''
+ visibility_prop_notls = ''
+ if name in public_libs:
+ visibility_prop = 'visibility: ["//visibility:public"],'
+ visibility_prop_notls = 'visibility: ["//external/protobuf"],'
+
+ bp_deps_for_bp = ['"' + d + '"' for d in bp_deps]
+ src_files_for_bp = ['"' + h + '"' for h in srcs]
+ bp += f'''
+ {module_type} {{
+ name: "{bp_mod_name}",
+ defaults: ["{defaults_module}"],
+ {visibility_prop}
+ srcs: [
+ {',\n'.join(src_files_for_bp)}
+ ],
+ {generated_hdrs_attr}
+ whole_static_libs: [
+ {',\n'.join(bp_deps_for_bp)}
+ ],
+ export_static_lib_headers: [
+ {',\n'.join(bp_deps_for_bp)}
+ ],
+ {extra_attributes}
+ }}
+ '''
+
+ # We need to generate separate versions of the library with TLS disabled
+ # for use in the dynamic linker and its dependencies, which does not
+ # support ELF TLS segments when loading itself.
+ bp_notls_deps_for_bp = ['"' + d + '_notls"' for d in bp_deps]
+ bp += f'''
+ {module_type} {{
+ name: "{bp_mod_name}_notls",
+ defaults: ["{notls_defaults_module}"],
+ {visibility_prop_notls}
+ srcs: [
+ {',\n'.join(src_files_for_bp)}
+ ],
+ {generated_hdrs_attr}
+ whole_static_libs: [
+ {',\n'.join(bp_notls_deps_for_bp)}
+ ],
+ export_static_lib_headers: [
+ {',\n'.join(bp_notls_deps_for_bp)}
+ ],
+ {extra_attributes}
+ }}
+ '''
+
+ queue.extend(deps)
+
+ with open('Android.bp', 'w') as f:
+ f.write(bp)
+ subprocess.check_call(['bpfmt', '-w', 'Android.bp'])
+
+if __name__ == "__main__":
+ main()