summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--CMake/AbseilConfigureCopts.cmake145
-rw-r--r--CMake/AbseilHelpers.cmake228
-rw-r--r--CMake/AbseilInstallDirs.cmake20
-rw-r--r--CMake/Googletest/CMakeLists.txt.in (renamed from CMake/CMakeLists.txt.in)0
-rw-r--r--CMake/Googletest/DownloadGTest.cmake (renamed from CMake/DownloadGTest.cmake)0
-rw-r--r--CMake/README.md20
-rw-r--r--CMake/abslConfig.cmake.in7
-rw-r--r--CMake/install_test_project/CMakeLists.txt27
-rw-r--r--CMake/install_test_project/simple.cc23
-rwxr-xr-xCMake/install_test_project/test.sh144
-rw-r--r--CMakeLists.txt105
-rw-r--r--LICENSE7
-rw-r--r--LTS.md1
-rw-r--r--README.md10
-rw-r--r--UPGRADES.md17
-rw-r--r--WORKSPACE6
-rw-r--r--absl/BUILD.bazel17
-rw-r--r--absl/CMakeLists.txt4
-rw-r--r--absl/algorithm/BUILD.bazel10
-rw-r--r--absl/algorithm/CMakeLists.txt6
-rw-r--r--absl/algorithm/algorithm.h8
-rw-r--r--absl/algorithm/algorithm_test.cc2
-rw-r--r--absl/algorithm/container.h18
-rw-r--r--absl/algorithm/container_test.cc15
-rw-r--r--absl/algorithm/equal_benchmark.cc2
-rw-r--r--absl/base/BUILD.bazel151
-rw-r--r--absl/base/CMakeLists.txt130
-rw-r--r--absl/base/attributes.h23
-rw-r--r--absl/base/bit_cast_test.cc6
-rw-r--r--absl/base/call_once.h8
-rw-r--r--absl/base/call_once_test.cc11
-rw-r--r--absl/base/casts.h29
-rw-r--r--absl/base/config.h46
-rw-r--r--absl/base/config_test.cc2
-rw-r--r--absl/base/const_init.h74
-rw-r--r--absl/base/dynamic_annotations.cc2
-rw-r--r--absl/base/dynamic_annotations.h5
-rw-r--r--absl/base/exception_safety_testing_test.cc2
-rw-r--r--absl/base/inline_variable_test.cc6
-rw-r--r--absl/base/inline_variable_test_a.cc6
-rw-r--r--absl/base/inline_variable_test_b.cc6
-rw-r--r--absl/base/internal/atomic_hook.h6
-rw-r--r--absl/base/internal/atomic_hook_test.cc2
-rw-r--r--absl/base/internal/bits.h6
-rw-r--r--absl/base/internal/bits_test.cc2
-rw-r--r--absl/base/internal/cmake_thread_test.cc22
-rw-r--r--absl/base/internal/cycleclock.cc32
-rw-r--r--absl/base/internal/cycleclock.h21
-rw-r--r--absl/base/internal/direct_mmap.h10
-rw-r--r--absl/base/internal/endian.h10
-rw-r--r--absl/base/internal/endian_test.cc6
-rw-r--r--absl/base/internal/exception_safety_testing.cc2
-rw-r--r--absl/base/internal/exception_safety_testing.h12
-rw-r--r--absl/base/internal/exception_testing.h2
-rw-r--r--absl/base/internal/hide_ptr.h6
-rw-r--r--absl/base/internal/identity.h6
-rw-r--r--absl/base/internal/inline_variable.h2
-rw-r--r--absl/base/internal/inline_variable_testing.h6
-rw-r--r--absl/base/internal/invoke.h43
-rw-r--r--absl/base/internal/low_level_alloc.cc11
-rw-r--r--absl/base/internal/low_level_alloc.h8
-rw-r--r--absl/base/internal/low_level_alloc_test.cc7
-rw-r--r--absl/base/internal/low_level_scheduling.h9
-rw-r--r--absl/base/internal/per_thread_tls.h14
-rw-r--r--absl/base/internal/pretty_function.h2
-rw-r--r--absl/base/internal/raw_logging.cc9
-rw-r--r--absl/base/internal/raw_logging.h17
-rw-r--r--absl/base/internal/scheduling_mode.h6
-rw-r--r--absl/base/internal/scoped_set_env.cc81
-rw-r--r--absl/base/internal/scoped_set_env.h43
-rw-r--r--absl/base/internal/scoped_set_env_test.cc99
-rw-r--r--absl/base/internal/spinlock.cc6
-rw-r--r--absl/base/internal/spinlock.h13
-rw-r--r--absl/base/internal/spinlock_akaros.inc2
-rw-r--r--absl/base/internal/spinlock_benchmark.cc2
-rw-r--r--absl/base/internal/spinlock_linux.inc19
-rw-r--r--absl/base/internal/spinlock_posix.inc2
-rw-r--r--absl/base/internal/spinlock_wait.cc19
-rw-r--r--absl/base/internal/spinlock_wait.h6
-rw-r--r--absl/base/internal/spinlock_win32.inc2
-rw-r--r--absl/base/internal/sysinfo.cc6
-rw-r--r--absl/base/internal/sysinfo.h6
-rw-r--r--absl/base/internal/sysinfo_test.cc12
-rw-r--r--absl/base/internal/thread_annotations.h271
-rw-r--r--absl/base/internal/thread_identity.cc6
-rw-r--r--absl/base/internal/thread_identity.h11
-rw-r--r--absl/base/internal/thread_identity_benchmark.cc2
-rw-r--r--absl/base/internal/thread_identity_test.cc6
-rw-r--r--absl/base/internal/throw_delegate.cc6
-rw-r--r--absl/base/internal/throw_delegate.h6
-rw-r--r--absl/base/internal/tsan_mutex_interface.h2
-rw-r--r--absl/base/internal/unaligned_access.h181
-rw-r--r--absl/base/internal/unscaledcycleclock.cc6
-rw-r--r--absl/base/internal/unscaledcycleclock.h11
-rw-r--r--absl/base/invoke_test.cc27
-rw-r--r--absl/base/log_severity.cc (renamed from absl/types/optional.cc)19
-rw-r--r--absl/base/log_severity.h12
-rw-r--r--absl/base/log_severity_test.cc43
-rw-r--r--absl/base/macros.h19
-rw-r--r--absl/base/optimization.h28
-rw-r--r--absl/base/policy_checks.h2
-rw-r--r--absl/base/port.h2
-rw-r--r--absl/base/raw_logging_test.cc2
-rw-r--r--absl/base/spinlock_test_common.cc10
-rw-r--r--absl/base/thread_annotations.h186
-rw-r--r--absl/base/throw_delegate_test.cc2
-rw-r--r--absl/compiler_config_setting.bzl43
-rw-r--r--absl/container/BUILD.bazel197
-rw-r--r--absl/container/CMakeLists.txt190
-rw-r--r--absl/container/fixed_array.h7
-rw-r--r--absl/container/fixed_array_benchmark.cc11
-rw-r--r--absl/container/fixed_array_exception_safety_test.cc11
-rw-r--r--absl/container/fixed_array_test.cc77
-rw-r--r--absl/container/flat_hash_map.h25
-rw-r--r--absl/container/flat_hash_map_test.cc32
-rw-r--r--absl/container/flat_hash_set.h20
-rw-r--r--absl/container/flat_hash_set_test.cc14
-rw-r--r--absl/container/inlined_vector.h1504
-rw-r--r--absl/container/inlined_vector_benchmark.cc561
-rw-r--r--absl/container/inlined_vector_exception_safety_test.cc489
-rw-r--r--absl/container/inlined_vector_test.cc230
-rw-r--r--absl/container/internal/common.h198
-rw-r--r--absl/container/internal/compressed_tuple.h162
-rw-r--r--absl/container/internal/compressed_tuple_test.cc269
-rw-r--r--absl/container/internal/container_memory.h69
-rw-r--r--absl/container/internal/container_memory_test.cc6
-rw-r--r--absl/container/internal/counting_allocator.h81
-rw-r--r--absl/container/internal/hash_function_defaults.h11
-rw-r--r--absl/container/internal/hash_function_defaults_test.cc28
-rw-r--r--absl/container/internal/hash_generator_testing.cc6
-rw-r--r--absl/container/internal/hash_generator_testing.h6
-rw-r--r--absl/container/internal/hash_policy_testing.h6
-rw-r--r--absl/container/internal/hash_policy_testing_test.cc6
-rw-r--r--absl/container/internal/hash_policy_traits.h6
-rw-r--r--absl/container/internal/hash_policy_traits_test.cc6
-rw-r--r--absl/container/internal/hashtable_debug.h8
-rw-r--r--absl/container/internal/hashtable_debug_hooks.h6
-rw-r--r--absl/container/internal/hashtablez_sampler.cc310
-rw-r--r--absl/container/internal/hashtablez_sampler.h290
-rw-r--r--absl/container/internal/hashtablez_sampler_force_weak_definition.cc29
-rw-r--r--absl/container/internal/hashtablez_sampler_test.cc357
-rw-r--r--absl/container/internal/have_sse.h49
-rw-r--r--absl/container/internal/inlined_vector.h895
-rw-r--r--absl/container/internal/layout.h9
-rw-r--r--absl/container/internal/layout_test.cc34
-rw-r--r--absl/container/internal/node_hash_policy.h6
-rw-r--r--absl/container/internal/node_hash_policy_test.cc6
-rw-r--r--absl/container/internal/raw_hash_map.h21
-rw-r--r--absl/container/internal/raw_hash_set.cc6
-rw-r--r--absl/container/internal/raw_hash_set.h392
-rw-r--r--absl/container/internal/raw_hash_set_allocator_test.cc6
-rw-r--r--absl/container/internal/raw_hash_set_test.cc304
-rw-r--r--absl/container/internal/test_instance_tracker.cc6
-rw-r--r--absl/container/internal/test_instance_tracker.h18
-rw-r--r--absl/container/internal/test_instance_tracker_test.cc4
-rw-r--r--absl/container/internal/tracked.h6
-rw-r--r--absl/container/internal/unordered_map_constructor_test.h148
-rw-r--r--absl/container/internal/unordered_map_lookup_test.h8
-rw-r--r--absl/container/internal/unordered_map_members_test.h87
-rw-r--r--absl/container/internal/unordered_map_modifiers_test.h8
-rw-r--r--absl/container/internal/unordered_map_test.cc14
-rw-r--r--absl/container/internal/unordered_set_constructor_test.h155
-rw-r--r--absl/container/internal/unordered_set_lookup_test.h8
-rw-r--r--absl/container/internal/unordered_set_members_test.h86
-rw-r--r--absl/container/internal/unordered_set_modifiers_test.h8
-rw-r--r--absl/container/internal/unordered_set_test.cc24
-rw-r--r--absl/container/node_hash_map.h6
-rw-r--r--absl/container/node_hash_map_test.cc14
-rw-r--r--absl/container/node_hash_set.h6
-rw-r--r--absl/container/node_hash_set_test.cc16
-rw-r--r--absl/copts.bzl170
-rw-r--r--absl/copts/AbseilConfigureCopts.cmake60
-rw-r--r--absl/copts/GENERATED_AbseilCopts.cmake236
-rw-r--r--absl/copts/GENERATED_copts.bzl237
-rw-r--r--absl/copts/configure_copts.bzl89
-rw-r--r--absl/copts/copts.py214
-rwxr-xr-xabsl/copts/generate_copts.py109
-rw-r--r--absl/debugging/BUILD.bazel47
-rw-r--r--absl/debugging/CMakeLists.txt28
-rw-r--r--absl/debugging/failure_signal_handler.cc6
-rw-r--r--absl/debugging/failure_signal_handler.h6
-rw-r--r--absl/debugging/failure_signal_handler_test.cc11
-rw-r--r--absl/debugging/internal/address_is_readable.cc10
-rw-r--r--absl/debugging/internal/address_is_readable.h7
-rw-r--r--absl/debugging/internal/demangle.cc16
-rw-r--r--absl/debugging/internal/demangle.h6
-rw-r--r--absl/debugging/internal/demangle_test.cc12
-rw-r--r--absl/debugging/internal/elf_mem_image.cc6
-rw-r--r--absl/debugging/internal/elf_mem_image.h8
-rw-r--r--absl/debugging/internal/examine_stack.cc6
-rw-r--r--absl/debugging/internal/examine_stack.h6
-rw-r--r--absl/debugging/internal/stack_consumption.cc6
-rw-r--r--absl/debugging/internal/stack_consumption.h6
-rw-r--r--absl/debugging/internal/stack_consumption_test.cc6
-rw-r--r--absl/debugging/internal/stacktrace_aarch64-inl.inc4
-rw-r--r--absl/debugging/internal/stacktrace_arm-inl.inc4
-rw-r--r--absl/debugging/internal/stacktrace_config.h2
-rw-r--r--absl/debugging/internal/stacktrace_generic-inl.inc40
-rw-r--r--absl/debugging/internal/stacktrace_powerpc-inl.inc12
-rw-r--r--absl/debugging/internal/stacktrace_unimplemented-inl.inc4
-rw-r--r--absl/debugging/internal/stacktrace_win32-inl.inc8
-rw-r--r--absl/debugging/internal/stacktrace_x86-inl.inc7
-rw-r--r--absl/debugging/internal/symbolize.h17
-rw-r--r--absl/debugging/internal/vdso_support.cc6
-rw-r--r--absl/debugging/internal/vdso_support.h6
-rw-r--r--absl/debugging/leak_check.cc11
-rw-r--r--absl/debugging/leak_check.h6
-rw-r--r--absl/debugging/leak_check_disable.cc2
-rw-r--r--absl/debugging/leak_check_fail_test.cc2
-rw-r--r--absl/debugging/leak_check_test.cc2
-rw-r--r--absl/debugging/stacktrace.cc7
-rw-r--r--absl/debugging/stacktrace.h6
-rw-r--r--absl/debugging/symbolize.cc2
-rw-r--r--absl/debugging/symbolize.h6
-rw-r--r--absl/debugging/symbolize_elf.inc72
-rw-r--r--absl/debugging/symbolize_test.cc17
-rw-r--r--absl/debugging/symbolize_unimplemented.inc9
-rw-r--r--absl/debugging/symbolize_win32.inc14
-rw-r--r--absl/flags/BUILD.bazel384
-rw-r--r--absl/flags/CMakeLists.txt346
-rw-r--r--absl/flags/config.h48
-rw-r--r--absl/flags/config_test.cc61
-rw-r--r--absl/flags/declare.h60
-rw-r--r--absl/flags/flag.cc46
-rw-r--r--absl/flags/flag.h259
-rw-r--r--absl/flags/flag_test.cc482
-rw-r--r--absl/flags/flag_test_defs.cc22
-rw-r--r--absl/flags/internal/commandlineflag.cc496
-rw-r--r--absl/flags/internal/commandlineflag.h385
-rw-r--r--absl/flags/internal/commandlineflag_test.cc196
-rw-r--r--absl/flags/internal/flag.h123
-rw-r--r--absl/flags/internal/parse.h50
-rw-r--r--absl/flags/internal/path_util.h62
-rw-r--r--absl/flags/internal/path_util_test.cc46
-rw-r--r--absl/flags/internal/program_name.cc55
-rw-r--r--absl/flags/internal/program_name.h49
-rw-r--r--absl/flags/internal/program_name_test.cc60
-rw-r--r--absl/flags/internal/registry.cc445
-rw-r--r--absl/flags/internal/registry.h169
-rw-r--r--absl/flags/internal/type_erased.cc108
-rw-r--r--absl/flags/internal/type_erased.h99
-rw-r--r--absl/flags/internal/type_erased_test.cc147
-rw-r--r--absl/flags/internal/usage.cc385
-rw-r--r--absl/flags/internal/usage.h80
-rw-r--r--absl/flags/internal/usage_test.cc404
-rw-r--r--absl/flags/marshalling.cc191
-rw-r--r--absl/flags/marshalling.h255
-rw-r--r--absl/flags/marshalling_test.cc899
-rw-r--r--absl/flags/parse.cc755
-rw-r--r--absl/flags/parse.h60
-rw-r--r--absl/flags/parse_test.cc858
-rw-r--r--absl/flags/usage.cc58
-rw-r--r--absl/flags/usage.h42
-rw-r--r--absl/flags/usage_config.cc154
-rw-r--r--absl/flags/usage_config.h133
-rw-r--r--absl/flags/usage_config_test.cc198
-rw-r--r--absl/hash/BUILD.bazel11
-rw-r--r--absl/hash/CMakeLists.txt8
-rw-r--r--absl/hash/hash.h42
-rw-r--r--absl/hash/hash_test.cc404
-rw-r--r--absl/hash/hash_testing.h10
-rw-r--r--absl/hash/internal/city.cc6
-rw-r--r--absl/hash/internal/city.h9
-rw-r--r--absl/hash/internal/city_test.cc6
-rw-r--r--absl/hash/internal/hash.cc6
-rw-r--r--absl/hash/internal/hash.h205
-rw-r--r--absl/hash/internal/print_hash_of.cc2
-rw-r--r--absl/hash/internal/spy_hash_state.h12
-rw-r--r--absl/memory/BUILD.bazel9
-rw-r--r--absl/memory/CMakeLists.txt2
-rw-r--r--absl/memory/memory.h25
-rw-r--r--absl/memory/memory_exception_safety_test.cc6
-rw-r--r--absl/memory/memory_test.cc6
-rw-r--r--absl/meta/BUILD.bazel6
-rw-r--r--absl/meta/CMakeLists.txt60
-rw-r--r--absl/meta/type_traits.h314
-rw-r--r--absl/meta/type_traits_test.cc425
-rw-r--r--absl/numeric/BUILD.bazel8
-rw-r--r--absl/numeric/CMakeLists.txt78
-rw-r--r--absl/numeric/int128.cc30
-rw-r--r--absl/numeric/int128.h42
-rw-r--r--absl/numeric/int128_benchmark.cc2
-rw-r--r--absl/numeric/int128_have_intrinsic.inc4
-rw-r--r--absl/numeric/int128_no_intrinsic.inc4
-rw-r--r--absl/numeric/int128_stream_test.cc2
-rw-r--r--absl/numeric/int128_test.cc45
-rw-r--r--absl/random/BUILD.bazel390
-rw-r--r--absl/random/CMakeLists.txt1034
-rw-r--r--absl/random/benchmarks.cc383
-rw-r--r--absl/random/bernoulli_distribution.h200
-rw-r--r--absl/random/bernoulli_distribution_test.cc213
-rw-r--r--absl/random/beta_distribution.h416
-rw-r--r--absl/random/beta_distribution_test.cc614
-rw-r--r--absl/random/discrete_distribution.cc98
-rw-r--r--absl/random/discrete_distribution.h247
-rw-r--r--absl/random/discrete_distribution_test.cc246
-rw-r--r--absl/random/distribution_format_traits.h251
-rw-r--r--absl/random/distributions.h444
-rw-r--r--absl/random/distributions_test.cc494
-rw-r--r--absl/random/examples_test.cc99
-rw-r--r--absl/random/exponential_distribution.h159
-rw-r--r--absl/random/exponential_distribution_test.cc422
-rw-r--r--absl/random/gaussian_distribution.cc104
-rw-r--r--absl/random/gaussian_distribution.h262
-rw-r--r--absl/random/gaussian_distribution_test.cc573
-rw-r--r--absl/random/generators_test.cc179
-rw-r--r--absl/random/internal/BUILD.bazel658
-rw-r--r--absl/random/internal/chi_square.cc232
-rw-r--r--absl/random/internal/chi_square.h87
-rw-r--r--absl/random/internal/chi_square_test.cc365
-rw-r--r--absl/random/internal/distribution_caller.h58
-rw-r--r--absl/random/internal/distribution_impl.h262
-rw-r--r--absl/random/internal/distribution_impl_test.cc506
-rw-r--r--absl/random/internal/distribution_test_util.cc418
-rw-r--r--absl/random/internal/distribution_test_util.h113
-rw-r--r--absl/random/internal/distribution_test_util_test.cc193
-rw-r--r--absl/random/internal/distributions.h84
-rw-r--r--absl/random/internal/explicit_seed_seq.h89
-rw-r--r--absl/random/internal/explicit_seed_seq_test.cc204
-rw-r--r--absl/random/internal/fast_uniform_bits.h262
-rw-r--r--absl/random/internal/fast_uniform_bits_test.cc274
-rw-r--r--absl/random/internal/fastmath.h74
-rw-r--r--absl/random/internal/fastmath_test.cc110
-rw-r--r--absl/random/internal/gaussian_distribution_gentables.cc147
-rw-r--r--absl/random/internal/iostream_state_saver.h245
-rw-r--r--absl/random/internal/iostream_state_saver_test.cc369
-rw-r--r--absl/random/internal/named_generator.cc30
-rw-r--r--absl/random/internal/nanobenchmark.cc812
-rw-r--r--absl/random/internal/nanobenchmark.h170
-rw-r--r--absl/random/internal/nanobenchmark_test.cc77
-rw-r--r--absl/random/internal/nonsecure_base.h150
-rw-r--r--absl/random/internal/nonsecure_base_test.cc244
-rw-r--r--absl/random/internal/pcg_engine.h307
-rw-r--r--absl/random/internal/pcg_engine_test.cc638
-rw-r--r--absl/random/internal/platform.h170
-rw-r--r--absl/random/internal/pool_urbg.cc254
-rw-r--r--absl/random/internal/pool_urbg.h131
-rw-r--r--absl/random/internal/pool_urbg_test.cc182
-rw-r--r--absl/random/internal/randen-keys.inc207
-rw-r--r--absl/random/internal/randen.cc91
-rw-r--r--absl/random/internal/randen.h102
-rw-r--r--absl/random/internal/randen_benchmarks.cc174
-rw-r--r--absl/random/internal/randen_detect.cc221
-rw-r--r--absl/random/internal/randen_detect.h31
-rw-r--r--absl/random/internal/randen_engine.h230
-rw-r--r--absl/random/internal/randen_engine_test.cc656
-rw-r--r--absl/random/internal/randen_hwaes.cc704
-rw-r--r--absl/random/internal/randen_hwaes.h48
-rw-r--r--absl/random/internal/randen_hwaes_test.cc102
-rw-r--r--absl/random/internal/randen_slow.cc514
-rw-r--r--absl/random/internal/randen_slow.h45
-rw-r--r--absl/random/internal/randen_slow_test.cc61
-rw-r--r--absl/random/internal/randen_test.cc70
-rw-r--r--absl/random/internal/randen_traits.h61
-rw-r--r--absl/random/internal/salted_seed_seq.h167
-rw-r--r--absl/random/internal/salted_seed_seq_test.cc168
-rw-r--r--absl/random/internal/seed_material.cc207
-rw-r--r--absl/random/internal/seed_material.h104
-rw-r--r--absl/random/internal/seed_material_test.cc202
-rw-r--r--absl/random/internal/seed_salting_sequence_generator.cc30
-rw-r--r--absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc30
-rw-r--r--absl/random/internal/sequence_urbg.h58
-rw-r--r--absl/random/internal/traits.h101
-rw-r--r--absl/random/internal/traits_test.cc126
-rw-r--r--absl/random/internal/uniform_helper.h152
-rw-r--r--absl/random/log_uniform_int_distribution.h252
-rw-r--r--absl/random/log_uniform_int_distribution_test.cc277
-rw-r--r--absl/random/poisson_distribution.h256
-rw-r--r--absl/random/poisson_distribution_test.cc565
-rw-r--r--absl/random/random.h189
-rw-r--r--absl/random/seed_gen_exception.cc46
-rw-r--r--absl/random/seed_gen_exception.h53
-rw-r--r--absl/random/seed_sequences.cc29
-rw-r--r--absl/random/seed_sequences.h110
-rw-r--r--absl/random/seed_sequences_test.cc127
-rw-r--r--absl/random/uniform_int_distribution.h275
-rw-r--r--absl/random/uniform_int_distribution_test.cc250
-rw-r--r--absl/random/uniform_real_distribution.h195
-rw-r--r--absl/random/uniform_real_distribution_test.cc322
-rw-r--r--absl/random/zipf_distribution.h271
-rw-r--r--absl/random/zipf_distribution_test.cc423
-rw-r--r--absl/strings/BUILD.bazel13
-rw-r--r--absl/strings/CMakeLists.txt793
-rw-r--r--absl/strings/ascii.cc6
-rw-r--r--absl/strings/ascii.h6
-rw-r--r--absl/strings/ascii_benchmark.cc2
-rw-r--r--absl/strings/ascii_test.cc2
-rw-r--r--absl/strings/charconv.cc13
-rw-r--r--absl/strings/charconv.h10
-rw-r--r--absl/strings/charconv_benchmark.cc2
-rw-r--r--absl/strings/charconv_test.cc5
-rw-r--r--absl/strings/escaping.cc54
-rw-r--r--absl/strings/escaping.h24
-rw-r--r--absl/strings/escaping_benchmark.cc2
-rw-r--r--absl/strings/escaping_test.cc80
-rw-r--r--absl/strings/internal/char_map.h6
-rw-r--r--absl/strings/internal/char_map_benchmark.cc2
-rw-r--r--absl/strings/internal/char_map_test.cc2
-rw-r--r--absl/strings/internal/charconv_bigint.cc6
-rw-r--r--absl/strings/internal/charconv_bigint.h20
-rw-r--r--absl/strings/internal/charconv_bigint_test.cc6
-rw-r--r--absl/strings/internal/charconv_parse.cc6
-rw-r--r--absl/strings/internal/charconv_parse.h6
-rw-r--r--absl/strings/internal/charconv_parse_test.cc2
-rw-r--r--absl/strings/internal/escaping_test_common.h6
-rw-r--r--absl/strings/internal/memutil.cc6
-rw-r--r--absl/strings/internal/memutil.h6
-rw-r--r--absl/strings/internal/memutil_benchmark.cc2
-rw-r--r--absl/strings/internal/memutil_test.cc2
-rw-r--r--absl/strings/internal/numbers_test_common.h6
-rw-r--r--absl/strings/internal/ostringstream.cc6
-rw-r--r--absl/strings/internal/ostringstream.h22
-rw-r--r--absl/strings/internal/ostringstream_benchmark.cc2
-rw-r--r--absl/strings/internal/ostringstream_test.cc2
-rw-r--r--absl/strings/internal/pow10_helper.cc6
-rw-r--r--absl/strings/internal/pow10_helper.h12
-rw-r--r--absl/strings/internal/pow10_helper_test.cc6
-rw-r--r--absl/strings/internal/resize_uninitialized.h47
-rw-r--r--absl/strings/internal/resize_uninitialized_test.cc26
-rw-r--r--absl/strings/internal/stl_type_traits.h6
-rw-r--r--absl/strings/internal/str_format/arg.cc4
-rw-r--r--absl/strings/internal/str_format/arg.h16
-rw-r--r--absl/strings/internal/str_format/arg_test.cc6
-rw-r--r--absl/strings/internal/str_format/bind.cc15
-rw-r--r--absl/strings/internal/str_format/bind.h32
-rw-r--r--absl/strings/internal/str_format/bind_test.cc28
-rw-r--r--absl/strings/internal/str_format/checker.h4
-rw-r--r--absl/strings/internal/str_format/checker_test.cc70
-rw-r--r--absl/strings/internal/str_format/convert_test.cc27
-rw-r--r--absl/strings/internal/str_format/extension.cc6
-rw-r--r--absl/strings/internal/str_format/extension.h9
-rw-r--r--absl/strings/internal/str_format/extension_test.cc3
-rw-r--r--absl/strings/internal/str_format/float_conversion.cc8
-rw-r--r--absl/strings/internal/str_format/float_conversion.h4
-rw-r--r--absl/strings/internal/str_format/output.cc6
-rw-r--r--absl/strings/internal/str_format/output.h6
-rw-r--r--absl/strings/internal/str_format/output_test.cc13
-rw-r--r--absl/strings/internal/str_format/parser.cc150
-rw-r--r--absl/strings/internal/str_format/parser.h132
-rw-r--r--absl/strings/internal/str_format/parser_test.cc31
-rw-r--r--absl/strings/internal/str_join_internal.h19
-rw-r--r--absl/strings/internal/str_split_internal.h18
-rw-r--r--absl/strings/internal/utf8.cc6
-rw-r--r--absl/strings/internal/utf8.h7
-rw-r--r--absl/strings/internal/utf8_test.cc19
-rw-r--r--absl/strings/match.cc19
-rw-r--r--absl/strings/match.h13
-rw-r--r--absl/strings/match_test.cc6
-rw-r--r--absl/strings/numbers.cc67
-rw-r--r--absl/strings/numbers.h39
-rw-r--r--absl/strings/numbers_benchmark.cc2
-rw-r--r--absl/strings/numbers_test.cc15
-rw-r--r--absl/strings/str_cat.cc26
-rw-r--r--absl/strings/str_cat.h44
-rw-r--r--absl/strings/str_cat_benchmark.cc2
-rw-r--r--absl/strings/str_cat_test.cc55
-rw-r--r--absl/strings/str_format.h67
-rw-r--r--absl/strings/str_format_test.cc57
-rw-r--r--absl/strings/str_join.h84
-rw-r--r--absl/strings/str_join_benchmark.cc5
-rw-r--r--absl/strings/str_join_test.cc14
-rw-r--r--absl/strings/str_replace.cc11
-rw-r--r--absl/strings/str_replace.h46
-rw-r--r--absl/strings/str_replace_benchmark.cc14
-rw-r--r--absl/strings/str_replace_test.cc4
-rw-r--r--absl/strings/str_split.cc6
-rw-r--r--absl/strings/str_split.h51
-rw-r--r--absl/strings/str_split_benchmark.cc28
-rw-r--r--absl/strings/str_split_test.cc62
-rw-r--r--absl/strings/string_view.cc20
-rw-r--r--absl/strings/string_view.h71
-rw-r--r--absl/strings/string_view_benchmark.cc2
-rw-r--r--absl/strings/string_view_test.cc24
-rw-r--r--absl/strings/strip.h6
-rw-r--r--absl/strings/strip_test.cc5
-rw-r--r--absl/strings/substitute.cc6
-rw-r--r--absl/strings/substitute.h91
-rw-r--r--absl/strings/substitute_test.cc14
-rw-r--r--absl/synchronization/BUILD.bazel37
-rw-r--r--absl/synchronization/CMakeLists.txt273
-rw-r--r--absl/synchronization/barrier.cc6
-rw-r--r--absl/synchronization/barrier.h6
-rw-r--r--absl/synchronization/barrier_test.cc2
-rw-r--r--absl/synchronization/blocking_counter.cc6
-rw-r--r--absl/synchronization/blocking_counter.h6
-rw-r--r--absl/synchronization/blocking_counter_test.cc6
-rw-r--r--absl/synchronization/internal/create_thread_identity.cc35
-rw-r--r--absl/synchronization/internal/create_thread_identity.h7
-rw-r--r--absl/synchronization/internal/graphcycles.cc6
-rw-r--r--absl/synchronization/internal/graphcycles.h6
-rw-r--r--absl/synchronization/internal/graphcycles_benchmark.cc2
-rw-r--r--absl/synchronization/internal/graphcycles_test.cc6
-rw-r--r--absl/synchronization/internal/kernel_timeout.h12
-rw-r--r--absl/synchronization/internal/mutex_nonprod.cc6
-rw-r--r--absl/synchronization/internal/mutex_nonprod.inc7
-rw-r--r--absl/synchronization/internal/per_thread_sem.cc7
-rw-r--r--absl/synchronization/internal/per_thread_sem.h7
-rw-r--r--absl/synchronization/internal/per_thread_sem_test.cc23
-rw-r--r--absl/synchronization/internal/thread_pool.h9
-rw-r--r--absl/synchronization/internal/waiter.cc65
-rw-r--r--absl/synchronization/internal/waiter.h26
-rw-r--r--absl/synchronization/lifetime_test.cc50
-rw-r--r--absl/synchronization/mutex.cc148
-rw-r--r--absl/synchronization/mutex.h32
-rw-r--r--absl/synchronization/mutex_benchmark.cc2
-rw-r--r--absl/synchronization/mutex_test.cc45
-rw-r--r--absl/synchronization/notification.cc6
-rw-r--r--absl/synchronization/notification.h7
-rw-r--r--absl/synchronization/notification_test.cc16
-rw-r--r--absl/time/BUILD.bazel10
-rw-r--r--absl/time/CMakeLists.txt167
-rw-r--r--absl/time/civil_time.cc21
-rw-r--r--absl/time/civil_time.h25
-rw-r--r--absl/time/civil_time_benchmark.cc2
-rw-r--r--absl/time/civil_time_test.cc16
-rw-r--r--absl/time/clock.cc20
-rw-r--r--absl/time/clock.h6
-rw-r--r--absl/time/clock_benchmark.cc4
-rw-r--r--absl/time/clock_test.cc2
-rw-r--r--absl/time/duration.cc19
-rw-r--r--absl/time/duration_benchmark.cc3
-rw-r--r--absl/time/duration_test.cc8
-rw-r--r--absl/time/format.cc17
-rw-r--r--absl/time/format_benchmark.cc2
-rw-r--r--absl/time/format_test.cc11
-rw-r--r--absl/time/internal/cctz/BUILD.bazel27
-rw-r--r--absl/time/internal/cctz/include/cctz/civil_time.h14
-rw-r--r--absl/time/internal/cctz/include/cctz/civil_time_detail.h68
-rw-r--r--absl/time/internal/cctz/include/cctz/time_zone.h8
-rw-r--r--absl/time/internal/cctz/include/cctz/zone_info_source.h10
-rw-r--r--absl/time/internal/cctz/src/cctz_benchmark.cc53
-rw-r--r--absl/time/internal/cctz/src/civil_time_detail.cc6
-rw-r--r--absl/time/internal/cctz/src/civil_time_test.cc22
-rw-r--r--absl/time/internal/cctz/src/time_zone_fixed.cc22
-rw-r--r--absl/time/internal/cctz/src/time_zone_fixed.h6
-rw-r--r--absl/time/internal/cctz/src/time_zone_format.cc104
-rw-r--r--absl/time/internal/cctz/src/time_zone_format_test.cc367
-rw-r--r--absl/time/internal/cctz/src/time_zone_if.cc6
-rw-r--r--absl/time/internal/cctz/src/time_zone_if.h6
-rw-r--r--absl/time/internal/cctz/src/time_zone_impl.cc6
-rw-r--r--absl/time/internal/cctz/src/time_zone_impl.h6
-rw-r--r--absl/time/internal/cctz/src/time_zone_info.cc29
-rw-r--r--absl/time/internal/cctz/src/time_zone_info.h8
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc109
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.h6
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup.cc41
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc33
-rw-r--r--absl/time/internal/cctz/src/time_zone_posix.cc16
-rw-r--r--absl/time/internal/cctz/src/time_zone_posix.h6
-rw-r--r--absl/time/internal/cctz/src/tzfile.h20
-rw-r--r--absl/time/internal/cctz/src/zone_info_source.cc34
-rw-r--r--absl/time/internal/cctz/testdata/version2
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjanbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Accrabin828 -> 816 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Abababin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiersbin751 -> 735 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmarabin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmerabin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamakobin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Banguibin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjulbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyrebin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzavillebin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumburabin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairobin1963 -> 1955 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablancabin1533 -> 2429 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceutabin2050 -> 2036 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakrybin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakarbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaambin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Djiboutibin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Doualabin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiunbin1403 -> 2295 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetownbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaboronebin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Hararebin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburgbin262 -> 246 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Jubabin669 -> 653 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampalabin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoumbin699 -> 679 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigalibin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasabin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagosbin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Librevillebin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Lomebin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Luandabin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashibin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusakabin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabobin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputobin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Maserubin262 -> 246 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabanebin262 -> 246 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishubin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Monroviabin224 -> 208 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobibin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamenabin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Niameybin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchottbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougoubin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novobin157 -> 149 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tomebin225 -> 254 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktubin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripolibin641 -> 625 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunisbin701 -> 689 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoekbin979 -> 955 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Anguillabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Antiguabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Araguainabin896 -> 884 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Airesbin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarcabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadaviabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordobabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuybin1072 -> 1048 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Riojabin1114 -> 1090 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendozabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegosbin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Saltabin1072 -> 1048 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juanbin1114 -> 1090 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luisbin1130 -> 1102 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucumanbin1128 -> 1104 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaiabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Arubabin198 -> 186 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Asuncionbin2068 -> 2044 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Bahiabin1036 -> 1024 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderasbin1574 -> 1546 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Barbadosbin330 -> 314 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Belembin588 -> 576 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Belizebin964 -> 948 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vistabin644 -> 632 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Bogotabin262 -> 246 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Airesbin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grandebin2002 -> 1444 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Cancunbin802 -> 782 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Caracasbin280 -> 264 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Catamarcabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Cayennebin210 -> 198 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Caymanbin194 -> 182 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahuabin1508 -> 1484 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Cordobabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Ricabin332 -> 316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Crestonbin224 -> 208 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Cuiababin1974 -> 1416 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Curacaobin198 -> 186 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Dominicabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepebin676 -> 656 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvadorbin236 -> 224 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Fortalezabin728 -> 716 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turkbin1872 -> 1848 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Grenadabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupebin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Guatemalabin292 -> 280 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquilbin262 -> 246 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Guyanabin252 -> 236 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Havanabin2428 -> 2416 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillobin440 -> 416 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Inuvikbin1914 -> 1894 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Jamaicabin498 -> 482 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Jujuybin1072 -> 1048 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijkbin198 -> 186 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/La_Pazbin248 -> 232 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Limabin422 -> 406 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princesbin198 -> 186 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Maceiobin756 -> 744 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Managuabin454 -> 430 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Manausbin616 -> 604 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Marigotbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Martiniquebin248 -> 232 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Matamorosbin1402 -> 1390 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlanbin1550 -> 1526 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Mendozabin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Meridabin1442 -> 1422 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatlabin1409 -> 1423 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_Citybin1604 -> 1584 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Miquelonbin1682 -> 1666 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Monterreybin1402 -> 1390 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Montevideobin1550 -> 1510 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Montserratbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Nassaubin2270 -> 2258 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Noronhabin728 -> 716 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Ojinagabin1508 -> 1484 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Panamabin194 -> 182 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribobin282 -> 262 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Phoenixbin344 -> 328 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Princebin1446 -> 1434 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spainbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acrebin648 -> 628 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velhobin588 -> 576 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inletbin1916 -> 1892 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Recifebin728 -> 716 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Resolutebin1916 -> 1892 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Brancobin648 -> 628 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Rosariobin1100 -> 1076 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Santarembin618 -> 602 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingobin482 -> 458 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulobin2002 -> 1444 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemybin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/St_Kittsbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/St_Luciabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomasbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincentbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpabin264 -> 252 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Thulebin1514 -> 1502 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Tortolabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Virginbin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/America/Winnipegbin2882 -> 2868 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrvillebin202 -> 194 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquariebin1534 -> 1520 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawsonbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdobin2451 -> 2437 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rotherabin172 -> 164 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Polebin2451 -> 2437 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowabin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostokbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyenbin2242 -> 2228 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Adenbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Almatybin1017 -> 997 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ammanbin1863 -> 1853 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyrbin1208 -> 1188 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtaubin1003 -> 983 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobebin1033 -> 1011 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabatbin637 -> 619 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabadbin637 -> 619 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyraubin1011 -> 991 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdadbin995 -> 983 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrainbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Bakubin1255 -> 1227 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkokbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaulbin1241 -> 1221 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirutbin2166 -> 2154 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkekbin999 -> 983 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Bruneibin215 -> 203 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcuttabin303 -> 285 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Chitabin1243 -> 1221 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsanbin977 -> 949 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqingbin545 -> 533 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungkingbin545 -> 533 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombobin404 -> 372 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Daccabin361 -> 337 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascusbin2306 -> 2294 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhakabin361 -> 337 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Dilibin239 -> 227 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubaibin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbebin607 -> 591 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Gazabin2286 -> 2316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbinbin545 -> 533 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebronbin2314 -> 2344 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minhbin375 -> 351 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kongbin1175 -> 1193 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovdbin907 -> 891 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutskbin1267 -> 1243 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbulbin2157 -> 2143 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakartabin383 -> 355 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapurabin237 -> 221 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalembin2256 -> 2288 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabulbin220 -> 208 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatkabin1184 -> 1166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachibin403 -> 379 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgarbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandubin224 -> 212 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandubin224 -> 212 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandygabin1297 -> 1271 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkatabin303 -> 285 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarskbin1229 -> 1207 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpurbin415 -> 383 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuchingbin507 -> 483 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwaitbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Macaobin1241 -> 1227 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Macaubin1241 -> 1227 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadanbin1244 -> 1222 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassarbin274 -> 254 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Manilabin350 -> 328 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscatbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetskbin1183 -> 1165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirskbin1241 -> 1221 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Omskbin1229 -> 1207 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Oralbin1025 -> 1005 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penhbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianakbin381 -> 353 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyangbin253 -> 237 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatarbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanaybin0 -> 1011 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylordabin1017 -> 1025 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoonbin288 -> 268 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadhbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigonbin375 -> 351 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalinbin1220 -> 1202 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkandbin605 -> 577 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoulbin517 -> 493 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghaibin545 -> 533 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Singaporebin415 -> 383 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymskbin1230 -> 1208 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipeibin781 -> 761 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkentbin621 -> 591 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisibin1071 -> 1035 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehranbin1704 -> 2582 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Avivbin2256 -> 2288 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbubin215 -> 203 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphubin215 -> 203 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomskbin1241 -> 1221 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandangbin274 -> 254 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatarbin907 -> 891 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Batorbin907 -> 891 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqibin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nerabin1276 -> 1252 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientianebin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostokbin1230 -> 1208 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutskbin1229 -> 1207 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangonbin288 -> 268 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburgbin1267 -> 1243 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevanbin1199 -> 1151 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermudabin1990 -> 1978 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayenbin2242 -> 2228 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavikbin1174 -> 1162 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgiabin172 -> 164 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helenabin156 -> 148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanleybin1242 -> 1214 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/ACTbin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaidebin2233 -> 2222 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbanebin443 -> 433 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hillbin2269 -> 2243 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberrabin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Curriebin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwinbin318 -> 304 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Euclabin494 -> 484 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobartbin2326 -> 2316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/LHIbin1880 -> 1860 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindemanbin513 -> 489 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howebin1880 -> 1860 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbournebin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/NSWbin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Northbin318 -> 304 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Perthbin470 -> 460 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Queenslandbin443 -> 433 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Southbin2233 -> 2222 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydneybin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmaniabin2326 -> 2316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoriabin2214 -> 2204 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Westbin470 -> 460 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinnabin2269 -> 2243 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acrebin648 -> 628 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronhabin728 -> 716 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Brazil/Eastbin2002 -> 1444 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Brazil/Westbin616 -> 604 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/CETbin2102 -> 2094 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/CST6CDTbin2294 -> 2310 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Canada/Centralbin2882 -> 2868 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Cubabin2428 -> 2416 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/EETbin1876 -> 1908 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/ESTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/EST5EDTbin2294 -> 2310 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Egyptbin1963 -> 1955 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Eirebin3522 -> 3492 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9bin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10bin122 -> 118 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11bin122 -> 118 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12bin122 -> 118 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13bin122 -> 118 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14bin122 -> 118 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9bin121 -> 117 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwichbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/UCTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/UTCbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/Universalbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulubin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdambin2940 -> 2910 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhanbin1183 -> 1165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfastbin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgradebin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlinbin2326 -> 2298 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislavabin2329 -> 2301 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Brusselsbin2961 -> 2933 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharestbin2212 -> 2184 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapestbin2396 -> 2368 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinaubin2436 -> 2390 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagenbin2151 -> 2137 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublinbin3522 -> 3492 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernseybin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Manbin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbulbin2157 -> 2143 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Jerseybin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningradbin1509 -> 1479 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljanabin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Londonbin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourgbin2960 -> 2946 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Madridbin2628 -> 2614 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Minskbin1361 -> 1321 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslobin2242 -> 2228 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgoricabin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Praguebin2329 -> 2301 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Rigabin2226 -> 2198 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Romebin2683 -> 2641 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marinobin2683 -> 2641 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevobin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopolbin1481 -> 1453 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopjebin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofiabin2121 -> 2077 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinnbin2178 -> 2148 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspolbin2436 -> 2390 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorodbin2094 -> 2050 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaticanbin2683 -> 2641 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Viennabin2228 -> 2200 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilniusbin2190 -> 2162 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgogradbin1183 -> 1165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsawbin2696 -> 2654 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagrebbin1948 -> 1920 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Factorybin120 -> 116 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GBbin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GB-Eirebin3678 -> 3648 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GMTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GMT+0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GMT-0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/GMT0bin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Greenwichbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/HSTbin119 -> 115 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Hongkongbin1175 -> 1193 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Icelandbin1174 -> 1162 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivobin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagosbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmasbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocosbin182 -> 174 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Comorobin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelenbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahebin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldivesbin211 -> 199 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritiusbin253 -> 241 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayottebin271 -> 251 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunionbin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Iranbin1704 -> 2582 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Israelbin2256 -> 2288 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Jamaicabin498 -> 482 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Kwajaleinbin250 -> 316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Libyabin641 -> 625 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/METbin2102 -> 2094 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/MSTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/MST7MDTbin2294 -> 2310 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSurbin1550 -> 1526 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Mexico/Generalbin1604 -> 1584 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/NZbin2451 -> 2437 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/NZ-CHATbin2078 -> 2068 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/PRCbin545 -> 533 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/PST8PDTbin2294 -> 2310 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apiabin1125 -> 1097 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Aucklandbin2451 -> 2437 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainvillebin286 -> 268 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chathambin2078 -> 2068 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuukbin174 -> 269 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efatebin478 -> 466 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderburybin250 -> 234 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofobin212 -> 200 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fijibin1090 -> 1078 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafutibin174 -> 166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagosbin254 -> 238 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambierbin172 -> 164 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanalbin174 -> 166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guambin216 -> 494 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimatibin254 -> 238 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosraebin242 -> 351 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajaleinbin250 -> 316 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majurobin212 -> 310 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesasbin181 -> 173 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midwaybin187 -> 175 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Naurubin268 -> 252 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niuebin257 -> 241 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolkbin314 -> 294 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumeabin314 -> 304 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pagobin187 -> 175 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palaubin173 -> 180 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairnbin214 -> 202 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpeibin174 -> 303 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponapebin174 -> 303 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresbybin196 -> 186 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotongabin593 -> 577 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipanbin216 -> 494 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoabin187 -> 175 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahitibin173 -> 165 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawabin174 -> 166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapubin384 -> 372 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Trukbin174 -> 269 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wakebin174 -> 166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallisbin174 -> 166 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yapbin174 -> 269 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Polandbin2696 -> 2654 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/ROCbin781 -> 761 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/ROKbin517 -> 493 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Singaporebin415 -> 383 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Turkeybin2157 -> 2143 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/UCTbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/US/Arizonabin344 -> 328 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/US/Samoabin187 -> 175 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/UTCbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Universalbin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/WETbin1873 -> 1905 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/Zulubin118 -> 114 bytes
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab8
-rw-r--r--absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab4
-rw-r--r--absl/time/internal/get_current_time_chrono.inc6
-rw-r--r--absl/time/internal/get_current_time_posix.inc4
-rw-r--r--absl/time/internal/test_util.cc10
-rw-r--r--absl/time/internal/test_util.h6
-rw-r--r--absl/time/time.cc16
-rw-r--r--absl/time/time.h40
-rw-r--r--absl/time/time_benchmark.cc2
-rw-r--r--absl/time/time_test.cc24
-rw-r--r--absl/time/time_zone_test.cc2
-rw-r--r--absl/types/BUILD.bazel69
-rw-r--r--absl/types/CMakeLists.txt462
-rw-r--r--absl/types/any.h12
-rw-r--r--absl/types/any_exception_safety_test.cc3
-rw-r--r--absl/types/any_test.cc70
-rw-r--r--absl/types/bad_any_cast.cc6
-rw-r--r--absl/types/bad_any_cast.h10
-rw-r--r--absl/types/bad_optional_access.cc6
-rw-r--r--absl/types/bad_optional_access.h10
-rw-r--r--absl/types/bad_variant_access.cc6
-rw-r--r--absl/types/bad_variant_access.h10
-rw-r--r--absl/types/compare.h510
-rw-r--r--absl/types/compare_test.cc313
-rw-r--r--absl/types/internal/optional.h396
-rw-r--r--absl/types/internal/span.h128
-rw-r--r--absl/types/internal/variant.h74
-rw-r--r--absl/types/optional.h454
-rw-r--r--absl/types/optional_exception_safety_test.cc6
-rw-r--r--absl/types/optional_test.cc90
-rw-r--r--absl/types/span.h221
-rw-r--r--absl/types/span_test.cc57
-rw-r--r--absl/types/variant.h33
-rw-r--r--absl/types/variant_benchmark.cc6
-rw-r--r--absl/types/variant_exception_safety_test.cc15
-rw-r--r--absl/types/variant_test.cc242
-rw-r--r--absl/utility/BUILD.bazel5
-rw-r--r--absl/utility/CMakeLists.txt56
-rw-r--r--absl/utility/utility.h99
-rw-r--r--absl/utility/utility_test.cc35
-rwxr-xr-xci/cmake_install_test.sh33
-rwxr-xr-xci/linux_clang-latest_libcxx_asan_bazel.sh89
-rwxr-xr-xci/linux_clang-latest_libcxx_bazel.sh78
-rwxr-xr-xci/linux_clang-latest_libcxx_tsan_bazel.sh83
-rwxr-xr-xci/linux_clang-latest_libstdcxx_bazel.sh77
-rwxr-xr-xci/linux_gcc-4.8_libstdcxx_cmake.sh61
-rwxr-xr-xci/linux_gcc-4.9_libstdcxx_bazel.sh75
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_bazel.sh75
-rwxr-xr-xci/linux_gcc-latest_libstdcxx_cmake.sh61
-rwxr-xr-xci/macos_xcode_bazel.sh41
-rwxr-xr-xci/macos_xcode_cmake.sh43
-rw-r--r--conanfile.py51
1069 files changed, 48041 insertions, 6846 deletions
diff --git a/.gitignore b/.gitignore
index 7175c4f8..d54fa5a9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@ build
CMakeLists.txt.user
# Ignore VS Code files
.vscode/*
+# Ignore generated python artifacts
+*.pyc
+copts/__pycache__/
diff --git a/CMake/AbseilConfigureCopts.cmake b/CMake/AbseilConfigureCopts.cmake
deleted file mode 100644
index 96e0390b..00000000
--- a/CMake/AbseilConfigureCopts.cmake
+++ /dev/null
@@ -1,145 +0,0 @@
-# Abseil-specific compiler flags. See absl/copts.bzl for description.
-# DO NOT CHANGE THIS FILE WITHOUT THE CORRESPONDING CHANGE TO absl/copts.bzl
-
-list(APPEND GCC_FLAGS
- -Wall
- -Wextra
- -Wcast-qual
- -Wconversion-null
- -Wmissing-declarations
- -Woverlength-strings
- -Wpointer-arith
- -Wunused-local-typedefs
- -Wunused-result
- -Wvarargs
- -Wwrite-strings
- -Wno-sign-compare
-)
-
-list(APPEND GCC_TEST_FLAGS
- -Wno-conversion-null
- -Wno-missing-declarations
- -Wno-sign-compare
- -Wno-unused-function
- -Wno-unused-parameter
- -Wno-unused-private-field
-)
-
-list(APPEND LLVM_FLAGS
- -Wall
- -Wextra
- -Weverything
- -Wno-c++98-compat-pedantic
- -Wno-conversion
- -Wno-covered-switch-default
- -Wno-deprecated
- -Wno-disabled-macro-expansion
- -Wno-double-promotion
- -Wno-comma
- -Wno-extra-semi
- -Wno-packed
- -Wno-padded
- -Wno-sign-compare
- -Wno-float-conversion
- -Wno-float-equal
- -Wno-format-nonliteral
- -Wno-gcc-compat
- -Wno-global-constructors
- -Wno-exit-time-destructors
- -Wno-nested-anon-types
- -Wno-non-modular-include-in-module
- -Wno-old-style-cast
- -Wno-range-loop-analysis
- -Wno-reserved-id-macro
- -Wno-shorten-64-to-32
- -Wno-switch-enum
- -Wno-thread-safety-negative
- -Wno-undef
- -Wno-unknown-warning-option
- -Wno-unreachable-code
- -Wno-unused-macros
- -Wno-weak-vtables
- -Wbitfield-enum-conversion
- -Wbool-conversion
- -Wconstant-conversion
- -Wenum-conversion
- -Wint-conversion
- -Wliteral-conversion
- -Wnon-literal-null-conversion
- -Wnull-conversion
- -Wobjc-literal-conversion
- -Wno-sign-conversion
- -Wstring-conversion
-)
-
-list(APPEND LLVM_TEST_FLAGS
- -Wno-c99-extensions
- -Wno-missing-noreturn
- -Wno-missing-prototypes
- -Wno-missing-variable-declarations
- -Wno-null-conversion
- -Wno-shadow
- -Wno-shift-sign-overflow
- -Wno-sign-compare
- -Wno-unused-function
- -Wno-unused-member-function
- -Wno-unused-parameter
- -Wno-unused-private-field
- -Wno-unused-template
- -Wno-used-but-marked-unused
- -Wno-zero-as-null-pointer-constant
- -Wno-gnu-zero-variadic-macro-arguments
-)
-
-list(APPEND MSVC_FLAGS
- /W3
- /wd4005
- /wd4018
- /wd4068
- /wd4180
- /wd4244
- /wd4267
- /wd4800
- /DNOMINMAX
- /DWIN32_LEAN_AND_MEAN
- /D_CRT_SECURE_NO_WARNINGS
- /D_SCL_SECURE_NO_WARNINGS
- /D_ENABLE_EXTENDED_ALIGNED_STORAGE
-)
-
-list(APPEND MSVC_TEST_FLAGS
- /wd4101
- /wd4503
-)
-
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(ABSL_DEFAULT_COPTS "${GCC_FLAGS}")
- set(ABSL_TEST_COPTS "${GCC_FLAGS};${GCC_TEST_FLAGS}")
- set(ABSL_EXCEPTIONS_FLAG "-fexceptions")
-elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
- # MATCHES so we get both Clang and AppleClang
- set(ABSL_DEFAULT_COPTS "${LLVM_FLAGS}")
- set(ABSL_TEST_COPTS "${LLVM_FLAGS};${LLVM_TEST_FLAGS}")
- set(ABSL_EXCEPTIONS_FLAG "-fexceptions")
-elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
- set(ABSL_DEFAULT_COPTS "${MSVC_FLAGS}")
- set(ABSL_TEST_COPTS "${MSVC_FLAGS};${MSVC_TEST_FLAGS}")
- set(ABSL_EXCEPTIONS_FLAG "/U_HAS_EXCEPTIONS;/D_HAS_EXCEPTIONS=1;/EHsc")
-else()
- message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags")
- set(ABSL_DEFAULT_COPTS "")
- set(ABSL_TEST_COPTS "")
- set(ABSL_EXCEPTIONS_FLAG "")
-endif()
-
-# This flag is used internally for Bazel builds and is kept here for consistency
-set(ABSL_EXCEPTIONS_FLAG_LINKOPTS "")
-
-if("${CMAKE_CXX_STANDARD}" EQUAL 98)
- message(FATAL_ERROR "Abseil requires at least C++11")
-elseif(NOT "${CMAKE_CXX_STANDARD}")
- message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
- set(ABSL_CXX_STANDARD 11)
-else()
- set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
-endif()
diff --git a/CMake/AbseilHelpers.cmake b/CMake/AbseilHelpers.cmake
index 5402bf51..58f98c8c 100644
--- a/CMake/AbseilHelpers.cmake
+++ b/CMake/AbseilHelpers.cmake
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -16,6 +16,7 @@
include(CMakeParseArguments)
include(AbseilConfigureCopts)
+include(AbseilInstallDirs)
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
# project that sets
@@ -23,53 +24,8 @@ include(AbseilConfigureCopts)
# For example, Visual Studio supports folders.
set(ABSL_IDE_FOLDER Abseil)
+# absl_cc_library()
#
-# create a library in the absl namespace
-#
-# parameters
-# SOURCES : sources files for the library
-# PUBLIC_LIBRARIES: targets and flags for linking phase
-# PRIVATE_COMPILE_FLAGS: compile flags for the library. Will not be exported.
-# EXPORT_NAME: export name for the absl:: target export
-# TARGET: target name
-#
-# create a target associated to <NAME>
-# libraries are installed under CMAKE_INSTALL_FULL_LIBDIR by default
-#
-function(absl_library)
- cmake_parse_arguments(ABSL_LIB
- "DISABLE_INSTALL" # keep that in case we want to support installation one day
- "TARGET;EXPORT_NAME"
- "SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS"
- ${ARGN}
- )
-
- set(_NAME ${ABSL_LIB_TARGET})
- string(TOUPPER ${_NAME} _UPPER_NAME)
-
- add_library(${_NAME} STATIC ${ABSL_LIB_SOURCES})
-
- target_compile_options(${_NAME}
- PRIVATE
- ${ABSL_LIB_PRIVATE_COMPILE_FLAGS}
- ${ABSL_DEFAULT_COPTS}
- )
- target_link_libraries(${_NAME} PUBLIC ${ABSL_LIB_PUBLIC_LIBRARIES})
- target_include_directories(${_NAME}
- PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
- PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS}
- )
- # Add all Abseil targets to a a folder in the IDE for organization.
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
-
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
-
- if(ABSL_LIB_EXPORT_NAME)
- add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
- endif()
-endfunction()
-
# CMake function to imitate Bazel's cc_library rule.
#
# Parameters:
@@ -80,13 +36,13 @@ endfunction()
# COPTS: List of private compile options
# DEFINES: List of public defines
# LINKOPTS: List of link options
-# PUBLIC: Add this so that this library will be exported under absl:: (see Note).
+# PUBLIC: Add this so that this library will be exported under absl::
# Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
# TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
#
# Note:
-# By default, absl_cc_library will always create a library named absl_internal_${NAME},
-# and alias target absl::${NAME}.
+# By default, absl_cc_library will always create a library named absl_${NAME},
+# and alias target absl::${NAME}. The absl:: form should always be used.
# This is to reduce namespace pollution.
#
# absl_cc_library(
@@ -103,21 +59,18 @@ endfunction()
# SRCS
# "b.cc"
# DEPS
-# absl_internal_awesome # not "awesome"!
+# absl::awesome # not "awesome" !
+# PUBLIC
# )
#
-# If PUBLIC is set, absl_cc_library will instead create a target named
-# absl_${NAME} and still an alias absl::${NAME}.
-#
# absl_cc_library(
# NAME
# main_lib
# ...
-# PUBLIC
+# DEPS
+# absl::fantastic_lib
# )
#
-# User can then use the library as absl::main_lib (although absl_main_lib is defined too).
-#
# TODO: Implement "ALWAYSLINK"
function(absl_cc_library)
cmake_parse_arguments(ABSL_CC_LIB
@@ -127,15 +80,24 @@ function(absl_cc_library)
${ARGN}
)
- if (NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
- if (ABSL_CC_LIB_PUBLIC)
- set(_NAME "absl_${ABSL_CC_LIB_NAME}")
+ if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
+ if(ABSL_ENABLE_INSTALL)
+ set(_NAME "${ABSL_CC_LIB_NAME}")
else()
- set(_NAME "absl_internal_${ABSL_CC_LIB_NAME}")
+ set(_NAME "absl_${ABSL_CC_LIB_NAME}")
endif()
# Check if this is a header-only library
- if ("${ABSL_CC_LIB_SRCS}" STREQUAL "")
+ # Note that as of February 2019, many popular OS's (for example, Ubuntu
+ # 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't
+ # use list(FILTER...)
+ set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}")
+ foreach(src_file IN LISTS ABSL_CC_SRCS)
+ if(${src_file} MATCHES ".*\\.(h|inc)")
+ list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}")
+ endif()
+ endforeach()
+ if("${ABSL_CC_SRCS}" STREQUAL "")
set(ABSL_CC_LIB_IS_INTERFACE 1)
else()
set(ABSL_CC_LIB_IS_INTERFACE 0)
@@ -145,12 +107,17 @@ function(absl_cc_library)
add_library(${_NAME} STATIC "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
target_include_directories(${_NAME}
- PUBLIC ${ABSL_COMMON_INCLUDE_DIRS})
+ PUBLIC
+ $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>
+ $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ )
target_compile_options(${_NAME}
PRIVATE ${ABSL_CC_LIB_COPTS})
target_link_libraries(${_NAME}
PUBLIC ${ABSL_CC_LIB_DEPS}
- PRIVATE ${ABSL_CC_LIB_LINKOPTS}
+ PRIVATE
+ ${ABSL_CC_LIB_LINKOPTS}
+ ${ABSL_DEFAULT_LINKOPTS}
)
target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
@@ -166,17 +133,40 @@ function(absl_cc_library)
# INTERFACE libraries can't have the CXX_STANDARD property set
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+
+ # When being installed, we lose the absl_ prefix. We want to put it back
+ # to have properly named lib files. This is a no-op when we are not being
+ # installed.
+ set_target_properties(${_NAME} PROPERTIES
+ OUTPUT_NAME "absl_${_NAME}"
+ )
else()
# Generating header-only library
add_library(${_NAME} INTERFACE)
target_include_directories(${_NAME}
- INTERFACE ${ABSL_COMMON_INCLUDE_DIRS})
+ INTERFACE
+ $<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>
+ $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
+ )
target_link_libraries(${_NAME}
- INTERFACE ${ABSL_CC_LIB_DEPS} ${ABSL_CC_LIB_LINKOPTS}
+ INTERFACE
+ ${ABSL_CC_LIB_DEPS}
+ ${ABSL_CC_LIB_LINKOPTS}
+ ${ABSL_DEFAULT_LINKOPTS}
)
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
endif()
+ # TODO currently we don't install googletest alongside abseil sources, so
+ # installed abseil can't be tested.
+ if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
+ install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
+ RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
+ )
+ endif()
+
add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})
endif()
endfunction()
@@ -256,116 +246,10 @@ function(absl_cc_test)
add_test(NAME ${_NAME} COMMAND ${_NAME})
endfunction()
-#
-# header only virtual target creation
-#
-function(absl_header_library)
- cmake_parse_arguments(ABSL_HO_LIB
- "DISABLE_INSTALL"
- "EXPORT_NAME;TARGET"
- "PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS;PRIVATE_INCLUDE_DIRS"
- ${ARGN}
- )
-
- set(_NAME ${ABSL_HO_LIB_TARGET})
-
- set(__dummy_header_only_lib_file "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}_header_only_dummy.cc")
-
- if(NOT EXISTS ${__dummy_header_only_lib_file})
- file(WRITE ${__dummy_header_only_lib_file}
- "/* generated file for header-only cmake target */
-
- namespace absl {
-
- // single meaningless symbol
- void ${_NAME}__header_fakesym() {}
- } // namespace absl
- "
- )
- endif()
-
-
- add_library(${_NAME} ${__dummy_header_only_lib_file})
- target_link_libraries(${_NAME} PUBLIC ${ABSL_HO_LIB_PUBLIC_LIBRARIES})
- target_include_directories(${_NAME}
- PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_HO_LIB_PUBLIC_INCLUDE_DIRS}
- PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS}
- )
-
- # Add all Abseil targets to a a folder in the IDE for organization.
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
-
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
-
- if(ABSL_HO_LIB_EXPORT_NAME)
- add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
- endif()
-
-endfunction()
-
-#
-# create an abseil unit_test and add it to the executed test list
-#
-# parameters
-# TARGET: target name prefix
-# SOURCES: sources files for the tests
-# PUBLIC_LIBRARIES: targets and flags for linking phase.
-# PRIVATE_COMPILE_FLAGS: compile flags for the test. Will not be exported.
-#
-# create a target associated to <NAME>_bin
-#
-# all tests will be register for execution with add_test()
-#
-# test compilation and execution is disable when ABSL_RUN_TESTS=OFF
-#
-function(absl_test)
-
- cmake_parse_arguments(ABSL_TEST
- ""
- "TARGET"
- "SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS"
- ${ARGN}
- )
-
-
- if(ABSL_RUN_TESTS)
-
- set(_NAME "absl_${ABSL_TEST_TARGET}")
- string(TOUPPER ${_NAME} _UPPER_NAME)
-
- add_executable(${_NAME} ${ABSL_TEST_SOURCES})
-
- target_compile_options(${_NAME}
- PRIVATE
- ${ABSL_TEST_PRIVATE_COMPILE_FLAGS}
- ${ABSL_TEST_COPTS}
- )
- target_link_libraries(${_NAME} PUBLIC ${ABSL_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COMMON_LIBRARIES})
- target_include_directories(${_NAME}
- PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_TEST_PUBLIC_INCLUDE_DIRS}
- PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
- )
-
- # Add all Abseil targets to a a folder in the IDE for organization.
- set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
-
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
- set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
-
- add_test(NAME ${_NAME} COMMAND ${_NAME})
- endif(ABSL_RUN_TESTS)
-
-endfunction()
-
-
-
function(check_target my_target)
-
if(NOT TARGET ${my_target})
message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project,
see CMake/README.md for more details")
endif(NOT TARGET ${my_target})
-
endfunction()
diff --git a/CMake/AbseilInstallDirs.cmake b/CMake/AbseilInstallDirs.cmake
new file mode 100644
index 00000000..b67272f8
--- /dev/null
+++ b/CMake/AbseilInstallDirs.cmake
@@ -0,0 +1,20 @@
+include(GNUInstallDirs)
+
+# absl_VERSION is only set if we are an LTS release being installed, in which
+# case it may be into a system directory and so we need to make subdirectories
+# for each installed version of Abseil. This mechanism is implemented in
+# Abseil's internal Copybara (https://github.com/google/copybara) workflows and
+# isn't visible in the CMake buildsystem itself.
+
+if(absl_VERSION)
+ set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
+ set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
+ set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
+ set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}")
+ set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
+else()
+ set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
+ set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+ set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
+ set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
+endif() \ No newline at end of file
diff --git a/CMake/CMakeLists.txt.in b/CMake/Googletest/CMakeLists.txt.in
index d60a33e9..d60a33e9 100644
--- a/CMake/CMakeLists.txt.in
+++ b/CMake/Googletest/CMakeLists.txt.in
diff --git a/CMake/DownloadGTest.cmake b/CMake/Googletest/DownloadGTest.cmake
index 3c682aef..3c682aef 100644
--- a/CMake/DownloadGTest.cmake
+++ b/CMake/Googletest/DownloadGTest.cmake
diff --git a/CMake/README.md b/CMake/README.md
index 79bbe24d..469dfef5 100644
--- a/CMake/README.md
+++ b/CMake/README.md
@@ -3,7 +3,7 @@
Abseil comes with a CMake build script ([CMakeLists.txt](../CMakeLists.txt))
that can be used on a wide range of platforms ("C" stands for cross-platform.).
If you don't have CMake installed already, you can download it for free from
-<http://www.cmake.org/>.
+<https://www.cmake.org/>.
CMake works by generating native makefiles or build projects that can
be used in the compiler environment of your choice.
@@ -37,20 +37,12 @@ section of your executable or of your library.<br>
Here is a short CMakeLists.txt example of a project file using Abseil.
```cmake
-cmake_minimum_required(VERSION 2.8.12)
+cmake_minimum_required(VERSION 3.5)
project(my_project)
-set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
-
-if(MSVC)
- # /wd4005 macro-redefinition
- # /wd4068 unknown pragma
- # /wd4244 conversion from 'type1' to 'type2'
- # /wd4267 conversion from 'size_t' to 'type2'
- # /wd4800 force value to bool 'true' or 'false' (performance warning)
- add_compile_options(/wd4005 /wd4068 /wd4244 /wd4267 /wd4800)
- add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
-endif()
+# Pick the C++ standard to compile with.
+# Abseil currently supports C++11, C++14, and C++17.
+set(CMAKE_CXX_STANDARD 11)
add_subdirectory(abseil-cpp)
@@ -95,8 +87,8 @@ Here's a non-exhaustive list of Abseil CMake public targets:
```cmake
absl::base
absl::algorithm
-absl::container
absl::debugging
+absl::flat_hash_map
absl::memory
absl::meta
absl::numeric
diff --git a/CMake/abslConfig.cmake.in b/CMake/abslConfig.cmake.in
new file mode 100644
index 00000000..60847fa7
--- /dev/null
+++ b/CMake/abslConfig.cmake.in
@@ -0,0 +1,7 @@
+# absl CMake configuration file.
+
+include(FindThreads)
+
+@PACKAGE_INIT@
+
+include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") \ No newline at end of file
diff --git a/CMake/install_test_project/CMakeLists.txt b/CMake/install_test_project/CMakeLists.txt
new file mode 100644
index 00000000..06b797e9
--- /dev/null
+++ b/CMake/install_test_project/CMakeLists.txt
@@ -0,0 +1,27 @@
+#
+# 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.
+
+# A simple CMakeLists.txt for testing cmake installation
+
+cmake_minimum_required(VERSION 3.5)
+project(absl_cmake_testing CXX)
+
+set(CMAKE_CXX_STANDARD 11)
+
+add_executable(simple simple.cc)
+
+find_package(absl REQUIRED)
+
+target_link_libraries(simple absl::strings)
diff --git a/CMake/install_test_project/simple.cc b/CMake/install_test_project/simple.cc
new file mode 100644
index 00000000..e9e35291
--- /dev/null
+++ b/CMake/install_test_project/simple.cc
@@ -0,0 +1,23 @@
+//
+// 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.
+
+#include <iostream>
+#include "absl/strings/substitute.h"
+
+int main(int argc, char** argv) {
+ for (int i = 0; i < argc; ++i) {
+ std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]);
+ }
+}
diff --git a/CMake/install_test_project/test.sh b/CMake/install_test_project/test.sh
new file mode 100755
index 00000000..99989b03
--- /dev/null
+++ b/CMake/install_test_project/test.sh
@@ -0,0 +1,144 @@
+#!/bin/bash
+#
+# 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.
+
+# "Unit" and integration tests for Absl CMake installation
+
+# TODO(absl-team): This script isn't fully hermetic because
+# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
+# version of GoogleTest. This means that an upstream change to GoogleTest could
+# break this test. Fix this by allowing this script to pin to a known-good
+# version of GoogleTest.
+
+# Fail on any error. Treat unset variables an error. Print commands as executed.
+set -euox pipefail
+
+install_absl() {
+ pushd "${absl_build_dir}"
+ if [[ "${#}" -eq 1 ]]; then
+ cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}"
+ else
+ cmake "${absl_dir}"
+ fi
+ cmake --build . --target install -- -j
+ popd
+}
+
+uninstall_absl() {
+ xargs rm < "${absl_build_dir}"/install_manifest.txt
+ rm -rf "${absl_build_dir}"
+ mkdir -p "${absl_build_dir}"
+}
+
+lts_install=""
+
+while getopts ":l" lts; do
+ case "${lts}" in
+ l )
+ lts_install="true"
+ ;;
+ esac
+done
+
+absl_dir=/abseil-cpp
+absl_build_dir=/buildfs/absl-build
+project_dir="${absl_dir}"/CMake/install_test_project
+project_build_dir=/buildfs/project-build
+
+mkdir -p "${absl_build_dir}"
+mkdir -p "${project_build_dir}"
+
+if [[ "${lts_install}" ]]; then
+ install_dir="/usr/local"
+else
+ install_dir="${project_build_dir}"/install
+fi
+mkdir -p "${install_dir}"
+
+# Test build, install, and link against installed abseil
+pushd "${project_build_dir}"
+if [[ "${lts_install}" ]]; then
+ install_absl
+ cmake "${project_dir}"
+else
+ install_absl "${install_dir}"
+ cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}"
+fi
+
+cmake --build . --target simple
+
+output="$(${project_build_dir}/simple "printme" 2>&1)"
+if [[ "${output}" != *"Arg 1: printme"* ]]; then
+ echo "Faulty output on simple project:"
+ echo "${output}"
+ exit 1
+fi
+
+popd
+
+# Test that we haven't accidentally made absl::abslblah
+pushd "${install_dir}"
+
+# Starting in CMake 3.12 the default install dir is lib$bit_width
+if [[ -d lib64 ]]; then
+ libdir="lib64"
+elif [[ -d lib ]]; then
+ libdir="lib"
+else
+ echo "ls *, */*, */*/*:"
+ ls *
+ ls */*
+ ls */*/*
+ echo "unknown lib dir"
+fi
+
+if [[ "${lts_install}" ]]; then
+ # LTS versions append the date of the release to the subdir.
+ # 9999/99/99 is the dummy date used in the local_lts workflow.
+ absl_subdir="absl_99999999"
+else
+ absl_subdir="absl"
+fi
+
+if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then
+ cat "${libdir}"/cmake/absl/abslTargets.cmake
+ echo "CMake targets named incorrectly"
+ exit 1
+fi
+
+uninstall_absl
+popd
+
+if [[ ! "${lts_install}" ]]; then
+ # Test that we warn if installed without a prefix or a system prefix
+ output="$(install_absl 2>&1)"
+ if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
+ echo "Install without prefix didn't warn as expected. Output:"
+ echo "${output}"
+ exit 1
+ fi
+ uninstall_absl
+
+ output="$(install_absl /usr 2>&1)"
+ if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
+ echo "Install with /usr didn't warn as expected. Output:"
+ echo "${output}"
+ exit 1
+ fi
+ uninstall_absl
+fi
+
+echo "Install test complete!"
+exit 0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1eafa407..74a3a4ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,44 +14,40 @@
# limitations under the License.
#
-# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of
-# CXX_STANDARD in our targets.
-cmake_minimum_required(VERSION 3.1)
+# Most widely used distributions have cmake 3.5 or greater available as of March
+# 2019. A notable exception is RHEL-7 (CentOS7). You can install a current
+# version of CMake by first installing Extra Packages for Enterprise Linux
+# (https://fedoraproject.org/wiki/EPEL#Extra_Packages_for_Enterprise_Linux_.28EPEL.29)
+# and then issuing `yum install cmake3` on the command line.
+cmake_minimum_required(VERSION 3.5)
# Compiler id for Apple Clang is now AppleClang.
-if (POLICY CMP0025)
- cmake_policy(SET CMP0025 NEW)
-endif()
-
-project(absl)
+cmake_policy(SET CMP0025 NEW)
-list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/CMake)
+# if command can use IN_LIST
+cmake_policy(SET CMP0057 NEW)
-include(GNUInstallDirs)
-include(AbseilHelpers)
+# Project version variables are the empty std::string if version is unspecified
+cmake_policy(SET CMP0048 NEW)
+project(absl CXX)
-# config options
-if (MSVC)
- # /wd4005 macro-redefinition
- # /wd4068 unknown pragma
- # /wd4244 conversion from 'type1' to 'type2'
- # /wd4267 conversion from 'size_t' to 'type2'
- # /wd4800 force value to bool 'true' or 'false' (performance warning)
- add_compile_options(/W3 /wd4005 /wd4068 /wd4244 /wd4267 /wd4800)
- # /D_ENABLE_EXTENDED_ALIGNED_STORAGE Introduced in VS 2017 15.8, before the
- # member type would non-conformingly have an alignment of only alignof(max_align_t).
- add_definitions(
- /DNOMINMAX
- /DWIN32_LEAN_AND_MEAN=1
- /D_CRT_SECURE_NO_WARNINGS
- /D_SCL_SECURE_NO_WARNINGS
- /D_ENABLE_EXTENDED_ALIGNED_STORAGE
- )
+# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
+# in the source tree of a project that uses it, install rules are disabled.
+if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
+ set(ABSL_ENABLE_INSTALL FALSE)
else()
- set(ABSL_STD_CXX_FLAG "-std=c++11" CACHE STRING "c++ std flag (default: c++11)")
+ set(ABSL_ENABLE_INSTALL TRUE)
endif()
+list(APPEND CMAKE_MODULE_PATH
+ ${CMAKE_CURRENT_LIST_DIR}/CMake
+ ${CMAKE_CURRENT_LIST_DIR}/absl/copts
+)
+
+include(AbseilInstallDirs)
+include(CMakePackageConfigHelpers)
+include(AbseilHelpers)
##
@@ -68,12 +64,6 @@ endif()
# include current path
list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
-# -std=X
-set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
-
-# -fexceptions
-set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
-
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(ABSL_USING_CLANG ON)
else()
@@ -100,7 +90,9 @@ endif()
if(BUILD_TESTING)
if(${ABSL_USE_GOOGLETEST_HEAD})
- include(CMake/DownloadGTest.cmake)
+ include(CMake/Googletest/DownloadGTest.cmake)
+ set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
+ set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
endif()
check_target(gtest)
@@ -116,3 +108,42 @@ if(BUILD_TESTING)
endif()
add_subdirectory(absl)
+
+if(ABSL_ENABLE_INSTALL)
+
+ # install as a subdirectory only
+ install(EXPORT ${PROJECT_NAME}Targets
+ NAMESPACE absl::
+ DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+ )
+
+ configure_package_config_file(
+ CMake/abslConfig.cmake.in
+ "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+ )
+ install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
+ DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
+ )
+
+ # Abseil only has a version in LTS releases. This mechanism is accomplished
+ # Abseil's internal Copybara (https://github.com/google/copybara) workflows and
+ # isn't visible in the CMake buildsystem itself.
+ if(absl_VERSION)
+ write_basic_package_version_file(
+ "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+ COMPATIBILITY ExactVersion
+ )
+
+ install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
+ DESTINATION ${ABSL_INSTALL_CONFIGDIR}
+ )
+ endif() # absl_VERSION
+
+ install(DIRECTORY absl
+ DESTINATION ${ABSL_INSTALL_INCLUDEDIR}
+ FILES_MATCHING
+ PATTERN "*.inc"
+ PATTERN "*.h"
+ )
+endif() # ABSL_ENABLE_INSTALL
diff --git a/LICENSE b/LICENSE
index fef7d967..ccd61dcf 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
Apache License
Version 2.0, January 2004
- http://www.apache.org/licenses/
+ https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -193,12 +193,11 @@
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ 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.
-
- \ No newline at end of file
+
diff --git a/LTS.md b/LTS.md
index 385b4f06..08606f15 100644
--- a/LTS.md
+++ b/LTS.md
@@ -10,4 +10,5 @@ turn, use Abseil. (For more information about our releases, see the
The following lists LTS branches and the dates on which they have been released:
+* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
diff --git a/README.md b/README.md
index e9362be2..85de5696 100644
--- a/README.md
+++ b/README.md
@@ -42,8 +42,8 @@ the Abseil code, running tests, and getting a simple binary working.
<a name="build"></a>
## Building Abseil
-[Bazel](http://bazel.build) is the official build system for Abseil,
-which is supported on most major platforms (Linux, Windows, MacOS, for example)
+[Bazel](https://bazel.build) is the official build system for Abseil,
+which is supported on most major platforms (Linux, Windows, macOS, for example)
and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
more information on building Abseil using the Bazel build system.
@@ -106,9 +106,9 @@ license. See [LICENSE](LICENSE) for more information.
For more information about Abseil:
-* Consult our [Abseil Introduction](http://abseil.io/about/intro)
-* Read [Why Adopt Abseil](http://abseil.io/about/philosophy) to understand our
+* Consult our [Abseil Introduction](https://abseil.io/about/intro)
+* Read [Why Adopt Abseil](https://abseil.io/about/philosophy) to understand our
design philosophy.
* Peruse our
- [Abseil Compatibility Guarantees](http://abseil.io/about/compatibility) to
+ [Abseil Compatibility Guarantees](https://abseil.io/about/compatibility) to
understand both what we promise to you, and what we expect of you in return.
diff --git a/UPGRADES.md b/UPGRADES.md
new file mode 100644
index 00000000..35599d08
--- /dev/null
+++ b/UPGRADES.md
@@ -0,0 +1,17 @@
+# C++ Upgrade Tools
+
+Abseil may occassionally release API-breaking changes. As noted in our
+[Compatibility Guidelines][compatibility-guide], we will aim to provide a tool
+to do the work of effecting such API-breaking changes, when absolutely
+necessary.
+
+These tools will be listed on the [C++ Upgrade Tools][upgrade-tools] guide on
+https://abseil.io.
+
+For more information, the [C++ Automated Upgrade Guide][api-upgrades-guide]
+outlines this process.
+
+[compatibility-guide]: https://abseil.io/about/compatibility
+[api-upgrades-guide]: https://abseil.io/docs/cpp/tools/api-upgrades
+[upgrade-tools]: https://abseil.io/docs/cpp/tools/upgrades/
+
diff --git a/WORKSPACE b/WORKSPACE
index 72ef1398..49e2d3cb 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -15,9 +15,9 @@ http_archive(
# GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive(
name = "com_google_googletest",
- urls = ["https://github.com/google/googletest/archive/b4d4438df9479675a632b2f11125e57133822ece.zip"], # 2018-07-16
- strip_prefix = "googletest-b4d4438df9479675a632b2f11125e57133822ece",
- sha256 = "5aaa5d566517cae711e2a3505ea9a6438be1b37fcaae0ebcb96ccba9aa56f23a",
+ urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07
+ strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb",
+ sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86",
)
# Google benchmark.
diff --git a/absl/BUILD.bazel b/absl/BUILD.bazel
index edd0274c..853330d4 100644
--- a/absl/BUILD.bazel
+++ b/absl/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -25,13 +25,18 @@ create_llvm_config(
visibility = [":__subpackages__"],
)
-# following configs are based on mapping defined in: https://git.io/v5Ijz
+config_setting(
+ name = "osx",
+ constraint_values = [
+ "@bazel_tools//platforms:osx",
+ ],
+)
+
config_setting(
name = "ios",
- values = {
- "cpu": "darwin",
- },
- visibility = [":__subpackages__"],
+ constraint_values = [
+ "@bazel_tools//platforms:ios",
+ ],
)
config_setting(
diff --git a/absl/CMakeLists.txt b/absl/CMakeLists.txt
index 1d09b193..3e78397c 100644
--- a/absl/CMakeLists.txt
+++ b/absl/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -20,10 +20,12 @@ add_subdirectory(base)
add_subdirectory(algorithm)
add_subdirectory(container)
add_subdirectory(debugging)
+add_subdirectory(flags)
add_subdirectory(hash)
add_subdirectory(memory)
add_subdirectory(meta)
add_subdirectory(numeric)
+add_subdirectory(random)
add_subdirectory(strings)
add_subdirectory(synchronization)
add_subdirectory(time)
diff --git a/absl/algorithm/BUILD.bazel b/absl/algorithm/BUILD.bazel
index d04dc712..c506f3b9 100644
--- a/absl/algorithm/BUILD.bazel
+++ b/absl/algorithm/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -28,6 +29,7 @@ cc_library(
name = "algorithm",
hdrs = ["algorithm.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
)
cc_test(
@@ -35,6 +37,7 @@ cc_test(
size = "small",
srcs = ["algorithm_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":algorithm",
"@com_google_googletest//:gtest_main",
@@ -45,6 +48,7 @@ cc_test(
name = "algorithm_benchmark",
srcs = ["equal_benchmark.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
deps = [
":algorithm",
@@ -59,6 +63,7 @@ cc_library(
"container.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":algorithm",
"//absl/base:core_headers",
@@ -70,6 +75,7 @@ cc_test(
name = "container_test",
srcs = ["container_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container",
"//absl/base",
diff --git a/absl/algorithm/CMakeLists.txt b/absl/algorithm/CMakeLists.txt
index 87a165c0..9fbe36f6 100644
--- a/absl/algorithm/CMakeLists.txt
+++ b/absl/algorithm/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -29,6 +29,8 @@ absl_cc_test(
algorithm_test
SRCS
"algorithm_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::algorithm
gmock_main
@@ -53,6 +55,8 @@ absl_cc_test(
container_test
SRCS
"container_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::algorithm_container
absl::base
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
index 1eef16cb..7c2b787e 100644
--- a/absl/algorithm/algorithm.h
+++ b/absl/algorithm/algorithm.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,7 +27,7 @@
#include <type_traits>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace algorithm_internal {
@@ -95,7 +95,7 @@ It RotateImpl(It first, It middle, It last, std::false_type) {
// then the predicate is never invoked and the function returns false.
//
// This is a C++11-compatible implementation of C++14 `std::equal`. See
-// http://en.cppreference.com/w/cpp/algorithm/equal for more information.
+// https://en.cppreference.com/w/cpp/algorithm/equal for more information.
template <typename InputIter1, typename InputIter2, typename Pred>
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
InputIter2 last2, Pred&& pred) {
@@ -146,7 +146,7 @@ ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
ForwardIterator>());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_ALGORITHM_ALGORITHM_H_
diff --git a/absl/algorithm/algorithm_test.cc b/absl/algorithm/algorithm_test.cc
index e4322bc4..81fccb61 100644
--- a/absl/algorithm/algorithm_test.cc
+++ b/absl/algorithm/algorithm_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h
index b7718206..16389be7 100644
--- a/absl/algorithm/container.h
+++ b/absl/algorithm/container.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -36,7 +36,6 @@
// For template parameter and variable naming, `C` indicates the container type
// to which the function is applied, `Pred` indicates the predicate object type
// to be used by the function and `T` indicates the applicable element type.
-//
#ifndef ABSL_ALGORITHM_CONTAINER_H_
#define ABSL_ALGORITHM_CONTAINER_H_
@@ -56,7 +55,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_algorithm_internal {
// NOTE: it is important to defer to ADL lookup for building with C++ modules,
@@ -512,6 +511,16 @@ OutputIterator c_move(C&& src, OutputIterator dest) {
container_algorithm_internal::c_end(src), dest);
}
+// c_move_backward()
+//
+// Container-based version of the <algorithm> `std::move_backward()` function to
+// move a container's elements into an iterator in reverse order.
+template <typename C, typename BidirectionalIterator>
+BidirectionalIterator c_move_backward(C&& src, BidirectionalIterator dest) {
+ return std::move_backward(container_algorithm_internal::c_begin(src),
+ container_algorithm_internal::c_end(src), dest);
+}
+
// c_swap_ranges()
//
// Container-based version of the <algorithm> `std::swap_ranges()` function to
@@ -649,7 +658,6 @@ container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n,
// and `unique()` are omitted, because it's not clear whether or not such
// functions should call erase on their supplied sequences afterwards. Either
// behavior would be surprising for a different set of users.
-//
// c_remove_copy()
//
@@ -1698,7 +1706,7 @@ OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
output_first, std::forward<BinaryOp>(op));
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_ALGORITHM_CONTAINER_H_
diff --git a/absl/algorithm/container_test.cc b/absl/algorithm/container_test.cc
index 1502b17f..86bf9d3e 100644
--- a/absl/algorithm/container_test.cc
+++ b/absl/algorithm/container_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -636,6 +636,19 @@ TEST(MutatingTest, Move) {
Pointee(5)));
}
+TEST(MutatingTest, MoveBackward) {
+ std::vector<std::unique_ptr<int>> actual;
+ actual.emplace_back(absl::make_unique<int>(1));
+ actual.emplace_back(absl::make_unique<int>(2));
+ actual.emplace_back(absl::make_unique<int>(3));
+ actual.emplace_back(absl::make_unique<int>(4));
+ actual.emplace_back(absl::make_unique<int>(5));
+ auto subrange = absl::MakeSpan(actual.data(), 3);
+ absl::c_move_backward(subrange, actual.end());
+ EXPECT_THAT(actual, ElementsAre(IsNull(), IsNull(), Pointee(1), Pointee(2),
+ Pointee(3)));
+}
+
TEST(MutatingTest, MoveWithRvalue) {
auto MakeRValueSrc = [] {
std::vector<std::unique_ptr<int>> src;
diff --git a/absl/algorithm/equal_benchmark.cc b/absl/algorithm/equal_benchmark.cc
index 19c0780c..7bf62c9a 100644
--- a/absl/algorithm/equal_benchmark.cc
+++ b/absl/algorithm/equal_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 4566c697..a512272a 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,11 +15,12 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
- "ABSL_TEST_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
@@ -27,6 +28,34 @@ package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
cc_library(
+ name = "atomic_hook",
+ hdrs = ["internal/atomic_hook.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+)
+
+cc_library(
+ name = "log_severity",
+ srcs = ["log_severity.cc"],
+ hdrs = ["log_severity.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [":core_headers"],
+)
+
+cc_library(
+ name = "raw_logging_internal",
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+)
+
+cc_library(
name = "spinlock_wait",
srcs = [
"internal/spinlock_akaros.inc",
@@ -40,6 +69,7 @@ cc_library(
"internal/spinlock_wait.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/base:__pkg__",
],
@@ -53,6 +83,7 @@ cc_library(
"policy_checks.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
)
cc_library(
@@ -61,18 +92,24 @@ cc_library(
hdrs = ["dynamic_annotations.h"],
copts = ABSL_DEFAULT_COPTS,
defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
)
cc_library(
name = "core_headers",
+ srcs = [
+ "internal/thread_annotations.h",
+ ],
hdrs = [
"attributes.h",
+ "const_init.h",
"macros.h",
"optimization.h",
"port.h",
"thread_annotations.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
],
@@ -88,6 +125,10 @@ cc_library(
"internal/low_level_alloc.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -110,9 +151,13 @@ cc_library(
"internal/scheduling_mode.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
+ deps = [
+ "//absl/meta:type_traits",
+ ],
)
cc_library(
@@ -128,7 +173,6 @@ cc_library(
hdrs = [
"call_once.h",
"casts.h",
- "internal/atomic_hook.h",
"internal/cycleclock.h",
"internal/low_level_scheduling.h",
"internal/per_thread_tls.h",
@@ -138,15 +182,21 @@ cc_library(
"internal/thread_identity.h",
"internal/tsan_mutex_interface.h",
"internal/unscaledcycleclock.h",
- "log_severity.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":atomic_hook",
":base_internal",
":config",
":core_headers",
":dynamic_annotations",
+ ":log_severity",
":spinlock_wait",
+ "//absl/meta:type_traits",
],
)
@@ -155,8 +205,9 @@ cc_test(
size = "small",
srcs = ["internal/atomic_hook_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
- ":base",
+ ":atomic_hook",
":core_headers",
"@com_google_googletest//:gtest_main",
],
@@ -169,6 +220,7 @@ cc_test(
"bit_cast_test.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
":core_headers",
@@ -181,7 +233,7 @@ cc_library(
srcs = ["internal/throw_delegate.cc"],
hdrs = ["internal/throw_delegate.h"],
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -195,7 +247,7 @@ cc_test(
name = "throw_delegate_test",
srcs = ["throw_delegate_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":throw_delegate",
"@com_google_googletest//:gtest_main",
@@ -207,6 +259,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/exception_testing.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -219,6 +272,7 @@ cc_library(
cc_library(
name = "pretty_function",
hdrs = ["internal/pretty_function.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//absl:__subpackages__"],
)
@@ -228,9 +282,8 @@ cc_library(
srcs = ["internal/exception_safety_testing.cc"],
hdrs = ["internal/exception_safety_testing.h"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
- ":base",
":config",
":pretty_function",
"//absl/memory",
@@ -245,7 +298,7 @@ cc_test(
name = "exception_safety_testing_test",
srcs = ["exception_safety_testing_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":exception_safety_testing",
"//absl/memory",
@@ -263,6 +316,7 @@ cc_test(
"internal/inline_variable_testing.h",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base_internal",
"@com_google_googletest//:gtest_main",
@@ -274,6 +328,7 @@ cc_test(
size = "small",
srcs = ["invoke_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base_internal",
"//absl/memory",
@@ -289,6 +344,7 @@ cc_library(
testonly = 1,
srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
":core_headers",
@@ -304,7 +360,7 @@ cc_test(
size = "medium",
srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS,
- tags = ["no_test_wasm"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
":core_headers",
@@ -318,7 +374,8 @@ cc_library(
name = "spinlock_benchmark_common",
testonly = 1,
srcs = ["internal/spinlock_benchmark.cc"],
- copts = ABSL_DEFAULT_COPTS,
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/base:__pkg__",
],
@@ -335,6 +392,7 @@ cc_binary(
name = "spinlock_benchmark",
testonly = 1,
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
":spinlock_benchmark_common",
@@ -348,6 +406,7 @@ cc_library(
"internal/unaligned_access.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":core_headers",
@@ -359,7 +418,6 @@ cc_test(
srcs = ["internal/endian_test.cc"],
copts = ABSL_TEST_COPTS,
deps = [
- ":base",
":config",
":endian",
"@com_google_googletest//:gtest_main",
@@ -370,9 +428,7 @@ cc_test(
name = "config_test",
srcs = ["config_test.cc"],
copts = ABSL_TEST_COPTS,
- tags = [
- "no_test_wasm",
- ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
"//absl/synchronization:thread_pool",
@@ -384,9 +440,7 @@ cc_test(
name = "call_once_test",
srcs = ["call_once_test.cc"],
copts = ABSL_TEST_COPTS,
- tags = [
- "no_test_wasm",
- ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
":core_headers",
@@ -399,6 +453,7 @@ cc_test(
name = "raw_logging_test",
srcs = ["raw_logging_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
"//absl/strings",
@@ -411,6 +466,7 @@ cc_test(
size = "small",
srcs = ["internal/sysinfo_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
"//absl/synchronization",
@@ -420,13 +476,10 @@ cc_test(
cc_test(
name = "low_level_alloc_test",
- size = "small",
+ size = "medium",
srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_ios_x86_64"],
deps = [":malloc_internal"],
)
@@ -436,13 +489,7 @@ cc_test(
size = "small",
srcs = ["internal/thread_identity_test.cc"],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
- tags = [
- "no_test_wasm",
- ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":base",
":core_headers",
@@ -455,6 +502,7 @@ cc_test(
name = "thread_identity_benchmark",
srcs = ["internal/thread_identity_benchmark.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
@@ -467,6 +515,7 @@ cc_test(
cc_library(
name = "bits",
hdrs = ["internal/bits.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -478,8 +527,46 @@ cc_test(
size = "small",
srcs = ["internal/bits_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bits",
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "scoped_set_env",
+ testonly = 1,
+ srcs = ["internal/scoped_set_env.cc"],
+ hdrs = ["internal/scoped_set_env.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl:__subpackages__",
+ ],
+ deps = [":base"],
+)
+
+cc_test(
+ name = "scoped_set_env_test",
+ size = "small",
+ srcs = ["internal/scoped_set_env_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":scoped_set_env",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "log_severity_test",
+ size = "small",
+ srcs = ["log_severity_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":base",
+ ":log_severity",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 212dd083..cc7960e3 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -16,6 +16,35 @@
absl_cc_library(
NAME
+ atomic_hook
+ HDRS
+ "internal/atomic_hook.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ log_severity
+ HDRS
+ "log_severity.h"
+ SRCS
+ "log_severity.cc"
+ DEPS
+ absl::core_headers
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
+ raw_logging_internal
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
spinlock_wait
HDRS
"internal/scheduling_mode.h"
@@ -26,6 +55,8 @@ absl_cc_library(
"internal/spinlock_posix.inc"
"internal/spinlock_wait.cc"
"internal/spinlock_win32.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
DEPS
absl::core_headers
)
@@ -60,10 +91,12 @@ absl_cc_library(
core_headers
HDRS
"attributes.h"
+ "const_init.h"
"macros.h"
"optimization.h"
"port.h"
"thread_annotations.h"
+ "internal/thread_annotations.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -87,6 +120,7 @@ absl_cc_library(
absl::core_headers
absl::dynamic_annotations
absl::spinlock_wait
+ Threads::Threads
)
absl_cc_library(
@@ -99,6 +133,8 @@ absl_cc_library(
"internal/invoke.h"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::type_traits
)
absl_cc_library(
@@ -107,7 +143,6 @@ absl_cc_library(
HDRS
"call_once.h"
"casts.h"
- "internal/atomic_hook.h"
"internal/cycleclock.h"
"internal/low_level_scheduling.h"
"internal/per_thread_tls.h"
@@ -125,14 +160,19 @@ absl_cc_library(
"internal/sysinfo.cc"
"internal/thread_identity.cc"
"internal/unscaledcycleclock.cc"
+ "log_severity.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::atomic_hook
absl::base_internal
absl::config
absl::core_headers
absl::dynamic_annotations
+ absl::log_severity
absl::spinlock_wait
+ absl::type_traits
+ Threads::Threads
PUBLIC
)
@@ -180,10 +220,11 @@ absl_cc_library(
SRCS
"internal/exception_safety_testing.cc"
COPTS
- ${ABSL_DEFAULT_COPTS}
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
DEPS
- absl::base
absl::config
absl::pretty_function
absl::memory
@@ -200,6 +241,7 @@ absl_cc_test(
SRCS
"exception_safety_testing_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
LINKOPTS
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
@@ -214,8 +256,10 @@ absl_cc_test(
atomic_hook_test
SRCS
"internal/atomic_hook_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
- absl::base
+ absl::atomic_hook
absl::core_headers
gtest_main
)
@@ -225,6 +269,8 @@ absl_cc_test(
bit_cast_test
SRCS
"bit_cast_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::core_headers
@@ -236,9 +282,11 @@ absl_cc_test(
throw_delegate_test
SRCS
"throw_delegate_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
- absl_internal_throw_delegate
+ absl::throw_delegate
gtest_main
)
@@ -250,6 +298,8 @@ absl_cc_test(
"inline_variable_test.cc"
"inline_variable_test_a.cc"
"inline_variable_test_b.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base_internal
gtest_main
@@ -260,6 +310,8 @@ absl_cc_test(
invoke_test
SRCS
"invoke_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base_internal
absl::memory
@@ -290,6 +342,8 @@ absl_cc_test(
spinlock_test
SRCS
"spinlock_test_common.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::core_headers
@@ -317,6 +371,8 @@ absl_cc_test(
endian_test
SRCS
"internal/endian_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::config
@@ -329,6 +385,8 @@ absl_cc_test(
config_test
SRCS
"config_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::config
absl::synchronization
@@ -340,6 +398,8 @@ absl_cc_test(
call_once_test
SRCS
"call_once_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::core_headers
@@ -352,6 +412,8 @@ absl_cc_test(
raw_logging_test
SRCS
"raw_logging_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::strings
@@ -363,6 +425,8 @@ absl_cc_test(
sysinfo_test
SRCS
"internal/sysinfo_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::synchronization
@@ -374,6 +438,8 @@ absl_cc_test(
low_level_alloc_test
SRCS
"internal/low_level_alloc_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::malloc_internal
Threads::Threads
@@ -384,6 +450,8 @@ absl_cc_test(
thread_identity_test
SRCS
"internal/thread_identity_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::base
absl::core_headers
@@ -408,7 +476,57 @@ absl_cc_test(
bits_test
SRCS
"internal/bits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::bits
gtest_main
)
+
+absl_cc_library(
+ NAME
+ scoped_set_env
+ SRCS
+ "internal/scoped_set_env.cc"
+ HDRS
+ "internal/scoped_set_env.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+)
+
+absl_cc_test(
+ NAME
+ scoped_set_env_test
+ SRCS
+ "internal/scoped_set_env_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::scoped_set_env
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ cmake_thread_test
+ SRCS
+ "internal/cmake_thread_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+)
+
+absl_cc_test(
+ NAME
+ log_severity_test
+ SRCS
+ "log_severity_test.cc"
+ DEPS
+ absl::base
+ absl::log_severity
+ gmock
+ gtest_main
+)
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 291ad89e..a7da62af 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -80,7 +80,7 @@
//
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
-// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
+// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
#if defined(__cplusplus) && defined(__has_cpp_attribute)
// NOTE: requiring __cplusplus above should not be necessary, but
@@ -102,7 +102,7 @@
//
// Tells the compiler to perform `printf` format string checking if the
// compiler supports it; see the 'format' attribute in
-// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
+// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
//
// Note: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
@@ -232,7 +232,7 @@
// out of bounds or does other scary things with memory.
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
+#if defined(__GNUC__)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
@@ -246,7 +246,7 @@
// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals
// with initialized-ness rather than addressability issues.
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
-#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
+#if defined(__clang__)
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
@@ -257,7 +257,7 @@
// Tells the ThreadSanitizer to not instrument a given function.
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html
-#if defined(__GNUC__) && defined(THREAD_SANITIZER)
+#if defined(__GNUC__)
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
@@ -287,6 +287,17 @@
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
#endif
+// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+//
+// Tells the SafeStack to not instrument a given function.
+// See https://clang.llvm.org/docs/SafeStack.html for details.
+#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
+ __attribute__((no_sanitize("safe-stack")))
+#else
+#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
+#endif
+
// ABSL_ATTRIBUTE_RETURNS_NONNULL
//
// Tells the compiler that a particular function never returns a null pointer.
diff --git a/absl/base/bit_cast_test.cc b/absl/base/bit_cast_test.cc
index 5af036df..be201856 100644
--- a/absl/base/bit_cast_test.cc
+++ b/absl/base/bit_cast_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/base/macros.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
template <int N>
@@ -105,5 +105,5 @@ TEST(BitCast, Double) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/call_once.h b/absl/base/call_once.h
index aea9197b..373f015f 100644
--- a/absl/base/call_once.h
+++ b/absl/base/call_once.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -29,6 +29,7 @@
#include <atomic>
#include <cstdint>
#include <type_traits>
+#include <utility>
#include "absl/base/internal/invoke.h"
#include "absl/base/internal/low_level_scheduling.h"
@@ -36,10 +37,11 @@
#include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock_wait.h"
#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class once_flag;
@@ -208,7 +210,7 @@ void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
}
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_CALL_ONCE_H_
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
index 4d98a405..0e89bd24 100644
--- a/absl/base/call_once_test.cc
+++ b/absl/base/call_once_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,15 +18,18 @@
#include <vector>
#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
absl::once_flag once;
-Mutex counters_mu;
+
+ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
int running_thread_count GUARDED_BY(counters_mu) = 0;
int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
@@ -100,5 +103,5 @@ TEST(CallOnceTest, ExecutionCount) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/casts.h b/absl/base/casts.h
index bba623b4..b67b047c 100644
--- a/absl/base/casts.h
+++ b/absl/base/casts.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,32 +27,25 @@
#include <cstring>
#include <memory>
#include <type_traits>
+#include <utility>
#include "absl/base/internal/identity.h"
#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace internal_casts {
-// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`.
-// TODO(calabrese) Branch on implementations that directly provide
-// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly
-// expose in meta/type_traits.
-template <class T>
-struct is_trivially_copyable
- : std::integral_constant<
- bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) &&
- __has_trivial_copy(T) && __has_trivial_assign(T)> {};
-
template <class Dest, class Source>
struct is_bitcastable
- : std::integral_constant<bool,
- sizeof(Dest) == sizeof(Source) &&
- is_trivially_copyable<Source>::value &&
- is_trivially_copyable<Dest>::value &&
- std::is_default_constructible<Dest>::value> {};
+ : std::integral_constant<
+ bool,
+ sizeof(Dest) == sizeof(Source) &&
+ type_traits_internal::is_trivially_copyable<Source>::value &&
+ type_traits_internal::is_trivially_copyable<Dest>::value &&
+ std::is_default_constructible<Dest>::value> {};
} // namespace internal_casts
@@ -185,7 +178,7 @@ inline Dest bit_cast(const Source& source) {
return dest;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_CASTS_H_
diff --git a/absl/base/config.h b/absl/base/config.h
index db4c4539..1c3cb08e 100644
--- a/absl/base/config.h
+++ b/absl/base/config.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -118,7 +118,7 @@
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
-// either libc++ or libstdc++, and Visual Studio.
+// either libc++ or libstdc++, and Visual Studio (but not NVCC).
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
@@ -127,7 +127,7 @@
(!defined(__clang__) && defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
- defined(_MSC_VER)
+ (defined(_MSC_VER) && !defined(__NVCC__))
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
@@ -181,6 +181,13 @@
#endif
#endif // defined(__ANDROID__) && defined(__clang__)
+// Emscripten doesn't yet support `thread_local` or `__thread`.
+// https://github.com/emscripten-core/emscripten/issues/3502
+#if defined(__EMSCRIPTEN__)
+#undef ABSL_HAVE_TLS
+#undef ABSL_HAVE_THREAD_LOCAL
+#endif // defined(__EMSCRIPTEN__)
+
// ABSL_HAVE_INTRINSIC_INT128
//
// Checks whether the __int128 compiler extension for a 128-bit integral type is
@@ -191,15 +198,13 @@
// * On Clang:
// * Building using Clang for Windows, where the Clang runtime library has
// 128-bit support only on LP64 architectures, but Windows is LLP64.
-// * Building for aarch64, where __int128 exists but has exhibits a sporadic
-// compiler crashing bug.
// * On Nvidia's nvcc:
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
// actually support __int128.
#ifdef ABSL_HAVE_INTRINSIC_INT128
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
-#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
+#if (defined(__clang__) && !defined(_WIN32)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define ABSL_HAVE_INTRINSIC_INT128 1
@@ -255,7 +260,7 @@
// Linux and Linux-derived __linux__
// Android __ANDROID__ (implies __linux__)
// Linux (non-Android) __linux__ && !__ANDROID__
-// Darwin (Mac OS X and iOS) __APPLE__
+// Darwin (macOS and iOS) __APPLE__
// Akaros (http://akaros.org) __ros__
// Windows _WIN32
// NaCL __native_client__
@@ -365,16 +370,25 @@
#error "absl endian detection needs to be set up for your compiler"
#endif
-// MacOS 10.13 doesn't let you use <any>, <optional>, or <variant> even though
-// the headers exist and are publicly noted to work. See
+// macOS 10.13 and iOS 10.11 don't let you use <any>, <optional>, or <variant>
+// even though the headers exist and are publicly noted to work. See
// https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
+// libc++ spells out the availability requirements in the file
+// llvm-project/libcxx/include/__config via the #define
+// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
- defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \
- __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400
-#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 1
+ ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
+ (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
+ (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 120000) || \
+ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
+ __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000))
+#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else
-#define ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES 0
+#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
#endif
// ABSL_HAVE_STD_ANY
@@ -386,7 +400,7 @@
#ifdef __has_include
#if __has_include(<any>) && __cplusplus >= 201703L && \
- ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
+ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_ANY 1
#endif
#endif
@@ -400,7 +414,7 @@
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L && \
- ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
+ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_OPTIONAL 1
#endif
#endif
@@ -414,7 +428,7 @@
#ifdef __has_include
#if __has_include(<variant>) && __cplusplus >= 201703L && \
- ABSL_INTERNAL_MACOS_HAS_CXX_17_TYPES
+ !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_VARIANT 1
#endif
#endif
diff --git a/absl/base/config_test.cc b/absl/base/config_test.cc
index c839712a..7e0c033d 100644
--- a/absl/base/config_test.cc
+++ b/absl/base/config_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/const_init.h b/absl/base/const_init.h
new file mode 100644
index 00000000..30d6a3ca
--- /dev/null
+++ b/absl/base/const_init.h
@@ -0,0 +1,74 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// kConstInit
+// -----------------------------------------------------------------------------
+//
+// A constructor tag used to mark an object as safe for use as a global
+// variable, avoiding the usual lifetime issues that can affect globals.
+
+#ifndef ABSL_BASE_CONST_INIT_H_
+#define ABSL_BASE_CONST_INIT_H_
+
+// In general, objects with static storage duration (such as global variables)
+// can trigger tricky object lifetime situations. Attempting to access them
+// from the constructors or destructors of other global objects can result in
+// undefined behavior, unless their constructors and destructors are designed
+// with this issue in mind.
+//
+// The normal way to deal with this issue in C++11 is to use constant
+// initialization and trivial destructors.
+//
+// Constant initialization is guaranteed to occur before any other code
+// executes. Constructors that are declared 'constexpr' are eligible for
+// constant initialization. You can annotate a variable declaration with the
+// ABSL_CONST_INIT macro to express this intent. For compilers that support
+// it, this annotation will cause a compilation error for declarations that
+// aren't subject to constant initialization (perhaps because a runtime value
+// was passed as a constructor argument).
+//
+// On program shutdown, lifetime issues can be avoided on global objects by
+// ensuring that they contain trivial destructors. A class has a trivial
+// destructor unless it has a user-defined destructor, a virtual method or base
+// class, or a data member or base class with a non-trivial destructor of its
+// own. Objects with static storage duration and a trivial destructor are not
+// cleaned up on program shutdown, and are thus safe to access from other code
+// running during shutdown.
+//
+// For a few core Abseil classes, we make a best effort to allow for safe global
+// instances, even though these classes have non-trivial destructors. These
+// objects can be created with the absl::kConstInit tag. For example:
+// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
+//
+// The line above declares a global variable of type absl::Mutex which can be
+// accessed at any point during startup or shutdown. global_mutex's destructor
+// will still run, but will not invalidate the object. Note that C++ specifies
+// that accessing an object after its destructor has run results in undefined
+// behavior, but this pattern works on the toolchains we support.
+//
+// The absl::kConstInit tag should only be used to define objects with static
+// or thread_local storage duration.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+enum ConstInitType {
+ kConstInit,
+};
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_BASE_CONST_INIT_H_
diff --git a/absl/base/dynamic_annotations.cc b/absl/base/dynamic_annotations.cc
index 08c27e51..21e822e5 100644
--- a/absl/base/dynamic_annotations.cc
+++ b/absl/base/dynamic_annotations.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/dynamic_annotations.h b/absl/base/dynamic_annotations.h
index 7e328d96..65a54b44 100644
--- a/absl/base/dynamic_annotations.h
+++ b/absl/base/dynamic_annotations.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -139,6 +139,7 @@
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */
#endif /* DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */
+
/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the
appropriate feature ID. */
#if defined(__clang__) && (!defined(SWIG)) \
@@ -376,7 +377,7 @@ inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */
struct { char x[8] __attribute__ ((aligned (8))); } name
#else
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
-#define ADDRESS_SANITIZER_REDZONE(name)
+#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
#endif // ADDRESS_SANITIZER
/* Undefine the macros intended only in this file. */
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index 7518264d..2ed38606 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc
index b968b10f..40e8b57b 100644
--- a/absl/base/inline_variable_test.cc
+++ b/absl/base/inline_variable_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace inline_variable_testing_internal {
namespace {
@@ -60,5 +60,5 @@ TEST(InlineVariableTest, FunPtrType) {
} // namespace
} // namespace inline_variable_testing_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/inline_variable_test_a.cc b/absl/base/inline_variable_test_a.cc
index a51b1d81..c19a6e55 100644
--- a/absl/base/inline_variable_test_a.cc
+++ b/absl/base/inline_variable_test_a.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace inline_variable_testing_internal {
const Foo& get_foo_a() { return inline_variable_foo; }
@@ -23,5 +23,5 @@ const Foo& get_foo_a() { return inline_variable_foo; }
const int& get_int_a() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc
index 5041e20a..ae8da104 100644
--- a/absl/base/inline_variable_test_b.cc
+++ b/absl/base/inline_variable_test_b.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/base/internal/inline_variable_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace inline_variable_testing_internal {
const Foo& get_foo_b() { return inline_variable_foo; }
@@ -23,5 +23,5 @@ const Foo& get_foo_b() { return inline_variable_foo; }
const int& get_int_b() { return inline_variable_int; }
} // namespace inline_variable_testing_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/atomic_hook.h b/absl/base/internal/atomic_hook.h
index 58ddf272..6757e75b 100644
--- a/absl/base/internal/atomic_hook.h
+++ b/absl/base/internal/atomic_hook.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
template <typename T>
@@ -161,7 +161,7 @@ class AtomicHook<ReturnType (*)(Args...)> {
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
diff --git a/absl/base/internal/atomic_hook_test.cc b/absl/base/internal/atomic_hook_test.cc
index cf740757..ecc80406 100644
--- a/absl/base/internal/atomic_hook_test.cc
+++ b/absl/base/internal/atomic_hook_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/bits.h b/absl/base/internal/bits.h
index 29657426..ef978e9b 100644
--- a/absl/base/internal/bits.h
+++ b/absl/base/internal/bits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -46,7 +46,7 @@
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
@@ -189,7 +189,7 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
#undef ABSL_BASE_INTERNAL_FORCEINLINE
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_BITS_H_
diff --git a/absl/base/internal/bits_test.cc b/absl/base/internal/bits_test.cc
index e5d991d6..7855fa62 100644
--- a/absl/base/internal/bits_test.cc
+++ b/absl/base/internal/bits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/cmake_thread_test.cc b/absl/base/internal/cmake_thread_test.cc
new file mode 100644
index 00000000..f70bb24e
--- /dev/null
+++ b/absl/base/internal/cmake_thread_test.cc
@@ -0,0 +1,22 @@
+// 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.
+
+#include <iostream>
+#include "absl/base/internal/thread_identity.h"
+
+int main() {
+ auto* tid = absl::base_internal::CurrentThreadIdentityIfPresent();
+ // Make sure the above call can't be optimized out
+ std::cout << (void*)tid << std::endl;
+}
diff --git a/absl/base/internal/cycleclock.cc b/absl/base/internal/cycleclock.cc
index d99b63d3..9868e549 100644
--- a/absl/base/internal/cycleclock.cc
+++ b/absl/base/internal/cycleclock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,12 +22,13 @@
#include "absl/base/internal/cycleclock.h"
+#include <atomic>
#include <chrono> // NOLINT(build/c++11)
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK
@@ -53,17 +54,40 @@ static constexpr int32_t kShift = 2;
#endif
static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
+static std::atomic<CycleClockSourceFunc> cycle_clock_source;
+
+CycleClockSourceFunc LoadCycleClockSource() {
+ // Optimize for the common case (no callback) by first doing a relaxed load;
+ // this is significantly faster on non-x86 platforms.
+ if (cycle_clock_source.load(std::memory_order_relaxed) == nullptr) {
+ return nullptr;
+ }
+ // This corresponds to the store(std::memory_order_release) in
+ // CycleClockSource::Register, and makes sure that any updates made prior to
+ // registering the callback are visible to this thread before the callback is
+ // invoked.
+ return cycle_clock_source.load(std::memory_order_acquire);
+}
} // namespace
int64_t CycleClock::Now() {
- return base_internal::UnscaledCycleClock::Now() >> kShift;
+ auto fn = LoadCycleClockSource();
+ if (fn == nullptr) {
+ return base_internal::UnscaledCycleClock::Now() >> kShift;
+ }
+ return fn() >> kShift;
}
double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
+void CycleClockSource::Register(CycleClockSourceFunc source) {
+ // Corresponds to the load(std::memory_order_acquire) in LoadCycleClockSource.
+ cycle_clock_source.store(source, std::memory_order_release);
+}
+
#else
int64_t CycleClock::Now() {
@@ -79,5 +103,5 @@ double CycleClock::Frequency() {
#endif
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/cycleclock.h b/absl/base/internal/cycleclock.h
index ae5ede3e..39bce06a 100644
--- a/absl/base/internal/cycleclock.h
+++ b/absl/base/internal/cycleclock.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,6 @@
// not necessarily "CPU cycles" and code should not rely on that behavior, even
// if experimentally observed.
//
-//
// An arbitrary offset may have been added to the counter at power on.
//
// On some platforms, the rate and offset of the counter may differ
@@ -46,7 +45,7 @@
#include <cstdint>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// -----------------------------------------------------------------------------
@@ -72,8 +71,22 @@ class CycleClock {
CycleClock& operator=(const CycleClock&) = delete;
};
+using CycleClockSourceFunc = int64_t (*)();
+
+class CycleClockSource {
+ private:
+ // CycleClockSource::Register()
+ //
+ // Register a function that provides an alternate source for the unscaled CPU
+ // cycle count value. The source function must be async signal safe, must not
+ // call CycleClock::Now(), and must have a frequency that matches that of the
+ // unscaled clock used by CycleClock. A nullptr value resets CycleClock to use
+ // the default source.
+ static void Register(CycleClockSourceFunc source);
+};
+
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
diff --git a/absl/base/internal/direct_mmap.h b/absl/base/internal/direct_mmap.h
index f064e363..2e5e422c 100644
--- a/absl/base/internal/direct_mmap.h
+++ b/absl/base/internal/direct_mmap.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -62,7 +62,7 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#endif // __BIONIC__
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// Platform specific logic extracted from
@@ -129,7 +129,7 @@ inline int DirectMunmap(void* start, size_t length) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // !__linux__
@@ -138,7 +138,7 @@ inline int DirectMunmap(void* start, size_t length) {
// actual mmap()/munmap() methods.
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
@@ -151,7 +151,7 @@ inline int DirectMunmap(void* start, size_t length) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // __linux__
diff --git a/absl/base/internal/endian.h b/absl/base/internal/endian.h
index 52c09c5b..8643bffa 100644
--- a/absl/base/internal/endian.h
+++ b/absl/base/internal/endian.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#elif defined(__APPLE__)
-// Mac OS X / Darwin features
+// macOS / Darwin features
#include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
@@ -34,7 +34,7 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Use compiler byte-swapping intrinsics if they are available. 32-bit
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
@@ -76,7 +76,7 @@ inline uint64_t gbswap_64(uint64_t host_int) {
if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int);
} else {
- register uint64_t result;
+ uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result;
}
@@ -268,7 +268,7 @@ inline void Store64(void *p, uint64_t v) {
} // namespace big_endian
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
diff --git a/absl/base/internal/endian_test.cc b/absl/base/internal/endian_test.cc
index 14ac4765..0c683286 100644
--- a/absl/base/internal/endian_test.cc
+++ b/absl/base/internal/endian_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "absl/base/config.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
const uint64_t kInitialNumber{0x0123456789abcdef};
@@ -261,5 +261,5 @@ TEST(EndianessTest, big_endian) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc
index 8207b7d7..6ef4325c 100644
--- a/absl/base/internal/exception_safety_testing.cc
+++ b/absl/base/internal/exception_safety_testing.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index d4d41a8a..be38ba54 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -169,8 +169,10 @@ class ConstructorTracker {
return current_tracker_instance_ != nullptr;
}
- static std::string ErrorMessage(void* address, const std::string& address_description,
- int countdown, const std::string& error_description) {
+ static std::string ErrorMessage(void* address,
+ const std::string& address_description,
+ int countdown,
+ const std::string& error_description) {
return absl::Substitute(
"With coundtown at $0:\n"
" $1\n"
@@ -556,8 +558,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
// We provide both regular and templated operator delete because if only the
// templated version is provided as we did with operator new, the compiler has
// no way of knowing which overload of operator delete to call. See
- // http://en.cppreference.com/w/cpp/memory/new/operator_delete and
- // http://en.cppreference.com/w/cpp/language/delete for the gory details.
+ // https://en.cppreference.com/w/cpp/memory/new/operator_delete and
+ // https://en.cppreference.com/w/cpp/language/delete for the gory details.
void operator delete(void* p) noexcept { ::operator delete(p); }
template <typename... Args>
diff --git a/absl/base/internal/exception_testing.h b/absl/base/internal/exception_testing.h
index 0cf7918e..01b54655 100644
--- a/absl/base/internal/exception_testing.h
+++ b/absl/base/internal/exception_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/hide_ptr.h b/absl/base/internal/hide_ptr.h
index ce390dc4..3720db18 100644
--- a/absl/base/internal/hide_ptr.h
+++ b/absl/base/internal/hide_ptr.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include <cstdint>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// Arbitrary value with high bits set. Xor'ing with it is unlikely
@@ -43,7 +43,7 @@ inline T* UnhidePtr(uintptr_t hidden) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_
diff --git a/absl/base/internal/identity.h b/absl/base/internal/identity.h
index d57c83f4..b9d0f621 100644
--- a/absl/base/internal/identity.h
+++ b/absl/base/internal/identity.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#define ABSL_BASE_INTERNAL_IDENTITY_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace internal {
template <typename T>
@@ -29,7 +29,7 @@ template <typename T>
using identity_t = typename identity<T>::type;
} // namespace internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_
diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h
index f7bb8c56..130d8c24 100644
--- a/absl/base/internal/inline_variable.h
+++ b/absl/base/internal/inline_variable.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h
index be0b0b96..0ebdb9d8 100644
--- a/absl/base/internal/inline_variable_testing.h
+++ b/absl/base/internal/inline_variable_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include "absl/base/internal/inline_variable.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace inline_variable_testing_internal {
struct Foo {
@@ -40,7 +40,7 @@ const int& get_int_a();
const int& get_int_b();
} // namespace inline_variable_testing_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
diff --git a/absl/base/internal/invoke.h b/absl/base/internal/invoke.h
index 1372ef50..030b98df 100644
--- a/absl/base/internal/invoke.h
+++ b/absl/base/internal/invoke.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -39,11 +39,13 @@
#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 {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// The five classes below each implement one of the clauses from the definition
@@ -68,15 +70,11 @@ struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename... Params, typename Obj,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...), Obj, Args...>
- : std::is_base_of<C, Obj> {};
-
- template <typename R, typename C, typename... Params, typename Obj,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...>
- : std::is_base_of<C, Obj> {};
+ 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>().*
@@ -93,15 +91,11 @@ struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
template <typename... Args>
struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename... Params, typename Ptr,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...), Ptr, Args...>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
-
- template <typename R, typename C, typename... Params, typename Ptr,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+ 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>()).*
@@ -120,7 +114,9 @@ struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
struct AcceptImpl : std::false_type {};
template <typename R, typename C, typename Obj>
- struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, 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(
@@ -137,7 +133,8 @@ struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
template <typename R, typename C, typename Ptr>
struct AcceptImpl<R C::*, Ptr>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
+ : 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(
@@ -184,7 +181,7 @@ InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
std::forward<Args>(args)...);
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_INVOKE_H_
diff --git a/absl/base/internal/low_level_alloc.cc b/absl/base/internal/low_level_alloc.cc
index 10d805cc..419c0e45 100644
--- a/absl/base/internal/low_level_alloc.cc
+++ b/absl/base/internal/low_level_alloc.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -63,7 +63,7 @@
#endif // __APPLE__
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// A first-fit allocator with amortized logarithmic free() time.
@@ -295,7 +295,10 @@ class SCOPED_LOCKABLE ArenaLock {
arena_->mu.Unlock();
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
if (mask_valid_) {
- pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+ const int err = pthread_sigmask(SIG_SETMASK, &mask_, nullptr);
+ if (err != 0) {
+ ABSL_RAW_LOG(FATAL, "pthread_sigmask failed: %d", err);
+ }
}
#endif
left_ = true;
@@ -612,7 +615,7 @@ void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/base/internal/low_level_alloc.h b/absl/base/internal/low_level_alloc.h
index 87cfc934..32b6ec17 100644
--- a/absl/base/internal/low_level_alloc.h
+++ b/absl/base/internal/low_level_alloc.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,6 +25,7 @@
// IWYU pragma: private, include "base/low_level_alloc.h"
#include <sys/types.h>
+
#include <cstdint>
#include "absl/base/attributes.h"
@@ -54,7 +55,7 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
class LowLevelAlloc {
@@ -119,6 +120,7 @@ class LowLevelAlloc {
};
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
diff --git a/absl/base/internal/low_level_alloc_test.cc b/absl/base/internal/low_level_alloc_test.cc
index 65bb519d..b6eb8b30 100644
--- a/absl/base/internal/low_level_alloc_test.cc
+++ b/absl/base/internal/low_level_alloc_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include <utility>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
namespace {
@@ -138,6 +138,7 @@ static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
TEST_ASSERT(LowLevelAlloc::DeleteArena(arena));
}
}
+
// LowLevelAlloc is designed to be safe to call before main().
static struct BeforeMain {
BeforeMain() {
@@ -149,7 +150,7 @@ static struct BeforeMain {
} // namespace
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
int main(int argc, char *argv[]) {
diff --git a/absl/base/internal/low_level_scheduling.h b/absl/base/internal/low_level_scheduling.h
index 7cb6117e..b762279d 100644
--- a/absl/base/internal/low_level_scheduling.h
+++ b/absl/base/internal/low_level_scheduling.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@ extern "C" bool __google_disable_rescheduling(void);
extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard.
@@ -87,6 +87,7 @@ class SchedulingGuard {
//------------------------------------------------------------------------------
// End of public interfaces.
//------------------------------------------------------------------------------
+
inline bool SchedulingGuard::ReschedulingIsAllowed() {
return false;
}
@@ -99,8 +100,8 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
return;
}
-
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
diff --git a/absl/base/internal/per_thread_tls.h b/absl/base/internal/per_thread_tls.h
index 2428bdc1..cf5e97a0 100644
--- a/absl/base/internal/per_thread_tls.h
+++ b/absl/base/internal/per_thread_tls.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,13 +16,17 @@
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
// This header defines two macros:
+//
// If the platform supports thread-local storage:
-// ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
-// thread-local variable ABSL_PER_THREAD_TLS is 1
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
+// thread-local variable
+// * ABSL_PER_THREAD_TLS is 1
//
// Otherwise:
-// ABSL_PER_THREAD_TLS_KEYWORD is empty
-// ABSL_PER_THREAD_TLS is 0
+//
+// * ABSL_PER_THREAD_TLS_KEYWORD is empty
+// * ABSL_PER_THREAD_TLS is 0
//
// Microsoft C supports thread-local storage.
// GCC supports it if the appropriate version of glibc is available,
diff --git a/absl/base/internal/pretty_function.h b/absl/base/internal/pretty_function.h
index 01b0547b..35d51676 100644
--- a/absl/base/internal/pretty_function.h
+++ b/absl/base/internal/pretty_function.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/raw_logging.cc b/absl/base/internal/raw_logging.cc
index ed8b8d7c..1a36d5b6 100644
--- a/absl/base/internal/raw_logging.cc
+++ b/absl/base/internal/raw_logging.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -36,7 +36,8 @@
// This preprocessor token is also defined in raw_io.cc. If you need to copy
// this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
- defined(__Fuchsia__) || defined(__native_client__)
+ defined(__Fuchsia__) || defined(__native_client__) || \
+ defined(__EMSCRIPTEN__)
#include <unistd.h>
@@ -181,7 +182,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
} // namespace
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE)
@@ -232,5 +233,5 @@ void RegisterInternalLogFunction(InternalLogFunction func) {
}
} // namespace raw_logging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/raw_logging.h b/absl/base/internal/raw_logging.h
index 2786a3de..8e5a34ef 100644
--- a/absl/base/internal/raw_logging.h
+++ b/absl/base/internal/raw_logging.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,6 +38,7 @@
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
// This will print an almost standard log line like this to stderr only:
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
+
#define ABSL_RAW_LOG(severity, ...) \
do { \
constexpr const char* absl_raw_logging_internal_basename = \
@@ -79,13 +80,13 @@
absl_raw_logging_internal_basename, __LINE__, message); \
} while (0)
-#define ABSL_INTERNAL_CHECK(condition, message) \
- do { \
- if (ABSL_PREDICT_FALSE(!(condition))) { \
+#define ABSL_INTERNAL_CHECK(condition, message) \
+ do { \
+ if (ABSL_PREDICT_FALSE(!(condition))) { \
std::string death_message = "Check " #condition " failed: "; \
death_message += std::string(message); \
- ABSL_INTERNAL_LOG(FATAL, death_message); \
- } \
+ ABSL_INTERNAL_LOG(FATAL, death_message); \
+ } \
} while (0)
#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo
@@ -96,7 +97,7 @@
::absl::NormalizeLogSeverity(severity)
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace raw_logging_internal {
// Helper function to implement ABSL_RAW_LOG
@@ -176,7 +177,7 @@ extern base_internal::AtomicHook<InternalLogFunction> internal_log_function;
void RegisterInternalLogFunction(InternalLogFunction func);
} // namespace raw_logging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
diff --git a/absl/base/internal/scheduling_mode.h b/absl/base/internal/scheduling_mode.h
index 19a7514c..48767920 100644
--- a/absl/base/internal/scheduling_mode.h
+++ b/absl/base/internal/scheduling_mode.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,7 @@
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// Used to describe how a thread may be scheduled. Typically associated with
@@ -50,7 +50,7 @@ enum SchedulingMode {
};
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
diff --git a/absl/base/internal/scoped_set_env.cc b/absl/base/internal/scoped_set_env.cc
new file mode 100644
index 00000000..eb7a0116
--- /dev/null
+++ b/absl/base/internal/scoped_set_env.cc
@@ -0,0 +1,81 @@
+// 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.
+
+#include "absl/base/internal/scoped_set_env.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include <cstdlib>
+
+#include "absl/base/internal/raw_logging.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace base_internal {
+
+namespace {
+
+#ifdef _WIN32
+const int kMaxEnvVarValueSize = 1024;
+#endif
+
+void SetEnvVar(const char* name, const char* value) {
+#ifdef _WIN32
+ SetEnvironmentVariableA(name, value);
+#else
+ if (value == nullptr) {
+ ::unsetenv(name);
+ } else {
+ ::setenv(name, value, 1);
+ }
+#endif
+}
+
+} // namespace
+
+ScopedSetEnv::ScopedSetEnv(const char* var_name, const char* new_value)
+ : var_name_(var_name), was_unset_(false) {
+#ifdef _WIN32
+ char buf[kMaxEnvVarValueSize];
+ auto get_res = GetEnvironmentVariableA(var_name_.c_str(), buf, sizeof(buf));
+ ABSL_INTERNAL_CHECK(get_res < sizeof(buf), "value exceeds buffer size");
+
+ if (get_res == 0) {
+ was_unset_ = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
+ } else {
+ old_value_.assign(buf, get_res);
+ }
+
+ SetEnvironmentVariableA(var_name_.c_str(), new_value);
+#else
+ const char* val = ::getenv(var_name_.c_str());
+ if (val == nullptr) {
+ was_unset_ = true;
+ } else {
+ old_value_ = val;
+ }
+#endif
+
+ SetEnvVar(var_name_.c_str(), new_value);
+}
+
+ScopedSetEnv::~ScopedSetEnv() {
+ SetEnvVar(var_name_.c_str(), was_unset_ ? nullptr : old_value_.c_str());
+}
+
+} // namespace base_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/base/internal/scoped_set_env.h b/absl/base/internal/scoped_set_env.h
new file mode 100644
index 00000000..709843bc
--- /dev/null
+++ b/absl/base/internal/scoped_set_env.h
@@ -0,0 +1,43 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+#define ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
+
+#include <string>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace base_internal {
+
+class ScopedSetEnv {
+ public:
+ ScopedSetEnv(const char* var_name, const char* new_value);
+ ~ScopedSetEnv();
+
+ private:
+ std::string var_name_;
+ std::string old_value_;
+
+ // True if the environment variable was initially not set.
+ bool was_unset_;
+};
+
+} // namespace base_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
diff --git a/absl/base/internal/scoped_set_env_test.cc b/absl/base/internal/scoped_set_env_test.cc
new file mode 100644
index 00000000..5cbad246
--- /dev/null
+++ b/absl/base/internal/scoped_set_env_test.cc
@@ -0,0 +1,99 @@
+// 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.
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/scoped_set_env.h"
+
+namespace {
+
+using absl::base_internal::ScopedSetEnv;
+
+std::string GetEnvVar(const char* name) {
+#ifdef _WIN32
+ char buf[1024];
+ auto get_res = GetEnvironmentVariableA(name, buf, sizeof(buf));
+ if (get_res >= sizeof(buf)) {
+ return "TOO_BIG";
+ }
+
+ if (get_res == 0) {
+ return "UNSET";
+ }
+
+ return std::string(buf, get_res);
+#else
+ const char* val = ::getenv(name);
+ if (val == nullptr) {
+ return "UNSET";
+ }
+
+ return val;
+#endif
+}
+
+TEST(ScopedSetEnvTest, SetNonExistingVarToString) {
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+}
+
+TEST(ScopedSetEnvTest, SetNonExistingVarToNull) {
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr);
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+}
+
+TEST(ScopedSetEnvTest, SetExistingVarToString) {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "new_value");
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "new_value");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+}
+
+TEST(ScopedSetEnvTest, SetExistingVarToNull) {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", "value");
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+
+ {
+ ScopedSetEnv scoped_set("SCOPED_SET_ENV_TEST_VAR", nullptr);
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "UNSET");
+ }
+
+ EXPECT_EQ(GetEnvVar("SCOPED_SET_ENV_TEST_VAR"), "value");
+}
+
+} // namespace
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 8f8eef82..5f443bfa 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -54,7 +54,7 @@
// holder to acquire the lock. There may be outstanding waiter(s).
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
@@ -229,5 +229,5 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/spinlock.h b/absl/base/internal/spinlock.h
index d53878b2..df947661 100644
--- a/absl/base/internal/spinlock.h
+++ b/absl/base/internal/spinlock.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,6 +32,7 @@
#include <stdint.h>
#include <sys/types.h>
+
#include <atomic>
#include "absl/base/attributes.h"
@@ -45,7 +46,7 @@
#include "absl/base/thread_annotations.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
class LOCKABLE SpinLock {
@@ -58,8 +59,10 @@ class LOCKABLE SpinLock {
//
// static SpinLock lock(base_internal::kLinkerInitialized);
//
- // When intialized using this constructor, we depend on the fact
- // that the linker has already initialized the memory appropriately.
+ // When initialized using this constructor, we depend on the fact
+ // that the linker has already initialized the memory appropriately. The lock
+ // is initialized in non-cooperative mode.
+ //
// A SpinLock constructed like this can be freely used from global
// initializers without worrying about the order in which global
// initializers run.
@@ -235,7 +238,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
diff --git a/absl/base/internal/spinlock_akaros.inc b/absl/base/internal/spinlock_akaros.inc
index 051c8cf8..bc468940 100644
--- a/absl/base/internal/spinlock_akaros.inc
+++ b/absl/base/internal/spinlock_akaros.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/spinlock_benchmark.cc b/absl/base/internal/spinlock_benchmark.cc
index 907d3e27..0451c65f 100644
--- a/absl/base/internal/spinlock_benchmark.cc
+++ b/absl/base/internal/spinlock_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/spinlock_linux.inc b/absl/base/internal/spinlock_linux.inc
index 94c861dc..28e29d19 100644
--- a/absl/base/internal/spinlock_linux.inc
+++ b/absl/base/internal/spinlock_linux.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -51,17 +51,12 @@ extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode) {
- if (loop != 0) {
- int save_errno = errno;
- struct timespec tm;
- tm.tv_sec = 0;
- // Increase the delay; we expect (but do not rely on) explicit wakeups.
- // We don't rely on explicit wakeups because we intentionally allow for
- // a race on the kSpinLockSleeper bit.
- tm.tv_nsec = 16 * absl::base_internal::SpinLockSuggestedDelayNS(loop);
- syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
- errno = save_errno;
- }
+ int save_errno = errno;
+ struct timespec tm;
+ tm.tv_sec = 0;
+ tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
+ syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, &tm);
+ errno = save_errno;
}
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
diff --git a/absl/base/internal/spinlock_posix.inc b/absl/base/internal/spinlock_posix.inc
index 0098c1c7..f025b5f8 100644
--- a/absl/base/internal/spinlock_posix.inc
+++ b/absl/base/internal/spinlock_posix.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/spinlock_wait.cc b/absl/base/internal/spinlock_wait.cc
index 3f8e43f0..60a85196 100644
--- a/absl/base/internal/spinlock_wait.cc
+++ b/absl/base/internal/spinlock_wait.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,7 +32,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// See spinlock_wait.h for spec.
@@ -66,19 +66,16 @@ int SpinLockSuggestedDelayNS(int loop) {
r = 0x5deece66dLL * r + 0xb; // numbers from nrand48()
delay_rand.store(r, std::memory_order_relaxed);
- r <<= 16; // 48-bit random number now in top 48-bits.
if (loop < 0 || loop > 32) { // limit loop to 0..32
loop = 32;
}
- // loop>>3 cannot exceed 4 because loop cannot exceed 32.
- // Select top 20..24 bits of lower 48 bits,
- // giving approximately 0ms to 16ms.
- // Mean is exponential in loop for first 32 iterations, then 8ms.
- // The futex path multiplies this by 16, since we expect explicit wakeups
- // almost always on that path.
- return static_cast<int>(r >> (44 - (loop >> 3)));
+ const int kMinDelay = 128 << 10; // 128us
+ // Double delay every 8 iterations, up to 16x (2ms).
+ int delay = kMinDelay << (loop / 8);
+ // Randomize in delay..2*delay range, for resulting 128us..4ms range.
+ return delay | ((delay - 1) & static_cast<int>(r));
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/spinlock_wait.h b/absl/base/internal/spinlock_wait.h
index 5eb727f1..7e139de0 100644
--- a/absl/base/internal/spinlock_wait.h
+++ b/absl/base/internal/spinlock_wait.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "absl/base/internal/scheduling_mode.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// SpinLockWait() waits until it can perform one of several transitions from
@@ -63,7 +63,7 @@ void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
int SpinLockSuggestedDelayNS(int loop);
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
diff --git a/absl/base/internal/spinlock_win32.inc b/absl/base/internal/spinlock_win32.inc
index 32c8fc0b..78654b5b 100644
--- a/absl/base/internal/spinlock_win32.inc
+++ b/absl/base/internal/spinlock_win32.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/sysinfo.cc b/absl/base/internal/sysinfo.cc
index ce14fc0f..0d5cf821 100644
--- a/absl/base/internal/sysinfo.cc
+++ b/absl/base/internal/sysinfo.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -56,7 +56,7 @@
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
static once_flag init_system_info_once;
@@ -402,5 +402,5 @@ pid_t GetTID() {
#endif
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/sysinfo.h b/absl/base/internal/sysinfo.h
index 79100f61..22739aeb 100644
--- a/absl/base/internal/sysinfo.h
+++ b/absl/base/internal/sysinfo.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,7 +33,7 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// Nominal core processor cycles per second of each processor. This is _not_
@@ -59,7 +59,7 @@ using pid_t = DWORD;
pid_t GetTID();
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_
diff --git a/absl/base/internal/sysinfo_test.cc b/absl/base/internal/sysinfo_test.cc
index c072ebc2..c8323e52 100644
--- a/absl/base/internal/sysinfo_test.cc
+++ b/absl/base/internal/sysinfo_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
namespace {
@@ -38,12 +38,12 @@ TEST(SysinfoTest, NumCPUs) {
}
TEST(SysinfoTest, NominalCPUFrequency) {
-#if !(defined(__aarch64__) && defined(__linux__))
+#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
EXPECT_GE(NominalCPUFrequency(), 1000.0)
<< "NominalCPUFrequency() did not return a reasonable value";
#else
- // TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we
- // get back 1.0. Fix once the value is available.
+ // Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
+ // Emscripten does not have a sysfs to read from at all.
EXPECT_EQ(NominalCPUFrequency(), 1.0)
<< "CPU frequency detection was fixed! Please update unittest.";
#endif
@@ -96,5 +96,5 @@ TEST(SysinfoTest, LinuxGetTID) {
} // namespace
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/thread_annotations.h b/absl/base/internal/thread_annotations.h
new file mode 100644
index 00000000..4dab6a9c
--- /dev/null
+++ b/absl/base/internal/thread_annotations.h
@@ -0,0 +1,271 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: thread_annotations.h
+// -----------------------------------------------------------------------------
+//
+// WARNING: This is a backwards compatible header and it will be removed after
+// the migration to prefixed thread annotations is finished; please include
+// "absl/base/thread_annotations.h".
+//
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+
+#ifndef ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
+#define ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
+
+#if defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+// GUARDED_BY()
+//
+// Documents if a shared field or global variable needs to be protected by a
+// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// should be held when accessing the annotated variable.
+//
+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// local variables, a local variable and its associated mutex can often be
+// combined into a small class or struct, thereby allowing the annotation.
+//
+// Example:
+//
+// class Foo {
+// Mutex mu_;
+// int p1_ GUARDED_BY(mu_);
+// ...
+// };
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+// PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+// class Foo {
+// Mutex mu_;
+// int *p1_ PT_GUARDED_BY(mu_);
+// ...
+// };
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+// // `q_`, guarded by `mu1_`, points to a shared memory location that is
+// // guarded by `mu2_`:
+// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+//
+// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// fields or global variables.
+//
+// Example:
+//
+// Mutex m1_;
+// Mutex m2_ ACQUIRED_AFTER(m1_);
+#define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define ACQUIRED_BEFORE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// An exclusive lock allows read-write access to the guarded data member(s), and
+// only one thread can acquire a lock exclusively at any one time. A shared lock
+// allows read-only access, and any number of threads can acquire a shared lock
+// concurrently.
+//
+// Generally, non-const methods should be annotated with
+// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// SHARED_LOCKS_REQUIRED.
+//
+// Example:
+//
+// Mutex mu1, mu2;
+// int a GUARDED_BY(mu1);
+// int b GUARDED_BY(mu2);
+//
+// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+#define SHARED_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#define LOCKS_EXCLUDED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it. For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with LOCK_RETURNED.
+#define LOCK_RETURNED(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#define LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#define SCOPED_LOCKABLE \
+ THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#define SHARED_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#define UNLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+#define ASSERT_SHARED_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#define NO_THREAD_SAFETY_ANALYSIS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes. These
+// annotations will be ignored by the analysis.
+#define TS_UNCHECKED(x) ""
+
+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to TS_UNCHECKED.
+#define TS_FIXME(x) ""
+
+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// a particular function. However, this attribute is used to mark functions
+// that are incorrect and need to be fixed. It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// annotation that needs to be fixed, because it is producing thread safety
+// warning. It disables the GUARDED_BY.
+#define GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation. This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+
+
+namespace thread_safety_analysis {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+} // namespace thread_safety_analysis
+
+#endif // ABSL_BASE_INTERNAL_THREAD_ANNOTATIONS_H_
diff --git a/absl/base/internal/thread_identity.cc b/absl/base/internal/thread_identity.cc
index b35bee34..dbec326a 100644
--- a/absl/base/internal/thread_identity.cc
+++ b/absl/base/internal/thread_identity.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/base/internal/spinlock.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
@@ -131,5 +131,5 @@ ThreadIdentity* CurrentThreadIdentityIfPresent() {
#endif
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/thread_identity.h b/absl/base/internal/thread_identity.h
index 17ac2a7c..bb5aa074 100644
--- a/absl/base/internal/thread_identity.h
+++ b/absl/base/internal/thread_identity.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,7 +33,7 @@
#include "absl/base/internal/per_thread_tls.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
struct SynchLocksHeld;
struct SynchWaitParams;
@@ -43,9 +43,9 @@ namespace base_internal {
class SpinLock;
struct ThreadIdentity;
-// Used by the implementation of base::Mutex and base::CondVar.
+// Used by the implementation of absl::Mutex and absl::CondVar.
struct PerThreadSynch {
- // The internal representation of base::Mutex and base::CondVar rely
+ // The internal representation of absl::Mutex and absl::CondVar rely
// on the alignment of PerThreadSynch. Both store the address of the
// PerThreadSynch in the high-order bits of their internal state,
// which means the low kLowZeroBits of the address of PerThreadSynch
@@ -237,6 +237,7 @@ inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
#endif
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
diff --git a/absl/base/internal/thread_identity_benchmark.cc b/absl/base/internal/thread_identity_benchmark.cc
index 242522b4..0ae10f2b 100644
--- a/absl/base/internal/thread_identity_benchmark.cc
+++ b/absl/base/internal/thread_identity_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/thread_identity_test.cc b/absl/base/internal/thread_identity_test.cc
index ec93fc27..8de6d9eb 100644
--- a/absl/base/internal/thread_identity_test.cc
+++ b/absl/base/internal/thread_identity_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
namespace {
@@ -124,5 +124,5 @@ TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
} // namespace
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/throw_delegate.cc b/absl/base/internal/throw_delegate.cc
index 0f73c3eb..bee404d4 100644
--- a/absl/base/internal/throw_delegate.cc
+++ b/absl/base/internal/throw_delegate.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
namespace {
@@ -104,5 +104,5 @@ void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/internal/throw_delegate.h b/absl/base/internal/throw_delegate.h
index 7e5510c0..60ed4f32 100644
--- a/absl/base/internal/throw_delegate.h
+++ b/absl/base/internal/throw_delegate.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// Helper functions that allow throwing exceptions consistently from anywhere.
@@ -67,7 +67,7 @@ namespace base_internal {
// [[noreturn]] void ThrowStdBadArrayNewLength();
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
diff --git a/absl/base/internal/tsan_mutex_interface.h b/absl/base/internal/tsan_mutex_interface.h
index 6bb4faed..2a510603 100644
--- a/absl/base/internal/tsan_mutex_interface.h
+++ b/absl/base/internal/tsan_mutex_interface.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/internal/unaligned_access.h b/absl/base/internal/unaligned_access.h
index 07a64bba..a709a446 100644
--- a/absl/base/internal/unaligned_access.h
+++ b/absl/base/internal/unaligned_access.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,15 +25,6 @@
// unaligned APIs
// Portable handling of unaligned loads, stores, and copies.
-// On some platforms, like ARM, the copy functions can be more efficient
-// then a load and a store.
-//
-// It is possible to implement all of these these using constant-length memcpy
-// calls, which is portable and will usually be inlined into simple loads and
-// stores if the architecture supports it. However, such inlining usually
-// happens in a pass that's quite late in compilation, which means the resulting
-// loads and stores cannot participate in many other optimizations, leading to
-// overall worse code.
// The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C.
@@ -65,7 +56,7 @@ void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
@@ -93,7 +84,7 @@ inline void UnalignedStore64(void *p, uint64_t v) {
}
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
@@ -110,172 +101,10 @@ inline void UnalignedStore64(void *p, uint64_t v) {
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
-#elif defined(UNDEFINED_BEHAVIOR_SANITIZER)
-
-namespace absl {
-inline namespace lts_2018_12_18 {
-namespace base_internal {
-
-inline uint16_t UnalignedLoad16(const void *p) {
- uint16_t t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline uint32_t UnalignedLoad32(const void *p) {
- uint32_t t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline uint64_t UnalignedLoad64(const void *p) {
- uint64_t t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
-
-inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
-
-inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
-
-} // namespace base_internal
-} // inline namespace lts_2018_12_18
-} // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
- (absl::base_internal::UnalignedLoad16(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
- (absl::base_internal::UnalignedLoad32(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
- (absl::base_internal::UnalignedLoad64(_p))
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
- (absl::base_internal::UnalignedStore16(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
- (absl::base_internal::UnalignedStore32(_p, _val))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
- (absl::base_internal::UnalignedStore64(_p, _val))
-
-#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
- defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \
- defined(__ppc64__) || defined(__PPC64__)
-
-// x86 and x86-64 can perform unaligned loads/stores directly;
-// modern PowerPC hardware can also do unaligned integer loads and stores;
-// but note: the FPU still sends unaligned loads and stores to a trap handler!
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
- (*reinterpret_cast<const uint16_t *>(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
- (*reinterpret_cast<const uint32_t *>(_p))
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
- (*reinterpret_cast<const uint64_t *>(_p))
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
- (*reinterpret_cast<uint16_t *>(_p) = (_val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
- (*reinterpret_cast<uint32_t *>(_p) = (_val))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
- (*reinterpret_cast<uint64_t *>(_p) = (_val))
-
-#elif defined(__arm__) && \
- !defined(__ARM_ARCH_5__) && \
- !defined(__ARM_ARCH_5T__) && \
- !defined(__ARM_ARCH_5TE__) && \
- !defined(__ARM_ARCH_5TEJ__) && \
- !defined(__ARM_ARCH_6__) && \
- !defined(__ARM_ARCH_6J__) && \
- !defined(__ARM_ARCH_6K__) && \
- !defined(__ARM_ARCH_6Z__) && \
- !defined(__ARM_ARCH_6ZK__) && \
- !defined(__ARM_ARCH_6T2__)
-
-
-// ARMv7 and newer support native unaligned accesses, but only of 16-bit
-// and 32-bit values (not 64-bit); older versions either raise a fatal signal,
-// do an unaligned read and rotate the words around a bit, or do the reads very
-// slowly (trip through kernel mode). There's no simple #define that says just
-// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6
-// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define,
-// so in time, maybe we can move on to that.
-//
-// This is a mess, but there's not much we can do about it.
-//
-// To further complicate matters, only LDR instructions (single reads) are
-// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we
-// explicitly tell the compiler that these accesses can be unaligned, it can and
-// will combine accesses. On armcc, the way to signal this is done by accessing
-// through the type (uint32_t __packed *), but GCC has no such attribute
-// (it ignores __attribute__((packed)) on individual variables). However,
-// we can tell it that a _struct_ is unaligned, which has the same effect,
-// so we do that.
-
-namespace absl {
-inline namespace lts_2018_12_18 {
-namespace base_internal {
-
-struct Unaligned16Struct {
- uint16_t value;
- uint8_t dummy; // To make the size non-power-of-two.
-} ABSL_ATTRIBUTE_PACKED;
-
-struct Unaligned32Struct {
- uint32_t value;
- uint8_t dummy; // To make the size non-power-of-two.
-} ABSL_ATTRIBUTE_PACKED;
-
-} // namespace base_internal
-} // inline namespace lts_2018_12_18
-} // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
- ((reinterpret_cast<const ::absl::base_internal::Unaligned16Struct *>(_p)) \
- ->value)
-#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
- ((reinterpret_cast<const ::absl::base_internal::Unaligned32Struct *>(_p)) \
- ->value)
-
-#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
- ((reinterpret_cast< ::absl::base_internal::Unaligned16Struct *>(_p)) \
- ->value = (_val))
-#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
- ((reinterpret_cast< ::absl::base_internal::Unaligned32Struct *>(_p)) \
- ->value = (_val))
-
-namespace absl {
-inline namespace lts_2018_12_18 {
-namespace base_internal {
-
-inline uint64_t UnalignedLoad64(const void *p) {
- uint64_t t;
- memcpy(&t, p, sizeof t);
- return t;
-}
-
-inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
-
-} // namespace base_internal
-} // inline namespace lts_2018_12_18
-} // namespace absl
-
-#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
- (absl::base_internal::UnalignedLoad64(_p))
-#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
- (absl::base_internal::UnalignedStore64(_p, _val))
-
#else
-// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform
-// doesn't support unaligned access.
-#define ABSL_INTERNAL_NEED_ALIGNED_LOADS
-
-// These functions are provided for architectures that don't support
-// unaligned loads and stores.
-
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
@@ -303,7 +132,7 @@ inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index 888caf1e..29a927d3 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,7 +27,7 @@
#include "absl/base/internal/sysinfo.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
#if defined(__i386__)
@@ -97,7 +97,7 @@ double UnscaledCycleClock::Frequency() {
#endif
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
diff --git a/absl/base/internal/unscaledcycleclock.h b/absl/base/internal/unscaledcycleclock.h
index c71674f3..e6fc9103 100644
--- a/absl/base/internal/unscaledcycleclock.h
+++ b/absl/base/internal/unscaledcycleclock.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -59,7 +59,8 @@
// CycleClock that runs at atleast 1 MHz. We've found some Android
// ARM64 devices where this is not the case, so we disable it by
// default on Android ARM64.
-#if defined(__native_client__) || TARGET_OS_IPHONE || \
+#if defined(__native_client__) || \
+ (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
(defined(__ANDROID__) && defined(__aarch64__))
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
#else
@@ -83,8 +84,9 @@
defined(_M_IX86) || defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif
+
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
class UnscaledCycleClockWrapperForGetCurrentTime;
} // namespace time_internal
@@ -114,8 +116,9 @@ class UnscaledCycleClock {
};
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_
diff --git a/absl/base/invoke_test.cc b/absl/base/invoke_test.cc
index 4df637ac..685501a4 100644
--- a/absl/base/invoke_test.cc
+++ b/absl/base/invoke_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
namespace {
@@ -71,6 +71,10 @@ struct OverloadedFunctor {
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;
};
@@ -152,8 +156,18 @@ TEST(InvokeTest, ReferenceWrapper) {
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, Invoke(&Class::Method, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT
+ EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2));
@@ -163,6 +177,13 @@ TEST(InvokeTest, MemberFunction) {
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2));
+ EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2));
+
EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2));
@@ -198,5 +219,5 @@ TEST(InvokeTest, SfinaeFriendly) {
} // namespace
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/types/optional.cc b/absl/base/log_severity.cc
index 5c77f154..8109da19 100644
--- a/absl/types/optional.cc
+++ b/absl/base/log_severity.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,15 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/types/optional.h"
+#include "absl/base/log_severity.h"
-#ifndef ABSL_HAVE_STD_OPTIONAL
-namespace absl {
-inline namespace lts_2018_12_18 {
+#include <ostream>
-nullopt_t::init_t nullopt_t::init;
-extern const nullopt_t nullopt{nullopt_t::init};
+namespace absl {
+inline namespace lts_2019_08_08 {
-} // inline namespace lts_2018_12_18
+std::ostream& operator<<(std::ostream& os, absl::LogSeverity s) {
+ if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s);
+ return os << "absl::LogSeverity(" << static_cast<int>(s) << ")";
+}
+} // inline namespace lts_2019_08_08
} // namespace absl
-#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/base/log_severity.h b/absl/base/log_severity.h
index c24fad79..45f79cca 100644
--- a/absl/base/log_severity.h
+++ b/absl/base/log_severity.h
@@ -4,24 +4,24 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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_LOG_SEVERITY_H_
#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#include <array>
+#include <ostream>
#include "absl/base/attributes.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Four severity levels are defined. Logging APIs should terminate the program
// when a message is logged at severity `kFatal`; the other levels have no
@@ -63,7 +63,11 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
}
-} // inline namespace lts_2018_12_18
+// The exact representation of a streamed `absl::LogSeverity` is deliberately
+// unspecified; do not rely on it.
+std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
+
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
diff --git a/absl/base/log_severity_test.cc b/absl/base/log_severity_test.cc
new file mode 100644
index 00000000..1de2d101
--- /dev/null
+++ b/absl/base/log_severity_test.cc
@@ -0,0 +1,43 @@
+// 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.
+
+#include "absl/base/log_severity.h"
+
+#include <sstream>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace {
+using testing::Eq;
+
+std::string StreamHelper(absl::LogSeverity value) {
+ std::ostringstream stream;
+ stream << value;
+ return stream.str();
+}
+
+TEST(StreamTest, Works) {
+ EXPECT_THAT(StreamHelper(static_cast<absl::LogSeverity>(-100)),
+ Eq("absl::LogSeverity(-100)"));
+ EXPECT_THAT(StreamHelper(absl::LogSeverity::kInfo), Eq("INFO"));
+ EXPECT_THAT(StreamHelper(absl::LogSeverity::kWarning), Eq("WARNING"));
+ EXPECT_THAT(StreamHelper(absl::LogSeverity::kError), Eq("ERROR"));
+ EXPECT_THAT(StreamHelper(absl::LogSeverity::kFatal), Eq("FATAL"));
+ EXPECT_THAT(StreamHelper(static_cast<absl::LogSeverity>(4)),
+ Eq("absl::LogSeverity(4)"));
+}
+
+} // namespace
diff --git a/absl/base/macros.h b/absl/base/macros.h
index 14c4b0a3..3121088a 100644
--- a/absl/base/macros.h
+++ b/absl/base/macros.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,6 @@
// This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms.
-//
#ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_
@@ -32,6 +31,7 @@
#include <cassert>
#include <cstddef>
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
// ABSL_ARRAYSIZE()
@@ -43,14 +43,14 @@
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace macros_internal {
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// kLinkerInitialized
@@ -74,13 +74,13 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
// // Invocation
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
enum LinkerInitialized {
kLinkerInitialized = 0,
};
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// ABSL_FALLTHROUGH_INTENDED
@@ -196,10 +196,11 @@ enum LinkerInitialized {
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
-#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0)
+#define ABSL_ASSERT(expr) \
+ (false ? static_cast<void>(expr) : static_cast<void>(0))
#else
-#define ABSL_ASSERT(expr) \
- (ABSL_PREDICT_TRUE((expr)) ? (void)0 \
+#define ABSL_ASSERT(expr) \
+ (ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { assert(false && #expr); }()) // NOLINT
#endif
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index 2fddfc80..0dcbef32 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -111,9 +111,9 @@
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information.
//
-// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to
-// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is
-// not known to work, the macro expands to nothing.
+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
+// or `__declspec` attribute. For compilers where this is not known to work,
+// the macro expands to nothing.
//
// No further guarantees are made here. The result of applying the macro
// to variables and types is always implementation-defined.
@@ -122,6 +122,14 @@
// of causing bugs that are difficult to diagnose, crash, etc. It does not
// of itself guarantee that objects are aligned to a cache line.
//
+// NOTE: Some compilers are picky about the locations of annotations such as
+// this attribute, so prefer to put it at the beginning of your declaration.
+// For example,
+//
+// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
+//
+// class ABSL_CACHELINE_ALIGNED Bar { ...
+//
// Recommendations:
//
// 1) Consult compiler documentation; this comment is not kept in sync as
@@ -131,8 +139,10 @@
// 3) Prefer applying this attribute to individual variables. Avoid
// applying it to types. This tends to localize the effect.
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
-
-#else // not GCC
+#elif defined(_MSC_VER)
+#define ABSL_CACHELINE_SIZE 64
+#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
+#else
#define ABSL_CACHELINE_SIZE 64
#define ABSL_CACHELINE_ALIGNED
#endif
@@ -153,6 +163,12 @@
// Compilers can use the information that a certain branch is not likely to be
// taken (for instance, a CHECK failure) to optimize for the common case in
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
+//
+// Recommendation: Modern CPUs dynamically predict branch execution paths,
+// typically with accuracy greater than 97%. As a result, annotating every
+// branch in a codebase is likely counterproductive; however, annotating
+// specific branches that are both hot and consistently mispredicted is likely
+// to yield performance improvements.
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
diff --git a/absl/base/policy_checks.h b/absl/base/policy_checks.h
index 0a07fc03..699fb1a2 100644
--- a/absl/base/policy_checks.h
+++ b/absl/base/policy_checks.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/port.h b/absl/base/port.h
index 1c67257f..6c28068d 100644
--- a/absl/base/port.h
+++ b/absl/base/port.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/raw_logging_test.cc b/absl/base/raw_logging_test.cc
index b21cf651..3d30bd38 100644
--- a/absl/base/raw_logging_test.cc
+++ b/absl/base/raw_logging_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/base/spinlock_test_common.cc b/absl/base/spinlock_test_common.cc
index 95382977..06860e71 100644
--- a/absl/base/spinlock_test_common.cc
+++ b/absl/base/spinlock_test_common.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -36,7 +36,7 @@ constexpr int32_t kNumThreads = 10;
constexpr int32_t kIters = 1000;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace base_internal {
// This is defined outside of anonymous namespace so that it can be
@@ -55,6 +55,7 @@ namespace {
static constexpr int kArrayLength = 10;
static uint32_t values[kArrayLength];
+
static SpinLock static_spinlock(base_internal::kLinkerInitialized);
static SpinLock static_cooperative_spinlock(
base_internal::kLinkerInitialized,
@@ -62,7 +63,6 @@ static SpinLock static_cooperative_spinlock(
static SpinLock static_noncooperative_spinlock(
base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
-
// Simple integer hash function based on the public domain lookup2 hash.
// http://burtleburtle.net/bob/c/lookup2.c
static uint32_t Hash32(uint32_t a, uint32_t c) {
@@ -190,9 +190,11 @@ TEST(SpinLock, WaitCyclesEncoding) {
SpinLockTest::DecodeWaitCycles(before_max_value);
EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
}
+
TEST(SpinLockWithThreads, StaticSpinLock) {
ThreadedTest(&static_spinlock);
}
+
TEST(SpinLockWithThreads, StackSpinLock) {
SpinLock spinlock;
ThreadedTest(&spinlock);
@@ -265,5 +267,5 @@ TEST(SpinLockWithThreads, DoesNotDeadlock) {
} // namespace
} // namespace base_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h
index 2241ace4..f3e96589 100644
--- a/absl/base/thread_annotations.h
+++ b/absl/base/thread_annotations.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,6 @@
// code. The annotations can also help program analysis tools to identify
// potential thread safety issues.
//
-//
// These annotations are implemented using compiler attributes. Using the macros
// defined here instead of raw attributes allow for portability and future
// compatibility.
@@ -34,19 +33,23 @@
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
+
+// TODO(mbonadei): Remove after the backward compatibility period.
+#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
+
#if defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
#endif
-// GUARDED_BY()
+// ABSL_GUARDED_BY()
//
// Documents if a shared field or global variable needs to be protected by a
-// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
// should be held when accessing the annotated variable.
//
-// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to
+// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
// local variables, a local variable and its associated mutex can often be
// combined into a small class or struct, thereby allowing the annotation.
//
@@ -54,12 +57,13 @@
//
// class Foo {
// Mutex mu_;
-// int p1_ GUARDED_BY(mu_);
+// int p1_ ABSL_GUARDED_BY(mu_);
// ...
// };
-#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+#define ABSL_GUARDED_BY(x) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x))
-// PT_GUARDED_BY()
+// ABSL_PT_GUARDED_BY()
//
// Documents if the memory location pointed to by a pointer should be guarded
// by a mutex when dereferencing the pointer.
@@ -67,7 +71,7 @@
// Example:
// class Foo {
// Mutex mu_;
-// int *p1_ PT_GUARDED_BY(mu_);
+// int *p1_ ABSL_PT_GUARDED_BY(mu_);
// ...
// };
//
@@ -78,31 +82,32 @@
//
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`:
-// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_);
-#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
+#define ABSL_PT_GUARDED_BY(x) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x))
-// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
//
// Documents the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
-// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
-// and ACQUIRED_BEFORE.)
+// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
+// and ABSL_ACQUIRED_BEFORE.)
//
-// As with GUARDED_BY, this is only applicable to mutexes that are shared
+// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
// fields or global variables.
//
// Example:
//
// Mutex m1_;
-// Mutex m2_ ACQUIRED_AFTER(m1_);
-#define ACQUIRED_AFTER(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
+#define ABSL_ACQUIRED_AFTER(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__))
-#define ACQUIRED_BEFORE(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+#define ABSL_ACQUIRED_BEFORE(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__))
-// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
//
// Documents a function that expects a mutex to be held prior to entry.
// The mutex is expected to be held both on entry to, and exit from, the
@@ -114,77 +119,78 @@
// concurrently.
//
// Generally, non-const methods should be annotated with
-// EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
-// SHARED_LOCKS_REQUIRED.
+// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
+// ABSL_SHARED_LOCKS_REQUIRED.
//
// Example:
//
// Mutex mu1, mu2;
-// int a GUARDED_BY(mu1);
-// int b GUARDED_BY(mu2);
-//
-// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
-// void bar() const SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
-#define EXCLUSIVE_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+// int a ABSL_GUARDED_BY(mu1);
+// int b ABSL_GUARDED_BY(mu2);
+//
+// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
+// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
+#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_locks_required(__VA_ARGS__))
-#define SHARED_LOCKS_REQUIRED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+#define ABSL_SHARED_LOCKS_REQUIRED(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__))
-// LOCKS_EXCLUDED()
+// ABSL_LOCKS_EXCLUDED()
//
// Documents the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as Abseil's `Mutex` locks are
// non-reentrant).
-#define LOCKS_EXCLUDED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+#define ABSL_LOCKS_EXCLUDED(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__))
-// LOCK_RETURNED()
+// ABSL_LOCK_RETURNED()
//
// Documents a function that returns a mutex without acquiring it. For example,
// a public getter method that returns a pointer to a private mutex should
-// be annotated with LOCK_RETURNED.
-#define LOCK_RETURNED(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+// be annotated with ABSL_LOCK_RETURNED.
+#define ABSL_LOCK_RETURNED(x) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x))
-// LOCKABLE
+// ABSL_LOCKABLE
//
// Documents if a class/type is a lockable type (such as the `Mutex` class).
-#define LOCKABLE \
- THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable)
-// SCOPED_LOCKABLE
+// ABSL_SCOPED_LOCKABLE
//
// Documents if a class does RAII locking (such as the `MutexLock` class).
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked.
-#define SCOPED_LOCKABLE \
- THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+#define ABSL_SCOPED_LOCKABLE \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable)
-// EXCLUSIVE_LOCK_FUNCTION()
+// ABSL_EXCLUSIVE_LOCK_FUNCTION()
//
// Documents functions that acquire a lock in the body of a function, and do
// not release it.
-#define EXCLUSIVE_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_lock_function(__VA_ARGS__))
-// SHARED_LOCK_FUNCTION()
+// ABSL_SHARED_LOCK_FUNCTION()
//
// Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it.
-#define SHARED_LOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+#define ABSL_SHARED_LOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__))
-// UNLOCK_FUNCTION()
+// ABSL_UNLOCK_FUNCTION()
//
// Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function.
-#define UNLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+#define ABSL_UNLOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__))
-// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
//
// Documents functions that try to acquire a lock, and return success or failure
// (or a non-boolean value that can be interpreted as a boolean).
@@ -192,76 +198,82 @@
// success, or `false` for functions that return `false` on success. The second
// argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`.
-#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ exclusive_trylock_function(__VA_ARGS__))
-#define SHARED_TRYLOCK_FUNCTION(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \
+ shared_trylock_function(__VA_ARGS__))
-// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
//
// Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held.
-#define ASSERT_EXCLUSIVE_LOCK(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__))
-#define ASSERT_SHARED_LOCK(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+#define ABSL_ASSERT_SHARED_LOCK(...) \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__))
-// NO_THREAD_SAFETY_ANALYSIS
+// ABSL_NO_THREAD_SAFETY_ANALYSIS
//
// Turns off thread safety checking within the body of a particular function.
// This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle.
-#define NO_THREAD_SAFETY_ANALYSIS \
- THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
+ ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis)
//------------------------------------------------------------------------------
// Tool-Supplied Annotations
//------------------------------------------------------------------------------
-// TS_UNCHECKED should be placed around lock expressions that are not valid
+// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
// C++ syntax, but which are present for documentation purposes. These
// annotations will be ignored by the analysis.
-#define TS_UNCHECKED(x) ""
+#define ABSL_TS_UNCHECKED(x) ""
-// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
// It is used by automated tools to mark and disable invalid expressions.
-// The annotation should either be fixed, or changed to TS_UNCHECKED.
-#define TS_FIXME(x) ""
+// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
+#define ABSL_TS_FIXME(x) ""
-// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
-// a particular function. However, this attribute is used to mark functions
+// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
+// of a particular function. However, this attribute is used to mark functions
// that are incorrect and need to be fixed. It is used by automated tools to
// avoid breaking the build when the analysis is updated.
// Code owners are expected to eventually fix the routine.
-#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS
+#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
-// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
-// annotation that needs to be fixed, because it is producing thread safety
-// warning. It disables the GUARDED_BY.
-#define GUARDED_BY_FIXME(x)
+// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
+// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
+// thread safety warning. It disables the ABSL_GUARDED_BY.
+#define ABSL_GUARDED_BY_FIXME(x)
// Disables warnings for a single read operation. This can be used to avoid
// warnings when it is known that the read is not actually involved in a race,
// but the compiler cannot confirm that.
-#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
-
+#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
-namespace thread_safety_analysis {
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace base_internal {
// Takes a reference to a guarded data member, and returns an unguarded
// reference.
+// Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
template <typename T>
-inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v;
}
template <typename T>
-inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v;
}
-} // namespace thread_safety_analysis
+} // namespace base_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
diff --git a/absl/base/throw_delegate_test.cc b/absl/base/throw_delegate_test.cc
index 0f15df04..a74dd3cd 100644
--- a/absl/base/throw_delegate_test.cc
+++ b/absl/base/throw_delegate_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/compiler_config_setting.bzl b/absl/compiler_config_setting.bzl
index b77c4f56..66962294 100644
--- a/absl/compiler_config_setting.bzl
+++ b/absl/compiler_config_setting.bzl
@@ -5,35 +5,34 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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.
-#
"""Creates config_setting that allows selecting based on 'compiler' value."""
def create_llvm_config(name, visibility):
- # The "do_not_use_tools_cpp_compiler_present" attribute exists to
- # distinguish between older versions of Bazel that do not support
- # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
- # In the future, the only way to select on the compiler will be through
- # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
- # be removed.
- if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
- native.config_setting(
- name = name,
- flag_values = {
- "@bazel_tools//tools/cpp:compiler": "llvm",
- },
- visibility = visibility,
- )
- else:
- native.config_setting(
- name = name,
- values = {"compiler": "llvm"},
- visibility = visibility,
- )
+ # The "do_not_use_tools_cpp_compiler_present" attribute exists to
+ # distinguish between older versions of Bazel that do not support
+ # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
+ # In the future, the only way to select on the compiler will be through
+ # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
+ # be removed.
+ if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
+ native.config_setting(
+ name = name,
+ flag_values = {
+ "@bazel_tools//tools/cpp:compiler": "llvm",
+ },
+ visibility = visibility,
+ )
+ else:
+ native.config_setting(
+ name = name,
+ values = {"compiler": "llvm"},
+ visibility = visibility,
+ )
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index afc869f4..9e2a5b1e 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,11 +15,12 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
- "ABSL_TEST_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
@@ -30,6 +31,7 @@ cc_library(
name = "compressed_tuple",
hdrs = ["internal/compressed_tuple.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/utility",
],
@@ -39,8 +41,14 @@ cc_test(
name = "compressed_tuple_test",
srcs = ["internal/compressed_tuple_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":compressed_tuple",
+ ":test_instance_tracker",
+ "//absl/memory",
+ "//absl/types:any",
+ "//absl/types:optional",
+ "//absl/utility",
"@com_google_googletest//:gtest_main",
],
)
@@ -49,6 +57,7 @@ cc_library(
name = "fixed_array",
hdrs = ["fixed_array.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":compressed_tuple",
"//absl/algorithm",
@@ -63,7 +72,7 @@ cc_test(
name = "fixed_array_test",
srcs = ["fixed_array_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":fixed_array",
"//absl/base:exception_testing",
@@ -77,6 +86,7 @@ cc_test(
name = "fixed_array_test_noexceptions",
srcs = ["fixed_array_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fixed_array",
"//absl/base:exception_testing",
@@ -90,7 +100,7 @@ cc_test(
name = "fixed_array_exception_safety_test",
srcs = ["fixed_array_exception_safety_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":fixed_array",
"//absl/base:exception_safety_testing",
@@ -102,6 +112,7 @@ cc_test(
name = "fixed_array_benchmark",
srcs = ["fixed_array_benchmark.cc"],
copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
deps = [
":fixed_array",
@@ -110,10 +121,26 @@ cc_test(
)
cc_library(
+ name = "inlined_vector_internal",
+ hdrs = ["internal/inlined_vector.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":compressed_tuple",
+ "//absl/base:core_headers",
+ "//absl/memory",
+ "//absl/meta:type_traits",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
name = "inlined_vector",
hdrs = ["inlined_vector.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":inlined_vector_internal",
"//absl/algorithm",
"//absl/base:core_headers",
"//absl/base:throw_delegate",
@@ -121,12 +148,22 @@ cc_library(
],
)
+cc_library(
+ name = "counting_allocator",
+ testonly = 1,
+ hdrs = ["internal/counting_allocator.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
+)
+
cc_test(
name = "inlined_vector_test",
srcs = ["inlined_vector_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":counting_allocator",
":inlined_vector",
":test_instance_tracker",
"//absl/base",
@@ -143,7 +180,9 @@ cc_test(
name = "inlined_vector_test_noexceptions",
srcs = ["inlined_vector_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":counting_allocator",
":inlined_vector",
":test_instance_tracker",
"//absl/base",
@@ -160,30 +199,46 @@ cc_test(
name = "inlined_vector_benchmark",
srcs = ["inlined_vector_benchmark.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
deps = [
":inlined_vector",
"//absl/base",
+ "//absl/base:core_headers",
"//absl/strings",
"@com_github_google_benchmark//:benchmark_main",
],
)
+cc_test(
+ name = "inlined_vector_exception_safety_test",
+ srcs = ["inlined_vector_exception_safety_test.cc"],
+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
+ deps = [
+ ":inlined_vector",
+ "//absl/base:exception_safety_testing",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
cc_library(
name = "test_instance_tracker",
testonly = 1,
srcs = ["internal/test_instance_tracker.cc"],
hdrs = ["internal/test_instance_tracker.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
+ deps = ["//absl/types:compare"],
)
cc_test(
name = "test_instance_tracker_test",
srcs = ["internal/test_instance_tracker_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":test_instance_tracker",
"@com_google_googletest//:gtest_main",
@@ -208,6 +263,7 @@ cc_library(
name = "flat_hash_map",
hdrs = ["flat_hash_map.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
":hash_function_defaults",
@@ -220,13 +276,15 @@ cc_library(
cc_test(
name = "flat_hash_map_test",
srcs = ["flat_hash_map_test.cc"],
- copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":flat_hash_map",
":hash_generator_testing",
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"//absl/types:any",
"@com_google_googletest//:gtest_main",
@@ -237,6 +295,7 @@ cc_library(
name = "flat_hash_set",
hdrs = ["flat_hash_set.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
":hash_function_defaults",
@@ -251,12 +310,14 @@ cc_test(
name = "flat_hash_set_test",
srcs = ["flat_hash_set_test.cc"],
copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":flat_hash_set",
":hash_generator_testing",
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"//absl/memory",
"//absl/strings",
@@ -268,6 +329,7 @@ cc_library(
name = "node_hash_map",
hdrs = ["node_hash_map.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
":hash_function_defaults",
@@ -281,7 +343,8 @@ cc_library(
cc_test(
name = "node_hash_map_test",
srcs = ["node_hash_map_test.cc"],
- copts = ABSL_TEST_COPTS + ["-DUNORDERED_MAP_CXX17"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":hash_generator_testing",
@@ -289,6 +352,7 @@ cc_test(
":tracked",
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -298,6 +362,7 @@ cc_library(
name = "node_hash_set",
hdrs = ["node_hash_set.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_function_defaults",
":node_hash_policy",
@@ -311,12 +376,13 @@ cc_test(
name = "node_hash_set_test",
srcs = ["node_hash_set_test.cc"],
copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
- ":hash_generator_testing",
":node_hash_set",
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -326,6 +392,7 @@ cc_library(
name = "container_memory",
hdrs = ["internal/container_memory.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/memory",
"//absl/utility",
@@ -336,6 +403,7 @@ cc_test(
name = "container_memory_test",
srcs = ["internal/container_memory_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":container_memory",
@@ -348,6 +416,7 @@ cc_library(
name = "hash_function_defaults",
hdrs = ["internal/hash_function_defaults.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/hash",
@@ -359,6 +428,7 @@ cc_test(
name = "hash_function_defaults_test",
srcs = ["internal/hash_function_defaults_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS,
deps = [
":hash_function_defaults",
@@ -374,6 +444,7 @@ cc_library(
srcs = ["internal/hash_generator_testing.cc"],
hdrs = ["internal/hash_generator_testing.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_policy_testing",
"//absl/meta:type_traits",
@@ -386,6 +457,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/hash_policy_testing.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/hash",
"//absl/strings",
@@ -396,6 +468,7 @@ cc_test(
name = "hash_policy_testing_test",
srcs = ["internal/hash_policy_testing_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_policy_testing",
"@com_google_googletest//:gtest_main",
@@ -406,6 +479,7 @@ cc_library(
name = "hash_policy_traits",
hdrs = ["internal/hash_policy_traits.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = ["//absl/meta:type_traits"],
)
@@ -413,6 +487,7 @@ cc_test(
name = "hash_policy_traits_test",
srcs = ["internal/hash_policy_traits_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_policy_traits",
"@com_google_googletest//:gtest_main",
@@ -423,6 +498,7 @@ cc_library(
name = "hashtable_debug",
hdrs = ["internal/hashtable_debug.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hashtable_debug_hooks",
],
@@ -432,18 +508,56 @@ cc_library(
name = "hashtable_debug_hooks",
hdrs = ["internal/hashtable_debug_hooks.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+)
+
+cc_library(
+ name = "hashtablez_sampler",
+ srcs = [
+ "internal/hashtablez_sampler.cc",
+ "internal/hashtablez_sampler_force_weak_definition.cc",
+ ],
+ hdrs = ["internal/hashtablez_sampler.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":have_sse",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/debugging:stacktrace",
+ "//absl/memory",
+ "//absl/synchronization",
+ "//absl/utility",
+ ],
+)
+
+cc_test(
+ name = "hashtablez_sampler_test",
+ srcs = ["internal/hashtablez_sampler_test.cc"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":hashtablez_sampler",
+ ":have_sse",
+ "//absl/base:core_headers",
+ "//absl/synchronization",
+ "//absl/synchronization:thread_pool",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
)
cc_library(
name = "node_hash_policy",
hdrs = ["internal/node_hash_policy.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
)
cc_test(
name = "node_hash_policy_test",
srcs = ["internal/node_hash_policy_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_policy_traits",
":node_hash_policy",
@@ -455,9 +569,30 @@ cc_library(
name = "raw_hash_map",
hdrs = ["internal/raw_hash_map.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":container_memory",
":raw_hash_set",
+ "//absl/base:throw_delegate",
+ ],
+)
+
+cc_library(
+ name = "have_sse",
+ hdrs = ["internal/have_sse.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = ["//visibility:private"],
+)
+
+cc_library(
+ name = "common",
+ hdrs = ["internal/common.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ "//absl/types:optional",
],
)
@@ -466,11 +601,15 @@ cc_library(
srcs = ["internal/raw_hash_set.cc"],
hdrs = ["internal/raw_hash_set.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
+ ":common",
":compressed_tuple",
":container_memory",
":hash_policy_traits",
":hashtable_debug_hooks",
+ ":hashtablez_sampler",
+ ":have_sse",
":layout",
"//absl/base:bits",
"//absl/base:config",
@@ -478,7 +617,6 @@ cc_library(
"//absl/base:endian",
"//absl/memory",
"//absl/meta:type_traits",
- "//absl/types:optional",
"//absl/utility",
],
)
@@ -507,6 +645,7 @@ cc_test(
size = "small",
srcs = ["internal/raw_hash_set_allocator_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":raw_hash_set",
":tracked",
@@ -519,6 +658,7 @@ cc_library(
name = "layout",
hdrs = ["internal/layout.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:core_headers",
"//absl/meta:type_traits",
@@ -533,6 +673,7 @@ cc_test(
size = "small",
srcs = ["internal/layout_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS,
visibility = ["//visibility:private"],
deps = [
@@ -549,6 +690,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/tracked.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
)
cc_library(
@@ -556,6 +698,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_map_constructor_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
@@ -568,6 +711,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_map_lookup_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
@@ -580,6 +724,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_map_modifiers_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
@@ -592,9 +737,35 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_set_constructor_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "unordered_set_members_test",
+ testonly = 1,
+ hdrs = ["internal/unordered_set_members_test.h"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "unordered_map_members_test",
+ testonly = 1,
+ hdrs = ["internal/unordered_map_members_test.h"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/meta:type_traits",
"@com_google_googletest//:gtest",
],
)
@@ -604,6 +775,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_set_lookup_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
@@ -616,6 +788,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/unordered_set_modifiers_test.h"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash_generator_testing",
":hash_policy_testing",
@@ -627,10 +800,12 @@ cc_test(
name = "unordered_set_test",
srcs = ["internal/unordered_set_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":unordered_set_constructor_test",
":unordered_set_lookup_test",
+ ":unordered_set_members_test",
":unordered_set_modifiers_test",
"@com_google_googletest//:gtest_main",
],
@@ -640,10 +815,12 @@ cc_test(
name = "unordered_map_test",
srcs = ["internal/unordered_map_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_NONMOBILE,
deps = [
":unordered_map_constructor_test",
":unordered_map_lookup_test",
+ ":unordered_map_members_test",
":unordered_map_modifiers_test",
"@com_google_googletest//:gtest_main",
],
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 8605facc..7988b12f 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -20,10 +20,6 @@
absl_cc_library(
NAME
container
- SRCS
- "internal/raw_hash_set.cc"
- COPTS
- ${ABSL_DEFAULT_COPTS}
PUBLIC
)
@@ -31,7 +27,9 @@ absl_cc_library(
NAME
compressed_tuple
HDRS
- "internal/compressed_tuple.h"
+ "internal/compressed_tuple.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
DEPS
absl::utility
PUBLIC
@@ -42,8 +40,15 @@ absl_cc_test(
compressed_tuple_test
SRCS
"internal/compressed_tuple_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
+ absl::any
absl::compressed_tuple
+ absl::memory
+ absl::optional
+ absl::test_instance_tracker
+ absl::utility
gmock_main
)
@@ -70,6 +75,7 @@ absl_cc_test(
SRCS
"fixed_array_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
LINKOPTS
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
@@ -86,6 +92,8 @@ absl_cc_test(
fixed_array_test_noexceptions
SRCS
"fixed_array_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::fixed_array
absl::exception_testing
@@ -100,6 +108,7 @@ absl_cc_test(
SRCS
"fixed_array_exception_safety_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
LINKOPTS
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
@@ -111,6 +120,22 @@ absl_cc_test(
absl_cc_library(
NAME
+ inlined_vector_internal
+ HDRS
+ "internal/inlined_vector.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::compressed_tuple
+ absl::core_headers
+ absl::memory
+ absl::span
+ absl::type_traits
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
inlined_vector
HDRS
"inlined_vector.h"
@@ -119,21 +144,33 @@ absl_cc_library(
DEPS
absl::algorithm
absl::core_headers
+ absl::inlined_vector_internal
absl::throw_delegate
absl::memory
PUBLIC
)
+absl_cc_library(
+ NAME
+ counting_allocator
+ HDRS
+ "internal/counting_allocator.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
absl_cc_test(
NAME
inlined_vector_test
SRCS
"inlined_vector_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
LINKOPTS
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
DEPS
+ absl::counting_allocator
absl::inlined_vector
absl::test_instance_tracker
absl::base
@@ -150,6 +187,8 @@ absl_cc_test(
inlined_vector_test_noexceptions
SRCS
"inlined_vector_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::inlined_vector
absl::test_instance_tracker
@@ -162,6 +201,22 @@ absl_cc_test(
gmock_main
)
+absl_cc_test(
+ NAME
+ inlined_vector_exception_safety_test
+ SRCS
+ "inlined_vector_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::inlined_vector
+ absl::exception_safety_testing
+ gmock_main
+)
+
absl_cc_library(
NAME
test_instance_tracker
@@ -171,6 +226,8 @@ absl_cc_library(
"internal/test_instance_tracker.cc"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::compare
TESTONLY
)
@@ -179,6 +236,8 @@ absl_cc_test(
test_instance_tracker_test
SRCS
"internal/test_instance_tracker_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::test_instance_tracker
gmock_main
@@ -206,12 +265,13 @@ absl_cc_test(
SRCS
"flat_hash_map_test.cc"
COPTS
- "-DUNORDERED_MAP_CXX17"
+ ${ABSL_TEST_COPTS}
DEPS
absl::flat_hash_map
absl::hash_generator_testing
absl::unordered_map_constructor_test
absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
absl::unordered_map_modifiers_test
absl::any
gmock_main
@@ -240,12 +300,14 @@ absl_cc_test(
SRCS
"flat_hash_set_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
"-DUNORDERED_SET_CXX17"
DEPS
absl::flat_hash_set
absl::hash_generator_testing
absl::unordered_set_constructor_test
absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
absl::unordered_set_modifiers_test
absl::memory
absl::strings
@@ -275,13 +337,14 @@ absl_cc_test(
SRCS
"node_hash_map_test.cc"
COPTS
- "-DUNORDERED_MAP_CXX17"
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash_generator_testing
absl::node_hash_map
absl::tracked
absl::unordered_map_constructor_test
absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
absl::unordered_map_modifiers_test
gmock_main
)
@@ -308,12 +371,14 @@ absl_cc_test(
SRCS
"node_hash_set_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
"-DUNORDERED_SET_CXX17"
DEPS
absl::hash_generator_testing
absl::node_hash_set
absl::unordered_set_constructor_test
absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
absl::unordered_set_modifiers_test
gmock_main
)
@@ -336,6 +401,8 @@ absl_cc_test(
container_memory_test
SRCS
"internal/container_memory_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::container_memory
absl::strings
@@ -361,6 +428,8 @@ absl_cc_test(
hash_function_defaults_test
SRCS
"internal/hash_function_defaults_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash_function_defaults
absl::hash
@@ -402,6 +471,8 @@ absl_cc_test(
hash_policy_testing_test
SRCS
"internal/hash_policy_testing_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash_policy_testing
gmock_main
@@ -424,6 +495,8 @@ absl_cc_test(
hash_policy_traits_test
SRCS
"internal/hash_policy_traits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash_policy_traits
gmock_main
@@ -431,6 +504,35 @@ absl_cc_test(
absl_cc_library(
NAME
+ hashtablez_sampler
+ HDRS
+ "internal/hashtablez_sampler.h"
+ SRCS
+ "internal/hashtablez_sampler.cc"
+ "internal/hashtablez_sampler_force_weak_definition.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::have_sse
+ absl::synchronization
+)
+
+absl_cc_test(
+ NAME
+ hashtablez_sampler_test
+ SRCS
+ "internal/hashtablez_sampler_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::hashtablez_sampler
+ absl::have_sse
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
hashtable_debug
HDRS
"internal/hashtable_debug.h"
@@ -452,6 +554,15 @@ absl_cc_library(
absl_cc_library(
NAME
+ have_sse
+ HDRS
+ "internal/have_sse.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+)
+
+absl_cc_library(
+ NAME
node_hash_policy
HDRS
"internal/node_hash_policy.h"
@@ -465,6 +576,8 @@ absl_cc_test(
node_hash_policy_test
SRCS
"internal/node_hash_policy_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash_policy_traits
absl::node_hash_policy
@@ -481,11 +594,23 @@ absl_cc_library(
DEPS
absl::container_memory
absl::raw_hash_set
+ absl::throw_delegate
PUBLIC
)
absl_cc_library(
NAME
+ container_common
+ HDRS
+ "internal/commom.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::type_traits
+)
+
+absl_cc_library(
+ NAME
raw_hash_set
HDRS
"internal/raw_hash_set.h"
@@ -494,19 +619,22 @@ absl_cc_library(
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
+ absl::bits
absl::compressed_tuple
+ absl::config
+ absl::container_common
absl::container_memory
+ absl::core_headers
+ absl::endian
absl::hash_policy_traits
absl::hashtable_debug_hooks
+ absl::have_sse
absl::layout
- absl::bits
- absl::config
- absl::core_headers
- absl::endian
absl::memory
absl::meta
absl::optional
absl::utility
+ absl::hashtablez_sampler
PUBLIC
)
@@ -515,6 +643,8 @@ absl_cc_test(
raw_hash_set_test
SRCS
"internal/raw_hash_set_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::container_memory
absl::hash_function_defaults
@@ -532,6 +662,8 @@ absl_cc_test(
raw_hash_set_allocator_test
SRCS
"internal/raw_hash_set_allocator_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::raw_hash_set
absl::tracked
@@ -560,6 +692,8 @@ absl_cc_test(
layout_test
SRCS
"internal/layout_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::layout
absl::base
@@ -608,6 +742,19 @@ absl_cc_library(
absl_cc_library(
NAME
+ unordered_map_members_test
+ HDRS
+ "internal/unordered_map_members_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
unordered_map_modifiers_test
HDRS
"internal/unordered_map_modifiers_test.h"
@@ -650,6 +797,19 @@ absl_cc_library(
absl_cc_library(
NAME
+ unordered_set_members_test
+ HDRS
+ "internal/unordered_set_members_test.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
+ gmock
+ TESTONLY
+)
+
+absl_cc_library(
+ NAME
unordered_set_modifiers_test
HDRS
"internal/unordered_set_modifiers_test.h"
@@ -667,9 +827,12 @@ absl_cc_test(
unordered_set_test
SRCS
"internal/unordered_set_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::unordered_set_constructor_test
absl::unordered_set_lookup_test
+ absl::unordered_set_members_test
absl::unordered_set_modifiers_test
gmock_main
)
@@ -679,9 +842,12 @@ absl_cc_test(
unordered_map_test
SRCS
"internal/unordered_map_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::unordered_map_constructor_test
absl::unordered_map_lookup_test
+ absl::unordered_map_members_test
absl::unordered_map_modifiers_test
gmock_main
)
diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h
index 7f6a3afd..1e0da5eb 100644
--- a/absl/container/fixed_array.h
+++ b/absl/container/fixed_array.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -51,7 +51,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
@@ -515,6 +515,7 @@ void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
#endif // ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
diff --git a/absl/container/fixed_array_benchmark.cc b/absl/container/fixed_array_benchmark.cc
index b4f0cf2a..3c7a5a72 100644
--- a/absl/container/fixed_array_benchmark.cc
+++ b/absl/container/fixed_array_benchmark.cc
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/container/fixed_array.h"
-
#include <stddef.h>
+
#include <string>
#include "benchmark/benchmark.h"
+#include "absl/container/fixed_array.h"
namespace {
@@ -25,8 +25,9 @@ namespace {
// set an int to a constant..
class SimpleClass {
public:
- SimpleClass() : i(3) { }
+ SimpleClass() : i(3) {}
~SimpleClass() { i = 0; }
+
private:
int i;
};
diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc
index 4d0430b3..4a67bb46 100644
--- a/absl/container/fixed_array_exception_safety_test.cc
+++ b/absl/container/fixed_array_exception_safety_test.cc
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -14,13 +14,12 @@
#include <initializer_list>
-#include "absl/container/fixed_array.h"
-
#include "gtest/gtest.h"
#include "absl/base/internal/exception_safety_testing.h"
+#include "absl/container/fixed_array.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -115,5 +114,5 @@ TEST(FixedArrayExceptionSafety, Fill) {
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/fixed_array_test.cc b/absl/container/fixed_array_test.cc
index 205ff41f..2b1cf47e 100644
--- a/absl/container/fixed_array_test.cc
+++ b/absl/container/fixed_array_test.cc
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,6 +15,7 @@
#include "absl/container/fixed_array.h"
#include <stdio.h>
+
#include <cstring>
#include <list>
#include <memory>
@@ -42,11 +43,7 @@ static bool IsOnStack(const ArrayType& a) {
class ConstructionTester {
public:
- ConstructionTester()
- : self_ptr_(this),
- value_(0) {
- constructions++;
- }
+ ConstructionTester() : self_ptr_(this), value_(0) { constructions++; }
~ConstructionTester() {
assert(self_ptr_ == this);
self_ptr_ = nullptr;
@@ -58,9 +55,7 @@ class ConstructionTester {
static int constructions;
static int destructions;
- void CheckConstructed() {
- assert(self_ptr_ == this);
- }
+ void CheckConstructed() { assert(self_ptr_ == this); }
void set(int value) { value_ = value; }
int get() { return value_; }
@@ -150,7 +145,7 @@ TEST(FixedArrayTest, SmallObjects) {
}
{
- // Arrays of > default size should be on the stack
+ // Arrays of > default size should be on the heap
absl::FixedArray<int, 100> array(101);
EXPECT_FALSE(IsOnStack(array));
}
@@ -160,13 +155,13 @@ TEST(FixedArrayTest, SmallObjects) {
// same amount of stack space
absl::FixedArray<int> array1(0);
absl::FixedArray<char> array2(0);
- EXPECT_LE(sizeof(array1), sizeof(array2)+100);
- EXPECT_LE(sizeof(array2), sizeof(array1)+100);
+ EXPECT_LE(sizeof(array1), sizeof(array2) + 100);
+ EXPECT_LE(sizeof(array2), sizeof(array1) + 100);
}
{
// Ensure that vectors are properly constructed inside a fixed array.
- absl::FixedArray<std::vector<int> > array(2);
+ absl::FixedArray<std::vector<int>> array(2);
EXPECT_EQ(0, array[0].size());
EXPECT_EQ(0, array[1].size());
}
@@ -270,8 +265,8 @@ static void TestArray(int n) {
array.data()[i].set(i + 1);
}
for (int i = 0; i < n; i++) {
- EXPECT_THAT(array[i].get(), i+1);
- EXPECT_THAT(array.data()[i].get(), i+1);
+ EXPECT_THAT(array[i].get(), i + 1);
+ EXPECT_THAT(array.data()[i].get(), i + 1);
}
} // Close scope containing 'array'.
@@ -296,7 +291,7 @@ static void TestArrayOfArrays(int n) {
ASSERT_EQ(array.size(), n);
ASSERT_EQ(array.memsize(),
- sizeof(ConstructionTester) * elements_per_inner_array * n);
+ sizeof(ConstructionTester) * elements_per_inner_array * n);
ASSERT_EQ(array.begin() + n, array.end());
// Check that all elements were constructed
@@ -316,7 +311,7 @@ static void TestArrayOfArrays(int n) {
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < elements_per_inner_array; j++) {
- ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
+ ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
}
}
@@ -329,8 +324,7 @@ static void TestArrayOfArrays(int n) {
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < elements_per_inner_array; j++) {
- ASSERT_EQ((array[i])[j].get(),
- (i + 1) * elements_per_inner_array + j);
+ ASSERT_EQ((array[i])[j].get(), (i + 1) * elements_per_inner_array + j);
ASSERT_EQ((array.data()[i])[j].get(),
(i + 1) * elements_per_inner_array + j);
}
@@ -343,7 +337,7 @@ static void TestArrayOfArrays(int n) {
}
TEST(IteratorConstructorTest, NonInline) {
- int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed(
kInput, kInput + ABSL_ARRAYSIZE(kInput));
ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
@@ -353,7 +347,7 @@ TEST(IteratorConstructorTest, NonInline) {
}
TEST(IteratorConstructorTest, Inline) {
- int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed(
kInput, kInput + ABSL_ARRAYSIZE(kInput));
ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
@@ -363,9 +357,10 @@ TEST(IteratorConstructorTest, Inline) {
}
TEST(IteratorConstructorTest, NonPod) {
- char const* kInput[] =
- { "red", "orange", "yellow", "green", "blue", "indigo", "violet" };
- absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput));
+ char const* kInput[] = {"red", "orange", "yellow", "green",
+ "blue", "indigo", "violet"};
+ absl::FixedArray<std::string> const fixed(kInput,
+ kInput + ABSL_ARRAYSIZE(kInput));
ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
ASSERT_EQ(kInput[i], fixed[i]);
@@ -380,7 +375,7 @@ TEST(IteratorConstructorTest, FromEmptyVector) {
}
TEST(IteratorConstructorTest, FromNonEmptyVector) {
- int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
absl::FixedArray<int> const fixed(items.begin(), items.end());
ASSERT_EQ(items.size(), fixed.size());
@@ -390,7 +385,7 @@ TEST(IteratorConstructorTest, FromNonEmptyVector) {
}
TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
- int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ int const kInput[] = {2, 3, 5, 7, 11, 13, 17};
std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
absl::FixedArray<int> const fixed(items.begin(), items.end());
EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
@@ -507,9 +502,8 @@ struct PickyDelete {
TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
-
TEST(FixedArrayTest, Data) {
- static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
+ static const int kInput[] = {2, 3, 5, 7, 11, 13, 17};
absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
EXPECT_EQ(fa.data(), &*fa.begin());
EXPECT_EQ(fa.data(), &fa[0]);
@@ -823,7 +817,7 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
#ifdef ADDRESS_SANITIZER
TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
absl::FixedArray<int, 32> a(10);
- int *raw = a.data();
+ int* raw = a.data();
raw[0] = 0;
raw[9] = 0;
EXPECT_DEATH(raw[-2] = 0, "container-overflow");
@@ -834,7 +828,7 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
absl::FixedArray<char, 17> a(12);
- char *raw = a.data();
+ char* raw = a.data();
raw[0] = 0;
raw[11] = 0;
EXPECT_DEATH(raw[-7] = 0, "container-overflow");
@@ -845,7 +839,7 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
absl::FixedArray<uint64_t, 20> a(20);
- uint64_t *raw = a.data();
+ uint64_t* raw = a.data();
raw[0] = 0;
raw[19] = 0;
EXPECT_DEATH(raw[-1] = 0, "container-overflow");
@@ -854,7 +848,7 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
absl::FixedArray<ThreeInts> a(10);
- ThreeInts *raw = a.data();
+ ThreeInts* raw = a.data();
raw[0] = ThreeInts();
raw[9] = ThreeInts();
// Note: raw[-1] is pointing to 12 bytes before the container range. However,
@@ -869,4 +863,21 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
}
#endif // ADDRESS_SANITIZER
+TEST(FixedArrayTest, AbslHashValueWorks) {
+ using V = absl::FixedArray<int>;
+ std::vector<V> cases;
+
+ // Generate a variety of vectors some of these are small enough for the inline
+ // space but are stored out of line.
+ for (int i = 0; i < 10; ++i) {
+ V v(i);
+ for (int j = 0; j < i; ++j) {
+ v[j] = j;
+ }
+ cases.push_back(v);
+ }
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
} // namespace
diff --git a/absl/container/flat_hash_map.h b/absl/container/flat_hash_map.h
index ed453348..a711398e 100644
--- a/absl/container/flat_hash_map.h
+++ b/absl/container/flat_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -42,7 +42,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class K, class V>
struct FlatHashMapPolicy;
@@ -78,7 +78,7 @@ struct FlatHashMapPolicy;
// NOTE: A `flat_hash_map` stores its value types directly inside its
// implementation array to avoid memory indirection. Because a `flat_hash_map`
// is designed to move data when rehashed, map values will not retain pointer
-// stability. If you require pointer stability, or your values are large,
+// stability. If you require pointer stability, or if your values are large,
// consider using `absl::flat_hash_map<Key, std::unique_ptr<Value>>` instead.
// If your types are not moveable or you require pointer stability for keys,
// consider `absl::node_hash_map`.
@@ -220,8 +220,12 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
// Erases the element at `position` of the `flat_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):
//
@@ -528,25 +532,26 @@ namespace container_internal {
template <class K, class V>
struct FlatHashMapPolicy {
- using slot_type = container_internal::slot_type<K, V>;
+ using slot_policy = container_internal::map_slot_policy<K, V>;
+ using slot_type = typename slot_policy::slot_type;
using key_type = K;
using mapped_type = V;
using init_type = std::pair</*non const*/ key_type, mapped_type>;
template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
- slot_type::construct(alloc, slot, std::forward<Args>(args)...);
+ slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
}
template <class Allocator>
static void destroy(Allocator* alloc, slot_type* slot) {
- slot_type::destroy(alloc, slot);
+ slot_policy::destroy(alloc, slot);
}
template <class Allocator>
static void transfer(Allocator* alloc, slot_type* new_slot,
slot_type* old_slot) {
- slot_type::transfer(alloc, new_slot, old_slot);
+ slot_policy::transfer(alloc, new_slot, old_slot);
}
template <class F, class... Args>
@@ -576,7 +581,7 @@ struct IsUnorderedContainer<
} // namespace container_algorithm_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc
index 02d2fa81..3f11a52c 100644
--- a/absl/container/flat_hash_map_test.cc
+++ b/absl/container/flat_hash_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,11 +17,12 @@
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
#include "absl/types/any.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
@@ -31,19 +32,20 @@ using ::testing::Pair;
using ::testing::UnorderedElementsAre;
template <class K, class V>
-using Map =
- flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, Alloc<>>;
+using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<std::pair<const K, V>>>;
static_assert(!std::is_standard_layout<NonStandardLayout>(), "");
using MapTypes =
- ::testing::Types<Map<int, int>, Map<std::string, int>, Map<Enum, std::string>,
- Map<EnumClass, int>, Map<int, NonStandardLayout>,
- Map<NonStandardLayout, int>>;
+ ::testing::Types<Map<int, int>, Map<std::string, int>,
+ Map<Enum, std::string>, Map<EnumClass, int>,
+ Map<int, NonStandardLayout>, Map<NonStandardLayout, int>>;
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashMap, ModifiersTest, MapTypes);
TEST(FlatHashMap, StandardLayout) {
struct Int {
@@ -140,6 +142,7 @@ TEST(FlatHashMap, LazyKeyPattern) {
int conversions = 0;
int hashes = 0;
flat_hash_map<size_t, size_t, Hash, Eq> m(0, Hash{&hashes});
+ m.reserve(3);
m[LazyInt(1, &conversions)] = 1;
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 1)));
@@ -204,7 +207,9 @@ TEST(FlatHashMap, MergeExtractInsert) {
m.insert(std::move(node));
EXPECT_THAT(m, UnorderedElementsAre(Pair(1, 17), Pair(2, 9)));
}
-#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
+
+#if (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) && \
+ !defined(__EMSCRIPTEN__)
TEST(FlatHashMap, Any) {
absl::flat_hash_map<int, absl::any> m;
m.emplace(1, 7);
@@ -235,9 +240,10 @@ TEST(FlatHashMap, Any) {
ASSERT_NE(it2, m2.end());
EXPECT_EQ(7, it2->second);
}
-#endif // __ANDROID__
+#endif // (defined(ABSL_HAVE_STD_ANY) || !defined(_LIBCPP_VERSION)) &&
+ // !defined(__EMSCRIPTEN__)
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/flat_hash_set.h b/absl/container/flat_hash_set.h
index b175b1bf..8adbbcd5 100644
--- a/absl/container/flat_hash_set.h
+++ b/absl/container/flat_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -40,7 +40,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <typename T>
struct FlatHashSetPolicy;
@@ -56,9 +56,9 @@ struct FlatHashSetPolicy;
// following notable differences:
//
// * Requires keys that are CopyConstructible
-// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
-// `insert()`, provided that the set is provided a compatible heterogeneous
-// hashing function and equality operator.
+// * Supports heterogeneous lookup, through `find()` and `insert()`, provided
+// that the set is provided a compatible heterogeneous hashing function and
+// equality operator.
// * Invalidates any references and pointers to elements within the table after
// `rehash()`.
// * Contains a `capacity()` member function indicating the number of element
@@ -213,8 +213,12 @@ class flat_hash_set
// Erases the element at `position` of the `flat_hash_set`, 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_set` in particular (which
+ // return an iterator to the element following the erased element). If that
+ // iterator is needed, simply post increment the iterator:
+ //
+ // set.erase(it++);
//
// iterator erase(const_iterator first, const_iterator last):
//
@@ -485,7 +489,7 @@ struct IsUnorderedContainer<absl::flat_hash_set<Key, Hash, KeyEqual, Allocator>>
} // namespace container_algorithm_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_FLAT_HASH_SET_H_
diff --git a/absl/container/flat_hash_set_test.cc b/absl/container/flat_hash_set_test.cc
index cabc2b59..56140bbe 100644
--- a/absl/container/flat_hash_set_test.cc
+++ b/absl/container/flat_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,12 +19,13 @@
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_set_constructor_test.h"
#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/memory/memory.h"
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -41,9 +42,10 @@ using Set =
using SetTypes =
::testing::Types<Set<int>, Set<std::string>, Set<Enum>, Set<EnumClass>>;
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(FlatHashSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(FlatHashSet, ModifiersTest, SetTypes);
TEST(FlatHashSet, EmplaceString) {
std::vector<std::string> v = {"a", "b"};
@@ -124,5 +126,5 @@ TEST(FlatHashSet, MergeExtractInsert) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/inlined_vector.h b/absl/container/inlined_vector.h
index 37714baf..27186b15 100644
--- a/absl/container/inlined_vector.h
+++ b/absl/container/inlined_vector.h
@@ -1,10 +1,10 @@
-// Copyright 2018 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -50,11 +50,11 @@
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/optimization.h"
#include "absl/base/port.h"
+#include "absl/container/internal/inlined_vector.h"
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
-
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// InlinedVector
// -----------------------------------------------------------------------------
@@ -67,119 +67,181 @@ inline namespace lts_2018_12_18 {
// designed to cover the same API footprint as covered by `std::vector`.
template <typename T, size_t N, typename A = std::allocator<T>>
class InlinedVector {
- static_assert(N > 0, "InlinedVector requires inline capacity greater than 0");
- constexpr static typename A::size_type inlined_capacity() {
- return static_cast<typename A::size_type>(N);
- }
+ static_assert(N > 0, "`absl::InlinedVector` requires an inlined capacity.");
- template <typename Iterator>
- using DisableIfIntegral =
- absl::enable_if_t<!std::is_integral<Iterator>::value>;
+ using Storage = inlined_vector_internal::Storage<T, N, A>;
+ using rvalue_reference = typename Storage::rvalue_reference;
+ using MoveIterator = typename Storage::MoveIterator;
+ using AllocatorTraits = typename Storage::AllocatorTraits;
+ using IsMemcpyOk = typename Storage::IsMemcpyOk;
template <typename Iterator>
- using EnableIfInputIterator = absl::enable_if_t<std::is_convertible<
- typename std::iterator_traits<Iterator>::iterator_category,
- std::input_iterator_tag>::value>;
+ using IteratorValueAdapter =
+ typename Storage::template IteratorValueAdapter<Iterator>;
+ using CopyValueAdapter = typename Storage::CopyValueAdapter;
+ using DefaultValueAdapter = typename Storage::DefaultValueAdapter;
template <typename Iterator>
- using IteratorCategory =
- typename std::iterator_traits<Iterator>::iterator_category;
-
- using rvalue_reference = typename A::value_type&&;
+ using EnableIfAtLeastForwardIterator = absl::enable_if_t<
+ inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
+ template <typename Iterator>
+ using DisableIfAtLeastForwardIterator = absl::enable_if_t<
+ !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
public:
- using allocator_type = A;
- using value_type = typename allocator_type::value_type;
- using pointer = typename allocator_type::pointer;
- using const_pointer = typename allocator_type::const_pointer;
- using reference = typename allocator_type::reference;
- using const_reference = typename allocator_type::const_reference;
- using size_type = typename allocator_type::size_type;
- using difference_type = typename allocator_type::difference_type;
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using allocator_type = typename Storage::allocator_type;
+ using value_type = typename Storage::value_type;
+ using pointer = typename Storage::pointer;
+ using const_pointer = typename Storage::const_pointer;
+ using reference = typename Storage::reference;
+ using const_reference = typename Storage::const_reference;
+ using size_type = typename Storage::size_type;
+ using difference_type = typename Storage::difference_type;
+ using iterator = typename Storage::iterator;
+ using const_iterator = typename Storage::const_iterator;
+ using reverse_iterator = typename Storage::reverse_iterator;
+ using const_reverse_iterator = typename Storage::const_reverse_iterator;
// ---------------------------------------------------------------------------
// InlinedVector Constructors and Destructor
// ---------------------------------------------------------------------------
- // Creates an empty inlined vector with a default initialized allocator.
- InlinedVector() noexcept(noexcept(allocator_type()))
- : allocator_and_tag_(allocator_type()) {}
+ // Creates an empty inlined vector with a value-initialized allocator.
+ InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
- // Creates an empty inlined vector with a specified allocator.
+ // Creates an empty inlined vector with a copy of `alloc`.
explicit InlinedVector(const allocator_type& alloc) noexcept
- : allocator_and_tag_(alloc) {}
+ : storage_(alloc) {}
// Creates an inlined vector with `n` copies of `value_type()`.
explicit InlinedVector(size_type n,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- InitAssign(n);
+ : storage_(alloc) {
+ storage_.Initialize(DefaultValueAdapter(), n);
}
// Creates an inlined vector with `n` copies of `v`.
InlinedVector(size_type n, const_reference v,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- InitAssign(n, v);
+ : storage_(alloc) {
+ storage_.Initialize(CopyValueAdapter(v), n);
}
- // Creates an inlined vector of copies of the values in `init_list`.
- InlinedVector(std::initializer_list<value_type> init_list,
+ // Creates an inlined vector with copies of the elements of `list`.
+ InlinedVector(std::initializer_list<value_type> list,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- AppendRange(init_list.begin(), init_list.end(),
- IteratorCategory<decltype(init_list.begin())>{});
- }
+ : InlinedVector(list.begin(), list.end(), alloc) {}
// Creates an inlined vector with elements constructed from the provided
- // Iterator range [`first`, `last`).
+ // forward iterator range [`first`, `last`).
//
- // NOTE: The `enable_if` prevents ambiguous interpretation between a call to
+ // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
// this constructor with two integral arguments and a call to the above
// `InlinedVector(size_type, const_reference)` constructor.
- template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ InlinedVector(ForwardIterator first, ForwardIterator last,
+ const allocator_type& alloc = allocator_type())
+ : storage_(alloc) {
+ storage_.Initialize(IteratorValueAdapter<ForwardIterator>(first),
+ std::distance(first, last));
+ }
+
+ // Creates an inlined vector with elements constructed from the provided input
+ // iterator range [`first`, `last`).
+ template <typename InputIterator,
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
InlinedVector(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type())
- : allocator_and_tag_(alloc) {
- AppendRange(first, last, IteratorCategory<InputIterator>{});
+ : storage_(alloc) {
+ std::copy(first, last, std::back_inserter(*this));
}
- // Creates a copy of `other` using `other`'s allocator.
- InlinedVector(const InlinedVector& other);
+ // Creates an inlined vector by copying the contents of `other` using
+ // `other`'s allocator.
+ InlinedVector(const InlinedVector& other)
+ : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
- // Creates a copy of `other` but with a specified allocator.
- InlinedVector(const InlinedVector& other, const allocator_type& alloc);
+ // Creates an inlined vector by copying the contents of `other` using `alloc`.
+ InlinedVector(const InlinedVector& other, const allocator_type& alloc)
+ : storage_(alloc) {
+ if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
+ storage_.MemcpyFrom(other.storage_);
+ } else {
+ storage_.Initialize(IteratorValueAdapter<const_pointer>(other.data()),
+ other.size());
+ }
+ }
- // Creates an inlined vector by moving in the contents of `other`.
+ // Creates an inlined vector by moving in the contents of `other` without
+ // allocating. If `other` contains allocated memory, the newly-created inlined
+ // vector will take ownership of that memory. However, if `other` does not
+ // contain allocated memory, the newly-created inlined vector will perform
+ // element-wise move construction of the contents of `other`.
//
- // NOTE: This move constructor does not allocate and only moves the underlying
- // objects, so its `noexcept` specification depends on whether moving the
- // underlying objects can throw or not. We assume:
- // a) move constructors should only throw due to allocation failure and
+ // NOTE: since no allocation is performed for the inlined vector in either
+ // case, the `noexcept(...)` specification depends on whether moving the
+ // underlying objects can throw. It is assumed assumed that...
+ // a) move constructors should only throw due to allocation failure.
// b) if `value_type`'s move constructor allocates, it uses the same
- // allocation function as the `InlinedVector`'s allocator, so the move
- // constructor is non-throwing if the allocator is non-throwing or
- // `value_type`'s move constructor is specified as `noexcept`.
- InlinedVector(InlinedVector&& v) noexcept(
+ // allocation function as the inlined vector's allocator.
+ // Thus, the move constructor is non-throwing if the allocator is non-throwing
+ // or `value_type`'s move constructor is specified as `noexcept`.
+ InlinedVector(InlinedVector&& other) noexcept(
absl::allocator_is_nothrow<allocator_type>::value ||
- std::is_nothrow_move_constructible<value_type>::value);
+ std::is_nothrow_move_constructible<value_type>::value)
+ : storage_(*other.storage_.GetAllocPtr()) {
+ if (IsMemcpyOk::value) {
+ storage_.MemcpyFrom(other.storage_);
+
+ other.storage_.SetInlinedSize(0);
+ } else if (other.storage_.GetIsAllocated()) {
+ storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+ other.storage_.GetAllocatedCapacity());
+ storage_.SetAllocatedSize(other.storage_.GetSize());
+
+ other.storage_.SetInlinedSize(0);
+ } else {
+ IteratorValueAdapter<MoveIterator> other_values(
+ MoveIterator(other.storage_.GetInlinedData()));
+
+ inlined_vector_internal::ConstructElements(
+ storage_.GetAllocPtr(), storage_.GetInlinedData(), &other_values,
+ other.storage_.GetSize());
- // Creates an inlined vector by moving in the contents of `other`.
+ storage_.SetInlinedSize(other.storage_.GetSize());
+ }
+ }
+
+ // Creates an inlined vector by moving in the contents of `other` with a copy
+ // of `alloc`.
//
- // NOTE: This move constructor allocates and subsequently moves the underlying
- // objects, so its `noexcept` specification depends on whether the allocation
- // can throw and whether moving the underlying objects can throw. Based on the
- // same assumptions as above, the `noexcept` specification is dominated by
- // whether the allocation can throw regardless of whether `value_type`'s move
- // constructor is specified as `noexcept`.
- InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept(
- absl::allocator_is_nothrow<allocator_type>::value);
+ // NOTE: if `other`'s allocator is not equal to `alloc`, even if `other`
+ // contains allocated memory, this move constructor will still allocate. Since
+ // allocation is performed, this constructor can only be `noexcept` if the
+ // specified allocator is also `noexcept`.
+ InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
+ absl::allocator_is_nothrow<allocator_type>::value)
+ : storage_(alloc) {
+ if (IsMemcpyOk::value) {
+ storage_.MemcpyFrom(other.storage_);
+
+ other.storage_.SetInlinedSize(0);
+ } else if ((*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) &&
+ other.storage_.GetIsAllocated()) {
+ storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
+ other.storage_.GetAllocatedCapacity());
+ storage_.SetAllocatedSize(other.storage_.GetSize());
+
+ other.storage_.SetInlinedSize(0);
+ } else {
+ storage_.Initialize(
+ IteratorValueAdapter<MoveIterator>(MoveIterator(other.data())),
+ other.size());
+ }
+ }
- ~InlinedVector() { clear(); }
+ ~InlinedVector() {}
// ---------------------------------------------------------------------------
// InlinedVector Member Accessors
@@ -187,87 +249,102 @@ class InlinedVector {
// `InlinedVector::empty()`
//
- // Checks if the inlined vector has no elements.
+ // Returns whether the inlined vector contains no elements.
bool empty() const noexcept { return !size(); }
// `InlinedVector::size()`
//
// Returns the number of elements in the inlined vector.
- size_type size() const noexcept { return tag().size(); }
+ size_type size() const noexcept { return storage_.GetSize(); }
// `InlinedVector::max_size()`
//
- // Returns the maximum number of elements the vector can hold.
+ // Returns the maximum number of elements the inlined vector can hold.
size_type max_size() const noexcept {
// One bit of the size storage is used to indicate whether the inlined
- // vector is allocated. As a result, the maximum size of the container that
- // we can express is half of the max for `size_type`.
+ // vector contains allocated memory. As a result, the maximum size that the
+ // inlined vector can express is half of the max for `size_type`.
return (std::numeric_limits<size_type>::max)() / 2;
}
// `InlinedVector::capacity()`
//
- // Returns the number of elements that can be stored in the inlined vector
- // without requiring a reallocation of underlying memory.
+ // Returns the number of elements that could be stored in the inlined vector
+ // without requiring a reallocation.
//
- // NOTE: For most inlined vectors, `capacity()` should equal
- // `inlined_capacity()`. For inlined vectors which exceed this capacity, they
- // will no longer be inlined and `capacity()` will equal its capacity on the
- // allocated heap.
+ // NOTE: for most inlined vectors, `capacity()` should be equal to the
+ // template parameter `N`. For inlined vectors which exceed this capacity,
+ // they will no longer be inlined and `capacity()` will equal the capactity of
+ // the allocated memory.
size_type capacity() const noexcept {
- return allocated() ? allocation().capacity() : inlined_capacity();
+ return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
+ : storage_.GetInlinedCapacity();
}
// `InlinedVector::data()`
//
- // Returns a `pointer` to elements of the inlined vector. This pointer can be
- // used to access and modify the contained elements.
- // Only results within the range [`0`, `size()`) are defined.
+ // Returns a `pointer` to the elements of the inlined vector. This pointer
+ // can be used to access and modify the contained elements.
+ //
+ // NOTE: only elements within [`data()`, `data() + size()`) are valid.
pointer data() noexcept {
- return allocated() ? allocated_space() : inlined_space();
+ return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+ : storage_.GetInlinedData();
}
- // Overload of `InlinedVector::data()` to return a `const_pointer` to elements
- // of the inlined vector. This pointer can be used to access (but not modify)
- // the contained elements.
+ // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
+ // elements of the inlined vector. This pointer can be used to access but not
+ // modify the contained elements.
+ //
+ // NOTE: only elements within [`data()`, `data() + size()`) are valid.
const_pointer data() const noexcept {
- return allocated() ? allocated_space() : inlined_space();
+ return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
+ : storage_.GetInlinedData();
}
- // `InlinedVector::operator[]()`
+ // `InlinedVector::operator[](...)`
//
- // Returns a `reference` to the `i`th element of the inlined vector using the
- // array operator.
+ // Returns a `reference` to the `i`th element of the inlined vector.
reference operator[](size_type i) {
assert(i < size());
+
return data()[i];
}
- // Overload of `InlinedVector::operator[]()` to return a `const_reference` to
- // the `i`th element of the inlined vector.
+ // Overload of `InlinedVector::operator[](...)` that returns a
+ // `const_reference` to the `i`th element of the inlined vector.
const_reference operator[](size_type i) const {
assert(i < size());
+
return data()[i];
}
- // `InlinedVector::at()`
+ // `InlinedVector::at(...)`
//
// Returns a `reference` to the `i`th element of the inlined vector.
+ //
+ // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
+ // in both debug and non-debug builds, `std::out_of_range` will be thrown.
reference at(size_type i) {
if (ABSL_PREDICT_FALSE(i >= size())) {
base_internal::ThrowStdOutOfRange(
- "InlinedVector::at() failed bounds check");
+ "`InlinedVector::at(size_type)` failed bounds check");
}
+
return data()[i];
}
- // Overload of `InlinedVector::at()` to return a `const_reference` to the
- // `i`th element of the inlined vector.
+ // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
+ // the `i`th element of the inlined vector.
+ //
+ // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
+ // in both debug and non-debug builds, `std::out_of_range` will be thrown.
const_reference at(size_type i) const {
if (ABSL_PREDICT_FALSE(i >= size())) {
base_internal::ThrowStdOutOfRange(
- "InlinedVector::at() failed bounds check");
+ "`InlinedVector::at(size_type) const` failed bounds check");
}
+
return data()[i];
}
@@ -276,13 +353,15 @@ class InlinedVector {
// Returns a `reference` to the first element of the inlined vector.
reference front() {
assert(!empty());
+
return at(0);
}
- // Overload of `InlinedVector::front()` returns a `const_reference` to the
- // first element of the inlined vector.
+ // Overload of `InlinedVector::front()` that returns a `const_reference` to
+ // the first element of the inlined vector.
const_reference front() const {
assert(!empty());
+
return at(0);
}
@@ -291,13 +370,15 @@ class InlinedVector {
// Returns a `reference` to the last element of the inlined vector.
reference back() {
assert(!empty());
+
return at(size() - 1);
}
- // Overload of `InlinedVector::back()` to return a `const_reference` to the
+ // Overload of `InlinedVector::back()` that returns a `const_reference` to the
// last element of the inlined vector.
const_reference back() const {
assert(!empty());
+
return at(size() - 1);
}
@@ -306,7 +387,7 @@ class InlinedVector {
// Returns an `iterator` to the beginning of the inlined vector.
iterator begin() noexcept { return data(); }
- // Overload of `InlinedVector::begin()` to return a `const_iterator` to
+ // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
// the beginning of the inlined vector.
const_iterator begin() const noexcept { return data(); }
@@ -315,7 +396,7 @@ class InlinedVector {
// Returns an `iterator` to the end of the inlined vector.
iterator end() noexcept { return data() + size(); }
- // Overload of `InlinedVector::end()` to return a `const_iterator` to the
+ // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
// end of the inlined vector.
const_iterator end() const noexcept { return data() + size(); }
@@ -334,7 +415,7 @@ class InlinedVector {
// Returns a `reverse_iterator` from the end of the inlined vector.
reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
- // Overload of `InlinedVector::rbegin()` to return a
+ // Overload of `InlinedVector::rbegin()` that returns a
// `const_reverse_iterator` from the end of the inlined vector.
const_reverse_iterator rbegin() const noexcept {
return const_reverse_iterator(end());
@@ -345,7 +426,7 @@ class InlinedVector {
// Returns a `reverse_iterator` from the beginning of the inlined vector.
reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
- // Overload of `InlinedVector::rend()` to return a `const_reverse_iterator`
+ // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
// from the beginning of the inlined vector.
const_reverse_iterator rend() const noexcept {
return const_reverse_iterator(begin());
@@ -364,1086 +445,403 @@ class InlinedVector {
// `InlinedVector::get_allocator()`
//
- // Returns a copy of the allocator of the inlined vector.
- allocator_type get_allocator() const { return allocator(); }
+ // Returns a copy of the inlined vector's allocator.
+ allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
// ---------------------------------------------------------------------------
// InlinedVector Member Mutators
// ---------------------------------------------------------------------------
- // `InlinedVector::operator=()`
+ // `InlinedVector::operator=(...)`
//
- // Replaces the contents of the inlined vector with copies of the elements in
- // the provided `std::initializer_list`.
- InlinedVector& operator=(std::initializer_list<value_type> init_list) {
- AssignRange(init_list.begin(), init_list.end(),
- IteratorCategory<decltype(init_list.begin())>{});
+ // Replaces the elements of the inlined vector with copies of the elements of
+ // `list`.
+ InlinedVector& operator=(std::initializer_list<value_type> list) {
+ assign(list.begin(), list.end());
+
return *this;
}
- // Overload of `InlinedVector::operator=()` to replace the contents of the
- // inlined vector with the contents of `other`.
+ // Overload of `InlinedVector::operator=(...)` that replaces the elements of
+ // the inlined vector with copies of the elements of `other`.
InlinedVector& operator=(const InlinedVector& other) {
- if (ABSL_PREDICT_FALSE(this == &other)) return *this;
-
- // Optimized to avoid reallocation.
- // Prefer reassignment to copy construction for elements.
- if (size() < other.size()) { // grow
- reserve(other.size());
- std::copy(other.begin(), other.begin() + size(), begin());
- std::copy(other.begin() + size(), other.end(), std::back_inserter(*this));
- } else { // maybe shrink
- erase(begin() + other.size(), end());
- std::copy(other.begin(), other.end(), begin());
+ if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+ const_pointer other_data = other.data();
+ assign(other_data, other_data + other.size());
}
+
return *this;
}
- // Overload of `InlinedVector::operator=()` to replace the contents of the
- // inlined vector with the contents of `other`.
+ // Overload of `InlinedVector::operator=(...)` that moves the elements of
+ // `other` into the inlined vector.
//
- // NOTE: As a result of calling this overload, `other` may be empty or it's
- // contents may be left in a moved-from state.
+ // NOTE: as a result of calling this overload, `other` is left in a valid but
+ // unspecified state.
InlinedVector& operator=(InlinedVector&& other) {
- if (ABSL_PREDICT_FALSE(this == &other)) return *this;
-
- if (other.allocated()) {
- clear();
- tag().set_allocated_size(other.size());
- init_allocation(other.allocation());
- other.tag() = Tag();
- } else {
- if (allocated()) clear();
- // Both are inlined now.
- if (size() < other.size()) {
- auto mid = std::make_move_iterator(other.begin() + size());
- std::copy(std::make_move_iterator(other.begin()), mid, begin());
- UninitializedCopy(mid, std::make_move_iterator(other.end()), end());
+ if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+ if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
+ inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
+ size());
+ storage_.DeallocateIfAllocated();
+ storage_.MemcpyFrom(other.storage_);
+
+ other.storage_.SetInlinedSize(0);
} else {
- auto new_end = std::copy(std::make_move_iterator(other.begin()),
- std::make_move_iterator(other.end()), begin());
- Destroy(new_end, end());
+ storage_.Assign(IteratorValueAdapter<MoveIterator>(
+ MoveIterator(other.storage_.GetInlinedData())),
+ other.size());
}
- tag().set_inline_size(other.size());
}
+
return *this;
}
- // `InlinedVector::assign()`
+ // `InlinedVector::assign(...)`
//
// Replaces the contents of the inlined vector with `n` copies of `v`.
void assign(size_type n, const_reference v) {
- if (n <= size()) { // Possibly shrink
- std::fill_n(begin(), n, v);
- erase(begin() + n, end());
- return;
- }
- // Grow
- reserve(n);
- std::fill_n(begin(), size(), v);
- if (allocated()) {
- UninitializedFill(allocated_space() + size(), allocated_space() + n, v);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space() + size(), inlined_space() + n, v);
- tag().set_inline_size(n);
- }
+ storage_.Assign(CopyValueAdapter(v), n);
+ }
+
+ // Overload of `InlinedVector::assign(...)` that replaces the contents of the
+ // inlined vector with copies of the elements of `list`.
+ void assign(std::initializer_list<value_type> list) {
+ assign(list.begin(), list.end());
}
- // Overload of `InlinedVector::assign()` to replace the contents of the
- // inlined vector with copies of the values in the provided
- // `std::initializer_list`.
- void assign(std::initializer_list<value_type> init_list) {
- AssignRange(init_list.begin(), init_list.end(),
- IteratorCategory<decltype(init_list.begin())>{});
+ // Overload of `InlinedVector::assign(...)` to replace the contents of the
+ // inlined vector with the range [`first`, `last`).
+ //
+ // NOTE: this overload is for iterators that are "forward" category or better.
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ void assign(ForwardIterator first, ForwardIterator last) {
+ storage_.Assign(IteratorValueAdapter<ForwardIterator>(first),
+ std::distance(first, last));
}
- // Overload of `InlinedVector::assign()` to replace the contents of the
- // inlined vector with values constructed from the range [`first`, `last`).
- template <typename InputIterator, DisableIfIntegral<InputIterator>* = nullptr>
+ // Overload of `InlinedVector::assign(...)` to replace the contents of the
+ // inlined vector with the range [`first`, `last`).
+ //
+ // NOTE: this overload is for iterators that are "input" category.
+ template <typename InputIterator,
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
void assign(InputIterator first, InputIterator last) {
- AssignRange(first, last, IteratorCategory<InputIterator>{});
+ size_type i = 0;
+ for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
+ at(i) = *first;
+ }
+
+ erase(data() + i, data() + size());
+
+ std::copy(first, last, std::back_inserter(*this));
}
- // `InlinedVector::resize()`
+ // `InlinedVector::resize(...)`
+ //
+ // Resizes the inlined vector to contain `n` elements.
//
- // Resizes the inlined vector to contain `n` elements. If `n` is smaller than
- // the inlined vector's current size, extra elements are destroyed. If `n` is
- // larger than the initial size, new elements are value-initialized.
- void resize(size_type n);
+ // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
+ // is larger than `size()`, new elements are value-initialized.
+ void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); }
- // Overload of `InlinedVector::resize()` to resize the inlined vector to
- // contain `n` elements where, if `n` is larger than `size()`, the new values
- // will be copy-constructed from `v`.
- void resize(size_type n, const_reference v);
+ // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
+ // contain `n` elements.
+ //
+ // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
+ // is larger than `size()`, new elements are copied-constructed from `v`.
+ void resize(size_type n, const_reference v) {
+ storage_.Resize(CopyValueAdapter(v), n);
+ }
- // `InlinedVector::insert()`
+ // `InlinedVector::insert(...)`
//
- // Copies `v` into `position`, returning an `iterator` pointing to the newly
+ // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
// inserted element.
- iterator insert(const_iterator position, const_reference v) {
- return emplace(position, v);
+ iterator insert(const_iterator pos, const_reference v) {
+ return emplace(pos, v);
}
- // Overload of `InlinedVector::insert()` for moving `v` into `position`,
- // returning an iterator pointing to the newly inserted element.
- iterator insert(const_iterator position, rvalue_reference v) {
- return emplace(position, std::move(v));
+ // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
+ // move semantics, returning an `iterator` to the newly inserted element.
+ iterator insert(const_iterator pos, rvalue_reference v) {
+ return emplace(pos, std::move(v));
}
- // Overload of `InlinedVector::insert()` for inserting `n` contiguous copies
- // of `v` starting at `position`. Returns an `iterator` pointing to the first
- // of the newly inserted elements.
- iterator insert(const_iterator position, size_type n, const_reference v) {
- return InsertWithCount(position, n, v);
+ // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
+ // of `v` starting at `pos`, returning an `iterator` pointing to the first of
+ // the newly inserted elements.
+ iterator insert(const_iterator pos, size_type n, const_reference v) {
+ assert(pos >= begin());
+ assert(pos <= end());
+
+ if (ABSL_PREDICT_TRUE(n != 0)) {
+ value_type dealias = v;
+ return storage_.Insert(pos, CopyValueAdapter(dealias), n);
+ } else {
+ return const_cast<iterator>(pos);
+ }
}
- // Overload of `InlinedVector::insert()` for copying the contents of the
- // `std::initializer_list` into the vector starting at `position`. Returns an
- // `iterator` pointing to the first of the newly inserted elements.
- iterator insert(const_iterator position,
- std::initializer_list<value_type> init_list) {
- return insert(position, init_list.begin(), init_list.end());
+ // Overload of `InlinedVector::insert(...)` that inserts copies of the
+ // elements of `list` starting at `pos`, returning an `iterator` pointing to
+ // the first of the newly inserted elements.
+ iterator insert(const_iterator pos, std::initializer_list<value_type> list) {
+ return insert(pos, list.begin(), list.end());
+ }
+
+ // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
+ // `last`) starting at `pos`, returning an `iterator` pointing to the first
+ // of the newly inserted elements.
+ //
+ // NOTE: this overload is for iterators that are "forward" category or better.
+ template <typename ForwardIterator,
+ EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
+ iterator insert(const_iterator pos, ForwardIterator first,
+ ForwardIterator last) {
+ assert(pos >= begin());
+ assert(pos <= end());
+
+ if (ABSL_PREDICT_TRUE(first != last)) {
+ return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
+ std::distance(first, last));
+ } else {
+ return const_cast<iterator>(pos);
+ }
}
- // Overload of `InlinedVector::insert()` for inserting elements constructed
- // from the range [`first`, `last`). Returns an `iterator` pointing to the
- // first of the newly inserted elements.
+ // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
+ // `last`) starting at `pos`, returning an `iterator` pointing to the first
+ // of the newly inserted elements.
//
- // NOTE: The `enable_if` is intended to disambiguate the two three-argument
- // overloads of `insert()`.
+ // NOTE: this overload is for iterators that are "input" category.
template <typename InputIterator,
- typename = EnableIfInputIterator<InputIterator>>
- iterator insert(const_iterator position, InputIterator first,
- InputIterator last) {
- return InsertWithRange(position, first, last,
- IteratorCategory<InputIterator>());
+ DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
+ iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
+ assert(pos >= begin());
+ assert(pos <= end());
+
+ size_type index = std::distance(cbegin(), pos);
+ for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
+ insert(data() + i, *first);
+ }
+
+ return iterator(data() + index);
}
- // `InlinedVector::emplace()`
+ // `InlinedVector::emplace(...)`
//
- // Constructs and inserts an object in the inlined vector at the given
- // `position`, returning an `iterator` pointing to the newly emplaced element.
+ // Constructs and inserts an element using `args...` in the inlined vector at
+ // `pos`, returning an `iterator` pointing to the newly emplaced element.
template <typename... Args>
- iterator emplace(const_iterator position, Args&&... args);
+ iterator emplace(const_iterator pos, Args&&... args) {
+ assert(pos >= begin());
+ assert(pos <= end());
- // `InlinedVector::emplace_back()`
+ value_type dealias(std::forward<Args>(args)...);
+ return storage_.Insert(pos,
+ IteratorValueAdapter<MoveIterator>(
+ MoveIterator(std::addressof(dealias))),
+ 1);
+ }
+
+ // `InlinedVector::emplace_back(...)`
//
- // Constructs and appends a new element to the end of the inlined vector,
- // returning a `reference` to the emplaced element.
+ // Constructs and inserts an element using `args...` in the inlined vector at
+ // `end()`, returning a `reference` to the newly emplaced element.
template <typename... Args>
reference emplace_back(Args&&... args) {
- size_type s = size();
- assert(s <= capacity());
- if (ABSL_PREDICT_FALSE(s == capacity())) {
- return GrowAndEmplaceBack(std::forward<Args>(args)...);
- }
- assert(s < capacity());
-
- pointer space;
- if (allocated()) {
- tag().set_allocated_size(s + 1);
- space = allocated_space();
- } else {
- tag().set_inline_size(s + 1);
- space = inlined_space();
- }
- return Construct(space + s, std::forward<Args>(args)...);
+ return storage_.EmplaceBack(std::forward<Args>(args)...);
}
- // `InlinedVector::push_back()`
+ // `InlinedVector::push_back(...)`
//
- // Appends a copy of `v` to the end of the inlined vector.
+ // Inserts a copy of `v` in the inlined vector at `end()`.
void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
- // Overload of `InlinedVector::push_back()` for moving `v` into a newly
- // appended element.
+ // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
+ // using move semantics.
void push_back(rvalue_reference v) {
static_cast<void>(emplace_back(std::move(v)));
}
// `InlinedVector::pop_back()`
//
- // Destroys the element at the end of the inlined vector and shrinks the size
- // by `1` (unless the inlined vector is empty, in which case this is a no-op).
+ // Destroys the element at `back()`, reducing the size by `1`.
void pop_back() noexcept {
assert(!empty());
- size_type s = size();
- if (allocated()) {
- Destroy(allocated_space() + s - 1, allocated_space() + s);
- tag().set_allocated_size(s - 1);
- } else {
- Destroy(inlined_space() + s - 1, inlined_space() + s);
- tag().set_inline_size(s - 1);
- }
+
+ AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
+ storage_.SubtractSize(1);
}
- // `InlinedVector::erase()`
+ // `InlinedVector::erase(...)`
//
- // Erases the element at `position` of the inlined vector, returning an
- // `iterator` pointing to the first element following the erased element.
+ // Erases the element at `pos`, returning an `iterator` pointing to where the
+ // erased element was located.
//
- // NOTE: May return the end iterator, which is not dereferencable.
- iterator erase(const_iterator position) {
- assert(position >= begin());
- assert(position < end());
-
- iterator pos = const_cast<iterator>(position);
- std::move(pos + 1, end(), pos);
- pop_back();
- return pos;
+ // NOTE: may return `end()`, which is not dereferencable.
+ iterator erase(const_iterator pos) {
+ assert(pos >= begin());
+ assert(pos < end());
+
+ return storage_.Erase(pos, pos + 1);
}
- // Overload of `InlinedVector::erase()` for erasing all elements in the
- // range [`from`, `to`) in the inlined vector. Returns an `iterator` pointing
- // to the first element following the range erased or the end iterator if `to`
- // was the end iterator.
- iterator erase(const_iterator from, const_iterator to);
+ // Overload of `InlinedVector::erase(...)` that erases every element in the
+ // range [`from`, `to`), returning an `iterator` pointing to where the first
+ // erased element was located.
+ //
+ // NOTE: may return `end()`, which is not dereferencable.
+ iterator erase(const_iterator from, const_iterator to) {
+ assert(from >= begin());
+ assert(from <= to);
+ assert(to <= end());
+
+ if (ABSL_PREDICT_TRUE(from != to)) {
+ return storage_.Erase(from, to);
+ } else {
+ return const_cast<iterator>(from);
+ }
+ }
// `InlinedVector::clear()`
//
- // Destroys all elements in the inlined vector, sets the size of `0` and
- // deallocates the heap allocation if the inlined vector was allocated.
+ // Destroys all elements in the inlined vector, setting the size to `0` and
+ // deallocating any held memory.
void clear() noexcept {
- size_type s = size();
- if (allocated()) {
- Destroy(allocated_space(), allocated_space() + s);
- allocation().Dealloc(allocator());
- } else if (s != 0) { // do nothing for empty vectors
- Destroy(inlined_space(), inlined_space() + s);
- }
- tag() = Tag();
+ inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
+ size());
+ storage_.DeallocateIfAllocated();
+ storage_.SetInlinedSize(0);
}
- // `InlinedVector::reserve()`
+ // `InlinedVector::reserve(...)`
//
- // Enlarges the underlying representation of the inlined vector so it can hold
- // at least `n` elements. This method does not change `size()` or the actual
- // contents of the vector.
- //
- // NOTE: If `n` does not exceed `capacity()`, `reserve()` will have no
- // effects. Otherwise, `reserve()` will reallocate, performing an n-time
- // element-wise move of everything contained.
- void reserve(size_type n) {
- if (n > capacity()) {
- // Make room for new elements
- EnlargeBy(n - size());
- }
- }
+ // Ensures that there is enough room for at least `n` elements.
+ void reserve(size_type n) { storage_.Reserve(n); }
// `InlinedVector::shrink_to_fit()`
//
- // Reduces memory usage by freeing unused memory. After this call, calls to
- // `capacity()` will be equal to `(std::max)(inlined_capacity(), size())`.
+ // Reduces memory usage by freeing unused memory. After being called, calls to
+ // `capacity()` will be equal to `max(N, size())`.
//
- // If `size() <= inlined_capacity()` and the elements are currently stored on
- // the heap, they will be moved to the inlined storage and the heap memory
+ // If `size() <= N` and the inlined vector contains allocated memory, the
+ // elements will all be moved to the inlined space and the allocated memory
// will be deallocated.
//
- // If `size() > inlined_capacity()` and `size() < capacity()` the elements
- // will be moved to a smaller heap allocation.
+ // If `size() > N` and `size() < capacity()`, the elements will be moved to a
+ // smaller allocation.
void shrink_to_fit() {
- const auto s = size();
- if (ABSL_PREDICT_FALSE(!allocated() || s == capacity())) return;
-
- if (s <= inlined_capacity()) {
- // Move the elements to the inlined storage.
- // We have to do this using a temporary, because `inlined_storage` and
- // `allocation_storage` are in a union field.
- auto temp = std::move(*this);
- assign(std::make_move_iterator(temp.begin()),
- std::make_move_iterator(temp.end()));
- return;
+ if (storage_.GetIsAllocated()) {
+ storage_.ShrinkToFit();
}
-
- // Reallocate storage and move elements.
- // We can't simply use the same approach as above, because `assign()` would
- // call into `reserve()` internally and reserve larger capacity than we need
- Allocation new_allocation(allocator(), s);
- UninitializedCopy(std::make_move_iterator(allocated_space()),
- std::make_move_iterator(allocated_space() + s),
- new_allocation.buffer());
- ResetAllocation(new_allocation, s);
}
- // `InlinedVector::swap()`
+ // `InlinedVector::swap(...)`
//
- // Swaps the contents of this inlined vector with the contents of `other`.
- void swap(InlinedVector& other);
-
- template <typename Hash>
- friend Hash AbslHashValue(Hash hash, const InlinedVector& inlined_vector) {
- const_pointer p = inlined_vector.data();
- size_type n = inlined_vector.size();
- return Hash::combine(Hash::combine_contiguous(std::move(hash), p, n), n);
- }
-
- private:
- // Holds whether the vector is allocated or not in the lowest bit and the size
- // in the high bits:
- // `size_ = (size << 1) | is_allocated;`
- class Tag {
- public:
- Tag() : size_(0) {}
- size_type size() const { return size_ / 2; }
- void add_size(size_type n) { size_ += n * 2; }
- void set_inline_size(size_type n) { size_ = n * 2; }
- void set_allocated_size(size_type n) { size_ = (n * 2) + 1; }
- bool allocated() const { return size_ % 2; }
-
- private:
- size_type size_;
- };
-
- // Derives from `allocator_type` to use the empty base class optimization.
- // If the `allocator_type` is stateless, we can store our instance for free.
- class AllocatorAndTag : private allocator_type {
- public:
- explicit AllocatorAndTag(const allocator_type& a) : allocator_type(a) {}
-
- Tag& tag() { return tag_; }
- const Tag& tag() const { return tag_; }
-
- allocator_type& allocator() { return *this; }
- const allocator_type& allocator() const { return *this; }
-
- private:
- Tag tag_;
- };
-
- class Allocation {
- public:
- Allocation(allocator_type& a, size_type capacity)
- : capacity_(capacity), buffer_(Create(a, capacity)) {}
-
- void Dealloc(allocator_type& a) {
- std::allocator_traits<allocator_type>::deallocate(a, buffer_, capacity_);
- }
-
- size_type capacity() const { return capacity_; }
-
- const_pointer buffer() const { return buffer_; }
-
- pointer buffer() { return buffer_; }
-
- private:
- static pointer Create(allocator_type& a, size_type n) {
- return std::allocator_traits<allocator_type>::allocate(a, n);
+ // Swaps the contents of the inlined vector with `other`.
+ void swap(InlinedVector& other) {
+ if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
+ storage_.Swap(std::addressof(other.storage_));
}
-
- size_type capacity_;
- pointer buffer_;
- };
-
- const Tag& tag() const { return allocator_and_tag_.tag(); }
-
- Tag& tag() { return allocator_and_tag_.tag(); }
-
- Allocation& allocation() {
- return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation);
- }
-
- const Allocation& allocation() const {
- return reinterpret_cast<const Allocation&>(
- rep_.allocation_storage.allocation);
- }
-
- void init_allocation(const Allocation& allocation) {
- new (&rep_.allocation_storage.allocation) Allocation(allocation);
- }
-
- // TODO(absl-team): investigate whether the reinterpret_cast is appropriate.
- pointer inlined_space() {
- return reinterpret_cast<pointer>(
- std::addressof(rep_.inlined_storage.inlined[0]));
- }
-
- const_pointer inlined_space() const {
- return reinterpret_cast<const_pointer>(
- std::addressof(rep_.inlined_storage.inlined[0]));
- }
-
- pointer allocated_space() { return allocation().buffer(); }
-
- const_pointer allocated_space() const { return allocation().buffer(); }
-
- const allocator_type& allocator() const {
- return allocator_and_tag_.allocator();
}
- allocator_type& allocator() { return allocator_and_tag_.allocator(); }
-
- bool allocated() const { return tag().allocated(); }
-
- // Enlarge the underlying representation so we can store `size_ + delta` elems
- // in allocated space. The size is not changed, and any newly added memory is
- // not initialized.
- void EnlargeBy(size_type delta);
-
- // Shift all elements from `position` to `end()` by `n` places to the right.
- // If the vector needs to be enlarged, memory will be allocated.
- // Returns `iterator`s pointing to the start of the previously-initialized
- // portion and the start of the uninitialized portion of the created gap.
- // The number of initialized spots is `pair.second - pair.first`. The number
- // of raw spots is `n - (pair.second - pair.first)`.
- //
- // Updates the size of the InlinedVector internally.
- std::pair<iterator, iterator> ShiftRight(const_iterator position,
- size_type n);
-
- void ResetAllocation(Allocation new_allocation, size_type new_size) {
- if (allocated()) {
- Destroy(allocated_space(), allocated_space() + size());
- assert(begin() == allocated_space());
- allocation().Dealloc(allocator());
- allocation() = new_allocation;
- } else {
- Destroy(inlined_space(), inlined_space() + size());
- init_allocation(new_allocation); // bug: only init once
- }
- tag().set_allocated_size(new_size);
- }
-
- template <typename... Args>
- reference GrowAndEmplaceBack(Args&&... args) {
- assert(size() == capacity());
- const size_type s = size();
-
- Allocation new_allocation(allocator(), 2 * capacity());
-
- reference new_element =
- Construct(new_allocation.buffer() + s, std::forward<Args>(args)...);
- UninitializedCopy(std::make_move_iterator(data()),
- std::make_move_iterator(data() + s),
- new_allocation.buffer());
-
- ResetAllocation(new_allocation, s + 1);
-
- return new_element;
- }
-
- void InitAssign(size_type n);
-
- void InitAssign(size_type n, const_reference v);
-
- template <typename... Args>
- reference Construct(pointer p, Args&&... args) {
- std::allocator_traits<allocator_type>::construct(
- allocator(), p, std::forward<Args>(args)...);
- return *p;
- }
-
- template <typename Iterator>
- void UninitializedCopy(Iterator src, Iterator src_last, pointer dst) {
- for (; src != src_last; ++dst, ++src) Construct(dst, *src);
- }
-
- template <typename... Args>
- void UninitializedFill(pointer dst, pointer dst_last, const Args&... args) {
- for (; dst != dst_last; ++dst) Construct(dst, args...);
- }
-
- // Destroy [`from`, `to`) in place.
- void Destroy(pointer from, pointer to);
-
- template <typename Iterator>
- void AppendRange(Iterator first, Iterator last, std::forward_iterator_tag);
-
- template <typename Iterator>
- void AppendRange(Iterator first, Iterator last, std::input_iterator_tag);
-
- template <typename Iterator>
- void AssignRange(Iterator first, Iterator last, std::forward_iterator_tag);
+ private:
+ template <typename H, typename TheT, size_t TheN, typename TheA>
+ friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
- template <typename Iterator>
- void AssignRange(Iterator first, Iterator last, std::input_iterator_tag);
-
- iterator InsertWithCount(const_iterator position, size_type n,
- const_reference v);
-
- template <typename ForwardIterator>
- iterator InsertWithRange(const_iterator position, ForwardIterator first,
- ForwardIterator last, std::forward_iterator_tag);
-
- template <typename InputIterator>
- iterator InsertWithRange(const_iterator position, InputIterator first,
- InputIterator last, std::input_iterator_tag);
-
- // Stores either the inlined or allocated representation
- union Rep {
- using ValueTypeBuffer =
- absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>;
- using AllocationBuffer =
- absl::aligned_storage_t<sizeof(Allocation), alignof(Allocation)>;
-
- // Structs wrap the buffers to perform indirection that solves a bizarre
- // compilation error on Visual Studio (all known versions).
- struct InlinedRep {
- ValueTypeBuffer inlined[N];
- };
- struct AllocatedRep {
- AllocationBuffer allocation;
- };
-
- InlinedRep inlined_storage;
- AllocatedRep allocation_storage;
- };
-
- AllocatorAndTag allocator_and_tag_;
- Rep rep_;
+ Storage storage_;
};
// -----------------------------------------------------------------------------
// InlinedVector Non-Member Functions
// -----------------------------------------------------------------------------
-// `swap()`
+// `swap(...)`
//
-// Swaps the contents of two inlined vectors. This convenience function
-// simply calls `InlinedVector::swap()`.
+// Swaps the contents of two inlined vectors.
template <typename T, size_t N, typename A>
-void swap(InlinedVector<T, N, A>& a,
- InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
+void swap(absl::InlinedVector<T, N, A>& a,
+ absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
-// `operator==()`
+// `operator==(...)`
//
-// Tests the equivalency of the contents of two inlined vectors.
+// Tests for value-equality of two inlined vectors.
template <typename T, size_t N, typename A>
-bool operator==(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
- return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+bool operator==(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
+ auto a_data = a.data();
+ auto b_data = b.data();
+ return absl::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
}
-// `operator!=()`
+// `operator!=(...)`
//
-// Tests the inequality of the contents of two inlined vectors.
+// Tests for value-inequality of two inlined vectors.
template <typename T, size_t N, typename A>
-bool operator!=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+bool operator!=(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
return !(a == b);
}
-// `operator<()`
+// `operator<(...)`
//
-// Tests whether the contents of one inlined vector are less than the contents
-// of another through a lexicographical comparison operation.
+// Tests whether the value of an inlined vector is less than the value of
+// another inlined vector using a lexicographical comparison algorithm.
template <typename T, size_t N, typename A>
-bool operator<(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
- return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+bool operator<(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
+ auto a_data = a.data();
+ auto b_data = b.data();
+ return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
+ b_data + b.size());
}
-// `operator>()`
+// `operator>(...)`
//
-// Tests whether the contents of one inlined vector are greater than the
-// contents of another through a lexicographical comparison operation.
+// Tests whether the value of an inlined vector is greater than the value of
+// another inlined vector using a lexicographical comparison algorithm.
template <typename T, size_t N, typename A>
-bool operator>(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+bool operator>(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
return b < a;
}
-// `operator<=()`
+// `operator<=(...)`
//
-// Tests whether the contents of one inlined vector are less than or equal to
-// the contents of another through a lexicographical comparison operation.
+// Tests whether the value of an inlined vector is less than or equal to the
+// value of another inlined vector using a lexicographical comparison algorithm.
template <typename T, size_t N, typename A>
-bool operator<=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+bool operator<=(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
return !(b < a);
}
-// `operator>=()`
+// `operator>=(...)`
//
-// Tests whether the contents of one inlined vector are greater than or equal to
-// the contents of another through a lexicographical comparison operation.
+// Tests whether the value of an inlined vector is greater than or equal to the
+// value of another inlined vector using a lexicographical comparison algorithm.
template <typename T, size_t N, typename A>
-bool operator>=(const InlinedVector<T, N, A>& a,
- const InlinedVector<T, N, A>& b) {
+bool operator>=(const absl::InlinedVector<T, N, A>& a,
+ const absl::InlinedVector<T, N, A>& b) {
return !(a < b);
}
-// -----------------------------------------------------------------------------
-// Implementation of InlinedVector
+// `AbslHashValue(...)`
//
-// Do not depend on any below implementation details!
-// -----------------------------------------------------------------------------
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(const InlinedVector& other)
- : allocator_and_tag_(other.allocator()) {
- reserve(other.size());
- if (allocated()) {
- UninitializedCopy(other.begin(), other.end(), allocated_space());
- tag().set_allocated_size(other.size());
- } else {
- UninitializedCopy(other.begin(), other.end(), inlined_space());
- tag().set_inline_size(other.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(const InlinedVector& other,
- const allocator_type& alloc)
- : allocator_and_tag_(alloc) {
- reserve(other.size());
- if (allocated()) {
- UninitializedCopy(other.begin(), other.end(), allocated_space());
- tag().set_allocated_size(other.size());
- } else {
- UninitializedCopy(other.begin(), other.end(), inlined_space());
- tag().set_inline_size(other.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(InlinedVector&& other) noexcept(
- absl::allocator_is_nothrow<allocator_type>::value ||
- std::is_nothrow_move_constructible<value_type>::value)
- : allocator_and_tag_(other.allocator_and_tag_) {
- if (other.allocated()) {
- // We can just steal the underlying buffer from the source.
- // That leaves the source empty, so we clear its size.
- init_allocation(other.allocation());
- other.tag() = Tag();
- } else {
- UninitializedCopy(
- std::make_move_iterator(other.inlined_space()),
- std::make_move_iterator(other.inlined_space() + other.size()),
- inlined_space());
- }
-}
-
-template <typename T, size_t N, typename A>
-InlinedVector<T, N, A>::InlinedVector(InlinedVector&& other,
- const allocator_type& alloc) noexcept( //
- absl::allocator_is_nothrow<allocator_type>::value)
- : allocator_and_tag_(alloc) {
- if (other.allocated()) {
- if (alloc == other.allocator()) {
- // We can just steal the allocation from the source.
- tag() = other.tag();
- init_allocation(other.allocation());
- other.tag() = Tag();
- } else {
- // We need to use our own allocator
- reserve(other.size());
- UninitializedCopy(std::make_move_iterator(other.begin()),
- std::make_move_iterator(other.end()),
- allocated_space());
- tag().set_allocated_size(other.size());
- }
- } else {
- UninitializedCopy(
- std::make_move_iterator(other.inlined_space()),
- std::make_move_iterator(other.inlined_space() + other.size()),
- inlined_space());
- tag().set_inline_size(other.size());
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::InitAssign(size_type n, const_reference v) {
- if (n > inlined_capacity()) {
- Allocation new_allocation(allocator(), n);
- init_allocation(new_allocation);
- UninitializedFill(allocated_space(), allocated_space() + n, v);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space(), inlined_space() + n, v);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::InitAssign(size_type n) {
- if (n > inlined_capacity()) {
- Allocation new_allocation(allocator(), n);
- init_allocation(new_allocation);
- UninitializedFill(allocated_space(), allocated_space() + n);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space(), inlined_space() + n);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::resize(size_type n) {
- size_type s = size();
- if (n < s) {
- erase(begin() + n, end());
- return;
- }
- reserve(n);
- assert(capacity() >= n);
-
- // Fill new space with elements constructed in-place.
- if (allocated()) {
- UninitializedFill(allocated_space() + s, allocated_space() + n);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space() + s, inlined_space() + n);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::resize(size_type n, const_reference v) {
- size_type s = size();
- if (n < s) {
- erase(begin() + n, end());
- return;
- }
- reserve(n);
- assert(capacity() >= n);
-
- // Fill new space with copies of 'v'.
- if (allocated()) {
- UninitializedFill(allocated_space() + s, allocated_space() + n, v);
- tag().set_allocated_size(n);
- } else {
- UninitializedFill(inlined_space() + s, inlined_space() + n, v);
- tag().set_inline_size(n);
- }
-}
-
-template <typename T, size_t N, typename A>
-template <typename... Args>
-auto InlinedVector<T, N, A>::emplace(const_iterator position, Args&&... args)
- -> iterator {
- assert(position >= begin());
- assert(position <= end());
- if (ABSL_PREDICT_FALSE(position == end())) {
- emplace_back(std::forward<Args>(args)...);
- return end() - 1;
- }
-
- T new_t = T(std::forward<Args>(args)...);
-
- auto range = ShiftRight(position, 1);
- if (range.first == range.second) {
- // constructing into uninitialized memory
- Construct(range.first, std::move(new_t));
- } else {
- // assigning into moved-from object
- *range.first = T(std::move(new_t));
- }
-
- return range.first;
-}
-
-template <typename T, size_t N, typename A>
-auto InlinedVector<T, N, A>::erase(const_iterator from, const_iterator to)
- -> iterator {
- assert(begin() <= from);
- assert(from <= to);
- assert(to <= end());
-
- iterator range_start = const_cast<iterator>(from);
- iterator range_end = const_cast<iterator>(to);
-
- size_type s = size();
- ptrdiff_t erase_gap = std::distance(range_start, range_end);
- if (erase_gap > 0) {
- pointer space;
- if (allocated()) {
- space = allocated_space();
- tag().set_allocated_size(s - erase_gap);
- } else {
- space = inlined_space();
- tag().set_inline_size(s - erase_gap);
- }
- std::move(range_end, space + s, range_start);
- Destroy(space + s - erase_gap, space + s);
- }
- return range_start;
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::swap(InlinedVector& other) {
- using std::swap; // Augment ADL with `std::swap`.
- if (ABSL_PREDICT_FALSE(this == &other)) return;
-
- if (allocated() && other.allocated()) {
- // Both out of line, so just swap the tag, allocation, and allocator.
- swap(tag(), other.tag());
- swap(allocation(), other.allocation());
- swap(allocator(), other.allocator());
- return;
- }
- if (!allocated() && !other.allocated()) {
- // Both inlined: swap up to smaller size, then move remaining elements.
- InlinedVector* a = this;
- InlinedVector* b = &other;
- if (size() < other.size()) {
- swap(a, b);
- }
-
- const size_type a_size = a->size();
- const size_type b_size = b->size();
- assert(a_size >= b_size);
- // `a` is larger. Swap the elements up to the smaller array size.
- std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size,
- b->inlined_space());
-
- // Move the remaining elements:
- // [`b_size`, `a_size`) from `a` -> [`b_size`, `a_size`) from `b`
- b->UninitializedCopy(a->inlined_space() + b_size,
- a->inlined_space() + a_size,
- b->inlined_space() + b_size);
- a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size);
-
- swap(a->tag(), b->tag());
- swap(a->allocator(), b->allocator());
- assert(b->size() == a_size);
- assert(a->size() == b_size);
- return;
- }
-
- // One is out of line, one is inline.
- // We first move the elements from the inlined vector into the
- // inlined space in the other vector. We then put the other vector's
- // pointer/capacity into the originally inlined vector and swap
- // the tags.
- InlinedVector* a = this;
- InlinedVector* b = &other;
- if (a->allocated()) {
- swap(a, b);
- }
- assert(!a->allocated());
- assert(b->allocated());
- const size_type a_size = a->size();
- const size_type b_size = b->size();
- // In an optimized build, `b_size` would be unused.
- static_cast<void>(b_size);
-
- // Made Local copies of `size()`, don't need `tag()` accurate anymore
- swap(a->tag(), b->tag());
-
- // Copy `b_allocation` out before `b`'s union gets clobbered by `inline_space`
- Allocation b_allocation = b->allocation();
-
- b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size,
- b->inlined_space());
- a->Destroy(a->inlined_space(), a->inlined_space() + a_size);
-
- a->allocation() = b_allocation;
-
- if (a->allocator() != b->allocator()) {
- swap(a->allocator(), b->allocator());
- }
-
- assert(b->size() == a_size);
- assert(a->size() == b_size);
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::EnlargeBy(size_type delta) {
- const size_type s = size();
- assert(s <= capacity());
-
- size_type target = std::max(inlined_capacity(), s + delta);
-
- // Compute new capacity by repeatedly doubling current capacity
- // TODO(psrc): Check and avoid overflow?
- size_type new_capacity = capacity();
- while (new_capacity < target) {
- new_capacity <<= 1;
- }
-
- Allocation new_allocation(allocator(), new_capacity);
-
- UninitializedCopy(std::make_move_iterator(data()),
- std::make_move_iterator(data() + s),
- new_allocation.buffer());
-
- ResetAllocation(new_allocation, s);
-}
-
-template <typename T, size_t N, typename A>
-auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n)
- -> std::pair<iterator, iterator> {
- iterator start_used = const_cast<iterator>(position);
- iterator start_raw = const_cast<iterator>(position);
- size_type s = size();
- size_type required_size = s + n;
-
- if (required_size > capacity()) {
- // Compute new capacity by repeatedly doubling current capacity
- size_type new_capacity = capacity();
- while (new_capacity < required_size) {
- new_capacity <<= 1;
- }
- // Move everyone into the new allocation, leaving a gap of `n` for the
- // requested shift.
- Allocation new_allocation(allocator(), new_capacity);
- size_type index = position - begin();
- UninitializedCopy(std::make_move_iterator(data()),
- std::make_move_iterator(data() + index),
- new_allocation.buffer());
- UninitializedCopy(std::make_move_iterator(data() + index),
- std::make_move_iterator(data() + s),
- new_allocation.buffer() + index + n);
- ResetAllocation(new_allocation, s);
-
- // New allocation means our iterator is invalid, so we'll recalculate.
- // Since the entire gap is in new space, there's no used space to reuse.
- start_raw = begin() + index;
- start_used = start_raw;
- } else {
- // If we had enough space, it's a two-part move. Elements going into
- // previously-unoccupied space need an `UninitializedCopy()`. Elements
- // going into a previously-occupied space are just a `std::move()`.
- iterator pos = const_cast<iterator>(position);
- iterator raw_space = end();
- size_type slots_in_used_space = raw_space - pos;
- size_type new_elements_in_used_space = std::min(n, slots_in_used_space);
- size_type new_elements_in_raw_space = n - new_elements_in_used_space;
- size_type old_elements_in_used_space =
- slots_in_used_space - new_elements_in_used_space;
-
- UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space),
- std::make_move_iterator(raw_space),
- raw_space + new_elements_in_raw_space);
- std::move_backward(pos, pos + old_elements_in_used_space, raw_space);
-
- // If the gap is entirely in raw space, the used space starts where the raw
- // space starts, leaving no elements in used space. If the gap is entirely
- // in used space, the raw space starts at the end of the gap, leaving all
- // elements accounted for within the used space.
- start_used = pos;
- start_raw = pos + new_elements_in_used_space;
- }
- tag().add_size(n);
- return std::make_pair(start_used, start_raw);
-}
-
-template <typename T, size_t N, typename A>
-void InlinedVector<T, N, A>::Destroy(pointer from, pointer to) {
- for (pointer cur = from; cur != to; ++cur) {
- std::allocator_traits<allocator_type>::destroy(allocator(), cur);
- }
-#ifndef NDEBUG
- // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
- // Cast to `void*` to tell the compiler that we don't care that we might be
- // scribbling on a vtable pointer.
- if (from != to) {
- auto len = sizeof(value_type) * std::distance(from, to);
- std::memset(reinterpret_cast<void*>(from), 0xab, len);
- }
-#endif
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iterator>
-void InlinedVector<T, N, A>::AppendRange(Iterator first, Iterator last,
- std::forward_iterator_tag) {
- auto length = std::distance(first, last);
- reserve(size() + length);
- if (allocated()) {
- UninitializedCopy(first, last, allocated_space() + size());
- tag().set_allocated_size(size() + length);
- } else {
- UninitializedCopy(first, last, inlined_space() + size());
- tag().set_inline_size(size() + length);
- }
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iterator>
-void InlinedVector<T, N, A>::AppendRange(Iterator first, Iterator last,
- std::input_iterator_tag) {
- std::copy(first, last, std::back_inserter(*this));
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iterator>
-void InlinedVector<T, N, A>::AssignRange(Iterator first, Iterator last,
- std::forward_iterator_tag) {
- auto length = std::distance(first, last);
- // Prefer reassignment to copy construction for elements.
- if (static_cast<size_type>(length) <= size()) {
- erase(std::copy(first, last, begin()), end());
- return;
- }
- reserve(length);
- iterator out = begin();
- for (; out != end(); ++first, ++out) *out = *first;
- if (allocated()) {
- UninitializedCopy(first, last, out);
- tag().set_allocated_size(length);
- } else {
- UninitializedCopy(first, last, out);
- tag().set_inline_size(length);
- }
-}
-
-template <typename T, size_t N, typename A>
-template <typename Iterator>
-void InlinedVector<T, N, A>::AssignRange(Iterator first, Iterator last,
- std::input_iterator_tag) {
- // Optimized to avoid reallocation.
- // Prefer reassignment to copy construction for elements.
- iterator out = begin();
- for (; first != last && out != end(); ++first, ++out) {
- *out = *first;
- }
- erase(out, end());
- std::copy(first, last, std::back_inserter(*this));
-}
-
-template <typename T, size_t N, typename A>
-auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position,
- size_type n, const_reference v)
- -> iterator {
- assert(position >= begin() && position <= end());
- if (ABSL_PREDICT_FALSE(n == 0)) return const_cast<iterator>(position);
-
- value_type copy = v;
- std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
- std::fill(it_pair.first, it_pair.second, copy);
- UninitializedFill(it_pair.second, it_pair.first + n, copy);
-
- return it_pair.first;
-}
-
-template <typename T, size_t N, typename A>
-template <typename ForwardIterator>
-auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
- ForwardIterator first,
- ForwardIterator last,
- std::forward_iterator_tag)
- -> iterator {
- assert(position >= begin() && position <= end());
- if (ABSL_PREDICT_FALSE(first == last)) return const_cast<iterator>(position);
-
- auto n = std::distance(first, last);
- std::pair<iterator, iterator> it_pair = ShiftRight(position, n);
- size_type used_spots = it_pair.second - it_pair.first;
- ForwardIterator open_spot = std::next(first, used_spots);
- std::copy(first, open_spot, it_pair.first);
- UninitializedCopy(open_spot, last, it_pair.second);
- return it_pair.first;
-}
-
-template <typename T, size_t N, typename A>
-template <typename InputIterator>
-auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position,
- InputIterator first,
- InputIterator last,
- std::input_iterator_tag)
- -> iterator {
- assert(position >= begin() && position <= end());
- size_type index = position - cbegin();
- size_type i = index;
- while (first != last) insert(begin() + i++, *first++);
- return begin() + index;
+// Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
+// call this directly.
+template <typename H, typename T, size_t N, typename A>
+H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
+ auto size = a.size();
+ return H::combine(H::combine_contiguous(std::move(h), a.data(), size), size);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc
index a3ad0f8a..b99bbd62 100644
--- a/absl/container/inlined_vector_benchmark.cc
+++ b/absl/container/inlined_vector_benchmark.cc
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,28 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "absl/container/inlined_vector.h"
-
+#include <array>
#include <string>
#include <vector>
#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/inlined_vector.h"
#include "absl/strings/str_cat.h"
namespace {
-using IntVec = absl::InlinedVector<int, 8>;
-
void BM_InlinedVectorFill(benchmark::State& state) {
- const int len = state.range(0);
+ absl::InlinedVector<int, 8> v;
+ int val = 10;
for (auto _ : state) {
- IntVec v;
- for (int i = 0; i < len; i++) {
- v.push_back(i);
- }
+ benchmark::DoNotOptimize(v);
+ v.push_back(val);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
@@ -43,23 +40,25 @@ void BM_InlinedVectorFillRange(benchmark::State& state) {
for (int i = 0; i < len; i++) {
ia[i] = i;
}
+ auto* from = ia.get();
+ auto* to = from + len;
for (auto _ : state) {
- IntVec v(ia.get(), ia.get() + len);
+ benchmark::DoNotOptimize(from);
+ benchmark::DoNotOptimize(to);
+ absl::InlinedVector<int, 8> v(from, to);
benchmark::DoNotOptimize(v);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
void BM_StdVectorFill(benchmark::State& state) {
- const int len = state.range(0);
+ std::vector<int> v;
+ int val = 10;
for (auto _ : state) {
- std::vector<int> v;
- for (int i = 0; i < len; i++) {
- v.push_back(i);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(val);
+ v.push_back(val);
}
- state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
}
BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
@@ -89,7 +88,7 @@ void BM_InlinedVectorFillString(benchmark::State& state) {
const int len = state.range(0);
const int no_sso = GetNonShortStringOptimizationSize();
std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
- std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+ std::string(no_sso, 'C'), std::string(no_sso, 'D')};
for (auto _ : state) {
absl::InlinedVector<std::string, 8> v;
@@ -105,7 +104,7 @@ void BM_StdVectorFillString(benchmark::State& state) {
const int len = state.range(0);
const int no_sso = GetNonShortStringOptimizationSize();
std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
- std::string(no_sso, 'C'), std::string(no_sso, 'D')};
+ std::string(no_sso, 'C'), std::string(no_sso, 'D')};
for (auto _ : state) {
std::vector<std::string> v;
@@ -124,7 +123,7 @@ struct Buffer { // some arbitrary structure for benchmarking.
void* user_data;
};
-void BM_InlinedVectorTenAssignments(benchmark::State& state) {
+void BM_InlinedVectorAssignments(benchmark::State& state) {
const int len = state.range(0);
using BufferVec = absl::InlinedVector<Buffer, 2>;
@@ -133,18 +132,25 @@ void BM_InlinedVectorTenAssignments(benchmark::State& state) {
BufferVec dst;
for (auto _ : state) {
- for (int i = 0; i < 10; ++i) {
- dst = src;
- }
+ benchmark::DoNotOptimize(dst);
+ benchmark::DoNotOptimize(src);
+ dst = src;
}
}
-BENCHMARK(BM_InlinedVectorTenAssignments)
- ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
+BENCHMARK(BM_InlinedVectorAssignments)
+ ->Arg(0)
+ ->Arg(1)
+ ->Arg(2)
+ ->Arg(3)
+ ->Arg(4)
+ ->Arg(20);
void BM_CreateFromContainer(benchmark::State& state) {
for (auto _ : state) {
- absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
- benchmark::DoNotOptimize(x);
+ absl::InlinedVector<int, 4> src{1, 2, 3};
+ benchmark::DoNotOptimize(src);
+ absl::InlinedVector<int, 4> dst(std::move(src));
+ benchmark::DoNotOptimize(dst);
}
}
BENCHMARK(BM_CreateFromContainer);
@@ -159,15 +165,14 @@ struct LargeCopyableOnly {
struct LargeCopyableSwappable {
LargeCopyableSwappable() : d(1024, 17) {}
+
LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
- LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
using std::swap;
swap(*this, o);
return *this;
}
- LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
using std::swap;
@@ -215,6 +220,8 @@ void BM_SwapElements(benchmark::State& state) {
Vec b;
for (auto _ : state) {
using std::swap;
+ benchmark::DoNotOptimize(a);
+ benchmark::DoNotOptimize(b);
swap(a, b);
}
}
@@ -260,60 +267,44 @@ BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
void BM_InlinedVectorIndexInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorIndexInlined);
void BM_InlinedVectorIndexExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorIndexExternal);
void BM_StdVectorIndex(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- for (int i = 0; i < 1000; ++i) {
- benchmark::DoNotOptimize(v);
- benchmark::DoNotOptimize(v[4]);
- }
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v[4]);
}
- state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorIndex);
-#define UNROLL_2(x) \
- benchmark::DoNotOptimize(x); \
- benchmark::DoNotOptimize(x);
-
-#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
-#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
-#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
-
void BM_InlinedVectorDataInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorDataInlined);
void BM_InlinedVectorDataExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
@@ -322,7 +313,8 @@ BENCHMARK(BM_InlinedVectorDataExternal);
void BM_StdVectorData(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.data());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.data());
}
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
@@ -331,55 +323,482 @@ BENCHMARK(BM_StdVectorData);
void BM_InlinedVectorSizeInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorSizeInlined);
void BM_InlinedVectorSizeExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorSizeExternal);
void BM_StdVectorSize(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.size());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.size());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorSize);
void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorEmptyInlined);
void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_InlinedVectorEmptyExternal);
void BM_StdVectorEmpty(benchmark::State& state) {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (auto _ : state) {
- UNROLL_16(v.empty());
+ benchmark::DoNotOptimize(v);
+ benchmark::DoNotOptimize(v.empty());
}
- state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
}
BENCHMARK(BM_StdVectorEmpty);
+constexpr size_t kInlinedCapacity = 4;
+constexpr size_t kLargeSize = kInlinedCapacity * 2;
+constexpr size_t kSmallSize = kInlinedCapacity / 2;
+constexpr size_t kBatchSize = 100;
+
+#define ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_FunctionTemplate, T) \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize); \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize)
+
+#define ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_FunctionTemplate, T) \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize, kLargeSize); \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize, kSmallSize); \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize, kLargeSize); \
+ BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize, kSmallSize)
+
+template <typename T>
+using InlVec = absl::InlinedVector<T, kInlinedCapacity>;
+
+struct TrivialType {
+ size_t val;
+};
+
+class NontrivialType {
+ public:
+ ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {
+ benchmark::DoNotOptimize(*this);
+ }
+
+ ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other)
+ : val_(other.val_) {
+ benchmark::DoNotOptimize(*this);
+ }
+
+ ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=(
+ const NontrivialType& other) {
+ val_ = other.val_;
+ benchmark::DoNotOptimize(*this);
+ return *this;
+ }
+
+ ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {
+ benchmark::DoNotOptimize(*this);
+ }
+
+ private:
+ size_t val_;
+};
+
+template <typename T, typename PrepareVecFn, typename TestVecFn>
+void BatchedBenchmark(benchmark::State& state, PrepareVecFn prepare_vec,
+ TestVecFn test_vec) {
+ std::array<InlVec<T>, kBatchSize> vector_batch{};
+
+ while (state.KeepRunningBatch(kBatchSize)) {
+ // Prepare batch
+ state.PauseTiming();
+ for (size_t i = 0; i < kBatchSize; ++i) {
+ prepare_vec(vector_batch.data() + i, i);
+ }
+ benchmark::DoNotOptimize(vector_batch);
+ state.ResumeTiming();
+
+ // Test batch
+ for (size_t i = 0; i < kBatchSize; ++i) {
+ test_vec(vector_batch.data() + i, i);
+ }
+ }
+}
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromSize(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ auto size = ToSize;
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(size);
+ ::new (ptr) VecT(size);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromSizeRef(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ auto size = ToSize;
+ auto ref = T();
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(size);
+ benchmark::DoNotOptimize(ref);
+ ::new (ptr) VecT(size, ref);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromRange(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<T, ToSize> arr{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(arr);
+ ::new (ptr) VecT(arr.begin(), arr.end());
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromCopy(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ VecT other_vec(ToSize);
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) { vec->~VecT(); },
+ /* test_vec = */
+ [&](void* ptr, size_t) {
+ benchmark::DoNotOptimize(other_vec);
+ ::new (ptr) VecT(other_vec);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, NontrivialType);
+
+template <typename T, size_t ToSize>
+void BM_ConstructFromMove(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<VecT, kBatchSize> vector_batch{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ vector_batch[i].clear();
+ vector_batch[i].resize(ToSize);
+ vec->~VecT();
+ },
+ /* test_vec = */
+ [&](void* ptr, size_t i) {
+ benchmark::DoNotOptimize(vector_batch[i]);
+ ::new (ptr) VecT(std::move(vector_batch[i]));
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_AssignSizeRef(benchmark::State& state) {
+ auto size = ToSize;
+ auto ref = T();
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(size);
+ benchmark::DoNotOptimize(ref);
+ vec->assign(size, ref);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignSizeRef, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_AssignRange(benchmark::State& state) {
+ std::array<T, ToSize> arr{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(arr);
+ vec->assign(arr.begin(), arr.end());
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignRange, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_AssignFromCopy(benchmark::State& state) {
+ InlVec<T> other_vec(ToSize);
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(other_vec);
+ *vec = other_vec;
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromCopy, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromCopy, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_AssignFromMove(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<VecT, kBatchSize> vector_batch{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ vector_batch[i].clear();
+ vector_batch[i].resize(ToSize);
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ benchmark::DoNotOptimize(vector_batch[i]);
+ *vec = std::move(vector_batch[i]);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromMove, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromMove, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_ResizeSize(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) { vec->resize(ToSize); });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSize, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSize, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_ResizeSizeRef(benchmark::State& state) {
+ auto t = T();
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(t);
+ vec->resize(ToSize, t);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSizeRef, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_InsertSizeRef(benchmark::State& state) {
+ auto t = T();
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(t);
+ auto* pos = vec->data() + (vec->size() / 2);
+ vec->insert(pos, t);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertSizeRef, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertSizeRef, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_InsertRange(benchmark::State& state) {
+ InlVec<T> other_vec(ToSize);
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t) {
+ benchmark::DoNotOptimize(other_vec);
+ auto* pos = vec->data() + (vec->size() / 2);
+ vec->insert(pos, other_vec.begin(), other_vec.end());
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertRange, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_EmplaceBack(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) { vec->emplace_back(); });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EmplaceBack, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EmplaceBack, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_PopBack(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) { vec->pop_back(); });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_PopBack, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_PopBack, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_EraseOne(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) {
+ auto* pos = vec->data() + (vec->size() / 2);
+ vec->erase(pos);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseOne, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseOne, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_EraseRange(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) {
+ auto* pos = vec->data() + (vec->size() / 2);
+ vec->erase(pos, pos + 1);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseRange, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseRange, NontrivialType);
+
+template <typename T, size_t FromSize>
+void BM_Clear(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); },
+ /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->clear(); });
+}
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, TrivialType);
+ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToCapacity>
+void BM_Reserve(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [](InlVec<T>* vec, size_t) { vec->reserve(ToCapacity); });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Reserve, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Reserve, NontrivialType);
+
+template <typename T, size_t FromCapacity, size_t ToCapacity>
+void BM_ShrinkToFit(benchmark::State& state) {
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [](InlVec<T>* vec, size_t) {
+ vec->clear();
+ vec->resize(ToCapacity);
+ vec->reserve(FromCapacity);
+ },
+ /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->shrink_to_fit(); });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ShrinkToFit, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ShrinkToFit, NontrivialType);
+
+template <typename T, size_t FromSize, size_t ToSize>
+void BM_Swap(benchmark::State& state) {
+ using VecT = InlVec<T>;
+ std::array<VecT, kBatchSize> vector_batch{};
+ BatchedBenchmark<T>(
+ state,
+ /* prepare_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ vector_batch[i].clear();
+ vector_batch[i].resize(ToSize);
+ vec->resize(FromSize);
+ },
+ /* test_vec = */
+ [&](InlVec<T>* vec, size_t i) {
+ using std::swap;
+ benchmark::DoNotOptimize(vector_batch[i]);
+ swap(*vec, vector_batch[i]);
+ });
+}
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Swap, TrivialType);
+ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Swap, NontrivialType);
+
} // namespace
diff --git a/absl/container/inlined_vector_exception_safety_test.cc b/absl/container/inlined_vector_exception_safety_test.cc
new file mode 100644
index 00000000..ff0da75b
--- /dev/null
+++ b/absl/container/inlined_vector_exception_safety_test.cc
@@ -0,0 +1,489 @@
+// 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.
+
+#include <array>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/exception_safety_testing.h"
+#include "absl/container/inlined_vector.h"
+
+namespace {
+
+constexpr size_t kInlinedCapacity = 4;
+constexpr size_t kLargeSize = kInlinedCapacity * 2;
+constexpr size_t kSmallSize = kInlinedCapacity / 2;
+
+using Thrower = testing::ThrowingValue<>;
+using MovableThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
+using ThrowAlloc = testing::ThrowingAllocator<Thrower>;
+
+using ThrowerVec = absl::InlinedVector<Thrower, kInlinedCapacity>;
+using MovableThrowerVec = absl::InlinedVector<MovableThrower, kInlinedCapacity>;
+
+using ThrowAllocThrowerVec =
+ absl::InlinedVector<Thrower, kInlinedCapacity, ThrowAlloc>;
+using ThrowAllocMovableThrowerVec =
+ absl::InlinedVector<MovableThrower, kInlinedCapacity, ThrowAlloc>;
+
+// In GCC, if an element of a `std::initializer_list` throws during construction
+// the elements that were constructed before it are not destroyed. This causes
+// incorrect exception safety test failures. Thus, `testing::nothrow_ctor` is
+// required. See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66139
+#define ABSL_INTERNAL_MAKE_INIT_LIST(T, N) \
+ (N > kInlinedCapacity \
+ ? std::initializer_list<T>{T(0, testing::nothrow_ctor), \
+ T(1, testing::nothrow_ctor), \
+ T(2, testing::nothrow_ctor), \
+ T(3, testing::nothrow_ctor), \
+ T(4, testing::nothrow_ctor), \
+ T(5, testing::nothrow_ctor), \
+ T(6, testing::nothrow_ctor), \
+ T(7, testing::nothrow_ctor)} \
+ \
+ : std::initializer_list<T>{T(0, testing::nothrow_ctor), \
+ T(1, testing::nothrow_ctor)})
+static_assert((kLargeSize == 8 || kSmallSize == 2),
+ "Must update ABSL_INTERNAL_MAKE_INIT_LIST(...).");
+
+template <typename TheVecT, size_t... TheSizes>
+class TestParams {
+ public:
+ using VecT = TheVecT;
+ constexpr static size_t GetSizeAt(size_t i) { return kSizes[1 + i]; }
+
+ private:
+ constexpr static size_t kSizes[1 + sizeof...(TheSizes)] = {1, TheSizes...};
+};
+
+using NoSizeTestParams =
+ ::testing::Types<TestParams<ThrowerVec>, TestParams<MovableThrowerVec>,
+ TestParams<ThrowAllocThrowerVec>,
+ TestParams<ThrowAllocMovableThrowerVec>>;
+
+using OneSizeTestParams =
+ ::testing::Types<TestParams<ThrowerVec, kLargeSize>,
+ TestParams<ThrowerVec, kSmallSize>,
+ TestParams<MovableThrowerVec, kLargeSize>,
+ TestParams<MovableThrowerVec, kSmallSize>,
+ TestParams<ThrowAllocThrowerVec, kLargeSize>,
+ TestParams<ThrowAllocThrowerVec, kSmallSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kLargeSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kSmallSize>>;
+
+using TwoSizeTestParams = ::testing::Types<
+ TestParams<ThrowerVec, kLargeSize, kLargeSize>,
+ TestParams<ThrowerVec, kLargeSize, kSmallSize>,
+ TestParams<ThrowerVec, kSmallSize, kLargeSize>,
+ TestParams<ThrowerVec, kSmallSize, kSmallSize>,
+ TestParams<MovableThrowerVec, kLargeSize, kLargeSize>,
+ TestParams<MovableThrowerVec, kLargeSize, kSmallSize>,
+ TestParams<MovableThrowerVec, kSmallSize, kLargeSize>,
+ TestParams<MovableThrowerVec, kSmallSize, kSmallSize>,
+ TestParams<ThrowAllocThrowerVec, kLargeSize, kLargeSize>,
+ TestParams<ThrowAllocThrowerVec, kLargeSize, kSmallSize>,
+ TestParams<ThrowAllocThrowerVec, kSmallSize, kLargeSize>,
+ TestParams<ThrowAllocThrowerVec, kSmallSize, kSmallSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kLargeSize, kLargeSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kLargeSize, kSmallSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kSmallSize, kLargeSize>,
+ TestParams<ThrowAllocMovableThrowerVec, kSmallSize, kSmallSize>>;
+
+template <typename>
+struct NoSizeTest : ::testing::Test {};
+TYPED_TEST_SUITE(NoSizeTest, NoSizeTestParams);
+
+template <typename>
+struct OneSizeTest : ::testing::Test {};
+TYPED_TEST_SUITE(OneSizeTest, OneSizeTestParams);
+
+template <typename>
+struct TwoSizeTest : ::testing::Test {};
+TYPED_TEST_SUITE(TwoSizeTest, TwoSizeTestParams);
+
+template <typename VecT>
+bool InlinedVectorInvariants(VecT* vec) {
+ if (*vec != *vec) return false;
+ if (vec->size() > vec->capacity()) return false;
+ if (vec->size() > vec->max_size()) return false;
+ if (vec->capacity() > vec->max_size()) return false;
+ if (vec->data() != std::addressof(vec->at(0))) return false;
+ if (vec->data() != vec->begin()) return false;
+ if (*vec->data() != *vec->begin()) return false;
+ if (vec->begin() > vec->end()) return false;
+ if ((vec->end() - vec->begin()) != vec->size()) return false;
+ if (std::distance(vec->begin(), vec->end()) != vec->size()) return false;
+ return true;
+}
+
+// Function that always returns false is correct, but refactoring is required
+// for clarity. It's needed to express that, as a contract, certain operations
+// should not throw at all. Execution of this function means an exception was
+// thrown and thus the test should fail.
+// TODO(johnsoncj): Add `testing::NoThrowGuarantee` to the framework
+template <typename VecT>
+bool NoThrowGuarantee(VecT* /* vec */) {
+ return false;
+}
+
+TYPED_TEST(NoSizeTest, DefaultConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using allocator_type = typename VecT::allocator_type;
+
+ testing::TestThrowingCtor<VecT>();
+
+ testing::TestThrowingCtor<VecT>(allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, SizeConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ testing::TestThrowingCtor<VecT>(size);
+
+ testing::TestThrowingCtor<VecT>(size, allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, SizeRefConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ testing::TestThrowingCtor<VecT>(size, value_type{});
+
+ testing::TestThrowingCtor<VecT>(size, value_type{}, allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, InitializerListConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ testing::TestThrowingCtor<VecT>(
+ ABSL_INTERNAL_MAKE_INIT_LIST(value_type, size));
+
+ testing::TestThrowingCtor<VecT>(
+ ABSL_INTERNAL_MAKE_INIT_LIST(value_type, size), allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, RangeConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ std::array<value_type, size> arr{};
+
+ testing::TestThrowingCtor<VecT>(arr.begin(), arr.end());
+
+ testing::TestThrowingCtor<VecT>(arr.begin(), arr.end(), allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, CopyConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ VecT other_vec{size};
+
+ testing::TestThrowingCtor<VecT>(other_vec);
+
+ testing::TestThrowingCtor<VecT>(other_vec, allocator_type{});
+}
+
+TYPED_TEST(OneSizeTest, MoveConstructor) {
+ using VecT = typename TypeParam::VecT;
+ using allocator_type = typename VecT::allocator_type;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ if (!absl::allocator_is_nothrow<allocator_type>::value) {
+ testing::TestThrowingCtor<VecT>(VecT{size});
+
+ testing::TestThrowingCtor<VecT>(VecT{size}, allocator_type{});
+ }
+}
+
+TYPED_TEST(TwoSizeTest, Assign) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+ constexpr static auto to_size = TypeParam::GetSizeAt(1);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ *vec = ABSL_INTERNAL_MAKE_INIT_LIST(value_type, to_size);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ VecT other_vec{to_size};
+ *vec = other_vec;
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ VecT other_vec{to_size};
+ *vec = std::move(other_vec);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ value_type val{};
+ vec->assign(to_size, val);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->assign(ABSL_INTERNAL_MAKE_INIT_LIST(value_type, to_size));
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ std::array<value_type, to_size> arr{};
+ vec->assign(arr.begin(), arr.end());
+ }));
+}
+
+TYPED_TEST(TwoSizeTest, Resize) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+ constexpr static auto to_size = TypeParam::GetSizeAt(1);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>,
+ testing::strong_guarantee);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->resize(to_size); //
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->resize(to_size, value_type{}); //
+ }));
+}
+
+TYPED_TEST(OneSizeTest, Insert) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ vec->insert(it, value_type{});
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->insert(it, value_type{});
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->end();
+ vec->insert(it, value_type{});
+ }));
+}
+
+TYPED_TEST(TwoSizeTest, Insert) {
+ using VecT = typename TypeParam::VecT;
+ using value_type = typename VecT::value_type;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+ constexpr static auto count = TypeParam::GetSizeAt(1);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ vec->insert(it, count, value_type{});
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->insert(it, count, value_type{});
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->end();
+ vec->insert(it, count, value_type{});
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ vec->insert(it, ABSL_INTERNAL_MAKE_INIT_LIST(value_type, count));
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->insert(it, ABSL_INTERNAL_MAKE_INIT_LIST(value_type, count));
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->end();
+ vec->insert(it, ABSL_INTERNAL_MAKE_INIT_LIST(value_type, count));
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ std::array<value_type, count> arr{};
+ vec->insert(it, arr.begin(), arr.end());
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ std::array<value_type, count> arr{};
+ vec->insert(it, arr.begin(), arr.end());
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->end();
+ std::array<value_type, count> arr{};
+ vec->insert(it, arr.begin(), arr.end());
+ }));
+}
+
+TYPED_TEST(OneSizeTest, EmplaceBack) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ VecT full_vec{size};
+ full_vec.resize(full_vec.capacity());
+
+ VecT nonfull_vec{size};
+ nonfull_vec.reserve(size + 1);
+
+ auto tester = testing::MakeExceptionSafetyTester().WithContracts(
+ InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.WithInitialValue(nonfull_vec).Test([](VecT* vec) {
+ vec->emplace_back(); //
+ }));
+
+ EXPECT_TRUE(tester.WithInitialValue(full_vec).Test([](VecT* vec) {
+ vec->emplace_back(); //
+ }));
+}
+
+TYPED_TEST(OneSizeTest, PopBack) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{size})
+ .WithContracts(NoThrowGuarantee<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->pop_back(); //
+ }));
+}
+
+TYPED_TEST(OneSizeTest, Erase) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ vec->erase(it);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->erase(it);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() - 1);
+ vec->erase(it);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin();
+ vec->erase(it, it + 1);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() / 2);
+ vec->erase(it, it + 1);
+ }));
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ auto it = vec->begin() + (vec->size() - 1);
+ vec->erase(it, it + 1);
+ }));
+}
+
+TYPED_TEST(OneSizeTest, Clear) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{size})
+ .WithContracts(NoThrowGuarantee<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->clear(); //
+ }));
+}
+
+TYPED_TEST(TwoSizeTest, Reserve) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+ constexpr static auto to_capacity = TypeParam::GetSizeAt(1);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->reserve(to_capacity); //
+ }));
+}
+
+TYPED_TEST(OneSizeTest, ShrinkToFit) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto size = TypeParam::GetSizeAt(0);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ vec->shrink_to_fit(); //
+ }));
+}
+
+TYPED_TEST(TwoSizeTest, Swap) {
+ using VecT = typename TypeParam::VecT;
+ constexpr static auto from_size = TypeParam::GetSizeAt(0);
+ constexpr static auto to_size = TypeParam::GetSizeAt(1);
+
+ auto tester = testing::MakeExceptionSafetyTester()
+ .WithInitialValue(VecT{from_size})
+ .WithContracts(InlinedVectorInvariants<VecT>);
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ VecT other_vec{to_size};
+ vec->swap(other_vec);
+ }));
+
+ EXPECT_TRUE(tester.Test([](VecT* vec) {
+ using std::swap;
+ VecT other_vec{to_size};
+ swap(*vec, other_vec);
+ }));
+}
+
+} // namespace
diff --git a/absl/container/inlined_vector_test.cc b/absl/container/inlined_vector_test.cc
index 3a1ea8ac..bada4fec 100644
--- a/absl/container/inlined_vector_test.cc
+++ b/absl/container/inlined_vector_test.cc
@@ -1,10 +1,10 @@
-// Copyright 2017 The Abseil Authors.
+// 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
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,6 +30,7 @@
#include "absl/base/internal/exception_testing.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h"
+#include "absl/container/internal/counting_allocator.h"
#include "absl/container/internal/test_instance_tracker.h"
#include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h"
@@ -37,6 +38,7 @@
namespace {
+using absl::container_internal::CountingAllocator;
using absl::test_internal::CopyableMovableInstance;
using absl::test_internal::CopyableOnlyInstance;
using absl::test_internal::InstanceTracker;
@@ -68,18 +70,15 @@ MATCHER_P(ValueIs, e, "") {
// test_instance_tracker.h.
template <typename T>
class InstanceTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(InstanceTest);
+TYPED_TEST_SUITE_P(InstanceTest);
// A simple reference counted class to make sure that the proper elements are
// destroyed in the erase(begin, end) test.
class RefCounted {
public:
- RefCounted(int value, int* count) : value_(value), count_(count) {
- Ref();
- }
+ RefCounted(int value, int* count) : value_(value), count_(count) { Ref(); }
- RefCounted(const RefCounted& v)
- : value_(v.value_), count_(v.count_) {
+ RefCounted(const RefCounted& v) : value_(v.value_), count_(v.count_) {
Ref();
}
@@ -138,57 +137,6 @@ static IntVec Fill(int len, int offset = 0) {
return v;
}
-// This is a stateful allocator, but the state lives outside of the
-// allocator (in whatever test is using the allocator). This is odd
-// but helps in tests where the allocator is propagated into nested
-// containers - that chain of allocators uses the same state and is
-// thus easier to query for aggregate allocation information.
-template <typename T>
-class CountingAllocator : public std::allocator<T> {
- public:
- using Alloc = std::allocator<T>;
- using pointer = typename Alloc::pointer;
- using size_type = typename Alloc::size_type;
-
- CountingAllocator() : bytes_used_(nullptr) {}
- explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
-
- template <typename U>
- CountingAllocator(const CountingAllocator<U>& x)
- : Alloc(x), bytes_used_(x.bytes_used_) {}
-
- pointer allocate(size_type n,
- std::allocator<void>::const_pointer hint = nullptr) {
- assert(bytes_used_ != nullptr);
- *bytes_used_ += n * sizeof(T);
- return Alloc::allocate(n, hint);
- }
-
- void deallocate(pointer p, size_type n) {
- Alloc::deallocate(p, n);
- assert(bytes_used_ != nullptr);
- *bytes_used_ -= n * sizeof(T);
- }
-
- template<typename U>
- class rebind {
- public:
- using other = CountingAllocator<U>;
- };
-
- friend bool operator==(const CountingAllocator& a,
- const CountingAllocator& b) {
- return a.bytes_used_ == b.bytes_used_;
- }
-
- friend bool operator!=(const CountingAllocator& a,
- const CountingAllocator& b) {
- return !(a == b);
- }
-
- int64_t* bytes_used_;
-};
-
TEST(IntVec, SimpleOps) {
for (int len = 0; len < 20; len++) {
IntVec v;
@@ -239,6 +187,12 @@ TEST(IntVec, SimpleOps) {
}
}
+TEST(IntVec, PopBackNoOverflow) {
+ IntVec v = {1};
+ v.pop_back();
+ EXPECT_EQ(v.size(), 0);
+}
+
TEST(IntVec, AtThrows) {
IntVec v = {1, 2, 3};
EXPECT_EQ(v.at(2), 3);
@@ -333,7 +287,7 @@ TEST(RefCountedVec, EraseBeginEnd) {
}
// Check that the elements at the end are preserved.
- for (int i = erase_end; i< len; ++i) {
+ for (int i = erase_end; i < len; ++i) {
EXPECT_EQ(1, counts[i]);
}
}
@@ -595,10 +549,10 @@ TEST(IntVec, Resize) {
static const int kResizeElem = 1000000;
for (int k = 0; k < 10; k++) {
// Enlarging resize
- v.resize(len+k, kResizeElem);
- EXPECT_EQ(len+k, v.size());
- EXPECT_LE(len+k, v.capacity());
- for (int i = 0; i < len+k; i++) {
+ v.resize(len + k, kResizeElem);
+ EXPECT_EQ(len + k, v.size());
+ EXPECT_LE(len + k, v.capacity());
+ for (int i = 0; i < len + k; i++) {
if (i < len) {
EXPECT_EQ(i, v[i]);
} else {
@@ -909,7 +863,7 @@ TYPED_TEST_P(InstanceTest, Swap) {
auto min_len = std::min(l1, l2);
auto max_len = std::max(l1, l2);
for (int i = 0; i < l1; i++) a.push_back(Instance(i));
- for (int i = 0; i < l2; i++) b.push_back(Instance(100+i));
+ for (int i = 0; i < l2; i++) b.push_back(Instance(100 + i));
EXPECT_EQ(tracker.instances(), l1 + l2);
tracker.ResetCopiesMovesSwaps();
{
@@ -977,7 +931,7 @@ TEST(IntVec, EqualAndNotEqual) {
EXPECT_FALSE(a == b);
EXPECT_TRUE(a != b);
- b[i] = b[i] - 1; // Back to before
+ b[i] = b[i] - 1; // Back to before
EXPECT_TRUE(a == b);
EXPECT_FALSE(a != b);
}
@@ -1044,7 +998,7 @@ TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) {
// reserve() must not increase the number of initialized objects
SCOPED_TRACE("reserve");
- v.reserve(len+1000);
+ v.reserve(len + 1000);
EXPECT_EQ(tracker.instances(), len);
EXPECT_EQ(tracker.copies() + tracker.moves(), len);
@@ -1290,9 +1244,8 @@ void InstanceCountElemAssignWithAllocationTest() {
absl::InlinedVector<Instance, 2> v(original_contents.begin(),
original_contents.end());
v.assign(3, Instance(123));
- EXPECT_THAT(v,
- AllOf(SizeIs(3),
- ElementsAre(ValueIs(123), ValueIs(123), ValueIs(123))));
+ EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(ValueIs(123), ValueIs(123),
+ ValueIs(123))));
EXPECT_LE(v.size(), v.capacity());
}
}
@@ -1571,8 +1524,8 @@ TYPED_TEST_P(InstanceTest, InitializerListAssign) {
SCOPED_TRACE(original_size);
absl::InlinedVector<Instance, 2> v(original_size, Instance(12345));
v.assign({Instance(3), Instance(4), Instance(5)});
- EXPECT_THAT(v, AllOf(SizeIs(3),
- ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
+ EXPECT_THAT(
+ v, AllOf(SizeIs(3), ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5))));
EXPECT_LE(3, v.capacity());
}
}
@@ -1597,7 +1550,7 @@ TEST(DynamicVec, DynamicVecCompiles) {
TEST(AllocatorSupportTest, Constructors) {
using MyAlloc = CountingAllocator<int>;
using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
int64_t allocated = 0;
MyAlloc alloc(&allocated);
{ AllocVec ABSL_ATTRIBUTE_UNUSED v; }
@@ -1613,7 +1566,7 @@ TEST(AllocatorSupportTest, Constructors) {
TEST(AllocatorSupportTest, CountAllocations) {
using MyAlloc = CountingAllocator<int>;
using AllocVec = absl::InlinedVector<int, 4, MyAlloc>;
- const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+ const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
int64_t allocated = 0;
MyAlloc alloc(&allocated);
{
@@ -1677,8 +1630,8 @@ TEST(AllocatorSupportTest, SwapBothAllocated) {
int64_t allocated1 = 0;
int64_t allocated2 = 0;
{
- const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- const int ia2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+ const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
+ const int ia2[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
MyAlloc a1(&allocated1);
MyAlloc a2(&allocated2);
AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
@@ -1702,8 +1655,8 @@ TEST(AllocatorSupportTest, SwapOneAllocated) {
int64_t allocated1 = 0;
int64_t allocated2 = 0;
{
- const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
- const int ia2[] = { 0, 1, 2, 3 };
+ const int ia1[] = {0, 1, 2, 3, 4, 5, 6, 7};
+ const int ia2[] = {0, 1, 2, 3};
MyAlloc a1(&allocated1);
MyAlloc a2(&allocated2);
AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1);
@@ -1722,67 +1675,53 @@ TEST(AllocatorSupportTest, SwapOneAllocated) {
EXPECT_THAT(allocated2, 0);
}
-TEST(AllocatorSupportTest, ScopedAllocatorWorks) {
+TEST(AllocatorSupportTest, ScopedAllocatorWorksInlined) {
using StdVector = std::vector<int, CountingAllocator<int>>;
- using MyAlloc =
- std::scoped_allocator_adaptor<CountingAllocator<StdVector>>;
- using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>;
-
- // MSVC 2017's std::vector allocates different amounts of memory in debug
- // versus opt mode.
- int64_t test_allocated = 0;
- StdVector v(CountingAllocator<int>{&test_allocated});
- // The amount of memory allocated by a default constructed vector<int>
- auto default_std_vec_allocated = test_allocated;
- v.push_back(1);
- // The amound of memory allocated by a copy-constructed vector<int> with one
- // element.
- int64_t one_element_std_vec_copy_allocated = test_allocated;
+ using Alloc = CountingAllocator<StdVector>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
+ using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
- int64_t allocated = 0;
- AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}});
- EXPECT_EQ(allocated, 0);
+ int64_t total_allocated_byte_count = 0;
- // This default constructs a vector<int>, but the allocator should pass itself
- // into the vector<int>, so check allocation compared to that.
- // The absl::InlinedVector does not allocate any memory.
- // The vector<int> may allocate any memory.
- auto expected = default_std_vec_allocated;
- vec.resize(1);
- EXPECT_EQ(allocated, expected);
-
- // We make vector<int> allocate memory.
- // It must go through the allocator even though we didn't construct the
- // vector directly. This assumes that vec[0] doesn't need to grow its
- // allocation.
- expected += sizeof(int);
- vec[0].push_back(1);
- EXPECT_EQ(allocated, expected);
-
- // Another allocating vector.
- expected += one_element_std_vec_copy_allocated;
- vec.push_back(vec[0]);
- EXPECT_EQ(allocated, expected);
-
- // Overflow the inlined memory.
- // The absl::InlinedVector will now allocate.
- expected += sizeof(StdVector) * 8 + default_std_vec_allocated * 3;
- vec.resize(5);
- EXPECT_EQ(allocated, expected);
-
- // Adding one more in external mode should also work.
- expected += one_element_std_vec_copy_allocated;
- vec.push_back(vec[0]);
- EXPECT_EQ(allocated, expected);
-
- // And extending these should still work. This assumes that vec[0] does not
- // need to grow its allocation.
- expected += sizeof(int);
- vec[0].push_back(1);
- EXPECT_EQ(allocated, expected);
-
- vec.clear();
- EXPECT_EQ(allocated, 0);
+ AllocVec inlined_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
+
+ // Called only once to remain inlined
+ inlined_case.emplace_back();
+
+ int64_t absl_responsible_for_count = total_allocated_byte_count;
+ EXPECT_EQ(absl_responsible_for_count, 0);
+
+ inlined_case[0].emplace_back();
+ EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
+
+ inlined_case.clear();
+ inlined_case.shrink_to_fit();
+ EXPECT_EQ(total_allocated_byte_count, 0);
+}
+
+TEST(AllocatorSupportTest, ScopedAllocatorWorksAllocated) {
+ using StdVector = std::vector<int, CountingAllocator<int>>;
+ using Alloc = CountingAllocator<StdVector>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<Alloc>;
+ using AllocVec = absl::InlinedVector<StdVector, 1, ScopedAlloc>;
+
+ int64_t total_allocated_byte_count = 0;
+
+ AllocVec allocated_case(ScopedAlloc(Alloc(+&total_allocated_byte_count)));
+
+ // Called twice to force into being allocated
+ allocated_case.emplace_back();
+ allocated_case.emplace_back();
+
+ int64_t absl_responsible_for_count = total_allocated_byte_count;
+ EXPECT_GT(absl_responsible_for_count, 0);
+
+ allocated_case[1].emplace_back();
+ EXPECT_GT(total_allocated_byte_count, absl_responsible_for_count);
+
+ allocated_case.clear();
+ allocated_case.shrink_to_fit();
+ EXPECT_EQ(total_allocated_byte_count, 0);
}
TEST(AllocatorSupportTest, SizeAllocConstructor) {
@@ -1811,4 +1750,23 @@ TEST(AllocatorSupportTest, SizeAllocConstructor) {
}
}
+TEST(InlinedVectorTest, AbslHashValueWorks) {
+ using V = absl::InlinedVector<int, 4>;
+ std::vector<V> cases;
+
+ // Generate a variety of vectors some of these are small enough for the inline
+ // space but are stored out of line.
+ for (int i = 0; i < 10; ++i) {
+ V v;
+ for (int j = 0; j < i; ++j) {
+ v.push_back(j);
+ }
+ cases.push_back(v);
+ v.resize(i % 4);
+ cases.push_back(v);
+ }
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(cases));
+}
+
} // anonymous namespace
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h
new file mode 100644
index 00000000..a02cd5c3
--- /dev/null
+++ b/absl/container/internal/common.h
@@ -0,0 +1,198 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+#define ABSL_CONTAINER_INTERNAL_CONTAINER_H_
+
+#include <cassert>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+template <class, class = void>
+struct IsTransparent : std::false_type {};
+template <class T>
+struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
+ : std::true_type {};
+
+template <bool is_transparent>
+struct KeyArg {
+ // Transparent. Forward `K`.
+ template <typename K, typename key_type>
+ using type = K;
+};
+
+template <>
+struct KeyArg<false> {
+ // Not transparent. Always use `key_type`.
+ template <typename K, typename key_type>
+ using type = key_type;
+};
+
+// The node_handle concept from C++17.
+// We specialize node_handle for sets and maps. node_handle_base holds the
+// common API of both.
+template <typename PolicyTraits, typename Alloc>
+class node_handle_base {
+ protected:
+ using slot_type = typename PolicyTraits::slot_type;
+
+ public:
+ using allocator_type = Alloc;
+
+ constexpr node_handle_base() {}
+ node_handle_base(node_handle_base&& other) noexcept {
+ *this = std::move(other);
+ }
+ ~node_handle_base() { destroy(); }
+ node_handle_base& operator=(node_handle_base&& other) noexcept {
+ destroy();
+ if (!other.empty()) {
+ alloc_ = other.alloc_;
+ PolicyTraits::transfer(alloc(), slot(), other.slot());
+ other.reset();
+ }
+ return *this;
+ }
+
+ bool empty() const noexcept { return !alloc_; }
+ explicit operator bool() const noexcept { return !empty(); }
+ allocator_type get_allocator() const { return *alloc_; }
+
+ protected:
+ friend struct CommonAccess;
+
+ struct transfer_tag_t {};
+ node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
+ : alloc_(a) {
+ PolicyTraits::transfer(alloc(), slot(), s);
+ }
+
+ struct move_tag_t {};
+ node_handle_base(move_tag_t, const allocator_type& a, slot_type* s)
+ : alloc_(a) {
+ PolicyTraits::construct(alloc(), slot(), s);
+ }
+
+ void destroy() {
+ if (!empty()) {
+ PolicyTraits::destroy(alloc(), slot());
+ reset();
+ }
+ }
+
+ void reset() {
+ assert(alloc_.has_value());
+ alloc_ = absl::nullopt;
+ }
+
+ slot_type* slot() const {
+ assert(!empty());
+ return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
+ }
+ allocator_type* alloc() { return std::addressof(*alloc_); }
+
+ private:
+ absl::optional<allocator_type> alloc_;
+ mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
+ slot_space_;
+};
+
+// For sets.
+template <typename Policy, typename PolicyTraits, typename Alloc,
+ typename = void>
+class node_handle : public node_handle_base<PolicyTraits, Alloc> {
+ using Base = typename node_handle::node_handle_base;
+
+ public:
+ using value_type = typename PolicyTraits::value_type;
+
+ constexpr node_handle() {}
+
+ value_type& value() const { return PolicyTraits::element(this->slot()); }
+
+ private:
+ friend struct CommonAccess;
+
+ using Base::Base;
+};
+
+// For maps.
+template <typename Policy, typename PolicyTraits, typename Alloc>
+class node_handle<Policy, PolicyTraits, Alloc,
+ absl::void_t<typename Policy::mapped_type>>
+ : public node_handle_base<PolicyTraits, Alloc> {
+ using Base = typename node_handle::node_handle_base;
+
+ public:
+ using key_type = typename Policy::key_type;
+ using mapped_type = typename Policy::mapped_type;
+
+ constexpr node_handle() {}
+
+ auto key() const -> decltype(PolicyTraits::key(this->slot())) {
+ return PolicyTraits::key(this->slot());
+ }
+
+ mapped_type& mapped() const {
+ return PolicyTraits::value(&PolicyTraits::element(this->slot()));
+ }
+
+ private:
+ friend struct CommonAccess;
+
+ using Base::Base;
+};
+
+// Provide access to non-public node-handle functions.
+struct CommonAccess {
+ template <typename Node>
+ static auto GetSlot(const Node& node) -> decltype(node.slot()) {
+ return node.slot();
+ }
+
+ template <typename Node>
+ static void Reset(Node* node) {
+ node->reset();
+ }
+
+ template <typename T, typename... Args>
+ static T Transfer(Args&&... args) {
+ return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args>
+ static T Move(Args&&... args) {
+ return T(typename T::move_tag_t{}, std::forward<Args>(args)...);
+ }
+};
+
+// Implement the insert_return_type<> concept of C++17.
+template <class Iterator, class NodeType>
+struct InsertReturnType {
+ Iterator position;
+ bool inserted;
+ NodeType node;
+};
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_H_
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h
index 29fe7c12..fbace496 100644
--- a/absl/container/internal/compressed_tuple.h
+++ b/absl/container/internal/compressed_tuple.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,27 +27,28 @@
// const T2& t2 = value.get<2>();
// ...
//
-// http://en.cppreference.com/w/cpp/language/ebo
+// https://en.cppreference.com/w/cpp/language/ebo
#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
+#include <initializer_list>
#include <tuple>
#include <type_traits>
#include <utility>
#include "absl/utility/utility.h"
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__NVCC__)
// We need to mark these classes with this declspec to ensure that
// CompressedTuple happens.
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
-#else // _MSC_VER
+#else
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
-#endif // _MSC_VER
+#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <typename... Ts>
@@ -76,57 +77,110 @@ constexpr bool IsFinal() {
#endif
}
+// We can't use EBCO on other CompressedTuples because that would mean that we
+// derive from multiple Storage<> instantiations with the same I parameter,
+// and potentially from multiple identical Storage<> instantiations. So anytime
+// we use type inheritance rather than encapsulation, we mark
+// CompressedTupleImpl, to make this easy to detect.
+struct uses_inheritance {};
+
template <typename T>
constexpr bool ShouldUseBase() {
- return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>();
+ return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>() &&
+ !std::is_base_of<uses_inheritance, T>::value;
}
// The storage class provides two specializations:
// - For empty classes, it stores T as a base class.
// - For everything else, it stores T as a member.
-template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()>
+template <typename T, size_t I,
+#if defined(_MSC_VER)
+ bool UseBase =
+ ShouldUseBase<typename std::enable_if<true, T>::type>()>
+#else
+ bool UseBase = ShouldUseBase<T>()>
+#endif
struct Storage {
- using T = ElemT<D, I>;
T value;
constexpr Storage() = default;
- explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
- constexpr const T& get() const { return value; }
- T& get() { return value; }
+ template <typename V>
+ explicit constexpr Storage(absl::in_place_t, V&& v)
+ : value(absl::forward<V>(v)) {}
+ constexpr const T& get() const& { return value; }
+ T& get() & { return value; }
+ constexpr const T&& get() const&& { return absl::move(*this).value; }
+ T&& get() && { return std::move(*this).value; }
};
-template <typename D, size_t I>
-struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
- : ElemT<D, I> {
- using T = internal_compressed_tuple::ElemT<D, I>;
+template <typename T, size_t I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T {
constexpr Storage() = default;
- explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
- constexpr const T& get() const { return *this; }
- T& get() { return *this; }
+
+ template <typename V>
+ explicit constexpr Storage(absl::in_place_t, V&& v)
+ : T(absl::forward<V>(v)) {}
+
+ constexpr const T& get() const& { return *this; }
+ T& get() & { return *this; }
+ constexpr const T&& get() const&& { return absl::move(*this); }
+ T&& get() && { return std::move(*this); }
};
-template <typename D, typename I>
+template <typename D, typename I, bool ShouldAnyUseBase>
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
-template <typename... Ts, size_t... I>
-struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
- CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>>
+template <typename... Ts, size_t... I, bool ShouldAnyUseBase>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
+ CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase>
// We use the dummy identity function through std::integral_constant to
// convince MSVC of accepting and expanding I in that context. Without it
// you would get:
// error C3548: 'I': parameter pack cannot be used in this context
- : Storage<CompressedTuple<Ts...>,
- std::integral_constant<size_t, I>::value>... {
+ : uses_inheritance,
+ Storage<Ts, std::integral_constant<size_t, I>::value>... {
constexpr CompressedTupleImpl() = default;
- explicit constexpr CompressedTupleImpl(Ts&&... args)
- : Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {}
+ template <typename... Vs>
+ explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
+ : Storage<Ts, I>(absl::in_place, absl::forward<Vs>(args))... {}
+ friend CompressedTuple<Ts...>;
};
+template <typename... Ts, size_t... I>
+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
+ CompressedTuple<Ts...>, absl::index_sequence<I...>, false>
+ // We use the dummy identity function as above...
+ : Storage<Ts, std::integral_constant<size_t, I>::value, false>... {
+ constexpr CompressedTupleImpl() = default;
+ template <typename... Vs>
+ explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
+ : Storage<Ts, I, false>(absl::in_place, absl::forward<Vs>(args))... {}
+ friend CompressedTuple<Ts...>;
+};
+
+std::false_type Or(std::initializer_list<std::false_type>);
+std::true_type Or(std::initializer_list<bool>);
+
+// MSVC requires this to be done separately rather than within the declaration
+// of CompressedTuple below.
+template <typename... Ts>
+constexpr bool ShouldAnyUseBase() {
+ return decltype(
+ Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){};
+}
+
+template <typename T, typename V>
+using TupleMoveConstructible = typename std::conditional<
+ std::is_reference<T>::value, std::is_convertible<V, T>,
+ std::is_constructible<T, V&&>>::type;
+
} // namespace internal_compressed_tuple
// Helper class to perform the Empty Base Class Optimization.
// Ts can contain classes and non-classes, empty or not. For the ones that
// are empty classes, we perform the CompressedTuple. If all types in Ts are
-// empty classes, then CompressedTuple<Ts...> is itself an empty class.
+// empty classes, then CompressedTuple<Ts...> is itself an empty class. (This
+// does not apply when one or more of those empty classes is itself an empty
+// CompressedTuple.)
//
// To access the members, use member .get<N>() function.
//
@@ -138,28 +192,62 @@ struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
// const T2& t2 = value.get<2>();
// ...
//
-// http://en.cppreference.com/w/cpp/language/ebo
+// https://en.cppreference.com/w/cpp/language/ebo
template <typename... Ts>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
: private internal_compressed_tuple::CompressedTupleImpl<
- CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> {
+ CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>,
+ internal_compressed_tuple::ShouldAnyUseBase<Ts...>()> {
private:
template <int I>
using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
+ template <int I>
+ using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;
+
public:
+ // There seems to be a bug in MSVC dealing in which using '=default' here will
+ // cause the compiler to ignore the body of other constructors. The work-
+ // around is to explicitly implement the default constructor.
+#if defined(_MSC_VER)
+ constexpr CompressedTuple() : CompressedTuple::CompressedTupleImpl() {}
+#else
constexpr CompressedTuple() = default;
- explicit constexpr CompressedTuple(Ts... base)
- : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
+#endif
+ explicit constexpr CompressedTuple(const Ts&... base)
+ : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
+
+ template <typename... Vs,
+ absl::enable_if_t<
+ absl::conjunction<
+ // Ensure we are not hiding default copy/move constructors.
+ absl::negation<std::is_same<void(CompressedTuple),
+ void(absl::decay_t<Vs>...)>>,
+ internal_compressed_tuple::TupleMoveConstructible<
+ Ts, Vs&&>...>::value,
+ bool> = true>
+ explicit constexpr CompressedTuple(Vs&&... base)
+ : CompressedTuple::CompressedTupleImpl(absl::in_place,
+ absl::forward<Vs>(base)...) {}
+
+ template <int I>
+ ElemT<I>& get() & {
+ return internal_compressed_tuple::Storage<ElemT<I>, I>::get();
+ }
+
+ template <int I>
+ constexpr const ElemT<I>& get() const& {
+ return StorageT<I>::get();
+ }
template <int I>
- ElemT<I>& get() {
- return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
+ ElemT<I>&& get() && {
+ return std::move(*this).StorageT<I>::get();
}
template <int I>
- constexpr const ElemT<I>& get() const {
- return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
+ constexpr const ElemT<I>&& get() const&& {
+ return absl::move(*this).StorageT<I>::get();
}
};
@@ -169,7 +257,7 @@ template <>
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 2b5ed4a4..ec893b90 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -14,18 +14,26 @@
#include "absl/container/internal/compressed_tuple.h"
+#include <memory>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "absl/container/internal/test_instance_tracker.h"
+#include "absl/memory/memory.h"
+#include "absl/types/any.h"
+#include "absl/types/optional.h"
+#include "absl/utility/utility.h"
-namespace absl {
-inline namespace lts_2018_12_18 {
-namespace container_internal {
-namespace {
+// These are declared at global scope purely so that error messages
+// are smaller and easier to understand.
+enum class CallType { kConstRef, kConstMove };
template <int>
-struct Empty {};
+struct Empty {
+ constexpr CallType value() const& { return CallType::kConstRef; }
+ constexpr CallType value() const&& { return CallType::kConstMove; }
+};
template <typename T>
struct NotEmpty {
@@ -38,6 +46,15 @@ struct TwoValues {
U value2;
};
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+namespace {
+
+using absl::test_internal::CopyableMovableInstance;
+using absl::test_internal::InstanceTracker;
+
TEST(CompressedTupleTest, Sizeof) {
EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int>));
EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>>));
@@ -53,6 +70,141 @@ TEST(CompressedTupleTest, Sizeof) {
sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>, Empty<1>>));
}
+TEST(CompressedTupleTest, OneMoveOnRValueConstructionTemp) {
+ InstanceTracker tracker;
+ CompressedTuple<CopyableMovableInstance> x1(CopyableMovableInstance(1));
+ EXPECT_EQ(tracker.instances(), 1);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_LE(tracker.moves(), 1);
+ EXPECT_EQ(x1.get<0>().value(), 1);
+}
+
+TEST(CompressedTupleTest, OneMoveOnRValueConstructionMove) {
+ InstanceTracker tracker;
+
+ CopyableMovableInstance i1(1);
+ CompressedTuple<CopyableMovableInstance> x1(std::move(i1));
+ EXPECT_EQ(tracker.instances(), 2);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_LE(tracker.moves(), 1);
+ EXPECT_EQ(x1.get<0>().value(), 1);
+}
+
+TEST(CompressedTupleTest, OneMoveOnRValueConstructionMixedTypes) {
+ InstanceTracker tracker;
+ CopyableMovableInstance i1(1);
+ CopyableMovableInstance i2(2);
+ Empty<0> empty;
+ CompressedTuple<CopyableMovableInstance, CopyableMovableInstance&, Empty<0>>
+ x1(std::move(i1), i2, empty);
+ EXPECT_EQ(x1.get<0>().value(), 1);
+ EXPECT_EQ(x1.get<1>().value(), 2);
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+}
+
+struct IncompleteType;
+CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>>
+MakeWithIncomplete(CopyableMovableInstance i1,
+ IncompleteType& t, // NOLINT
+ Empty<0> empty) {
+ return CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>>{
+ std::move(i1), t, empty};
+}
+
+struct IncompleteType {};
+TEST(CompressedTupleTest, OneMoveOnRValueConstructionWithIncompleteType) {
+ InstanceTracker tracker;
+ CopyableMovableInstance i1(1);
+ Empty<0> empty;
+ struct DerivedType : IncompleteType {int value = 0;};
+ DerivedType fd;
+ fd.value = 7;
+
+ CompressedTuple<CopyableMovableInstance, IncompleteType&, Empty<0>> x1 =
+ MakeWithIncomplete(std::move(i1), fd, empty);
+
+ EXPECT_EQ(x1.get<0>().value(), 1);
+ EXPECT_EQ(static_cast<DerivedType&>(x1.get<1>()).value, 7);
+
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 2);
+}
+
+TEST(CompressedTupleTest,
+ OneMoveOnRValueConstructionMixedTypes_BraceInitPoisonPillExpected) {
+ InstanceTracker tracker;
+ CopyableMovableInstance i1(1);
+ CopyableMovableInstance i2(2);
+ CompressedTuple<CopyableMovableInstance, CopyableMovableInstance&, Empty<0>>
+ x1(std::move(i1), i2, {}); // NOLINT
+ EXPECT_EQ(x1.get<0>().value(), 1);
+ EXPECT_EQ(x1.get<1>().value(), 2);
+ EXPECT_EQ(tracker.instances(), 3);
+ // We are forced into the `const Ts&...` constructor (invoking copies)
+ // because we need it to deduce the type of `{}`.
+ // std::tuple also has this behavior.
+ // Note, this test is proof that this is expected behavior, but it is not
+ // _desired_ behavior.
+ EXPECT_EQ(tracker.copies(), 1);
+ EXPECT_EQ(tracker.moves(), 0);
+}
+
+TEST(CompressedTupleTest, OneCopyOnLValueConstruction) {
+ InstanceTracker tracker;
+ CopyableMovableInstance i1(1);
+
+ CompressedTuple<CopyableMovableInstance> x1(i1);
+ EXPECT_EQ(tracker.copies(), 1);
+ EXPECT_EQ(tracker.moves(), 0);
+
+ tracker.ResetCopiesMovesSwaps();
+
+ CopyableMovableInstance i2(2);
+ const CopyableMovableInstance& i2_ref = i2;
+ CompressedTuple<CopyableMovableInstance> x2(i2_ref);
+ EXPECT_EQ(tracker.copies(), 1);
+ EXPECT_EQ(tracker.moves(), 0);
+}
+
+TEST(CompressedTupleTest, OneMoveOnRValueAccess) {
+ InstanceTracker tracker;
+ CopyableMovableInstance i1(1);
+ CompressedTuple<CopyableMovableInstance> x(std::move(i1));
+ tracker.ResetCopiesMovesSwaps();
+
+ CopyableMovableInstance i2 = std::move(x).get<0>();
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+}
+
+TEST(CompressedTupleTest, OneCopyOnLValueAccess) {
+ InstanceTracker tracker;
+
+ CompressedTuple<CopyableMovableInstance> x(CopyableMovableInstance(0));
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+
+ CopyableMovableInstance t = x.get<0>();
+ EXPECT_EQ(tracker.copies(), 1);
+ EXPECT_EQ(tracker.moves(), 1);
+}
+
+TEST(CompressedTupleTest, ZeroCopyOnRefAccess) {
+ InstanceTracker tracker;
+
+ CompressedTuple<CopyableMovableInstance> x(CopyableMovableInstance(0));
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+
+ CopyableMovableInstance& t1 = x.get<0>();
+ const CopyableMovableInstance& t2 = x.get<0>();
+ EXPECT_EQ(tracker.copies(), 0);
+ EXPECT_EQ(tracker.moves(), 1);
+ EXPECT_EQ(t1.value(), 0);
+ EXPECT_EQ(t2.value(), 0);
+}
+
TEST(CompressedTupleTest, Access) {
struct S {
std::string x;
@@ -113,9 +265,14 @@ TEST(CompressedTupleTest, Nested) {
EXPECT_EQ(4 * sizeof(char),
sizeof(CompressedTuple<CompressedTuple<char, char>,
CompressedTuple<char, char>>));
- EXPECT_TRUE(
- (std::is_empty<CompressedTuple<CompressedTuple<Empty<0>>,
- CompressedTuple<Empty<1>>>>::value));
+ EXPECT_TRUE((std::is_empty<CompressedTuple<Empty<0>, Empty<1>>>::value));
+
+ // Make sure everything still works when things are nested.
+ struct CT_Empty : CompressedTuple<Empty<0>> {};
+ CompressedTuple<Empty<0>, CT_Empty> nested_empty;
+ auto contained = nested_empty.get<0>();
+ auto nested = nested_empty.get<1>().get<0>();
+ EXPECT_TRUE((std::is_same<decltype(contained), decltype(nested)>::value));
}
TEST(CompressedTupleTest, Reference) {
@@ -141,15 +298,103 @@ TEST(CompressedTupleTest, NoElements) {
EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
}
+TEST(CompressedTupleTest, MoveOnlyElements) {
+ CompressedTuple<std::unique_ptr<std::string>> str_tup(
+ absl::make_unique<std::string>("str"));
+
+ CompressedTuple<CompressedTuple<std::unique_ptr<std::string>>,
+ std::unique_ptr<int>>
+ x(std::move(str_tup), absl::make_unique<int>(5));
+
+ EXPECT_EQ(*x.get<0>().get<0>(), "str");
+ EXPECT_EQ(*x.get<1>(), 5);
+
+ std::unique_ptr<std::string> x0 = std::move(x.get<0>()).get<0>();
+ std::unique_ptr<int> x1 = std::move(x).get<1>();
+
+ EXPECT_EQ(*x0, "str");
+ EXPECT_EQ(*x1, 5);
+}
+
+TEST(CompressedTupleTest, MoveConstructionMoveOnlyElements) {
+ CompressedTuple<std::unique_ptr<std::string>> base(
+ absl::make_unique<std::string>("str"));
+ EXPECT_EQ(*base.get<0>(), "str");
+
+ CompressedTuple<std::unique_ptr<std::string>> copy(std::move(base));
+ EXPECT_EQ(*copy.get<0>(), "str");
+}
+
+TEST(CompressedTupleTest, AnyElements) {
+ any a(std::string("str"));
+ CompressedTuple<any, any&> x(any(5), a);
+ EXPECT_EQ(absl::any_cast<int>(x.get<0>()), 5);
+ EXPECT_EQ(absl::any_cast<std::string>(x.get<1>()), "str");
+
+ a = 0.5f;
+ EXPECT_EQ(absl::any_cast<float>(x.get<1>()), 0.5);
+
+ // Ensure copy construction work in the face of a type with a universal
+ // implicit constructor;
+ CompressedTuple<absl::any> c{}, d(c); // NOLINT
+}
+
TEST(CompressedTupleTest, Constexpr) {
- constexpr CompressedTuple<int, double, CompressedTuple<int>> x(
- 7, 1.25, CompressedTuple<int>(5));
+ struct NonTrivialStruct {
+ constexpr NonTrivialStruct() = default;
+ constexpr int value() const { return v; }
+ int v = 5;
+ };
+ struct TrivialStruct {
+ TrivialStruct() = default;
+ constexpr int value() const { return v; }
+ int v;
+ };
+ constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x(
+ 7, 1.25, CompressedTuple<int>(5), {});
constexpr int x0 = x.get<0>();
constexpr double x1 = x.get<1>();
constexpr int x2 = x.get<2>().get<0>();
+ constexpr CallType x3 = x.get<3>().value();
+
EXPECT_EQ(x0, 7);
EXPECT_EQ(x1, 1.25);
EXPECT_EQ(x2, 5);
+ EXPECT_EQ(x3, CallType::kConstRef);
+
+#if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4
+ constexpr CompressedTuple<Empty<0>, TrivialStruct, int> trivial = {};
+ constexpr CallType trivial0 = trivial.get<0>().value();
+ constexpr int trivial1 = trivial.get<1>().value();
+ constexpr int trivial2 = trivial.get<2>();
+
+ EXPECT_EQ(trivial0, CallType::kConstRef);
+ EXPECT_EQ(trivial1, 0);
+ EXPECT_EQ(trivial2, 0);
+#endif
+
+ constexpr CompressedTuple<Empty<0>, NonTrivialStruct, absl::optional<int>>
+ non_trivial = {};
+ constexpr CallType non_trivial0 = non_trivial.get<0>().value();
+ constexpr int non_trivial1 = non_trivial.get<1>().value();
+ constexpr absl::optional<int> non_trivial2 = non_trivial.get<2>();
+
+ EXPECT_EQ(non_trivial0, CallType::kConstRef);
+ EXPECT_EQ(non_trivial1, 5);
+ EXPECT_EQ(non_trivial2, absl::nullopt);
+
+ static constexpr char data[] = "DEF";
+ constexpr CompressedTuple<const char*> z(data);
+ constexpr const char* z1 = z.get<0>();
+ EXPECT_EQ(std::string(z1), std::string(data));
+
+#if defined(__clang__)
+ // An apparent bug in earlier versions of gcc claims these are ambiguous.
+ constexpr int x2m = absl::move(x.get<2>()).get<0>();
+ constexpr CallType x3m = absl::move(x).get<3>().value();
+ EXPECT_EQ(x2m, 5);
+ EXPECT_EQ(x3m, CallType::kConstMove);
+#endif
}
#if defined(__clang__) || defined(__GNUC__)
@@ -164,5 +409,5 @@ TEST(CompressedTupleTest, EmptyFinalClass) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index ddccbe05..eb6d7eb7 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -34,7 +34,7 @@
#include "absl/utility/utility.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// Allocates at least n bytes aligned to the specified alignment.
@@ -287,13 +287,48 @@ struct IsLayoutCompatible {
} // namespace memory_internal
-// If kMutableKeys is false, only the value member is accessed.
+// The internal storage type for key-value containers like flat_hash_map.
//
-// If kMutableKeys is true, key is accessed through all slots while value and
-// mutable_value are accessed only via INITIALIZED slots. Slots are created and
-// destroyed via mutable_value so that the key can be moved later.
+// It is convenient for the value_type of a flat_hash_map<K, V> to be
+// pair<const K, V>; the "const K" prevents accidental modification of the key
+// when dealing with the reference returned from find() and similar methods.
+// However, this creates other problems; we want to be able to emplace(K, V)
+// efficiently with move operations, and similarly be able to move a
+// pair<K, V> in insert().
+//
+// The solution is this union, which aliases the const and non-const versions
+// of the pair. This also allows flat_hash_map<const K, V> to work, even though
+// that has the same efficiency issues with move in emplace() and insert() -
+// but people do it anyway.
+//
+// If kMutableKeys is false, only the value member can be accessed.
+//
+// If kMutableKeys is true, key can be accessed through all slots while value
+// and mutable_value must be accessed only via INITIALIZED slots. Slots are
+// created and destroyed via mutable_value so that the key can be moved later.
+//
+// Accessing one of the union fields while the other is active is safe as
+// long as they are layout-compatible, which is guaranteed by the definition of
+// kMutableKeys. For C++11, the relevant section of the standard is
+// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
template <class K, class V>
-union slot_type {
+union map_slot_type {
+ map_slot_type() {}
+ ~map_slot_type() = delete;
+ using value_type = std::pair<const K, V>;
+ using mutable_value_type = std::pair<K, V>;
+
+ value_type value;
+ mutable_value_type mutable_value;
+ K key;
+};
+
+template <class K, class V>
+struct map_slot_policy {
+ using slot_type = map_slot_type<K, V>;
+ using value_type = std::pair<const K, V>;
+ using mutable_value_type = std::pair<K, V>;
+
private:
static void emplace(slot_type* slot) {
// The construction of union doesn't do anything at runtime but it allows us
@@ -303,19 +338,17 @@ union slot_type {
// If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
// or the other via slot_type. We are also free to access the key via
// slot_type::key in this case.
- using kMutableKeys =
- std::integral_constant<bool,
- memory_internal::IsLayoutCompatible<K, V>::value>;
+ using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
public:
- slot_type() {}
- ~slot_type() = delete;
- using value_type = std::pair<const K, V>;
- using mutable_value_type = std::pair<K, V>;
+ static value_type& element(slot_type* slot) { return slot->value; }
+ static const value_type& element(const slot_type* slot) {
+ return slot->value;
+ }
- value_type value;
- mutable_value_type mutable_value;
- K key;
+ static const K& key(const slot_type* slot) {
+ return kMutableKeys::value ? slot->key : slot->value.first;
+ }
template <class Allocator, class... Args>
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
@@ -401,7 +434,7 @@ union slot_type {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index da87ca20..ea9568dc 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -186,5 +186,5 @@ TEST(DecomposePair, NotDecomposable) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/counting_allocator.h b/absl/container/internal/counting_allocator.h
new file mode 100644
index 00000000..94a457ca
--- /dev/null
+++ b/absl/container/internal/counting_allocator.h
@@ -0,0 +1,81 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+#define ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
+
+#include <cassert>
+#include <cstdint>
+#include <memory>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+// This is a stateful allocator, but the state lives outside of the
+// allocator (in whatever test is using the allocator). This is odd
+// but helps in tests where the allocator is propagated into nested
+// containers - that chain of allocators uses the same state and is
+// thus easier to query for aggregate allocation information.
+template <typename T>
+class CountingAllocator : public std::allocator<T> {
+ public:
+ using Alloc = std::allocator<T>;
+ using pointer = typename Alloc::pointer;
+ using size_type = typename Alloc::size_type;
+
+ CountingAllocator() : bytes_used_(nullptr) {}
+ explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
+
+ template <typename U>
+ CountingAllocator(const CountingAllocator<U>& x)
+ : Alloc(x), bytes_used_(x.bytes_used_) {}
+
+ pointer allocate(size_type n,
+ std::allocator<void>::const_pointer hint = nullptr) {
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ += n * sizeof(T);
+ return Alloc::allocate(n, hint);
+ }
+
+ void deallocate(pointer p, size_type n) {
+ Alloc::deallocate(p, n);
+ assert(bytes_used_ != nullptr);
+ *bytes_used_ -= n * sizeof(T);
+ }
+
+ template<typename U>
+ class rebind {
+ public:
+ using other = CountingAllocator<U>;
+ };
+
+ friend bool operator==(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return a.bytes_used_ == b.bytes_used_;
+ }
+
+ friend bool operator!=(const CountingAllocator& a,
+ const CountingAllocator& b) {
+ return !(a == b);
+ }
+
+ int64_t* bytes_used_;
+};
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_COUNTING_ALLOCATOR_H_
diff --git a/absl/container/internal/hash_function_defaults.h b/absl/container/internal/hash_function_defaults.h
index 72c75fa0..2155076d 100644
--- a/absl/container/internal/hash_function_defaults.h
+++ b/absl/container/internal/hash_function_defaults.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -39,8 +39,8 @@
// equal functions are still bound to T. This is important because some type U
// can be hashed by/tested for equality differently depending on T. A notable
// example is `const char*`. `const char*` is treated as a c-style string when
-// the hash function is hash<string> but as a pointer when the hash function is
-// hash<void*>.
+// the hash function is hash<std::string> but as a pointer when the hash
+// function is hash<void*>.
//
#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
@@ -56,7 +56,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// The hash of an object of type T is computed by using absl::Hash.
@@ -84,6 +84,7 @@ struct StringHashEq {
}
};
};
+
template <>
struct HashEq<std::string> : StringHashEq {};
template <>
@@ -139,7 +140,7 @@ template <class T>
using hash_default_eq = typename container_internal::HashEq<T>::Eq;
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
diff --git a/absl/container/internal/hash_function_defaults_test.cc b/absl/container/internal/hash_function_defaults_test.cc
index 4610843a..ce6133f8 100644
--- a/absl/container/internal/hash_function_defaults_test.cc
+++ b/absl/container/internal/hash_function_defaults_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -78,14 +78,14 @@ struct EqString : ::testing::Test {
hash_default_eq<T> key_eq;
};
-TYPED_TEST_CASE(EqString, StringTypes);
+TYPED_TEST_SUITE(EqString, StringTypes);
template <class T>
struct HashString : ::testing::Test {
hash_default_hash<T> hasher;
};
-TYPED_TEST_CASE(HashString, StringTypes);
+TYPED_TEST_SUITE(HashString, StringTypes);
TYPED_TEST(EqString, Works) {
auto eq = this->key_eq;
@@ -122,14 +122,14 @@ struct EqPointer : ::testing::Test {
hash_default_eq<T> key_eq;
};
-TYPED_TEST_CASE(EqPointer, PointerTypes);
+TYPED_TEST_SUITE(EqPointer, PointerTypes);
template <class T>
struct HashPointer : ::testing::Test {
hash_default_hash<T> hasher;
};
-TYPED_TEST_CASE(HashPointer, PointerTypes);
+TYPED_TEST_SUITE(HashPointer, PointerTypes);
TYPED_TEST(EqPointer, Works) {
int dummy;
@@ -203,15 +203,11 @@ TYPED_TEST(HashPointer, Works) {
EXPECT_NE(hash(&dummy), hash(cuptr));
}
-// Cartesian product of (string, std::string, absl::string_view)
-// with (string, std::string, absl::string_view, const char*).
+// Cartesian product of (std::string, absl::string_view)
+// with (std::string, absl::string_view, const char*).
using StringTypesCartesianProduct = Types<
// clang-format off
- std::pair<std::string, std::string>,
- std::pair<std::string, absl::string_view>,
- std::pair<std::string, const char*>,
-
std::pair<absl::string_view, std::string>,
std::pair<absl::string_view, absl::string_view>,
std::pair<absl::string_view, const char*>>;
@@ -249,11 +245,11 @@ TYPED_TEST_P(StringLikeTest, HashEq) {
EXPECT_NE(this->hash(this->a1), this->hash(this->b2));
}
-TYPED_TEST_CASE(StringLikeTest, StringTypesCartesianProduct);
+TYPED_TEST_SUITE(StringLikeTest, StringTypesCartesianProduct);
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
enum Hash : size_t {
@@ -284,7 +280,7 @@ struct hash<Hashable<H>> {
} // namespace std
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -299,5 +295,5 @@ TEST(Delegate, HashDispatch) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/hash_generator_testing.cc b/absl/container/internal/hash_generator_testing.cc
index aef41d72..36b2571b 100644
--- a/absl/container/internal/hash_generator_testing.cc
+++ b/absl/container/internal/hash_generator_testing.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include <deque>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace hash_internal {
namespace {
@@ -70,5 +70,5 @@ absl::string_view Generator<absl::string_view>::operator()() const {
} // namespace hash_internal
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/hash_generator_testing.h b/absl/container/internal/hash_generator_testing.h
index 65e88964..27962c35 100644
--- a/absl/container/internal/hash_generator_testing.h
+++ b/absl/container/internal/hash_generator_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -31,7 +31,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace hash_internal {
namespace generator_internal {
@@ -146,7 +146,7 @@ using GeneratedType = decltype(
} // namespace hash_internal
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_GENERATOR_TESTING_H_
diff --git a/absl/container/internal/hash_policy_testing.h b/absl/container/internal/hash_policy_testing.h
index 9c310ad4..8f0d2a52 100644
--- a/absl/container/internal/hash_policy_testing.h
+++ b/absl/container/internal/hash_policy_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,7 +30,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace hash_testing_internal {
@@ -163,7 +163,7 @@ auto keys(const Set& s)
}
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS is false for glibcxx versions
diff --git a/absl/container/internal/hash_policy_testing_test.cc b/absl/container/internal/hash_policy_testing_test.cc
index 00c436b3..8fd1df00 100644
--- a/absl/container/internal/hash_policy_testing_test.cc
+++ b/absl/container/internal/hash_policy_testing_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -41,5 +41,5 @@ TEST(_, Hash) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/hash_policy_traits.h b/absl/container/internal/hash_policy_traits.h
index 41e26212..3d87e821 100644
--- a/absl/container/internal/hash_policy_traits.h
+++ b/absl/container/internal/hash_policy_traits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// Defines how slots are initialized/destroyed/moved.
@@ -185,7 +185,7 @@ struct hash_policy_traits {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
diff --git a/absl/container/internal/hash_policy_traits_test.cc b/absl/container/internal/hash_policy_traits_test.cc
index 07cecdfa..edfaf63e 100644
--- a/absl/container/internal/hash_policy_traits_test.cc
+++ b/absl/container/internal/hash_policy_traits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -140,5 +140,5 @@ TEST_F(Test, with_transfer) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/hashtable_debug.h b/absl/container/internal/hashtable_debug.h
index b6a43512..1d1a9c28 100644
--- a/absl/container/internal/hashtable_debug.h
+++ b/absl/container/internal/hashtable_debug.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,7 +38,7 @@
#include "absl/container/internal/hashtable_debug_hooks.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// Returns the number of probes required to lookup `key`. Returns 0 for a
@@ -61,7 +61,7 @@ std::vector<size_t> GetHashtableDebugNumProbesHistogram(const C& container) {
size_t num_probes = GetHashtableDebugNumProbes(
container,
absl::container_internal::hashtable_debug_internal::GetKey<C>(*it, 0));
- v.resize(std::max(v.size(), num_probes + 1));
+ v.resize((std::max)(v.size(), num_probes + 1));
v[num_probes]++;
}
return v;
@@ -104,7 +104,7 @@ size_t LowerBoundAllocatedByteSize(size_t num_elements) {
}
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_H_
diff --git a/absl/container/internal/hashtable_debug_hooks.h b/absl/container/internal/hashtable_debug_hooks.h
index 50ba6ba5..7b95fcef 100644
--- a/absl/container/internal/hashtable_debug_hooks.h
+++ b/absl/container/internal/hashtable_debug_hooks.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include <vector>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace hashtable_debug_internal {
@@ -77,7 +77,7 @@ struct HashtableDebugAccess {
} // namespace hashtable_debug_internal
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
new file mode 100644
index 00000000..2338045d
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -0,0 +1,310 @@
+// 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.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include <atomic>
+#include <cassert>
+#include <cmath>
+#include <functional>
+#include <limits>
+
+#include "absl/base/attributes.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/memory/memory.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+constexpr int HashtablezInfo::kMaxStackDepth;
+
+namespace {
+ABSL_CONST_INIT std::atomic<bool> g_hashtablez_enabled{
+ false
+};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_sample_parameter{1 << 10};
+ABSL_CONST_INIT std::atomic<int32_t> g_hashtablez_max_samples{1 << 20};
+
+// Returns the next pseudo-random value.
+// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
+// This is the lrand64 generator.
+uint64_t NextRandom(uint64_t rnd) {
+ const uint64_t prng_mult = uint64_t{0x5DEECE66D};
+ const uint64_t prng_add = 0xB;
+ const uint64_t prng_mod_power = 48;
+ const uint64_t prng_mod_mask = ~(~uint64_t{0} << prng_mod_power);
+ return (prng_mult * rnd + prng_add) & prng_mod_mask;
+}
+
+// Generates a geometric variable with the specified mean.
+// This is done by generating a random number between 0 and 1 and applying
+// the inverse cumulative distribution function for an exponential.
+// Specifically: Let m be the inverse of the sample period, then
+// the probability distribution function is m*exp(-mx) so the CDF is
+// p = 1 - exp(-mx), so
+// q = 1 - p = exp(-mx)
+// log_e(q) = -mx
+// -log_e(q)/m = x
+// log_2(q) * (-log_e(2) * 1/m) = x
+// In the code, q is actually in the range 1 to 2**26, hence the -26 below
+//
+int64_t GetGeometricVariable(int64_t mean) {
+#if ABSL_HAVE_THREAD_LOCAL
+ thread_local
+#else // ABSL_HAVE_THREAD_LOCAL
+ // SampleSlow and hence GetGeometricVariable is guarded by a single mutex when
+ // there are not thread locals. Thus, a single global rng is acceptable for
+ // that case.
+ static
+#endif // ABSL_HAVE_THREAD_LOCAL
+ uint64_t rng = []() {
+ // We don't get well distributed numbers from this so we call
+ // NextRandom() a bunch to mush the bits around. We use a global_rand
+ // to handle the case where the same thread (by memory address) gets
+ // created and destroyed repeatedly.
+ ABSL_CONST_INIT static std::atomic<uint32_t> global_rand(0);
+ uint64_t r = reinterpret_cast<uint64_t>(&rng) +
+ global_rand.fetch_add(1, std::memory_order_relaxed);
+ for (int i = 0; i < 20; ++i) {
+ r = NextRandom(r);
+ }
+ return r;
+ }();
+
+ rng = NextRandom(rng);
+
+ // Take the top 26 bits as the random number
+ // (This plus the 1<<58 sampling bound give a max possible step of
+ // 5194297183973780480 bytes.)
+ const uint64_t prng_mod_power = 48; // Number of bits in prng
+ // The uint32_t cast is to prevent a (hard-to-reproduce) NAN
+ // under piii debug for some binaries.
+ double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0;
+ // Put the computed p-value through the CDF of a geometric.
+ double interval = (log2(q) - 26) * (-std::log(2.0) * mean);
+
+ // Very large values of interval overflow int64_t. If we happen to
+ // hit such improbable condition, we simply cheat and clamp interval
+ // to largest supported value.
+ if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
+ return std::numeric_limits<int64_t>::max() / 2;
+ }
+
+ // Small values of interval are equivalent to just sampling next time.
+ if (interval < 1) {
+ return 1;
+ }
+ return static_cast<int64_t>(interval);
+}
+
+} // namespace
+
+HashtablezSampler& HashtablezSampler::Global() {
+ static auto* sampler = new HashtablezSampler();
+ return *sampler;
+}
+
+HashtablezSampler::DisposeCallback HashtablezSampler::SetDisposeCallback(
+ DisposeCallback f) {
+ return dispose_.exchange(f, std::memory_order_relaxed);
+}
+
+HashtablezInfo::HashtablezInfo() { PrepareForSampling(); }
+HashtablezInfo::~HashtablezInfo() = default;
+
+void HashtablezInfo::PrepareForSampling() {
+ capacity.store(0, std::memory_order_relaxed);
+ size.store(0, std::memory_order_relaxed);
+ num_erases.store(0, std::memory_order_relaxed);
+ max_probe_length.store(0, std::memory_order_relaxed);
+ total_probe_length.store(0, std::memory_order_relaxed);
+ hashes_bitwise_or.store(0, std::memory_order_relaxed);
+ hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
+
+ create_time = absl::Now();
+ // The inliner makes hardcoded skip_count difficult (especially when combined
+ // with LTO). We use the ability to exclude stacks by regex when encoding
+ // instead.
+ depth = absl::GetStackTrace(stack, HashtablezInfo::kMaxStackDepth,
+ /* skip_count= */ 0);
+ dead = nullptr;
+}
+
+HashtablezSampler::HashtablezSampler()
+ : dropped_samples_(0), size_estimate_(0), all_(nullptr), dispose_(nullptr) {
+ absl::MutexLock l(&graveyard_.init_mu);
+ graveyard_.dead = &graveyard_;
+}
+
+HashtablezSampler::~HashtablezSampler() {
+ HashtablezInfo* s = all_.load(std::memory_order_acquire);
+ while (s != nullptr) {
+ HashtablezInfo* next = s->next;
+ delete s;
+ s = next;
+ }
+}
+
+void HashtablezSampler::PushNew(HashtablezInfo* sample) {
+ sample->next = all_.load(std::memory_order_relaxed);
+ while (!all_.compare_exchange_weak(sample->next, sample,
+ std::memory_order_release,
+ std::memory_order_relaxed)) {
+ }
+}
+
+void HashtablezSampler::PushDead(HashtablezInfo* sample) {
+ if (auto* dispose = dispose_.load(std::memory_order_relaxed)) {
+ dispose(*sample);
+ }
+
+ absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+ absl::MutexLock sample_lock(&sample->init_mu);
+ sample->dead = graveyard_.dead;
+ graveyard_.dead = sample;
+}
+
+HashtablezInfo* HashtablezSampler::PopDead() {
+ absl::MutexLock graveyard_lock(&graveyard_.init_mu);
+
+ // The list is circular, so eventually it collapses down to
+ // graveyard_.dead == &graveyard_
+ // when it is empty.
+ HashtablezInfo* sample = graveyard_.dead;
+ if (sample == &graveyard_) return nullptr;
+
+ absl::MutexLock sample_lock(&sample->init_mu);
+ graveyard_.dead = sample->dead;
+ sample->PrepareForSampling();
+ return sample;
+}
+
+HashtablezInfo* HashtablezSampler::Register() {
+ int64_t size = size_estimate_.fetch_add(1, std::memory_order_relaxed);
+ if (size > g_hashtablez_max_samples.load(std::memory_order_relaxed)) {
+ size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+ dropped_samples_.fetch_add(1, std::memory_order_relaxed);
+ return nullptr;
+ }
+
+ HashtablezInfo* sample = PopDead();
+ if (sample == nullptr) {
+ // Resurrection failed. Hire a new warlock.
+ sample = new HashtablezInfo();
+ PushNew(sample);
+ }
+
+ return sample;
+}
+
+void HashtablezSampler::Unregister(HashtablezInfo* sample) {
+ PushDead(sample);
+ size_estimate_.fetch_sub(1, std::memory_order_relaxed);
+}
+
+int64_t HashtablezSampler::Iterate(
+ const std::function<void(const HashtablezInfo& stack)>& f) {
+ HashtablezInfo* s = all_.load(std::memory_order_acquire);
+ while (s != nullptr) {
+ absl::MutexLock l(&s->init_mu);
+ if (s->dead == nullptr) {
+ f(*s);
+ }
+ s = s->next;
+ }
+
+ return dropped_samples_.load(std::memory_order_relaxed);
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample) {
+ if (kAbslContainerInternalSampleEverything) {
+ *next_sample = 1;
+ return HashtablezSampler::Global().Register();
+ }
+
+ bool first = *next_sample < 0;
+ *next_sample = GetGeometricVariable(
+ g_hashtablez_sample_parameter.load(std::memory_order_relaxed));
+
+ // g_hashtablez_enabled can be dynamically flipped, we need to set a threshold
+ // low enough that we will start sampling in a reasonable time, so we just use
+ // the default sampling rate.
+ if (!g_hashtablez_enabled.load(std::memory_order_relaxed)) return nullptr;
+
+ // We will only be negative on our first count, so we should just retry in
+ // that case.
+ if (first) {
+ if (ABSL_PREDICT_TRUE(--*next_sample > 0)) return nullptr;
+ return SampleSlow(next_sample);
+ }
+
+ return HashtablezSampler::Global().Register();
+}
+
+#if ABSL_PER_THREAD_TLS == 1
+ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample = 0;
+#endif // ABSL_PER_THREAD_TLS == 1
+
+void UnsampleSlow(HashtablezInfo* info) {
+ HashtablezSampler::Global().Unregister(info);
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+ size_t distance_from_desired) {
+ // SwissTables probe in groups of 16, so scale this to count items probes and
+ // not offset from desired.
+ size_t probe_length = distance_from_desired;
+#if SWISSTABLE_HAVE_SSE2
+ probe_length /= 16;
+#else
+ probe_length /= 8;
+#endif
+
+ info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
+ info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
+ info->max_probe_length.store(
+ std::max(info->max_probe_length.load(std::memory_order_relaxed),
+ probe_length),
+ std::memory_order_relaxed);
+ info->total_probe_length.fetch_add(probe_length, std::memory_order_relaxed);
+ info->size.fetch_add(1, std::memory_order_relaxed);
+}
+
+void SetHashtablezEnabled(bool enabled) {
+ g_hashtablez_enabled.store(enabled, std::memory_order_release);
+}
+
+void SetHashtablezSampleParameter(int32_t rate) {
+ if (rate > 0) {
+ g_hashtablez_sample_parameter.store(rate, std::memory_order_release);
+ } else {
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez sample rate: %lld",
+ static_cast<long long>(rate)); // NOLINT(runtime/int)
+ }
+}
+
+void SetHashtablezMaxSamples(int32_t max) {
+ if (max > 0) {
+ g_hashtablez_max_samples.store(max, std::memory_order_release);
+ } else {
+ ABSL_RAW_LOG(ERROR, "Invalid hashtablez max samples: %lld",
+ static_cast<long long>(max)); // NOLINT(runtime/int)
+ }
+}
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
new file mode 100644
index 00000000..f17c425c
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -0,0 +1,290 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: hashtablez_sampler.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the API for a low level library to sample hashtables
+// and collect runtime statistics about them.
+//
+// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
+// store information about a single sample.
+//
+// `Record*` methods store information into samples.
+// `Sample()` and `Unsample()` make use of a single global sampler with
+// properties controlled by the flags hashtablez_enabled,
+// hashtablez_sample_rate, and hashtablez_max_samples.
+//
+// WARNING
+//
+// Using this sampling API may cause sampled Swiss tables to use the global
+// allocator (operator `new`) in addition to any custom allocator. If you
+// are using a table in an unusual circumstance where allocation or calling a
+// linux syscall is unacceptable, this could interfere.
+//
+// This utility is internal-only. Use at your own risk.
+
+#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <vector>
+
+#include "absl/base/internal/per_thread_tls.h"
+#include "absl/base/optimization.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/utility/utility.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+// Stores information about a sampled hashtable. All mutations to this *must*
+// be made through `Record*` functions below. All reads from this *must* only
+// occur in the callback to `HashtablezSampler::Iterate`.
+struct HashtablezInfo {
+ // Constructs the object but does not fill in any fields.
+ HashtablezInfo();
+ ~HashtablezInfo();
+ HashtablezInfo(const HashtablezInfo&) = delete;
+ HashtablezInfo& operator=(const HashtablezInfo&) = delete;
+
+ // Puts the object into a clean state, fills in the logically `const` members,
+ // blocking for any readers that are currently sampling the object.
+ void PrepareForSampling() EXCLUSIVE_LOCKS_REQUIRED(init_mu);
+
+ // These fields are mutated by the various Record* APIs and need to be
+ // thread-safe.
+ std::atomic<size_t> capacity;
+ std::atomic<size_t> size;
+ std::atomic<size_t> num_erases;
+ std::atomic<size_t> max_probe_length;
+ std::atomic<size_t> total_probe_length;
+ std::atomic<size_t> hashes_bitwise_or;
+ std::atomic<size_t> hashes_bitwise_and;
+
+ // `HashtablezSampler` maintains intrusive linked lists for all samples. See
+ // comments on `HashtablezSampler::all_` for details on these. `init_mu`
+ // guards the ability to restore the sample to a pristine state. This
+ // prevents races with sampling and resurrecting an object.
+ absl::Mutex init_mu;
+ HashtablezInfo* next;
+ HashtablezInfo* dead GUARDED_BY(init_mu);
+
+ // All of the fields below are set by `PrepareForSampling`, they must not be
+ // mutated in `Record*` functions. They are logically `const` in that sense.
+ // These are guarded by init_mu, but that is not externalized to clients, who
+ // can only read them during `HashtablezSampler::Iterate` which will hold the
+ // lock.
+ static constexpr int kMaxStackDepth = 64;
+ absl::Time create_time;
+ int32_t depth;
+ void* stack[kMaxStackDepth];
+};
+
+inline void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length) {
+#if SWISSTABLE_HAVE_SSE2
+ total_probe_length /= 16;
+#else
+ total_probe_length /= 8;
+#endif
+ info->total_probe_length.store(total_probe_length, std::memory_order_relaxed);
+ info->num_erases.store(0, std::memory_order_relaxed);
+}
+
+inline void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
+ size_t capacity) {
+ info->size.store(size, std::memory_order_relaxed);
+ info->capacity.store(capacity, std::memory_order_relaxed);
+ if (size == 0) {
+ // This is a clear, reset the total/num_erases too.
+ RecordRehashSlow(info, 0);
+ }
+}
+
+void RecordInsertSlow(HashtablezInfo* info, size_t hash,
+ size_t distance_from_desired);
+
+inline void RecordEraseSlow(HashtablezInfo* info) {
+ info->size.fetch_sub(1, std::memory_order_relaxed);
+ info->num_erases.fetch_add(1, std::memory_order_relaxed);
+}
+
+HashtablezInfo* SampleSlow(int64_t* next_sample);
+void UnsampleSlow(HashtablezInfo* info);
+
+class HashtablezInfoHandle {
+ public:
+ explicit HashtablezInfoHandle() : info_(nullptr) {}
+ explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
+ ~HashtablezInfoHandle() {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ UnsampleSlow(info_);
+ }
+
+ HashtablezInfoHandle(const HashtablezInfoHandle&) = delete;
+ HashtablezInfoHandle& operator=(const HashtablezInfoHandle&) = delete;
+
+ HashtablezInfoHandle(HashtablezInfoHandle&& o) noexcept
+ : info_(absl::exchange(o.info_, nullptr)) {}
+ HashtablezInfoHandle& operator=(HashtablezInfoHandle&& o) noexcept {
+ if (ABSL_PREDICT_FALSE(info_ != nullptr)) {
+ UnsampleSlow(info_);
+ }
+ info_ = absl::exchange(o.info_, nullptr);
+ return *this;
+ }
+
+ inline void RecordStorageChanged(size_t size, size_t capacity) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordStorageChangedSlow(info_, size, capacity);
+ }
+
+ inline void RecordRehash(size_t total_probe_length) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordRehashSlow(info_, total_probe_length);
+ }
+
+ inline void RecordInsert(size_t hash, size_t distance_from_desired) {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordInsertSlow(info_, hash, distance_from_desired);
+ }
+
+ inline void RecordErase() {
+ if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
+ RecordEraseSlow(info_);
+ }
+
+ friend inline void swap(HashtablezInfoHandle& lhs,
+ HashtablezInfoHandle& rhs) {
+ std::swap(lhs.info_, rhs.info_);
+ }
+
+ private:
+ friend class HashtablezInfoHandlePeer;
+ HashtablezInfo* info_;
+};
+
+#if ABSL_PER_THREAD_TLS == 1
+extern ABSL_PER_THREAD_TLS_KEYWORD int64_t global_next_sample;
+#endif // ABSL_PER_THREAD_TLS
+
+// Returns an RAII sampling handle that manages registration and unregistation
+// with the global sampler.
+inline HashtablezInfoHandle Sample() {
+#if ABSL_PER_THREAD_TLS == 0
+ static auto* mu = new absl::Mutex;
+ static int64_t global_next_sample = 0;
+ absl::MutexLock l(mu);
+#endif // !ABSL_HAVE_THREAD_LOCAL
+
+ if (ABSL_PREDICT_TRUE(--global_next_sample > 0)) {
+ return HashtablezInfoHandle(nullptr);
+ }
+ return HashtablezInfoHandle(SampleSlow(&global_next_sample));
+}
+
+// Holds samples and their associated stack traces with a soft limit of
+// `SetHashtablezMaxSamples()`.
+//
+// Thread safe.
+class HashtablezSampler {
+ public:
+ // Returns a global Sampler.
+ static HashtablezSampler& Global();
+
+ HashtablezSampler();
+ ~HashtablezSampler();
+
+ // Registers for sampling. Returns an opaque registration info.
+ HashtablezInfo* Register();
+
+ // Unregisters the sample.
+ void Unregister(HashtablezInfo* sample);
+
+ // The dispose callback will be called on all samples the moment they are
+ // being unregistered. Only affects samples that are unregistered after the
+ // callback has been set.
+ // Returns the previous callback.
+ using DisposeCallback = void (*)(const HashtablezInfo&);
+ DisposeCallback SetDisposeCallback(DisposeCallback f);
+
+ // Iterates over all the registered `StackInfo`s. Returning the number of
+ // samples that have been dropped.
+ int64_t Iterate(const std::function<void(const HashtablezInfo& stack)>& f);
+
+ private:
+ void PushNew(HashtablezInfo* sample);
+ void PushDead(HashtablezInfo* sample);
+ HashtablezInfo* PopDead();
+
+ std::atomic<size_t> dropped_samples_;
+ std::atomic<size_t> size_estimate_;
+
+ // Intrusive lock free linked lists for tracking samples.
+ //
+ // `all_` records all samples (they are never removed from this list) and is
+ // terminated with a `nullptr`.
+ //
+ // `graveyard_.dead` is a circular linked list. When it is empty,
+ // `graveyard_.dead == &graveyard`. The list is circular so that
+ // every item on it (even the last) has a non-null dead pointer. This allows
+ // `Iterate` to determine if a given sample is live or dead using only
+ // information on the sample itself.
+ //
+ // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead
+ // looks like this (G is the Graveyard):
+ //
+ // +---+ +---+ +---+ +---+ +---+
+ // all -->| A |--->| B |--->| C |--->| D |--->| E |
+ // | | | | | | | | | |
+ // +---+ | | +->| |-+ | | +->| |-+ | |
+ // | G | +---+ | +---+ | +---+ | +---+ | +---+
+ // | | | | | |
+ // | | --------+ +--------+ |
+ // +---+ |
+ // ^ |
+ // +--------------------------------------+
+ //
+ std::atomic<HashtablezInfo*> all_;
+ HashtablezInfo graveyard_;
+
+ std::atomic<DisposeCallback> dispose_;
+};
+
+// Enables or disables sampling for Swiss tables.
+void SetHashtablezEnabled(bool enabled);
+
+// Sets the rate at which Swiss tables will be sampled.
+void SetHashtablezSampleParameter(int32_t rate);
+
+// Sets a soft max for the number of samples that will be kept.
+void SetHashtablezMaxSamples(int32_t max);
+
+// Configuration override.
+// This allows process-wide sampling without depending on order of
+// initialization of static storage duration objects.
+// The definition of this constant is weak, which allows us to inject a
+// different value for it at link time.
+extern "C" const bool kAbslContainerInternalSampleEverything;
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
diff --git a/absl/container/internal/hashtablez_sampler_force_weak_definition.cc b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
new file mode 100644
index 00000000..d3f41c7c
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler_force_weak_definition.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include "absl/base/attributes.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+// See hashtablez_sampler.h for details.
+extern "C" ABSL_ATTRIBUTE_WEAK const bool
+ kAbslContainerInternalSampleEverything = false;
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
new file mode 100644
index 00000000..bdae75f3
--- /dev/null
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -0,0 +1,357 @@
+// 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.
+
+#include "absl/container/internal/hashtablez_sampler.h"
+
+#include <atomic>
+#include <limits>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/container/internal/have_sse.h"
+#include "absl/synchronization/blocking_counter.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"
+
+#if SWISSTABLE_HAVE_SSE2
+constexpr int kProbeLength = 16;
+#else
+constexpr int kProbeLength = 8;
+#endif
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+class HashtablezInfoHandlePeer {
+ public:
+ static bool IsSampled(const HashtablezInfoHandle& h) {
+ return h.info_ != nullptr;
+ }
+
+ static HashtablezInfo* GetInfo(HashtablezInfoHandle* h) { return h->info_; }
+};
+
+namespace {
+using ::absl::synchronization_internal::ThreadPool;
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+std::vector<size_t> GetSizes(HashtablezSampler* s) {
+ std::vector<size_t> res;
+ s->Iterate([&](const HashtablezInfo& info) {
+ res.push_back(info.size.load(std::memory_order_acquire));
+ });
+ return res;
+}
+
+HashtablezInfo* Register(HashtablezSampler* s, size_t size) {
+ auto* info = s->Register();
+ assert(info != nullptr);
+ info->size.store(size);
+ return info;
+}
+
+TEST(HashtablezInfoTest, PrepareForSampling) {
+ absl::Time test_start = absl::Now();
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+
+ EXPECT_EQ(info.capacity.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ EXPECT_EQ(info.total_probe_length.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+ EXPECT_GE(info.create_time, test_start);
+
+ info.capacity.store(1, std::memory_order_relaxed);
+ info.size.store(1, std::memory_order_relaxed);
+ info.num_erases.store(1, std::memory_order_relaxed);
+ info.max_probe_length.store(1, std::memory_order_relaxed);
+ info.total_probe_length.store(1, std::memory_order_relaxed);
+ info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
+ info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
+ info.create_time = test_start - absl::Hours(20);
+
+ info.PrepareForSampling();
+ EXPECT_EQ(info.capacity.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ EXPECT_EQ(info.total_probe_length.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
+ EXPECT_GE(info.create_time, test_start);
+}
+
+TEST(HashtablezInfoTest, RecordStorageChanged) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ RecordStorageChangedSlow(&info, 17, 47);
+ EXPECT_EQ(info.size.load(), 17);
+ EXPECT_EQ(info.capacity.load(), 47);
+ RecordStorageChangedSlow(&info, 20, 20);
+ EXPECT_EQ(info.size.load(), 20);
+ EXPECT_EQ(info.capacity.load(), 20);
+}
+
+TEST(HashtablezInfoTest, RecordInsert) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ EXPECT_EQ(info.max_probe_length.load(), 0);
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 6);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
+ RecordInsertSlow(&info, 0x000FF000, 4 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 6);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
+ RecordInsertSlow(&info, 0x00FF0000, 12 * kProbeLength);
+ EXPECT_EQ(info.max_probe_length.load(), 12);
+ EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
+ EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
+}
+
+TEST(HashtablezInfoTest, RecordErase) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ EXPECT_EQ(info.num_erases.load(), 0);
+ EXPECT_EQ(info.size.load(), 0);
+ RecordInsertSlow(&info, 0x0000FF00, 6 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 1);
+ RecordEraseSlow(&info);
+ EXPECT_EQ(info.size.load(), 0);
+ EXPECT_EQ(info.num_erases.load(), 1);
+}
+
+TEST(HashtablezInfoTest, RecordRehash) {
+ HashtablezInfo info;
+ absl::MutexLock l(&info.init_mu);
+ info.PrepareForSampling();
+ RecordInsertSlow(&info, 0x1, 0);
+ RecordInsertSlow(&info, 0x2, kProbeLength);
+ RecordInsertSlow(&info, 0x4, kProbeLength);
+ RecordInsertSlow(&info, 0x8, 2 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 4);
+ EXPECT_EQ(info.total_probe_length.load(), 4);
+
+ RecordEraseSlow(&info);
+ RecordEraseSlow(&info);
+ EXPECT_EQ(info.size.load(), 2);
+ EXPECT_EQ(info.total_probe_length.load(), 4);
+ EXPECT_EQ(info.num_erases.load(), 2);
+
+ RecordRehashSlow(&info, 3 * kProbeLength);
+ EXPECT_EQ(info.size.load(), 2);
+ EXPECT_EQ(info.total_probe_length.load(), 3);
+ EXPECT_EQ(info.num_erases.load(), 0);
+}
+
+TEST(HashtablezSamplerTest, SmallSampleParameter) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+
+ for (int i = 0; i < 1000; ++i) {
+ int64_t next_sample = 0;
+ HashtablezInfo* sample = SampleSlow(&next_sample);
+ EXPECT_GT(next_sample, 0);
+ EXPECT_NE(sample, nullptr);
+ UnsampleSlow(sample);
+ }
+}
+
+TEST(HashtablezSamplerTest, LargeSampleParameter) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(std::numeric_limits<int32_t>::max());
+
+ for (int i = 0; i < 1000; ++i) {
+ int64_t next_sample = 0;
+ HashtablezInfo* sample = SampleSlow(&next_sample);
+ EXPECT_GT(next_sample, 0);
+ EXPECT_NE(sample, nullptr);
+ UnsampleSlow(sample);
+ }
+}
+
+TEST(HashtablezSamplerTest, Sample) {
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+ int64_t num_sampled = 0;
+ int64_t total = 0;
+ double sample_rate = 0.0;
+ for (int i = 0; i < 1000000; ++i) {
+ HashtablezInfoHandle h = Sample();
+ ++total;
+ if (HashtablezInfoHandlePeer::IsSampled(h)) {
+ ++num_sampled;
+ }
+ sample_rate = static_cast<double>(num_sampled) / total;
+ if (0.005 < sample_rate && sample_rate < 0.015) break;
+ }
+ EXPECT_NEAR(sample_rate, 0.01, 0.005);
+}
+
+TEST(HashtablezSamplerTest, Handle) {
+ auto& sampler = HashtablezSampler::Global();
+ HashtablezInfoHandle h(sampler.Register());
+ auto* info = HashtablezInfoHandlePeer::GetInfo(&h);
+ info->hashes_bitwise_and.store(0x12345678, std::memory_order_relaxed);
+
+ bool found = false;
+ sampler.Iterate([&](const HashtablezInfo& h) {
+ if (&h == info) {
+ EXPECT_EQ(h.hashes_bitwise_and.load(), 0x12345678);
+ found = true;
+ }
+ });
+ EXPECT_TRUE(found);
+
+ h = HashtablezInfoHandle();
+ found = false;
+ sampler.Iterate([&](const HashtablezInfo& h) {
+ if (&h == info) {
+ // this will only happen if some other thread has resurrected the info
+ // the old handle was using.
+ if (h.hashes_bitwise_and.load() == 0x12345678) {
+ found = true;
+ }
+ }
+ });
+ EXPECT_FALSE(found);
+}
+
+TEST(HashtablezSamplerTest, Registration) {
+ HashtablezSampler sampler;
+ auto* info1 = Register(&sampler, 1);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1));
+
+ auto* info2 = Register(&sampler, 2);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(1, 2));
+ info1->size.store(3);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(3, 2));
+
+ sampler.Unregister(info1);
+ sampler.Unregister(info2);
+}
+
+TEST(HashtablezSamplerTest, Unregistration) {
+ HashtablezSampler sampler;
+ std::vector<HashtablezInfo*> infos;
+ for (size_t i = 0; i < 3; ++i) {
+ infos.push_back(Register(&sampler, i));
+ }
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 1, 2));
+
+ sampler.Unregister(infos[1]);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2));
+
+ infos.push_back(Register(&sampler, 3));
+ infos.push_back(Register(&sampler, 4));
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 3, 4));
+ sampler.Unregister(infos[3]);
+ EXPECT_THAT(GetSizes(&sampler), UnorderedElementsAre(0, 2, 4));
+
+ sampler.Unregister(infos[0]);
+ sampler.Unregister(infos[2]);
+ sampler.Unregister(infos[4]);
+ EXPECT_THAT(GetSizes(&sampler), IsEmpty());
+}
+
+TEST(HashtablezSamplerTest, MultiThreaded) {
+ HashtablezSampler sampler;
+ Notification stop;
+ ThreadPool pool(10);
+
+ for (int i = 0; i < 10; ++i) {
+ pool.Schedule([&sampler, &stop]() {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+
+ std::vector<HashtablezInfo*> infoz;
+ while (!stop.HasBeenNotified()) {
+ if (infoz.empty()) {
+ infoz.push_back(sampler.Register());
+ }
+ switch (std::uniform_int_distribution<>(0, 2)(gen)) {
+ case 0: {
+ infoz.push_back(sampler.Register());
+ break;
+ }
+ case 1: {
+ size_t p =
+ std::uniform_int_distribution<>(0, infoz.size() - 1)(gen);
+ HashtablezInfo* info = infoz[p];
+ infoz[p] = infoz.back();
+ infoz.pop_back();
+ sampler.Unregister(info);
+ break;
+ }
+ case 2: {
+ absl::Duration oldest = absl::ZeroDuration();
+ sampler.Iterate([&](const HashtablezInfo& info) {
+ oldest = std::max(oldest, absl::Now() - info.create_time);
+ });
+ ASSERT_GE(oldest, absl::ZeroDuration());
+ break;
+ }
+ }
+ }
+ });
+ }
+ // The threads will hammer away. Give it a little bit of time for tsan to
+ // spot errors.
+ absl::SleepFor(absl::Seconds(3));
+ stop.Notify();
+}
+
+TEST(HashtablezSamplerTest, Callback) {
+ HashtablezSampler sampler;
+
+ auto* info1 = Register(&sampler, 1);
+ auto* info2 = Register(&sampler, 2);
+
+ static const HashtablezInfo* expected;
+
+ auto callback = [](const HashtablezInfo& info) {
+ // We can't use `info` outside of this callback because the object will be
+ // disposed as soon as we return from here.
+ EXPECT_EQ(&info, expected);
+ };
+
+ // Set the callback.
+ EXPECT_EQ(sampler.SetDisposeCallback(callback), nullptr);
+ expected = info1;
+ sampler.Unregister(info1);
+
+ // Unset the callback.
+ EXPECT_EQ(callback, sampler.SetDisposeCallback(nullptr));
+ expected = nullptr; // no more calls.
+ sampler.Unregister(info2);
+}
+
+} // namespace
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/container/internal/have_sse.h b/absl/container/internal/have_sse.h
new file mode 100644
index 00000000..43414418
--- /dev/null
+++ b/absl/container/internal/have_sse.h
@@ -0,0 +1,49 @@
+// 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.
+//
+// Shared config probing for SSE instructions used in Swiss tables.
+#ifndef ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+#define ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
+
+#ifndef SWISSTABLE_HAVE_SSE2
+#if defined(__SSE2__) || \
+ (defined(_MSC_VER) && \
+ (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
+#define SWISSTABLE_HAVE_SSE2 1
+#else
+#define SWISSTABLE_HAVE_SSE2 0
+#endif
+#endif
+
+#ifndef SWISSTABLE_HAVE_SSSE3
+#ifdef __SSSE3__
+#define SWISSTABLE_HAVE_SSSE3 1
+#else
+#define SWISSTABLE_HAVE_SSSE3 0
+#endif
+#endif
+
+#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
+#error "Bad configuration!"
+#endif
+
+#if SWISSTABLE_HAVE_SSE2
+#include <emmintrin.h>
+#endif
+
+#if SWISSTABLE_HAVE_SSSE3
+#include <tmmintrin.h>
+#endif
+
+#endif // ABSL_CONTAINER_INTERNAL_HAVE_SSE_H_
diff --git a/absl/container/internal/inlined_vector.h b/absl/container/internal/inlined_vector.h
new file mode 100644
index 00000000..123e04c9
--- /dev/null
+++ b/absl/container/internal/inlined_vector.h
@@ -0,0 +1,895 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "absl/base/macros.h"
+#include "absl/container/internal/compressed_tuple.h"
+#include "absl/memory/memory.h"
+#include "absl/meta/type_traits.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace inlined_vector_internal {
+
+template <typename Iterator>
+using IsAtLeastForwardIterator = std::is_convertible<
+ typename std::iterator_traits<Iterator>::iterator_category,
+ std::forward_iterator_tag>;
+
+template <typename AllocatorType>
+using IsMemcpyOk = absl::conjunction<
+ std::is_same<std::allocator<typename AllocatorType::value_type>,
+ AllocatorType>,
+ absl::is_trivially_copy_constructible<typename AllocatorType::value_type>,
+ absl::is_trivially_copy_assignable<typename AllocatorType::value_type>,
+ absl::is_trivially_destructible<typename AllocatorType::value_type>>;
+
+template <typename AllocatorType, typename ValueType, typename SizeType>
+void DestroyElements(AllocatorType* alloc_ptr, ValueType* destroy_first,
+ SizeType destroy_size) {
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+ if (destroy_first != nullptr) {
+ for (auto i = destroy_size; i != 0;) {
+ --i;
+ AllocatorTraits::destroy(*alloc_ptr, destroy_first + i);
+ }
+
+#ifndef NDEBUG
+ // Overwrite unused memory with `0xab` so we can catch uninitialized usage.
+ //
+ // Cast to `void*` to tell the compiler that we don't care that we might be
+ // scribbling on a vtable pointer.
+ auto* memory_ptr = static_cast<void*>(destroy_first);
+ auto memory_size = sizeof(ValueType) * destroy_size;
+ std::memset(memory_ptr, 0xab, memory_size);
+#endif // NDEBUG
+ }
+}
+
+template <typename AllocatorType, typename ValueType, typename ValueAdapter,
+ typename SizeType>
+void ConstructElements(AllocatorType* alloc_ptr, ValueType* construct_first,
+ ValueAdapter* values_ptr, SizeType construct_size) {
+ for (SizeType i = 0; i < construct_size; ++i) {
+ ABSL_INTERNAL_TRY {
+ values_ptr->ConstructNext(alloc_ptr, construct_first + i);
+ }
+ ABSL_INTERNAL_CATCH_ANY {
+ inlined_vector_internal::DestroyElements(alloc_ptr, construct_first, i);
+ ABSL_INTERNAL_RETHROW;
+ }
+ }
+}
+
+template <typename ValueType, typename ValueAdapter, typename SizeType>
+void AssignElements(ValueType* assign_first, ValueAdapter* values_ptr,
+ SizeType assign_size) {
+ for (SizeType i = 0; i < assign_size; ++i) {
+ values_ptr->AssignNext(assign_first + i);
+ }
+}
+
+template <typename AllocatorType>
+struct StorageView {
+ using pointer = typename AllocatorType::pointer;
+ using size_type = typename AllocatorType::size_type;
+
+ pointer data;
+ size_type size;
+ size_type capacity;
+};
+
+template <typename AllocatorType, typename Iterator>
+class IteratorValueAdapter {
+ using pointer = typename AllocatorType::pointer;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+ public:
+ explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
+
+ void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ AllocatorTraits::construct(*alloc_ptr, construct_at, *it_);
+ ++it_;
+ }
+
+ void AssignNext(pointer assign_at) {
+ *assign_at = *it_;
+ ++it_;
+ }
+
+ private:
+ Iterator it_;
+};
+
+template <typename AllocatorType>
+class CopyValueAdapter {
+ using pointer = typename AllocatorType::pointer;
+ using const_pointer = typename AllocatorType::const_pointer;
+ using const_reference = typename AllocatorType::const_reference;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+ public:
+ explicit CopyValueAdapter(const_reference v) : ptr_(std::addressof(v)) {}
+
+ void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ AllocatorTraits::construct(*alloc_ptr, construct_at, *ptr_);
+ }
+
+ void AssignNext(pointer assign_at) { *assign_at = *ptr_; }
+
+ private:
+ const_pointer ptr_;
+};
+
+template <typename AllocatorType>
+class DefaultValueAdapter {
+ using pointer = typename AllocatorType::pointer;
+ using value_type = typename AllocatorType::value_type;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+ public:
+ explicit DefaultValueAdapter() {}
+
+ void ConstructNext(AllocatorType* alloc_ptr, pointer construct_at) {
+ AllocatorTraits::construct(*alloc_ptr, construct_at);
+ }
+
+ void AssignNext(pointer assign_at) { *assign_at = value_type(); }
+};
+
+template <typename AllocatorType>
+class AllocationTransaction {
+ using value_type = typename AllocatorType::value_type;
+ using pointer = typename AllocatorType::pointer;
+ using size_type = typename AllocatorType::size_type;
+ using AllocatorTraits = absl::allocator_traits<AllocatorType>;
+
+ public:
+ explicit AllocationTransaction(AllocatorType* alloc_ptr)
+ : alloc_data_(*alloc_ptr, nullptr) {}
+
+ ~AllocationTransaction() {
+ if (DidAllocate()) {
+ AllocatorTraits::deallocate(GetAllocator(), GetData(), GetCapacity());
+ }
+ }
+
+ AllocationTransaction(const AllocationTransaction&) = delete;
+ void operator=(const AllocationTransaction&) = delete;
+
+ AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
+ pointer& GetData() { return alloc_data_.template get<1>(); }
+ size_type& GetCapacity() { return capacity_; }
+
+ bool DidAllocate() { return GetData() != nullptr; }
+ pointer Allocate(size_type capacity) {
+ GetData() = AllocatorTraits::allocate(GetAllocator(), capacity);
+ GetCapacity() = capacity;
+ return GetData();
+ }
+
+ private:
+ container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
+ size_type capacity_ = 0;
+};
+
+template <typename AllocatorType>
+class ConstructionTransaction {
+ using pointer = typename AllocatorType::pointer;
+ using size_type = typename AllocatorType::size_type;
+
+ public:
+ explicit ConstructionTransaction(AllocatorType* alloc_ptr)
+ : alloc_data_(*alloc_ptr, nullptr) {}
+
+ ~ConstructionTransaction() {
+ if (DidConstruct()) {
+ inlined_vector_internal::DestroyElements(std::addressof(GetAllocator()),
+ GetData(), GetSize());
+ }
+ }
+
+ ConstructionTransaction(const ConstructionTransaction&) = delete;
+ void operator=(const ConstructionTransaction&) = delete;
+
+ AllocatorType& GetAllocator() { return alloc_data_.template get<0>(); }
+ pointer& GetData() { return alloc_data_.template get<1>(); }
+ size_type& GetSize() { return size_; }
+
+ bool DidConstruct() { return GetData() != nullptr; }
+ template <typename ValueAdapter>
+ void Construct(pointer data, ValueAdapter* values_ptr, size_type size) {
+ inlined_vector_internal::ConstructElements(std::addressof(GetAllocator()),
+ data, values_ptr, size);
+ GetData() = data;
+ GetSize() = size;
+ }
+ void Commit() {
+ GetData() = nullptr;
+ GetSize() = 0;
+ }
+
+ private:
+ container_internal::CompressedTuple<AllocatorType, pointer> alloc_data_;
+ size_type size_ = 0;
+};
+
+template <typename T, size_t N, typename A>
+class Storage {
+ public:
+ using allocator_type = A;
+ using value_type = typename allocator_type::value_type;
+ using pointer = typename allocator_type::pointer;
+ using const_pointer = typename allocator_type::const_pointer;
+ using reference = typename allocator_type::reference;
+ using const_reference = typename allocator_type::const_reference;
+ using rvalue_reference = typename allocator_type::value_type&&;
+ using size_type = typename allocator_type::size_type;
+ using difference_type = typename allocator_type::difference_type;
+ using iterator = pointer;
+ using const_iterator = const_pointer;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using MoveIterator = std::move_iterator<iterator>;
+ using AllocatorTraits = absl::allocator_traits<allocator_type>;
+ using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<allocator_type>;
+
+ using StorageView = inlined_vector_internal::StorageView<allocator_type>;
+
+ template <typename Iterator>
+ using IteratorValueAdapter =
+ inlined_vector_internal::IteratorValueAdapter<allocator_type, Iterator>;
+ using CopyValueAdapter =
+ inlined_vector_internal::CopyValueAdapter<allocator_type>;
+ using DefaultValueAdapter =
+ inlined_vector_internal::DefaultValueAdapter<allocator_type>;
+
+ using AllocationTransaction =
+ inlined_vector_internal::AllocationTransaction<allocator_type>;
+ using ConstructionTransaction =
+ inlined_vector_internal::ConstructionTransaction<allocator_type>;
+
+ static size_type NextCapacity(size_type current_capacity) {
+ return current_capacity * 2;
+ }
+
+ static size_type ComputeCapacity(size_type current_capacity,
+ size_type requested_capacity) {
+ return (std::max)(NextCapacity(current_capacity), requested_capacity);
+ }
+
+ // ---------------------------------------------------------------------------
+ // Storage Constructors and Destructor
+ // ---------------------------------------------------------------------------
+
+ Storage() : metadata_() {}
+
+ explicit Storage(const allocator_type& alloc)
+ : metadata_(alloc, /* empty and inlined */ 0) {}
+
+ ~Storage() {
+ pointer data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), data, GetSize());
+ DeallocateIfAllocated();
+ }
+
+ // ---------------------------------------------------------------------------
+ // Storage Member Accessors
+ // ---------------------------------------------------------------------------
+
+ size_type& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
+
+ const size_type& GetSizeAndIsAllocated() const {
+ return metadata_.template get<1>();
+ }
+
+ size_type GetSize() const { return GetSizeAndIsAllocated() >> 1; }
+
+ bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
+
+ pointer GetAllocatedData() { return data_.allocated.allocated_data; }
+
+ const_pointer GetAllocatedData() const {
+ return data_.allocated.allocated_data;
+ }
+
+ pointer GetInlinedData() {
+ return reinterpret_cast<pointer>(
+ std::addressof(data_.inlined.inlined_data[0]));
+ }
+
+ const_pointer GetInlinedData() const {
+ return reinterpret_cast<const_pointer>(
+ std::addressof(data_.inlined.inlined_data[0]));
+ }
+
+ size_type GetAllocatedCapacity() const {
+ return data_.allocated.allocated_capacity;
+ }
+
+ size_type GetInlinedCapacity() const { return static_cast<size_type>(N); }
+
+ StorageView MakeStorageView() {
+ return GetIsAllocated()
+ ? StorageView{GetAllocatedData(), GetSize(),
+ GetAllocatedCapacity()}
+ : StorageView{GetInlinedData(), GetSize(), GetInlinedCapacity()};
+ }
+
+ allocator_type* GetAllocPtr() {
+ return std::addressof(metadata_.template get<0>());
+ }
+
+ const allocator_type* GetAllocPtr() const {
+ return std::addressof(metadata_.template get<0>());
+ }
+
+ // ---------------------------------------------------------------------------
+ // Storage Member Mutators
+ // ---------------------------------------------------------------------------
+
+ template <typename ValueAdapter>
+ void Initialize(ValueAdapter values, size_type new_size);
+
+ template <typename ValueAdapter>
+ void Assign(ValueAdapter values, size_type new_size);
+
+ template <typename ValueAdapter>
+ void Resize(ValueAdapter values, size_type new_size);
+
+ template <typename ValueAdapter>
+ iterator Insert(const_iterator pos, ValueAdapter values,
+ size_type insert_count);
+
+ template <typename... Args>
+ reference EmplaceBack(Args&&... args);
+
+ iterator Erase(const_iterator from, const_iterator to);
+
+ void Reserve(size_type requested_capacity);
+
+ void ShrinkToFit();
+
+ void Swap(Storage* other_storage_ptr);
+
+ void SetIsAllocated() {
+ GetSizeAndIsAllocated() |= static_cast<size_type>(1);
+ }
+
+ void UnsetIsAllocated() {
+ GetSizeAndIsAllocated() &= ((std::numeric_limits<size_type>::max)() - 1);
+ }
+
+ void SetSize(size_type size) {
+ GetSizeAndIsAllocated() =
+ (size << 1) | static_cast<size_type>(GetIsAllocated());
+ }
+
+ void SetAllocatedSize(size_type size) {
+ GetSizeAndIsAllocated() = (size << 1) | static_cast<size_type>(1);
+ }
+
+ void SetInlinedSize(size_type size) {
+ GetSizeAndIsAllocated() = size << static_cast<size_type>(1);
+ }
+
+ void AddSize(size_type count) {
+ GetSizeAndIsAllocated() += count << static_cast<size_type>(1);
+ }
+
+ void SubtractSize(size_type count) {
+ assert(count <= GetSize());
+
+ GetSizeAndIsAllocated() -= count << static_cast<size_type>(1);
+ }
+
+ void SetAllocatedData(pointer data, size_type capacity) {
+ data_.allocated.allocated_data = data;
+ data_.allocated.allocated_capacity = capacity;
+ }
+
+ void AcquireAllocatedData(AllocationTransaction* allocation_tx_ptr) {
+ SetAllocatedData(allocation_tx_ptr->GetData(),
+ allocation_tx_ptr->GetCapacity());
+ allocation_tx_ptr->GetData() = nullptr;
+ allocation_tx_ptr->GetCapacity() = 0;
+ }
+
+ void MemcpyFrom(const Storage& other_storage) {
+ assert(IsMemcpyOk::value || other_storage.GetIsAllocated());
+
+ GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated();
+ data_ = other_storage.data_;
+ }
+
+ void DeallocateIfAllocated() {
+ if (GetIsAllocated()) {
+ AllocatorTraits::deallocate(*GetAllocPtr(), GetAllocatedData(),
+ GetAllocatedCapacity());
+ }
+ }
+
+ private:
+ using Metadata =
+ container_internal::CompressedTuple<allocator_type, size_type>;
+
+ struct Allocated {
+ pointer allocated_data;
+ size_type allocated_capacity;
+ };
+
+ struct Inlined {
+ using InlinedDataElement =
+ absl::aligned_storage_t<sizeof(value_type), alignof(value_type)>;
+ InlinedDataElement inlined_data[N];
+ };
+
+ union Data {
+ Allocated allocated;
+ Inlined inlined;
+ };
+
+ Metadata metadata_;
+ Data data_;
+};
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Initialize(ValueAdapter values, size_type new_size)
+ -> void {
+ // Only callable from constructors!
+ assert(!GetIsAllocated());
+ assert(GetSize() == 0);
+
+ pointer construct_data;
+
+ if (new_size > GetInlinedCapacity()) {
+ // Because this is only called from the `InlinedVector` constructors, it's
+ // safe to take on the allocation with size `0`. If `ConstructElements(...)`
+ // throws, deallocation will be automatically handled by `~Storage()`.
+ size_type new_capacity = ComputeCapacity(GetInlinedCapacity(), new_size);
+ pointer new_data = AllocatorTraits::allocate(*GetAllocPtr(), new_capacity);
+
+ SetAllocatedData(new_data, new_capacity);
+ SetIsAllocated();
+
+ construct_data = new_data;
+ } else {
+ construct_data = GetInlinedData();
+ }
+
+ inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
+ &values, new_size);
+
+ // Since the initial size was guaranteed to be `0` and the allocated bit is
+ // already correct for either case, *adding* `new_size` gives us the correct
+ // result faster than setting it directly.
+ AddSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Assign(ValueAdapter values, size_type new_size) -> void {
+ StorageView storage_view = MakeStorageView();
+
+ AllocationTransaction allocation_tx(GetAllocPtr());
+
+ absl::Span<value_type> assign_loop;
+ absl::Span<value_type> construct_loop;
+ absl::Span<value_type> destroy_loop;
+
+ if (new_size > storage_view.capacity) {
+ size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+
+ construct_loop = {new_data, new_size};
+ destroy_loop = {storage_view.data, storage_view.size};
+ } else if (new_size > storage_view.size) {
+ assign_loop = {storage_view.data, storage_view.size};
+ construct_loop = {storage_view.data + storage_view.size,
+ new_size - storage_view.size};
+ } else {
+ assign_loop = {storage_view.data, new_size};
+ destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
+ }
+
+ inlined_vector_internal::AssignElements(assign_loop.data(), &values,
+ assign_loop.size());
+
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), construct_loop.data(), &values, construct_loop.size());
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
+ destroy_loop.size());
+
+ if (allocation_tx.DidAllocate()) {
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+ SetIsAllocated();
+ }
+
+ SetSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Resize(ValueAdapter values, size_type new_size) -> void {
+ StorageView storage_view = MakeStorageView();
+
+ AllocationTransaction allocation_tx(GetAllocPtr());
+ ConstructionTransaction construction_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data));
+
+ absl::Span<value_type> construct_loop;
+ absl::Span<value_type> move_construct_loop;
+ absl::Span<value_type> destroy_loop;
+
+ if (new_size > storage_view.capacity) {
+ size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+ construct_loop = {new_data + storage_view.size,
+ new_size - storage_view.size};
+ move_construct_loop = {new_data, storage_view.size};
+ destroy_loop = {storage_view.data, storage_view.size};
+ } else if (new_size > storage_view.size) {
+ construct_loop = {storage_view.data + storage_view.size,
+ new_size - storage_view.size};
+ } else {
+ destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
+ }
+
+ construction_tx.Construct(construct_loop.data(), &values,
+ construct_loop.size());
+
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), move_construct_loop.data(), &move_values,
+ move_construct_loop.size());
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), destroy_loop.data(),
+ destroy_loop.size());
+
+ construction_tx.Commit();
+ if (allocation_tx.DidAllocate()) {
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+ SetIsAllocated();
+ }
+
+ SetSize(new_size);
+}
+
+template <typename T, size_t N, typename A>
+template <typename ValueAdapter>
+auto Storage<T, N, A>::Insert(const_iterator pos, ValueAdapter values,
+ size_type insert_count) -> iterator {
+ StorageView storage_view = MakeStorageView();
+
+ size_type insert_index =
+ std::distance(const_iterator(storage_view.data), pos);
+ size_type insert_end_index = insert_index + insert_count;
+ size_type new_size = storage_view.size + insert_count;
+
+ if (new_size > storage_view.capacity) {
+ AllocationTransaction allocation_tx(GetAllocPtr());
+ ConstructionTransaction construction_tx(GetAllocPtr());
+ ConstructionTransaction move_construciton_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data));
+
+ size_type new_capacity = ComputeCapacity(storage_view.capacity, new_size);
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+
+ construction_tx.Construct(new_data + insert_index, &values, insert_count);
+
+ move_construciton_tx.Construct(new_data, &move_values, insert_index);
+
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), new_data + insert_end_index, &move_values,
+ storage_view.size - insert_index);
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+ storage_view.size);
+
+ construction_tx.Commit();
+ move_construciton_tx.Commit();
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+
+ SetAllocatedSize(new_size);
+ return iterator(new_data + insert_index);
+ } else {
+ size_type move_construction_destination_index =
+ (std::max)(insert_end_index, storage_view.size);
+
+ ConstructionTransaction move_construction_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_construction_values(
+ MoveIterator(storage_view.data +
+ (move_construction_destination_index - insert_count)));
+ absl::Span<value_type> move_construction = {
+ storage_view.data + move_construction_destination_index,
+ new_size - move_construction_destination_index};
+
+ pointer move_assignment_values = storage_view.data + insert_index;
+ absl::Span<value_type> move_assignment = {
+ storage_view.data + insert_end_index,
+ move_construction_destination_index - insert_end_index};
+
+ absl::Span<value_type> insert_assignment = {move_assignment_values,
+ move_construction.size()};
+
+ absl::Span<value_type> insert_construction = {
+ insert_assignment.data() + insert_assignment.size(),
+ insert_count - insert_assignment.size()};
+
+ move_construction_tx.Construct(move_construction.data(),
+ &move_construction_values,
+ move_construction.size());
+
+ for (pointer destination = move_assignment.data() + move_assignment.size(),
+ last_destination = move_assignment.data(),
+ source = move_assignment_values + move_assignment.size();
+ ;) {
+ --destination;
+ --source;
+ if (destination < last_destination) break;
+ *destination = std::move(*source);
+ }
+
+ inlined_vector_internal::AssignElements(insert_assignment.data(), &values,
+ insert_assignment.size());
+
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), insert_construction.data(), &values,
+ insert_construction.size());
+
+ move_construction_tx.Commit();
+
+ AddSize(insert_count);
+ return iterator(storage_view.data + insert_index);
+ }
+}
+
+template <typename T, size_t N, typename A>
+template <typename... Args>
+auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> reference {
+ StorageView storage_view = MakeStorageView();
+
+ AllocationTransaction allocation_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data));
+
+ pointer construct_data;
+
+ if (storage_view.size == storage_view.capacity) {
+ size_type new_capacity = NextCapacity(storage_view.capacity);
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+
+ construct_data = new_data;
+ } else {
+ construct_data = storage_view.data;
+ }
+
+ pointer end = construct_data + storage_view.size;
+
+ AllocatorTraits::construct(*GetAllocPtr(), end, std::forward<Args>(args)...);
+
+ if (allocation_tx.DidAllocate()) {
+ ABSL_INTERNAL_TRY {
+ inlined_vector_internal::ConstructElements(
+ GetAllocPtr(), allocation_tx.GetData(), &move_values,
+ storage_view.size);
+ }
+ ABSL_INTERNAL_CATCH_ANY {
+ AllocatorTraits::destroy(*GetAllocPtr(), end);
+ ABSL_INTERNAL_RETHROW;
+ }
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+ storage_view.size);
+
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+ SetIsAllocated();
+ }
+
+ AddSize(1);
+ return *end;
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Erase(const_iterator from, const_iterator to)
+ -> iterator {
+ assert(from != to);
+
+ StorageView storage_view = MakeStorageView();
+
+ size_type erase_size = std::distance(from, to);
+ size_type erase_index =
+ std::distance(const_iterator(storage_view.data), from);
+ size_type erase_end_index = erase_index + erase_size;
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data + erase_end_index));
+
+ inlined_vector_internal::AssignElements(storage_view.data + erase_index,
+ &move_values,
+ storage_view.size - erase_end_index);
+
+ inlined_vector_internal::DestroyElements(
+ GetAllocPtr(), storage_view.data + (storage_view.size - erase_size),
+ erase_size);
+
+ SubtractSize(erase_size);
+ return iterator(storage_view.data + erase_index);
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Reserve(size_type requested_capacity) -> void {
+ StorageView storage_view = MakeStorageView();
+
+ if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
+
+ AllocationTransaction allocation_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data));
+
+ size_type new_capacity =
+ ComputeCapacity(storage_view.capacity, requested_capacity);
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+
+ inlined_vector_internal::ConstructElements(GetAllocPtr(), new_data,
+ &move_values, storage_view.size);
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+ storage_view.size);
+
+ DeallocateIfAllocated();
+ AcquireAllocatedData(&allocation_tx);
+ SetIsAllocated();
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::ShrinkToFit() -> void {
+ // May only be called on allocated instances!
+ assert(GetIsAllocated());
+
+ StorageView storage_view{GetAllocatedData(), GetSize(),
+ GetAllocatedCapacity()};
+
+ if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return;
+
+ AllocationTransaction allocation_tx(GetAllocPtr());
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(storage_view.data));
+
+ pointer construct_data;
+
+ if (storage_view.size > GetInlinedCapacity()) {
+ size_type new_capacity = storage_view.size;
+ pointer new_data = allocation_tx.Allocate(new_capacity);
+
+ construct_data = new_data;
+ } else {
+ construct_data = GetInlinedData();
+ }
+
+ ABSL_INTERNAL_TRY {
+ inlined_vector_internal::ConstructElements(GetAllocPtr(), construct_data,
+ &move_values, storage_view.size);
+ }
+ ABSL_INTERNAL_CATCH_ANY {
+ SetAllocatedData(storage_view.data, storage_view.capacity);
+ ABSL_INTERNAL_RETHROW;
+ }
+
+ inlined_vector_internal::DestroyElements(GetAllocPtr(), storage_view.data,
+ storage_view.size);
+
+ AllocatorTraits::deallocate(*GetAllocPtr(), storage_view.data,
+ storage_view.capacity);
+
+ if (allocation_tx.DidAllocate()) {
+ AcquireAllocatedData(&allocation_tx);
+ } else {
+ UnsetIsAllocated();
+ }
+}
+
+template <typename T, size_t N, typename A>
+auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
+ using std::swap;
+ assert(this != other_storage_ptr);
+
+ if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) {
+ swap(data_.allocated, other_storage_ptr->data_.allocated);
+ } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) {
+ Storage* small_ptr = this;
+ Storage* large_ptr = other_storage_ptr;
+ if (small_ptr->GetSize() > large_ptr->GetSize()) swap(small_ptr, large_ptr);
+
+ for (size_type i = 0; i < small_ptr->GetSize(); ++i) {
+ swap(small_ptr->GetInlinedData()[i], large_ptr->GetInlinedData()[i]);
+ }
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(large_ptr->GetInlinedData() + small_ptr->GetSize()));
+
+ inlined_vector_internal::ConstructElements(
+ large_ptr->GetAllocPtr(),
+ small_ptr->GetInlinedData() + small_ptr->GetSize(), &move_values,
+ large_ptr->GetSize() - small_ptr->GetSize());
+
+ inlined_vector_internal::DestroyElements(
+ large_ptr->GetAllocPtr(),
+ large_ptr->GetInlinedData() + small_ptr->GetSize(),
+ large_ptr->GetSize() - small_ptr->GetSize());
+ } else {
+ Storage* allocated_ptr = this;
+ Storage* inlined_ptr = other_storage_ptr;
+ if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr);
+
+ StorageView allocated_storage_view{allocated_ptr->GetAllocatedData(),
+ allocated_ptr->GetSize(),
+ allocated_ptr->GetAllocatedCapacity()};
+
+ IteratorValueAdapter<MoveIterator> move_values(
+ MoveIterator(inlined_ptr->GetInlinedData()));
+
+ ABSL_INTERNAL_TRY {
+ inlined_vector_internal::ConstructElements(
+ inlined_ptr->GetAllocPtr(), allocated_ptr->GetInlinedData(),
+ &move_values, inlined_ptr->GetSize());
+ }
+ ABSL_INTERNAL_CATCH_ANY {
+ allocated_ptr->SetAllocatedData(allocated_storage_view.data,
+ allocated_storage_view.capacity);
+ ABSL_INTERNAL_RETHROW;
+ }
+
+ inlined_vector_internal::DestroyElements(inlined_ptr->GetAllocPtr(),
+ inlined_ptr->GetInlinedData(),
+ inlined_ptr->GetSize());
+
+ inlined_ptr->SetAllocatedData(allocated_storage_view.data,
+ allocated_storage_view.capacity);
+ }
+
+ swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated());
+ swap(*GetAllocPtr(), *other_storage_ptr->GetAllocPtr());
+}
+
+} // namespace inlined_vector_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_INTERNAL_H_
diff --git a/absl/container/internal/layout.h b/absl/container/internal/layout.h
index f11a6ad2..3924b8aa 100644
--- a/absl/container/internal/layout.h
+++ b/absl/container/internal/layout.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -188,7 +188,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// A type wrapper that instructs `Layout` to use the specific alignment for the
@@ -644,7 +644,8 @@ class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>,
std::string DebugString() const {
const auto offsets = Offsets();
const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...};
- const std::string types[] = {adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
+ const std::string types[] = {
+ adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
for (size_t i = 0; i != NumOffsets - 1; ++i) {
absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],
@@ -734,7 +735,7 @@ class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_
diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc
index b9f98471..44d84607 100644
--- a/absl/container/internal/layout_test.cc
+++ b/absl/container/internal/layout_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/types/span.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -46,7 +46,7 @@ Expected Type(Actual val) {
return val;
}
-// Helper class to test different size and alignments.
+// Helper classes to test different size and alignments.
struct alignas(8) Int128 {
uint64_t a, b;
friend bool operator==(Int128 lhs, Int128 rhs) {
@@ -58,6 +58,14 @@ struct alignas(8) Int128 {
}
};
+// int64_t is *not* 8-byte aligned on all platforms!
+struct alignas(8) Int64 {
+ int64_t a;
+ friend bool operator==(Int64 lhs, Int64 rhs) {
+ return lhs.a == rhs.a;
+ }
+};
+
// Properties of types that this test relies on.
static_assert(sizeof(int8_t) == 1, "");
static_assert(alignof(int8_t) == 1, "");
@@ -65,6 +73,8 @@ static_assert(sizeof(int16_t) == 2, "");
static_assert(alignof(int16_t) == 2, "");
static_assert(sizeof(int32_t) == 4, "");
static_assert(alignof(int32_t) == 4, "");
+static_assert(sizeof(Int64) == 8, "");
+static_assert(alignof(Int64) == 8, "");
static_assert(sizeof(Int128) == 16, "");
static_assert(alignof(Int128) == 8, "");
@@ -1282,14 +1292,14 @@ TEST(Layout, OverAligned) {
TEST(Layout, Alignment) {
static_assert(Layout<int8_t>::Alignment() == 1, "");
static_assert(Layout<int32_t>::Alignment() == 4, "");
- static_assert(Layout<int64_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64>::Alignment() == 8, "");
static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, "");
- static_assert(Layout<int8_t, int32_t, int64_t>::Alignment() == 8, "");
- static_assert(Layout<int8_t, int64_t, int32_t>::Alignment() == 8, "");
- static_assert(Layout<int32_t, int8_t, int64_t>::Alignment() == 8, "");
- static_assert(Layout<int32_t, int64_t, int8_t>::Alignment() == 8, "");
- static_assert(Layout<int64_t, int8_t, int32_t>::Alignment() == 8, "");
- static_assert(Layout<int64_t, int32_t, int8_t>::Alignment() == 8, "");
+ static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, "");
+ static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, "");
+ static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, "");
+ static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, "");
+ static_assert(Layout<Int64, int32_t, int8_t>::Alignment() == 8, "");
}
TEST(Layout, ConstexprPartial) {
@@ -1324,7 +1334,7 @@ void ExpectPoisoned(const unsigned char (&buf)[N],
}
TEST(Layout, PoisonPadding) {
- using L = Layout<int8_t, int64_t, int32_t, Int128>;
+ using L = Layout<int8_t, Int64, int32_t, Int128>;
constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize();
{
@@ -1553,5 +1563,5 @@ TEST(CompactString, Works) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/node_hash_policy.h b/absl/container/internal/node_hash_policy.h
index e8d89f63..d7581360 100644
--- a/absl/container/internal/node_hash_policy.h
+++ b/absl/container/internal/node_hash_policy.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -40,7 +40,7 @@
#include <utility>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class Reference, class Policy>
@@ -84,7 +84,7 @@ struct node_hash_policy {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_NODE_HASH_POLICY_H_
diff --git a/absl/container/internal/node_hash_policy_test.cc b/absl/container/internal/node_hash_policy_test.cc
index a73c7bba..d53b7364 100644
--- a/absl/container/internal/node_hash_policy_test.cc
+++ b/absl/container/internal/node_hash_policy_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,7 @@
#include "absl/container/internal/hash_policy_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -65,5 +65,5 @@ TEST_F(NodeTest, transfer) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/raw_hash_map.h b/absl/container/internal/raw_hash_map.h
index 53d4619a..00caa373 100644
--- a/absl/container/internal/raw_hash_map.h
+++ b/absl/container/internal/raw_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,11 +19,12 @@
#include <type_traits>
#include <utility>
+#include "absl/base/internal/throw_delegate.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class Policy, class Hash, class Eq, class Alloc>
@@ -40,8 +41,8 @@ class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
using MappedConstReference = decltype(P::value(
std::addressof(std::declval<typename raw_hash_map::const_reference>())));
- using KeyArgImpl = container_internal::KeyArg<IsTransparent<Eq>::value &&
- IsTransparent<Hash>::value>;
+ using KeyArgImpl =
+ KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
public:
using key_type = typename Policy::key_type;
@@ -137,14 +138,20 @@ class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
template <class K = key_type, class P = Policy>
MappedReference<P> at(const key_arg<K>& key) {
auto it = this->find(key);
- if (it == this->end()) std::abort();
+ if (it == this->end()) {
+ base_internal::ThrowStdOutOfRange(
+ "absl::container_internal::raw_hash_map<>::at");
+ }
return Policy::value(&*it);
}
template <class K = key_type, class P = Policy>
MappedConstReference<P> at(const key_arg<K>& key) const {
auto it = this->find(key);
- if (it == this->end()) std::abort();
+ if (it == this->end()) {
+ base_internal::ThrowStdOutOfRange(
+ "absl::container_internal::raw_hash_map<>::at");
+ }
return Policy::value(&*it);
}
@@ -181,7 +188,7 @@ class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 4e690dac..02e74e21 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "absl/base/config.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
constexpr size_t Group::kWidth;
@@ -44,5 +44,5 @@ bool ShouldInsertBackwards(size_t hash, ctrl_t* ctrl) {
}
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 0c42e4ae..7b379d4f 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -91,36 +91,6 @@
#ifndef ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
#define ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
-#ifndef SWISSTABLE_HAVE_SSE2
-#if defined(__SSE2__) || \
- (defined(_MSC_VER) && \
- (defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
-#define SWISSTABLE_HAVE_SSE2 1
-#else
-#define SWISSTABLE_HAVE_SSE2 0
-#endif
-#endif
-
-#ifndef SWISSTABLE_HAVE_SSSE3
-#ifdef __SSSE3__
-#define SWISSTABLE_HAVE_SSSE3 1
-#else
-#define SWISSTABLE_HAVE_SSSE3 0
-#endif
-#endif
-
-#if SWISSTABLE_HAVE_SSSE3 && !SWISSTABLE_HAVE_SSE2
-#error "Bad configuration!"
-#endif
-
-#if SWISSTABLE_HAVE_SSE2
-#include <emmintrin.h>
-#endif
-
-#if SWISSTABLE_HAVE_SSSE3
-#include <tmmintrin.h>
-#endif
-
#include <algorithm>
#include <cmath>
#include <cstdint>
@@ -135,18 +105,20 @@
#include "absl/base/internal/bits.h"
#include "absl/base/internal/endian.h"
#include "absl/base/port.h"
+#include "absl/container/internal/common.h"
#include "absl/container/internal/compressed_tuple.h"
#include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_policy_traits.h"
#include "absl/container/internal/hashtable_debug_hooks.h"
+#include "absl/container/internal/hashtablez_sampler.h"
+#include "absl/container/internal/have_sse.h"
#include "absl/container/internal/layout.h"
#include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
-#include "absl/types/optional.h"
#include "absl/utility/utility.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <size_t Width>
@@ -194,12 +166,6 @@ struct IsDecomposable<
std::declval<Ts>()...))>,
Policy, Hash, Eq, Ts...> : std::true_type {};
-template <class, class = void>
-struct IsTransparent : std::false_type {};
-template <class T>
-struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
- : std::true_type {};
-
// TODO(alkis): Switch to std::is_nothrow_swappable when gcc/clang supports it.
template <class T>
constexpr bool IsNoThrowSwappable() {
@@ -385,7 +351,7 @@ struct GroupSse2Impl {
return BitMask<uint32_t, kWidth>(
_mm_movemask_epi8(_mm_sign_epi8(ctrl, ctrl)));
#else
- return Match(kEmpty);
+ return Match(static_cast<h2_t>(kEmpty));
#endif
}
@@ -481,9 +447,7 @@ using Group = GroupPortableImpl;
template <class Policy, class Hash, class Eq, class Alloc>
class raw_hash_set;
-inline bool IsValidCapacity(size_t n) {
- return ((n + 1) & n) == 0 && n >= Group::kWidth - 1;
-}
+inline bool IsValidCapacity(size_t n) { return ((n + 1) & n) == 0 && n > 0; }
// PRECONDITION:
// IsValidCapacity(capacity)
@@ -505,152 +469,32 @@ inline void ConvertDeletedToEmptyAndFullToDeleted(
ctrl[capacity] = kSentinel;
}
-// Rounds up the capacity to the next power of 2 minus 1 and ensures it is
-// greater or equal to Group::kWidth - 1.
+// Rounds up the capacity to the next power of 2 minus 1, with a minimum of 1.
inline size_t NormalizeCapacity(size_t n) {
- constexpr size_t kMinCapacity = Group::kWidth - 1;
- return n <= kMinCapacity
- ? kMinCapacity
- : (std::numeric_limits<size_t>::max)() >> LeadingZeros(n);
+ return n ? ~size_t{} >> LeadingZeros(n) : 1;
}
-// The node_handle concept from C++17.
-// We specialize node_handle for sets and maps. node_handle_base holds the
-// common API of both.
-template <typename Policy, typename Alloc>
-class node_handle_base {
- protected:
- using PolicyTraits = hash_policy_traits<Policy>;
- using slot_type = typename PolicyTraits::slot_type;
-
- public:
- using allocator_type = Alloc;
-
- constexpr node_handle_base() {}
- node_handle_base(node_handle_base&& other) noexcept {
- *this = std::move(other);
- }
- ~node_handle_base() { destroy(); }
- node_handle_base& operator=(node_handle_base&& other) {
- destroy();
- if (!other.empty()) {
- alloc_ = other.alloc_;
- PolicyTraits::transfer(alloc(), slot(), other.slot());
- other.reset();
- }
- return *this;
- }
-
- bool empty() const noexcept { return !alloc_; }
- explicit operator bool() const noexcept { return !empty(); }
- allocator_type get_allocator() const { return *alloc_; }
-
- protected:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
- PolicyTraits::transfer(alloc(), slot(), s);
- }
-
- void destroy() {
- if (!empty()) {
- PolicyTraits::destroy(alloc(), slot());
- reset();
- }
- }
-
- void reset() {
- assert(alloc_.has_value());
- alloc_ = absl::nullopt;
- }
-
- slot_type* slot() const {
- assert(!empty());
- return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
- }
- allocator_type* alloc() { return std::addressof(*alloc_); }
-
- private:
- absl::optional<allocator_type> alloc_;
- mutable absl::aligned_storage_t<sizeof(slot_type), alignof(slot_type)>
- slot_space_;
-};
-
-// For sets.
-template <typename Policy, typename Alloc, typename = void>
-class node_handle : public node_handle_base<Policy, Alloc> {
- using Base = typename node_handle::node_handle_base;
-
- public:
- using value_type = typename Base::PolicyTraits::value_type;
-
- constexpr node_handle() {}
-
- value_type& value() const {
- return Base::PolicyTraits::element(this->slot());
- }
-
- private:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// For maps.
-template <typename Policy, typename Alloc>
-class node_handle<Policy, Alloc, absl::void_t<typename Policy::mapped_type>>
- : public node_handle_base<Policy, Alloc> {
- using Base = typename node_handle::node_handle_base;
-
- public:
- using key_type = typename Policy::key_type;
- using mapped_type = typename Policy::mapped_type;
-
- constexpr node_handle() {}
-
- auto key() const -> decltype(Base::PolicyTraits::key(this->slot())) {
- return Base::PolicyTraits::key(this->slot());
- }
-
- mapped_type& mapped() const {
- return Base::PolicyTraits::value(
- &Base::PolicyTraits::element(this->slot()));
+// We use 7/8th as maximum load factor.
+// For 16-wide groups, that gives an average of two empty slots per group.
+inline size_t CapacityToGrowth(size_t capacity) {
+ assert(IsValidCapacity(capacity));
+ // `capacity*7/8`
+ if (Group::kWidth == 8 && capacity == 7) {
+ // x-x/8 does not work when x==7.
+ return 6;
}
-
- private:
- template <typename, typename, typename, typename>
- friend class raw_hash_set;
-
- node_handle(const Alloc& a, typename Base::slot_type* s) : Base(a, s) {}
-};
-
-// Implement the insert_return_type<> concept of C++17.
-template <class Iterator, class NodeType>
-struct insert_return_type {
- Iterator position;
- bool inserted;
- NodeType node;
-};
-
-// Helper trait to allow or disallow arbitrary keys when the hash and
-// eq functions are transparent.
-// It is very important that the inner template is an alias and that the type it
-// produces is not a dependent type. Otherwise, type deduction would fail.
-template <bool is_transparent>
-struct KeyArg {
- // Transparent. Forward `K`.
- template <typename K, typename key_type>
- using type = K;
-};
-
-template <>
-struct KeyArg<false> {
- // Not transparent. Always use `key_type`.
- template <typename K, typename key_type>
- using type = key_type;
-};
+ return capacity - capacity / 8;
+}
+// From desired "growth" to a lowerbound of the necessary capacity.
+// Might not be a valid one and required NormalizeCapacity().
+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;
+ }
+ return growth + static_cast<size_t>((static_cast<int64_t>(growth) - 1) / 7);
+}
// Policy: a policy defines how to perform different operations on
// the slots of the hashtable (see hash_policy_traits.h for the full interface
@@ -666,14 +510,14 @@ struct KeyArg<false> {
// if they are equal, false if they are not. If two keys compare equal, then
// their hash values as defined by Hash MUST be equal.
//
-// Allocator: an Allocator [http://devdocs.io/cpp/concept/allocator] with which
+// Allocator: an Allocator [https://devdocs.io/cpp/concept/allocator] with which
// the storage of the hashtable will be allocated and the elements will be
// constructed and destroyed.
template <class Policy, class Hash, class Eq, class Alloc>
class raw_hash_set {
using PolicyTraits = hash_policy_traits<Policy>;
- using KeyArgImpl = container_internal::KeyArg<IsTransparent<Eq>::value &&
- IsTransparent<Hash>::value>;
+ using KeyArgImpl =
+ KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
public:
using init_type = typename PolicyTraits::init_type;
@@ -814,7 +658,11 @@ class raw_hash_set {
}
ctrl_t* ctrl_ = nullptr;
- slot_type* slot_;
+ // To avoid uninitialized member warnigs, put slot_ in an anonymous union.
+ // The member is not initialized on singleton and end iterators.
+ union {
+ slot_type* slot_;
+ };
};
class const_iterator {
@@ -854,7 +702,8 @@ class raw_hash_set {
iterator inner_;
};
- using node_type = container_internal::node_handle<Policy, Alloc>;
+ using node_type = node_handle<Policy, hash_policy_traits<Policy>, Alloc>;
+ using insert_return_type = InsertReturnType<iterator, node_type>;
raw_hash_set() noexcept(
std::is_nothrow_default_constructible<hasher>::value&&
@@ -867,7 +716,7 @@ class raw_hash_set {
: ctrl_(EmptyGroup()), settings_(0, hash, eq, alloc) {
if (bucket_count) {
capacity_ = NormalizeCapacity(bucket_count);
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor);
+ reset_growth_left();
initialize_slots();
}
}
@@ -909,8 +758,8 @@ class raw_hash_set {
// that accept std::initializer_list<T> and std::initializer_list<init_type>.
// This is advantageous for performance.
//
- // // Turns {"abc", "def"} into std::initializer_list<std::string>, then copies
- // // the strings into the set.
+ // // Turns {"abc", "def"} into std::initializer_list<std::string>, then
+ // // copies the strings into the set.
// std::unordered_set<std::string> s = {"abc", "def"};
//
// // Turns {"abc", "def"} into std::initializer_list<const char*>, then
@@ -973,9 +822,10 @@ class raw_hash_set {
// than a full `insert`.
for (const auto& v : that) {
const size_t hash = PolicyTraits::apply(HashElement{hash_ref()}, v);
- const size_t i = find_first_non_full(hash);
- set_ctrl(i, H2(hash));
- emplace_at(i, v);
+ auto target = find_first_non_full(hash);
+ set_ctrl(target.offset, H2(hash));
+ emplace_at(target.offset, v);
+ infoz_.RecordInsert(hash, target.probe_length);
}
size_ = that.size();
growth_left() -= that.size();
@@ -989,6 +839,7 @@ class raw_hash_set {
slots_(absl::exchange(that.slots_, nullptr)),
size_(absl::exchange(that.size_, 0)),
capacity_(absl::exchange(that.capacity_, 0)),
+ infoz_(absl::exchange(that.infoz_, HashtablezInfoHandle())),
// 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.
@@ -1009,6 +860,7 @@ class raw_hash_set {
std::swap(size_, that.size_);
std::swap(capacity_, that.capacity_);
std::swap(growth_left(), that.growth_left());
+ std::swap(infoz_, that.infoz_);
} else {
reserve(that.size());
// Note: this will copy elements of dense_set and unordered_set instead of
@@ -1058,7 +910,7 @@ class raw_hash_set {
size_t capacity() const { return capacity_; }
size_t max_size() const { return (std::numeric_limits<size_t>::max)(); }
- void clear() {
+ ABSL_ATTRIBUTE_REINITIALIZES void clear() {
// 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
@@ -1076,9 +928,10 @@ class raw_hash_set {
}
size_ = 0;
reset_ctrl();
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor);
+ reset_growth_left();
}
assert(empty());
+ infoz_.RecordStorageChanged(0, capacity_);
}
// This overload kicks in when the argument is an rvalue of insertable and
@@ -1117,7 +970,7 @@ class raw_hash_set {
// This overload kicks in when the argument is an rvalue of init_type. Its
// purpose is to handle brace-init-list arguments.
//
- // flat_hash_set<std::string, int> s;
+ // flat_hash_map<std::string, int> s;
// s.insert({"abc", 42});
std::pair<iterator, bool> insert(init_type&& value) {
return emplace(std::move(value));
@@ -1158,13 +1011,14 @@ class raw_hash_set {
insert(ilist.begin(), ilist.end());
}
- insert_return_type<iterator, node_type> insert(node_type&& node) {
+ insert_return_type insert(node_type&& node) {
if (!node) return {end(), false, node_type()};
- const auto& elem = PolicyTraits::element(node.slot());
+ const auto& elem = PolicyTraits::element(CommonAccess::GetSlot(node));
auto res = PolicyTraits::apply(
- InsertSlot<false>{*this, std::move(*node.slot())}, elem);
+ InsertSlot<false>{*this, std::move(*CommonAccess::GetSlot(node))},
+ elem);
if (res.second) {
- node.reset();
+ CommonAccess::Reset(&node);
return {res.first, true, node_type()};
} else {
return {res.first, false, std::move(node)};
@@ -1328,7 +1182,8 @@ class raw_hash_set {
}
node_type extract(const_iterator position) {
- node_type node(alloc_ref(), position.inner_.slot_);
+ auto node =
+ CommonAccess::Transfer<node_type>(alloc_ref(), position.inner_.slot_);
erase_meta_only(position);
return node;
}
@@ -1353,6 +1208,7 @@ class raw_hash_set {
swap(growth_left(), that.growth_left());
swap(hash_ref(), that.hash_ref());
swap(eq_ref(), that.eq_ref());
+ swap(infoz_, that.infoz_);
if (AllocTraits::propagate_on_container_swap::value) {
swap(alloc_ref(), that.alloc_ref());
} else {
@@ -1363,17 +1219,21 @@ class raw_hash_set {
void rehash(size_t n) {
if (n == 0 && capacity_ == 0) return;
- if (n == 0 && size_ == 0) return destroy_slots();
- auto m = NormalizeCapacity(std::max(n, NumSlotsFast(size())));
+ if (n == 0 && size_ == 0) {
+ destroy_slots();
+ infoz_.RecordStorageChanged(0, 0);
+ 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 > capacity_) {
resize(m);
}
}
- void reserve(size_t n) {
- rehash(NumSlotsFast(n));
- }
+ void reserve(size_t n) { rehash(GrowthToLowerboundCapacity(n)); }
// Extension API: support for heterogeneous keys.
//
@@ -1551,13 +1411,6 @@ class raw_hash_set {
slot_type&& slot;
};
- // Computes std::ceil(n / kMaxLoadFactor). Faster than calling std::ceil.
- static inline size_t NumSlotsFast(size_t n) {
- return static_cast<size_t>(
- (n * kMaxLoadFactorDenominator + (kMaxLoadFactorNumerator - 1)) /
- kMaxLoadFactorNumerator);
- }
-
// "erases" the object from the container, except that it doesn't actually
// destroy the object. It only updates all the metadata of the class.
// This can be used in conjunction with Policy::transfer to move the object to
@@ -1580,17 +1433,34 @@ class raw_hash_set {
set_ctrl(index, was_never_full ? kEmpty : kDeleted);
growth_left() += was_never_full;
+ infoz_.RecordErase();
}
void initialize_slots() {
assert(capacity_);
+ // 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 wont 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.
+ //
+ // People are often sloppy with the exact type of their allocator (sometimes
+ // it has an extra const or is missing the pair, but rebinds made it work
+ // anyway). To avoid the ambiguity, we work off SlotAlloc which we have
+ // bound more carefully.
+ if (std::is_same<SlotAlloc, std::allocator<slot_type>>::value &&
+ slots_ == nullptr) {
+ infoz_ = Sample();
+ }
+
auto layout = MakeLayout(capacity_);
char* mem = static_cast<char*>(
Allocate<Layout::Alignment()>(&alloc_ref(), layout.AllocSize()));
ctrl_ = reinterpret_cast<ctrl_t*>(layout.template Pointer<0>(mem));
slots_ = layout.template Pointer<1>(mem);
reset_ctrl();
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_;
+ reset_growth_left();
+ infoz_.RecordStorageChanged(size_, capacity_);
}
void destroy_slots() {
@@ -1619,11 +1489,14 @@ class raw_hash_set {
capacity_ = new_capacity;
initialize_slots();
+ size_t total_probe_length = 0;
for (size_t i = 0; i != old_capacity; ++i) {
if (IsFull(old_ctrl[i])) {
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(old_slots + i));
- size_t new_i = find_first_non_full(hash);
+ auto target = find_first_non_full(hash);
+ size_t new_i = target.offset;
+ total_probe_length += target.probe_length;
set_ctrl(new_i, H2(hash));
PolicyTraits::transfer(&alloc_ref(), slots_ + new_i, old_slots + i);
}
@@ -1635,10 +1508,12 @@ class raw_hash_set {
Deallocate<Layout::Alignment()>(&alloc_ref(), old_ctrl,
layout.AllocSize());
}
+ infoz_.RecordRehash(total_probe_length);
}
void drop_deletes_without_resize() ABSL_ATTRIBUTE_NOINLINE {
assert(IsValidCapacity(capacity_));
+ assert(!is_small());
// Algorithm:
// - mark all DELETED slots as EMPTY
// - mark all FULL slots as DELETED
@@ -1658,12 +1533,15 @@ class raw_hash_set {
ConvertDeletedToEmptyAndFullToDeleted(ctrl_, capacity_);
typename std::aligned_storage<sizeof(slot_type), alignof(slot_type)>::type
raw;
+ size_t total_probe_length = 0;
slot_type* slot = reinterpret_cast<slot_type*>(&raw);
for (size_t i = 0; i != capacity_; ++i) {
if (!IsDeleted(ctrl_[i])) continue;
size_t hash = PolicyTraits::apply(HashElement{hash_ref()},
PolicyTraits::element(slots_ + i));
- size_t new_i = find_first_non_full(hash);
+ auto target = find_first_non_full(hash);
+ size_t new_i = target.offset;
+ total_probe_length += target.probe_length;
// Verify if the old and new i fall within the same group wrt the hash.
// If they do, we don't need to move the object as it falls already in the
@@ -1695,13 +1573,14 @@ class raw_hash_set {
--i; // repeat
}
}
- growth_left() = static_cast<size_t>(capacity_ * kMaxLoadFactor) - size_;
+ reset_growth_left();
+ infoz_.RecordRehash(total_probe_length);
}
void rehash_and_grow_if_necessary() {
if (capacity_ == 0) {
- resize(Group::kWidth - 1);
- } else if (size() <= kMaxLoadFactor / 2 * capacity_) {
+ resize(1);
+ } else if (size() <= CapacityToGrowth(capacity()) / 2) {
// Squash DELETED without growing if there is enough capacity.
drop_deletes_without_resize();
} else {
@@ -1736,24 +1615,26 @@ class raw_hash_set {
// - the input is already a set
// - there are enough slots
// - the element with the hash is not in the table
- size_t find_first_non_full(size_t hash) {
+ struct FindInfo {
+ size_t offset;
+ size_t probe_length;
+ };
+ FindInfo find_first_non_full(size_t hash) {
auto seq = probe(hash);
while (true) {
Group g{ctrl_ + seq.offset()};
auto mask = g.MatchEmptyOrDeleted();
if (mask) {
#if !defined(NDEBUG)
- // We want to force small tables to have random entries too, so
- // in debug build we will randomly insert in either the front or back of
+ // 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
- if (ShouldInsertBackwards(hash, ctrl_))
- return seq.offset(mask.HighestBitSet());
- else
- return seq.offset(mask.LowestBitSet());
-#else
- return seq.offset(mask.LowestBitSet());
+ if (!is_small() && ShouldInsertBackwards(hash, ctrl_)) {
+ return {seq.offset(mask.HighestBitSet()), seq.index()};
+ }
#endif
+ return {seq.offset(mask.LowestBitSet()), seq.index()};
}
assert(seq.index() < capacity_ && "full table!");
seq.next();
@@ -1792,15 +1673,17 @@ class raw_hash_set {
}
size_t prepare_insert(size_t hash) ABSL_ATTRIBUTE_NOINLINE {
- size_t target = find_first_non_full(hash);
- if (ABSL_PREDICT_FALSE(growth_left() == 0 && !IsDeleted(ctrl_[target]))) {
+ auto target = find_first_non_full(hash);
+ if (ABSL_PREDICT_FALSE(growth_left() == 0 &&
+ !IsDeleted(ctrl_[target.offset]))) {
rehash_and_grow_if_necessary();
target = find_first_non_full(hash);
}
++size_;
- growth_left() -= IsEmpty(ctrl_[target]);
- set_ctrl(target, H2(hash));
- return target;
+ growth_left() -= IsEmpty(ctrl_[target.offset]);
+ set_ctrl(target.offset, H2(hash));
+ infoz_.RecordInsert(hash, target.probe_length);
+ return target.offset;
}
// Constructs the value in the space pointed by the iterator. This only works
@@ -1838,6 +1721,10 @@ class raw_hash_set {
SanitizerPoisonMemoryRegion(slots_, sizeof(slot_type) * capacity_);
}
+ void reset_growth_left() {
+ growth_left() = CapacityToGrowth(capacity()) - size_;
+ }
+
// Sets the control byte, and if `i < Group::kWidth`, set the cloned byte at
// the end too.
void set_ctrl(size_t i, ctrl_t h) {
@@ -1850,11 +1737,28 @@ class raw_hash_set {
}
ctrl_[i] = h;
- ctrl_[((i - Group::kWidth) & capacity_) + Group::kWidth] = h;
+ ctrl_[((i - Group::kWidth) & capacity_) + 1 +
+ ((Group::kWidth - 1) & capacity_)] = h;
}
size_t& growth_left() { return settings_.template get<0>(); }
+ // The representation of the object has two modes:
+ // - small: For capacities < kWidth-1
+ // - large: For the rest.
+ //
+ // Differences:
+ // - 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 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.
+ bool is_small() const { return capacity_ < Group::kWidth - 1; }
+
hasher& hash_ref() { return settings_.template get<1>(); }
const hasher& hash_ref() const { return settings_.template get<1>(); }
key_equal& eq_ref() { return settings_.template get<2>(); }
@@ -1864,12 +1768,6 @@ class raw_hash_set {
return settings_.template get<3>();
}
- // On average each group has 2 empty slot (for the vectorized case).
- static constexpr int64_t kMaxLoadFactorNumerator = 14;
- static constexpr int64_t kMaxLoadFactorDenominator = 16;
- static constexpr float kMaxLoadFactor =
- 1.0 * kMaxLoadFactorNumerator / kMaxLoadFactorDenominator;
-
// TODO(alkis): Investigate removing some of these fields:
// - ctrl/slots can be derived from each other
// - size can be moved into the slot array
@@ -1877,6 +1775,7 @@ class raw_hash_set {
slot_type* slots_ = nullptr; // [capacity * slot_type]
size_t size_ = 0; // number of full slots
size_t capacity_ = 0; // total number of slots
+ HashtablezInfoHandle infoz_;
absl::container_internal::CompressedTuple<size_t /* growth_left */, hasher,
key_equal, allocator_type>
settings_{0, hasher{}, key_equal{}, allocator_type{}};
@@ -1929,10 +1828,9 @@ struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
}
static size_t LowerBoundAllocatedByteSize(size_t size) {
- size_t capacity = container_internal::NormalizeCapacity(
- std::ceil(size / Set::kMaxLoadFactor));
+ size_t capacity = GrowthToLowerboundCapacity(size);
if (capacity == 0) return 0;
- auto layout = Set::MakeLayout(capacity);
+ auto layout = Set::MakeLayout(NormalizeCapacity(capacity));
size_t m = layout.AllocSize();
size_t per_slot = Traits::space_used(static_cast<const Slot*>(nullptr));
if (per_slot != ~size_t{}) {
@@ -1944,7 +1842,7 @@ struct HashtableDebugAccess<Set, absl::void_t<typename Set::raw_hash_set>> {
} // namespace hashtable_debug_internal
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_SET_H_
diff --git a/absl/container/internal/raw_hash_set_allocator_test.cc b/absl/container/internal/raw_hash_set_allocator_test.cc
index f5779d62..5188b3ae 100644
--- a/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "absl/container/internal/tracked.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -426,5 +426,5 @@ TEST_F(PropagateOnAll, Swap) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 302f9758..2783f5c4 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -35,7 +35,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
struct RawHashSetTestOnlyAccess {
@@ -49,18 +49,47 @@ namespace {
using ::testing::DoubleNear;
using ::testing::ElementsAre;
+using ::testing::Ge;
+using ::testing::Lt;
using ::testing::Optional;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
TEST(Util, NormalizeCapacity) {
- constexpr size_t kMinCapacity = Group::kWidth - 1;
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(0));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(1));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(2));
- EXPECT_EQ(kMinCapacity, NormalizeCapacity(kMinCapacity));
- EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 1));
- EXPECT_EQ(kMinCapacity * 2 + 1, NormalizeCapacity(kMinCapacity + 2));
+ EXPECT_EQ(1, NormalizeCapacity(0));
+ EXPECT_EQ(1, NormalizeCapacity(1));
+ EXPECT_EQ(3, NormalizeCapacity(2));
+ EXPECT_EQ(3, NormalizeCapacity(3));
+ EXPECT_EQ(7, NormalizeCapacity(4));
+ EXPECT_EQ(7, NormalizeCapacity(7));
+ EXPECT_EQ(15, NormalizeCapacity(8));
+ EXPECT_EQ(15, NormalizeCapacity(15));
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 1));
+ EXPECT_EQ(15 * 2 + 1, NormalizeCapacity(15 + 2));
+}
+
+TEST(Util, GrowthAndCapacity) {
+ // Verify that GrowthToCapacity gives the minimum capacity that has enough
+ // growth.
+ for (size_t growth = 0; growth < 10000; ++growth) {
+ SCOPED_TRACE(growth);
+ size_t capacity = NormalizeCapacity(GrowthToLowerboundCapacity(growth));
+ // The capacity is large enough for `growth`
+ EXPECT_THAT(CapacityToGrowth(capacity), Ge(growth));
+ if (growth != 0 && capacity > 1) {
+ // There is no smaller capacity that works.
+ EXPECT_THAT(CapacityToGrowth(capacity / 2), Lt(growth));
+ }
+ }
+
+ for (size_t capacity = Group::kWidth - 1; capacity < 10000;
+ capacity = 2 * capacity + 1) {
+ SCOPED_TRACE(capacity);
+ size_t growth = CapacityToGrowth(capacity);
+ EXPECT_THAT(growth, Lt(capacity));
+ EXPECT_LE(GrowthToLowerboundCapacity(growth), capacity);
+ EXPECT_EQ(NormalizeCapacity(GrowthToLowerboundCapacity(growth)), capacity);
+ }
}
TEST(Util, probe_seq) {
@@ -107,14 +136,14 @@ TEST(BitMask, WithShift) {
}
TEST(BitMask, LeadingTrailing) {
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).LeadingZeros()), 3);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0001101001000000).TrailingZeros()), 6);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).LeadingZeros()), 3);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00001a40).TrailingZeros()), 6);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).LeadingZeros()), 15);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b0000000000000001).TrailingZeros()), 0);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).LeadingZeros()), 15);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00000001).TrailingZeros()), 0);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).LeadingZeros()), 0);
- EXPECT_EQ((BitMask<uint32_t, 16>(0b1000000000000000).TrailingZeros()), 15);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).LeadingZeros()), 0);
+ EXPECT_EQ((BitMask<uint32_t, 16>(0x00008000).TrailingZeros()), 15);
EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).LeadingZeros()), 3);
EXPECT_EQ((BitMask<uint64_t, 8, 3>(0x0000008080808000).TrailingZeros()), 1);
@@ -315,7 +344,25 @@ struct IntTable
: raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
std::equal_to<int64_t>, std::allocator<int64_t>> {
using Base = typename IntTable::raw_hash_set;
- IntTable() {}
+ using Base::Base;
+};
+
+template <typename T>
+struct CustomAlloc : std::allocator<T> {
+ CustomAlloc() {}
+
+ template <typename U>
+ CustomAlloc(const CustomAlloc<U>& other) {}
+
+ template<class U> struct rebind {
+ using other = CustomAlloc<U>;
+ };
+};
+
+struct CustomAllocIntTable
+ : raw_hash_set<IntPolicy, container_internal::hash_default_hash<int64_t>,
+ std::equal_to<int64_t>, CustomAlloc<int64_t>> {
+ using Base = typename CustomAllocIntTable::raw_hash_set;
using Base::Base;
};
@@ -343,6 +390,7 @@ TEST(Table, EmptyFunctorOptimization) {
size_t size;
size_t capacity;
size_t growth_left;
+ void* infoz;
};
struct StatelessHash {
size_t operator()(absl::string_view) const { return 0; }
@@ -385,10 +433,11 @@ TEST(Table, Prefetch) {
t.prefetch(2);
// Do not run in debug mode, when prefetch is not implemented, or when
- // sanitizers are enabled.
-#if defined(NDEBUG) && defined(__GNUC__) && !defined(ADDRESS_SANITIZER) && \
- !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
- !defined(UNDEFINED_BEHAVIOR_SANITIZER)
+ // sanitizers are enabled, or on WebAssembly.
+#if defined(NDEBUG) && defined(__GNUC__) && defined(__x86_64__) && \
+ !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+ !defined(THREAD_SANITIZER) && !defined(UNDEFINED_BEHAVIOR_SANITIZER) && \
+ !defined(__EMSCRIPTEN__)
const auto now = [] { return absl::base_internal::CycleClock::Now(); };
// Make size enough to not fit in L2 cache (16.7 Mb)
@@ -785,7 +834,7 @@ TEST(Table, EnsureNonQuadraticAsInRust) {
TEST(Table, ClearBug) {
IntTable t;
constexpr size_t capacity = container_internal::Group::kWidth - 1;
- constexpr size_t max_size = capacity / 2;
+ constexpr size_t max_size = capacity / 2 + 1;
for (size_t i = 0; i < max_size; ++i) {
t.insert(i);
}
@@ -816,6 +865,25 @@ TEST(Table, Erase) {
EXPECT_TRUE(t.find(0) == t.end());
}
+TEST(Table, EraseMaintainsValidIterator) {
+ IntTable t;
+ const int kNumElements = 100;
+ for (int i = 0; i < kNumElements; i ++) {
+ EXPECT_TRUE(t.emplace(i).second);
+ }
+ EXPECT_EQ(t.size(), kNumElements);
+
+ int num_erase_calls = 0;
+ auto it = t.begin();
+ while (it != t.end()) {
+ t.erase(it++);
+ num_erase_calls++;
+ }
+
+ EXPECT_TRUE(t.empty());
+ EXPECT_EQ(num_erase_calls, kNumElements);
+}
+
// Collect N bad keys by following algorithm:
// 1. Create an empty table and reserve it to 2 * N.
// 2. Insert N random elements.
@@ -1014,7 +1082,7 @@ ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys
ExpectedStats XorSeedExpectedStats() {
constexpr bool kRandomizesInserts =
-#if NDEBUG
+#ifdef NDEBUG
false;
#else // NDEBUG
true;
@@ -1051,6 +1119,7 @@ ExpectedStats XorSeedExpectedStats() {
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
+
TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
ProbeStatsPerSize stats;
std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
@@ -1107,7 +1176,7 @@ ProbeStats CollectProbeStatsOnLinearlyTransformedKeys(
ExpectedStats LinearTransformExpectedStats() {
constexpr bool kRandomizesInserts =
-#if NDEBUG
+#ifdef NDEBUG
false;
#else // NDEBUG
true;
@@ -1144,6 +1213,7 @@ ExpectedStats LinearTransformExpectedStats() {
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
+
TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
ProbeStatsPerSize stats;
std::vector<size_t> sizes = {Group::kWidth << 5, Group::kWidth << 10};
@@ -1296,37 +1366,31 @@ TEST(Table, ConstructFromInitList) {
TEST(Table, CopyConstruct) {
IntTable t;
- t.max_load_factor(.321f);
t.emplace(0);
EXPECT_EQ(1, t.size());
{
IntTable u(t);
EXPECT_EQ(1, u.size());
- EXPECT_EQ(t.max_load_factor(), u.max_load_factor());
EXPECT_THAT(*u.find(0), 0);
}
{
IntTable u{t};
EXPECT_EQ(1, u.size());
- EXPECT_EQ(t.max_load_factor(), u.max_load_factor());
EXPECT_THAT(*u.find(0), 0);
}
{
IntTable u = t;
EXPECT_EQ(1, u.size());
- EXPECT_EQ(t.max_load_factor(), u.max_load_factor());
EXPECT_THAT(*u.find(0), 0);
}
}
TEST(Table, CopyConstructWithAlloc) {
StringTable t;
- t.max_load_factor(.321f);
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u(t, Alloc<std::pair<std::string, std::string>>());
EXPECT_EQ(1, u.size());
- EXPECT_EQ(t.max_load_factor(), u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
@@ -1344,94 +1408,75 @@ TEST(Table, AllocWithExplicitCtor) {
TEST(Table, MoveConstruct) {
{
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u(std::move(t));
EXPECT_EQ(1, u.size());
- EXPECT_EQ(lf, u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
{
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u{std::move(t)};
EXPECT_EQ(1, u.size());
- EXPECT_EQ(lf, u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
{
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u = std::move(t);
EXPECT_EQ(1, u.size());
- EXPECT_EQ(lf, u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
}
TEST(Table, MoveConstructWithAlloc) {
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u(std::move(t), Alloc<std::pair<std::string, std::string>>());
EXPECT_EQ(1, u.size());
- EXPECT_EQ(lf, u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
TEST(Table, CopyAssign) {
StringTable t;
- t.max_load_factor(.321f);
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u;
u = t;
EXPECT_EQ(1, u.size());
- EXPECT_EQ(t.max_load_factor(), u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
TEST(Table, CopySelfAssign) {
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
t = *&t;
EXPECT_EQ(1, t.size());
- EXPECT_EQ(lf, t.max_load_factor());
EXPECT_THAT(*t.find("a"), Pair("a", "b"));
}
TEST(Table, MoveAssign) {
StringTable t;
- t.max_load_factor(.321f);
- const float lf = t.max_load_factor();
t.emplace("a", "b");
EXPECT_EQ(1, t.size());
StringTable u;
u = std::move(t);
EXPECT_EQ(1, u.size());
- EXPECT_EQ(lf, u.max_load_factor());
EXPECT_THAT(*u.find("a"), Pair("a", "b"));
}
TEST(Table, Equality) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v = {{"a", "b"}, {"aa", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v = {{"a", "b"},
+ {"aa", "bb"}};
t.insert(std::begin(v), std::end(v));
StringTable u = t;
EXPECT_EQ(u, t);
@@ -1439,20 +1484,24 @@ TEST(Table, Equality) {
TEST(Table, Equality2) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"}, {"aa", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v1 = {{"a", "b"},
+ {"aa", "bb"}};
t.insert(std::begin(v1), std::end(v1));
StringTable u;
- std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}};
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
+ {"aa", "aa"}};
u.insert(std::begin(v2), std::end(v2));
EXPECT_NE(u, t);
}
TEST(Table, Equality3) {
StringTable t;
- std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"}, {"bb", "bb"}};
+ std::vector<std::pair<std::string, std::string>> v1 = {{"b", "b"},
+ {"bb", "bb"}};
t.insert(std::begin(v1), std::end(v1));
StringTable u;
- std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"}, {"aa", "aa"}};
+ std::vector<std::pair<std::string, std::string>> v2 = {{"a", "a"},
+ {"aa", "aa"}};
u.insert(std::begin(v2), std::end(v2));
EXPECT_NE(u, t);
}
@@ -1677,7 +1726,7 @@ TEST(Nodes, ExtractInsert) {
EXPECT_FALSE(node.empty());
StringTable t2;
- auto res = t2.insert(std::move(node));
+ StringTable::insert_return_type res = t2.insert(std::move(node));
EXPECT_TRUE(res.inserted);
EXPECT_THAT(*res.position, Pair(k0, ""));
EXPECT_FALSE(res.node);
@@ -1707,80 +1756,74 @@ TEST(Nodes, ExtractInsert) {
EXPECT_FALSE(node);
}
-StringTable MakeSimpleTable(size_t size) {
- StringTable t;
- for (size_t i = 0; i < size; ++i) t.emplace(std::string(1, 'A' + i), "");
+IntTable MakeSimpleTable(size_t size) {
+ IntTable t;
+ while (t.size() < size) t.insert(t.size());
return t;
}
-std::string OrderOfIteration(const StringTable& t) {
- std::string order;
- for (auto& p : t) order += p.first;
- return order;
+std::vector<int> OrderOfIteration(const IntTable& t) {
+ return {t.begin(), t.end()};
}
+// 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.
TEST(Table, IterationOrderChangesByInstance) {
- // Needs to be more than kWidth elements to be able to affect order.
- const StringTable reference = MakeSimpleTable(20);
-
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed. It should not take many tries
- // for that.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- std::vector<StringTable> garbage;
- for (int i = 0; i < 10; ++i) {
- auto trial = MakeSimpleTable(20);
- if (OrderOfIteration(trial) != OrderOfIteration(reference)) {
- // We are done.
- return;
+ for (size_t size : {2, 6, 12, 20}) {
+ const auto reference_table = MakeSimpleTable(size);
+ const auto reference = OrderOfIteration(reference_table);
+
+ std::vector<IntTable> tables;
+ bool found_difference = false;
+ for (int i = 0; !found_difference && i < 5000; ++i) {
+ tables.push_back(MakeSimpleTable(size));
+ found_difference = OrderOfIteration(tables.back()) != reference;
+ }
+ if (!found_difference) {
+ FAIL()
+ << "Iteration order remained the same across many attempts with size "
+ << size;
}
- garbage.push_back(std::move(trial));
}
- FAIL();
}
TEST(Table, IterationOrderChangesOnRehash) {
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed. It should not take many tries
- // for that.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- std::vector<StringTable> garbage;
- for (int i = 0; i < 10; ++i) {
- // Needs to be more than kWidth elements to be able to affect order.
- StringTable t = MakeSimpleTable(20);
- const std::string reference = OrderOfIteration(t);
+ std::vector<IntTable> garbage;
+ for (int i = 0; i < 5000; ++i) {
+ auto t = MakeSimpleTable(20);
+ const auto reference = OrderOfIteration(t);
// Force rehash to the same size.
t.rehash(0);
- std::string trial = OrderOfIteration(t);
+ auto trial = OrderOfIteration(t);
if (trial != reference) {
// We are done.
return;
}
garbage.push_back(std::move(t));
}
- FAIL();
+ FAIL() << "Iteration order remained the same across many attempts.";
}
-TEST(Table, IterationOrderChangesForSmallTables) {
- // Since order is non-deterministic we can't just try once and verify.
- // We'll try until we find that order changed.
- // Important: we have to keep the old tables around. Otherwise tcmalloc will
- // just give us the same blocks and we would be doing the same order again.
- StringTable reference_table = MakeSimpleTable(5);
- const std::string reference = OrderOfIteration(reference_table);
- std::vector<StringTable> garbage;
- for (int i = 0; i < 50; ++i) {
- StringTable t = MakeSimpleTable(5);
- std::string trial = OrderOfIteration(t);
- if (trial != reference) {
- // We are done.
- return;
- }
- garbage.push_back(std::move(t));
- }
- FAIL() << "Iteration order remained the same across many attempts.";
+// Verify that pointers are invalidated as soon as a second element is inserted.
+// This prevents dependency on pointer stability on small tables.
+TEST(Table, UnstablePointers) {
+ IntTable table;
+
+ const auto addr = [&](int i) {
+ return reinterpret_cast<uintptr_t>(&*table.find(i));
+ };
+
+ table.insert(0);
+ const uintptr_t old_ptr = addr(0);
+
+ // This causes a rehash.
+ table.insert(1);
+
+ EXPECT_NE(old_ptr, addr(0));
}
// Confirm that we assert if we try to erase() end().
@@ -1799,9 +1842,52 @@ TEST(TableDeathTest, EraseOfEndAsserts) {
EXPECT_DEATH_IF_SUPPORTED(t.erase(t.end()), kDeathMsg);
}
+TEST(RawHashSamplerTest, Sample) {
+ // Enable the feature even if the prod default is off.
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+
+ auto& sampler = HashtablezSampler::Global();
+ size_t start_size = 0;
+ start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
+
+ std::vector<IntTable> tables;
+ for (int i = 0; i < 1000000; ++i) {
+ tables.emplace_back();
+ tables.back().insert(1);
+ }
+ size_t end_size = 0;
+ end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
+
+ EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
+ 0.01, 0.005);
+}
+
+TEST(RawHashSamplerTest, DoNotSampleCustomAllocators) {
+ // Enable the feature even if the prod default is off.
+ SetHashtablezEnabled(true);
+ SetHashtablezSampleParameter(100);
+
+ auto& sampler = HashtablezSampler::Global();
+ size_t start_size = 0;
+ start_size += sampler.Iterate([&](const HashtablezInfo&) { ++start_size; });
+
+ std::vector<CustomAllocIntTable> tables;
+ for (int i = 0; i < 1000000; ++i) {
+ tables.emplace_back();
+ tables.back().insert(1);
+ }
+ size_t end_size = 0;
+ end_size += sampler.Iterate([&](const HashtablezInfo&) { ++end_size; });
+
+ EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
+ 0.00, 0.001);
+}
+
#ifdef ADDRESS_SANITIZER
TEST(Sanitizer, PoisoningUnused) {
IntTable t;
+ t.reserve(5);
// Insert something to force an allocation.
int64_t& v1 = *t.insert(0).first;
@@ -1826,5 +1912,5 @@ TEST(Sanitizer, PoisoningOnErase) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/test_instance_tracker.cc b/absl/container/internal/test_instance_tracker.cc
index 91441729..f4b283fd 100644
--- a/absl/container/internal/test_instance_tracker.cc
+++ b/absl/container/internal/test_instance_tracker.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/container/internal/test_instance_tracker.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace test_internal {
int BaseCountedInstance::num_instances_ = 0;
int BaseCountedInstance::num_live_instances_ = 0;
@@ -25,5 +25,5 @@ int BaseCountedInstance::num_swaps_ = 0;
int BaseCountedInstance::num_comparisons_ = 0;
} // namespace test_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/test_instance_tracker.h b/absl/container/internal/test_instance_tracker.h
index 060077d0..ab7f9f22 100644
--- a/absl/container/internal/test_instance_tracker.h
+++ b/absl/container/internal/test_instance_tracker.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,11 +18,13 @@
#include <cstdlib>
#include <ostream>
+#include "absl/types/compare.h"
+
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace test_internal {
-// A type that counts number of occurences of the type, the live occurrences of
+// A type that counts number of occurrences of the type, the live occurrences of
// the type, as well as the number of copies, moves, swaps, and comparisons that
// have occurred on the type. This is used as a base class for the copyable,
// copyable+movable, and movable types below that are used in actual tests. Use
@@ -97,6 +99,14 @@ class BaseCountedInstance {
return value_ >= x.value_;
}
+ absl::weak_ordering compare(const BaseCountedInstance& x) const {
+ ++num_comparisons_;
+ return value_ < x.value_
+ ? absl::weak_ordering::less
+ : value_ == x.value_ ? absl::weak_ordering::equivalent
+ : absl::weak_ordering::greater;
+ }
+
int value() const {
if (!is_live_) std::abort();
return value_;
@@ -258,7 +268,7 @@ class MovableOnlyInstance : public BaseCountedInstance {
};
} // namespace test_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_
diff --git a/absl/container/internal/test_instance_tracker_test.cc b/absl/container/internal/test_instance_tracker_test.cc
index 0ae57636..1c6a4fa7 100644
--- a/absl/container/internal/test_instance_tracker_test.cc
+++ b/absl/container/internal/test_instance_tracker_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -174,6 +174,8 @@ TEST(TestInstanceTracker, Comparisons) {
EXPECT_EQ(5, tracker.comparisons());
EXPECT_FALSE(one >= two);
EXPECT_EQ(6, tracker.comparisons());
+ EXPECT_TRUE(one.compare(two) < 0); // NOLINT
+ EXPECT_EQ(7, tracker.comparisons());
tracker.ResetCopiesMovesSwaps();
EXPECT_EQ(0, tracker.comparisons());
diff --git a/absl/container/internal/tracked.h b/absl/container/internal/tracked.h
index f72c46ea..e9e6b95d 100644
--- a/absl/container/internal/tracked.h
+++ b/absl/container/internal/tracked.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include <utility>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
// A class that tracks its copies and moves so that it can be queried in tests.
@@ -74,7 +74,7 @@ class Tracked {
};
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_TRACKED_H_
diff --git a/absl/container/internal/unordered_map_constructor_test.h b/absl/container/internal/unordered_map_constructor_test.h
index 14ceeecb..b64b5520 100644
--- a/absl/container/internal/unordered_map_constructor_test.h
+++ b/absl/container/internal/unordered_map_constructor_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,13 +24,13 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordMap>
class ConstructorTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ConstructorTest);
+TYPED_TEST_SUITE_P(ConstructorTest);
TYPED_TEST_P(ConstructorTest, NoArgs) {
TypeParam m;
@@ -84,8 +84,28 @@ TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+template <typename T>
+struct is_std_unordered_map : std::false_type {};
+
+template <typename... T>
+struct is_std_unordered_map<std::unordered_map<T...>> : std::true_type {};
+
#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+using has_cxx14_std_apis = std::true_type;
+#else
+using has_cxx14_std_apis = std::false_type;
+#endif
+
+template <typename T>
+using expect_cxx14_apis =
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
+ has_cxx14_std_apis>;
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
@@ -93,11 +113,17 @@ TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::true_type) {
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
@@ -108,18 +134,38 @@ TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketAlloc) {
+TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+using has_alloc_std_constructors = std::true_type;
+#else
+using has_alloc_std_constructors = std::false_type;
+#endif
+
+template <typename T>
+using expect_alloc_constructors =
+ absl::disjunction<absl::negation<is_std_unordered_map<T>>,
+ has_alloc_std_constructors>;
+
+template <typename TypeParam>
+void AllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void AllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(m, ::testing::UnorderedElementsAre());
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, Alloc) {
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
@@ -141,8 +187,11 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
@@ -153,11 +202,17 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -171,7 +226,10 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, CopyConstructor) {
@@ -191,8 +249,11 @@ TYPED_TEST_P(ConstructorTest, CopyConstructor) {
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -207,7 +268,10 @@ TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on copy constructors.
@@ -230,8 +294,11 @@ TYPED_TEST_P(ConstructorTest, MoveConstructor) {
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -247,7 +314,10 @@ TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on move constructors.
@@ -270,8 +340,11 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::Generator<T> gen;
@@ -281,11 +354,17 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-#if defined(UNORDERED_MAP_CXX14) || defined(UNORDERED_MAP_CXX17)
+TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -298,7 +377,10 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(items(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, Assignment) {
@@ -391,17 +473,17 @@ TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
REGISTER_TYPED_TEST_CASE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
- BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc,
- BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
- MoveAssignment, AssignmentFromInitializerList,
- AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting,
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
+ MoveAssignmentOverwritesExisting,
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_map_lookup_test.h b/absl/container/internal/unordered_map_lookup_test.h
index d767aa8d..9ad78a79 100644
--- a/absl/container/internal/unordered_map_lookup_test.h
+++ b/absl/container/internal/unordered_map_lookup_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,13 +21,13 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordMap>
class LookupTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(LookupTest);
+TYPED_TEST_SUITE_P(LookupTest);
TYPED_TEST_P(LookupTest, At) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -111,7 +111,7 @@ REGISTER_TYPED_TEST_CASE_P(LookupTest, At, OperatorBracket, Count, Find,
EqualRange);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_map_members_test.h b/absl/container/internal/unordered_map_members_test.h
new file mode 100644
index 00000000..c4600405
--- /dev/null
+++ b/absl/container/internal/unordered_map_members_test.h
@@ -0,0 +1,87 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
+#define ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
+
+#include <type_traits>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+template <class UnordMap>
+class MembersTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(MembersTest);
+
+template <typename T>
+void UseType() {}
+
+TYPED_TEST_P(MembersTest, Typedefs) {
+ EXPECT_TRUE((std::is_same<std::pair<const typename TypeParam::key_type,
+ typename TypeParam::mapped_type>,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((absl::conjunction<
+ absl::negation<std::is_signed<typename TypeParam::size_type>>,
+ std::is_integral<typename TypeParam::size_type>>()));
+ EXPECT_TRUE((absl::conjunction<
+ std::is_signed<typename TypeParam::difference_type>,
+ std::is_integral<typename TypeParam::difference_type>>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::hasher&>()(
+ std::declval<const typename TypeParam::key_type&>())),
+ size_t>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::key_equal&>()(
+ std::declval<const typename TypeParam::key_type&>(),
+ std::declval<const typename TypeParam::key_type&>())),
+ bool>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::value_type&,
+ typename TypeParam::reference>()));
+ EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&,
+ typename TypeParam::const_reference>()));
+ EXPECT_TRUE((std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::pointer,
+ typename TypeParam::pointer>()));
+ EXPECT_TRUE(
+ (std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::const_pointer,
+ typename TypeParam::const_pointer>()));
+}
+
+TYPED_TEST_P(MembersTest, SimpleFunctions) {
+ EXPECT_GT(TypeParam().max_size(), 0);
+}
+
+TYPED_TEST_P(MembersTest, BeginEnd) {
+ TypeParam t = {typename TypeParam::value_type{}};
+ EXPECT_EQ(t.begin(), t.cbegin());
+ EXPECT_EQ(t.end(), t.cend());
+ EXPECT_NE(t.begin(), t.end());
+ EXPECT_NE(t.cbegin(), t.cend());
+}
+
+REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_modifiers_test.h b/absl/container/internal/unordered_map_modifiers_test.h
index 5d7f1fe3..89dd7894 100644
--- a/absl/container/internal/unordered_map_modifiers_test.h
+++ b/absl/container/internal/unordered_map_modifiers_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,13 +21,13 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordMap>
class ModifiersTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ModifiersTest);
+TYPED_TEST_SUITE_P(ModifiersTest);
TYPED_TEST_P(ModifiersTest, Clear) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -269,7 +269,7 @@ REGISTER_TYPED_TEST_CASE_P(ModifiersTest, Clear, Insert, InsertHint,
Erase, EraseRange, EraseKey, Swap);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_MAP_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_map_test.cc b/absl/container/internal/unordered_map_test.cc
index 548f69f7..51a90af8 100644
--- a/absl/container/internal/unordered_map_test.cc
+++ b/absl/container/internal/unordered_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,10 +16,11 @@
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -30,11 +31,12 @@ using MapTypes = ::testing::Types<
StatefulTestingEqual,
Alloc<std::pair<const std::string, std::string>>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedMap, ModifiersTest, MapTypes);
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/internal/unordered_set_constructor_test.h b/absl/container/internal/unordered_set_constructor_test.h
index f370b249..ac73a896 100644
--- a/absl/container/internal/unordered_set_constructor_test.h
+++ b/absl/container/internal/unordered_set_constructor_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,21 +16,23 @@
#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
#include <algorithm>
+#include <unordered_set>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/hash_policy_testing.h"
+#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordMap>
class ConstructorTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ConstructorTest);
+TYPED_TEST_SUITE_P(ConstructorTest);
TYPED_TEST_P(ConstructorTest, NoArgs) {
TypeParam m;
@@ -92,8 +94,28 @@ TYPED_TEST_P(ConstructorTest, BucketCountHashEqualAlloc) {
EXPECT_GE(cm.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+template <typename T>
+struct is_std_unordered_set : std::false_type {};
+
+template <typename... T>
+struct is_std_unordered_set<std::unordered_set<T...>> : std::true_type {};
+
#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+using has_cxx14_std_apis = std::true_type;
+#else
+using has_cxx14_std_apis = std::false_type;
+#endif
+
+template <typename T>
+using expect_cxx14_apis =
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
+ has_cxx14_std_apis>;
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountAllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(123, alloc);
@@ -101,11 +123,17 @@ TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, BucketCountAlloc) {
+ BucketCountAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void BucketCountHashAllocTest(std::true_type) {
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
H hasher;
@@ -116,18 +144,38 @@ TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, BucketAlloc) {
+TYPED_TEST_P(ConstructorTest, BucketCountHashAlloc) {
+ BucketCountHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+using has_alloc_std_constructors = std::true_type;
+#else
+using has_alloc_std_constructors = std::false_type;
+#endif
+
+template <typename T>
+using expect_alloc_constructors =
+ absl::disjunction<absl::negation<is_std_unordered_set<T>>,
+ has_alloc_std_constructors>;
+
+template <typename TypeParam>
+void AllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void AllocTest(std::true_type) {
using A = typename TypeParam::allocator_type;
A alloc(0);
TypeParam m(alloc);
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_TRUE(m.empty());
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAre());
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, Alloc) {
+ AllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
@@ -149,8 +197,11 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashEqualAlloc) {
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
A alloc(0);
@@ -161,11 +212,17 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketAlloc) {
+ InputIteratorBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InputIteratorBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -179,7 +236,10 @@ TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, InputIteratorBucketHashAlloc) {
+ InputIteratorBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
}
TYPED_TEST_P(ConstructorTest, CopyConstructor) {
@@ -197,10 +257,14 @@ TYPED_TEST_P(ConstructorTest, CopyConstructor) {
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_EQ(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
+ EXPECT_NE(TypeParam(0, hasher, equal, alloc), n);
}
-TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void CopyConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -215,7 +279,10 @@ TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, CopyConstructorAlloc) {
+ CopyConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on copy constructors.
@@ -238,8 +305,11 @@ TYPED_TEST_P(ConstructorTest, MoveConstructor) {
EXPECT_EQ(m, n);
}
-TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
-#if ABSL_UNORDERED_SUPPORTS_ALLOC_CTORS
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void MoveConstructorAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -255,7 +325,10 @@ TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
EXPECT_EQ(m.key_eq(), n.key_eq());
EXPECT_NE(m.get_allocator(), n.get_allocator());
EXPECT_EQ(m, n);
-#endif
+}
+
+TYPED_TEST_P(ConstructorTest, MoveConstructorAlloc) {
+ MoveConstructorAllocTest<TypeParam>(expect_alloc_constructors<TypeParam>());
}
// TODO(alkis): Test non-propagating allocators on move constructors.
@@ -278,8 +351,11 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashEqualAlloc) {
EXPECT_GE(m.bucket_count(), 123);
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using A = typename TypeParam::allocator_type;
hash_internal::Generator<T> gen;
@@ -289,11 +365,17 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
-#if defined(UNORDERED_SET_CXX14) || defined(UNORDERED_SET_CXX17)
+TYPED_TEST_P(ConstructorTest, InitializerListBucketAlloc) {
+ InitializerListBucketAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::false_type) {}
+
+template <typename TypeParam>
+void InitializerListBucketHashAllocTest(std::true_type) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using A = typename TypeParam::allocator_type;
@@ -306,10 +388,13 @@ TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
EXPECT_EQ(m.get_allocator(), alloc);
EXPECT_THAT(keys(m), ::testing::UnorderedElementsAreArray(values));
EXPECT_GE(m.bucket_count(), 123);
-#endif
}
-TYPED_TEST_P(ConstructorTest, Assignment) {
+TYPED_TEST_P(ConstructorTest, InitializerListBucketHashAlloc) {
+ InitializerListBucketHashAllocTest<TypeParam>(expect_cxx14_apis<TypeParam>());
+}
+
+TYPED_TEST_P(ConstructorTest, CopyAssignment) {
using T = hash_internal::GeneratedType<TypeParam>;
using H = typename TypeParam::hasher;
using E = typename TypeParam::key_equal;
@@ -395,17 +480,17 @@ TYPED_TEST_P(ConstructorTest, AssignmentOnSelf) {
REGISTER_TYPED_TEST_CASE_P(
ConstructorTest, NoArgs, BucketCount, BucketCountHash, BucketCountHashEqual,
- BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc,
- BucketAlloc, InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
+ BucketCountHashEqualAlloc, BucketCountAlloc, BucketCountHashAlloc, Alloc,
+ InputIteratorBucketHashEqualAlloc, InputIteratorBucketAlloc,
InputIteratorBucketHashAlloc, CopyConstructor, CopyConstructorAlloc,
MoveConstructor, MoveConstructorAlloc, InitializerListBucketHashEqualAlloc,
- InitializerListBucketAlloc, InitializerListBucketHashAlloc, Assignment,
- MoveAssignment, AssignmentFromInitializerList,
- AssignmentOverwritesExisting, MoveAssignmentOverwritesExisting,
+ InitializerListBucketAlloc, InitializerListBucketHashAlloc, CopyAssignment,
+ MoveAssignment, AssignmentFromInitializerList, AssignmentOverwritesExisting,
+ MoveAssignmentOverwritesExisting,
AssignmentFromInitializerListOverwritesExisting, AssignmentOnSelf);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_CONSTRUCTOR_TEST_H_
diff --git a/absl/container/internal/unordered_set_lookup_test.h b/absl/container/internal/unordered_set_lookup_test.h
index 9174279a..722fb1c2 100644
--- a/absl/container/internal/unordered_set_lookup_test.h
+++ b/absl/container/internal/unordered_set_lookup_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,13 +21,13 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordSet>
class LookupTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(LookupTest);
+TYPED_TEST_SUITE_P(LookupTest);
TYPED_TEST_P(LookupTest, Count) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -85,7 +85,7 @@ TYPED_TEST_P(LookupTest, EqualRange) {
REGISTER_TYPED_TEST_CASE_P(LookupTest, Count, Find, EqualRange);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_LOOKUP_TEST_H_
diff --git a/absl/container/internal/unordered_set_members_test.h b/absl/container/internal/unordered_set_members_test.h
new file mode 100644
index 00000000..756a95cb
--- /dev/null
+++ b/absl/container/internal/unordered_set_members_test.h
@@ -0,0 +1,86 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
+#define ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
+
+#include <type_traits>
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace container_internal {
+
+template <class UnordSet>
+class MembersTest : public ::testing::Test {};
+
+TYPED_TEST_SUITE_P(MembersTest);
+
+template <typename T>
+void UseType() {}
+
+TYPED_TEST_P(MembersTest, Typedefs) {
+ EXPECT_TRUE((std::is_same<typename TypeParam::key_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((absl::conjunction<
+ absl::negation<std::is_signed<typename TypeParam::size_type>>,
+ std::is_integral<typename TypeParam::size_type>>()));
+ EXPECT_TRUE((absl::conjunction<
+ std::is_signed<typename TypeParam::difference_type>,
+ std::is_integral<typename TypeParam::difference_type>>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::hasher&>()(
+ std::declval<const typename TypeParam::key_type&>())),
+ size_t>()));
+ EXPECT_TRUE((std::is_convertible<
+ decltype(std::declval<const typename TypeParam::key_equal&>()(
+ std::declval<const typename TypeParam::key_type&>(),
+ std::declval<const typename TypeParam::key_type&>())),
+ bool>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::allocator_type::value_type,
+ typename TypeParam::value_type>()));
+ EXPECT_TRUE((std::is_same<typename TypeParam::value_type&,
+ typename TypeParam::reference>()));
+ EXPECT_TRUE((std::is_same<const typename TypeParam::value_type&,
+ typename TypeParam::const_reference>()));
+ EXPECT_TRUE((std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::pointer,
+ typename TypeParam::pointer>()));
+ EXPECT_TRUE(
+ (std::is_same<typename std::allocator_traits<
+ typename TypeParam::allocator_type>::const_pointer,
+ typename TypeParam::const_pointer>()));
+}
+
+TYPED_TEST_P(MembersTest, SimpleFunctions) {
+ EXPECT_GT(TypeParam().max_size(), 0);
+}
+
+TYPED_TEST_P(MembersTest, BeginEnd) {
+ TypeParam t = {typename TypeParam::value_type{}};
+ EXPECT_EQ(t.begin(), t.cbegin());
+ EXPECT_EQ(t.end(), t.cend());
+ EXPECT_NE(t.begin(), t.end());
+ EXPECT_NE(t.cbegin(), t.cend());
+}
+
+REGISTER_TYPED_TEST_SUITE_P(MembersTest, Typedefs, SimpleFunctions, BeginEnd);
+
+} // namespace container_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MEMBERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_modifiers_test.h b/absl/container/internal/unordered_set_modifiers_test.h
index 0a1e9b1b..d3e534d3 100644
--- a/absl/container/internal/unordered_set_modifiers_test.h
+++ b/absl/container/internal/unordered_set_modifiers_test.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,13 +21,13 @@
#include "absl/container/internal/hash_policy_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class UnordSet>
class ModifiersTest : public ::testing::Test {};
-TYPED_TEST_CASE_P(ModifiersTest);
+TYPED_TEST_SUITE_P(ModifiersTest);
TYPED_TEST_P(ModifiersTest, Clear) {
using T = hash_internal::GeneratedType<TypeParam>;
@@ -184,7 +184,7 @@ REGISTER_TYPED_TEST_CASE_P(ModifiersTest, Clear, Insert, InsertHint,
EraseKey, Swap);
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_INTERNAL_UNORDERED_SET_MODIFIERS_TEST_H_
diff --git a/absl/container/internal/unordered_set_test.cc b/absl/container/internal/unordered_set_test.cc
index 263059eb..2356e187 100644
--- a/absl/container/internal/unordered_set_test.cc
+++ b/absl/container/internal/unordered_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,24 +16,26 @@
#include "absl/container/internal/unordered_set_constructor_test.h"
#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"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
-using SetTypes =
- ::testing::Types<std::unordered_set<int, StatefulTestingHash,
- StatefulTestingEqual, Alloc<int>>,
- std::unordered_set<std::string, StatefulTestingHash,
- StatefulTestingEqual, Alloc<std::string>>>;
+using SetTypes = ::testing::Types<
+ std::unordered_set<int, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<int>>,
+ std::unordered_set<std::string, StatefulTestingHash, StatefulTestingEqual,
+ Alloc<std::string>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(UnorderedSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(UnorderedSet, ModifiersTest, SetTypes);
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/node_hash_map.h b/absl/container/node_hash_map.h
index 48c7752e..addf120f 100644
--- a/absl/container/node_hash_map.h
+++ b/absl/container/node_hash_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -48,7 +48,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <class Key, class Value>
class NodeHashMapPolicy;
@@ -578,7 +578,7 @@ struct IsUnorderedContainer<
} // namespace container_algorithm_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_NODE_HASH_MAP_H_
diff --git a/absl/container/node_hash_map_test.cc b/absl/container/node_hash_map_test.cc
index 76a387b8..7ce7ca02 100644
--- a/absl/container/node_hash_map_test.cc
+++ b/absl/container/node_hash_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,10 +17,11 @@
#include "absl/container/internal/tracked.h"
#include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h"
+#include "absl/container/internal/unordered_map_members_test.h"
#include "absl/container/internal/unordered_map_modifiers_test.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
@@ -35,9 +36,10 @@ using MapTypes = ::testing::Types<
StatefulTestingEqual,
Alloc<std::pair<const std::string, std::string>>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ConstructorTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, LookupTest, MapTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashMap, ModifiersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ConstructorTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, LookupTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, MembersTest, MapTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashMap, ModifiersTest, MapTypes);
using M = absl::node_hash_map<std::string, Tracked<int>>;
@@ -216,5 +218,5 @@ TEST(NodeHashMap, MergeExtractInsert) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/container/node_hash_set.h b/absl/container/node_hash_set.h
index c4179195..103d32d2 100644
--- a/absl/container/node_hash_set.h
+++ b/absl/container/node_hash_set.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -44,7 +44,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
template <typename T>
struct NodeHashSetPolicy;
@@ -484,7 +484,7 @@ struct IsUnorderedContainer<absl::node_hash_set<Key, Hash, KeyEqual, Allocator>>
: std::true_type {};
} // namespace container_algorithm_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_CONTAINER_NODE_HASH_SET_H_
diff --git a/absl/container/node_hash_set_test.cc b/absl/container/node_hash_set_test.cc
index 59f25285..65d125ed 100644
--- a/absl/container/node_hash_set_test.cc
+++ b/absl/container/node_hash_set_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,10 +16,11 @@
#include "absl/container/internal/unordered_set_constructor_test.h"
#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"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace container_internal {
namespace {
using ::absl::container_internal::hash_internal::Enum;
@@ -30,14 +31,15 @@ using ::testing::UnorderedElementsAre;
using SetTypes = ::testing::Types<
node_hash_set<int, StatefulTestingHash, StatefulTestingEqual, Alloc<int>>,
node_hash_set<std::string, StatefulTestingHash, StatefulTestingEqual,
- Alloc<int>>,
+ Alloc<std::string>>,
node_hash_set<Enum, StatefulTestingHash, StatefulTestingEqual, Alloc<Enum>>,
node_hash_set<EnumClass, StatefulTestingHash, StatefulTestingEqual,
Alloc<EnumClass>>>;
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ConstructorTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, LookupTest, SetTypes);
-INSTANTIATE_TYPED_TEST_CASE_P(NodeHashSet, ModifiersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ConstructorTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, LookupTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, MembersTest, SetTypes);
+INSTANTIATE_TYPED_TEST_SUITE_P(NodeHashSet, ModifiersTest, SetTypes);
TEST(NodeHashSet, MoveableNotCopyableCompiles) {
node_hash_set<std::unique_ptr<void*>> t;
@@ -101,5 +103,5 @@ TEST(NodeHashSet, MergeExtractInsert) {
} // namespace
} // namespace container_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/copts.bzl b/absl/copts.bzl
deleted file mode 100644
index 49c4c9e0..00000000
--- a/absl/copts.bzl
+++ /dev/null
@@ -1,170 +0,0 @@
-"""absl specific copts.
-
-Flags specified here must not impact ABI. Code compiled with and without these
-opts will be linked together, and in some cases headers compiled with and
-without these options will be part of the same program.
-
-DO NOT CHANGE THIS FILE WITHOUT CHANGING THE SAME FLAG IN absl/CMake/AbseilConfigureCopts.cmake!!
-"""
-GCC_FLAGS = [
- "-Wall",
- "-Wextra",
- "-Wcast-qual",
- "-Wconversion-null",
- "-Wmissing-declarations",
- "-Woverlength-strings",
- "-Wpointer-arith",
- "-Wunused-local-typedefs",
- "-Wunused-result",
- "-Wvarargs",
- "-Wvla", # variable-length array
- "-Wwrite-strings",
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
-]
-
-GCC_TEST_FLAGS = [
- "-Wno-conversion-null",
- "-Wno-missing-declarations",
- "-Wno-sign-compare",
- "-Wno-unused-function",
- "-Wno-unused-parameter",
- "-Wno-unused-private-field",
-]
-
-# Docs on single flags is preceded by a comment.
-# Docs on groups of flags is preceded by ###.
-
-LLVM_FLAGS = [
- "-Wall",
- "-Wextra",
- "-Weverything",
- # Abseil does not support C++98
- "-Wno-c++98-compat-pedantic",
- # Turns off all implicit conversion warnings. Most are re-enabled below.
- "-Wno-conversion",
- "-Wno-covered-switch-default",
- "-Wno-deprecated",
- "-Wno-disabled-macro-expansion",
- "-Wno-double-promotion",
- ###
- # Turned off as they include valid C++ code.
- "-Wno-comma",
- "-Wno-extra-semi",
- "-Wno-packed",
- "-Wno-padded",
- ###
- # Google style does not use unsigned integers, though STL containers
- # have unsigned types.
- "-Wno-sign-compare",
- ###
- "-Wno-float-conversion",
- "-Wno-float-equal",
- "-Wno-format-nonliteral",
- # Too aggressive: warns on Clang extensions enclosed in Clang-only
- # compilation paths.
- "-Wno-gcc-compat",
- ###
- # Some internal globals are necessary. Don't do this at home.
- "-Wno-global-constructors",
- "-Wno-exit-time-destructors",
- ###
- "-Wno-nested-anon-types",
- "-Wno-non-modular-include-in-module",
- "-Wno-old-style-cast",
- # Warns on preferred usage of non-POD types such as string_view
- "-Wno-range-loop-analysis",
- "-Wno-reserved-id-macro",
- "-Wno-shorten-64-to-32",
- "-Wno-switch-enum",
- "-Wno-thread-safety-negative",
- "-Wno-undef",
- "-Wno-unknown-warning-option",
- "-Wno-unreachable-code",
- # Causes warnings on include guards
- "-Wno-unused-macros",
- "-Wno-weak-vtables",
- ###
- # Implicit conversion warnings turned off by -Wno-conversion
- # which are re-enabled below.
- "-Wbitfield-enum-conversion",
- "-Wbool-conversion",
- "-Wconstant-conversion",
- "-Wenum-conversion",
- "-Wint-conversion",
- "-Wliteral-conversion",
- "-Wnon-literal-null-conversion",
- "-Wnull-conversion",
- "-Wobjc-literal-conversion",
- "-Wno-sign-conversion",
- "-Wstring-conversion",
- ###
-]
-
-LLVM_TEST_FLAGS = [
- "-Wno-c99-extensions",
- "-Wno-missing-noreturn",
- "-Wno-missing-prototypes",
- "-Wno-missing-variable-declarations",
- "-Wno-null-conversion",
- "-Wno-shadow",
- "-Wno-shift-sign-overflow",
- "-Wno-sign-compare",
- "-Wno-unused-function",
- "-Wno-unused-member-function",
- "-Wno-unused-parameter",
- "-Wno-unused-private-field",
- "-Wno-unused-template",
- "-Wno-used-but-marked-unused",
- "-Wno-zero-as-null-pointer-constant",
- # gtest depends on this GNU extension being offered.
- "-Wno-gnu-zero-variadic-macro-arguments",
-]
-
-MSVC_FLAGS = [
- "/W3",
- "/wd4005", # macro-redefinition
- "/wd4068", # unknown pragma
- "/wd4180", # qualifier applied to function type has no meaning; ignored
- "/wd4244", # conversion from 'type1' to 'type2', possible loss of data
- "/wd4267", # conversion from 'size_t' to 'type', possible loss of data
- "/wd4800", # forcing value to bool 'true' or 'false' (performance warning)
- "/DNOMINMAX", # Don't define min and max macros (windows.h)
- "/DWIN32_LEAN_AND_MEAN", # Don't bloat namespace with incompatible winsock versions.
- "/D_CRT_SECURE_NO_WARNINGS", # Don't warn about usage of insecure C functions.
- "/D_SCL_SECURE_NO_WARNINGS", # Don't warm when the compiler encounters a function or
- # variable that is marked as deprecated (same as /wd4996).
- "/D_ENABLE_EXTENDED_ALIGNED_STORAGE", # Introduced in VS 2017 15.8,
- # before the member type would non-conformingly have an alignment of only alignof(max_align_t).
-]
-
-MSVC_TEST_FLAGS = [
- "/wd4018", # signed/unsigned mismatch
- "/wd4101", # unreferenced local variable
- "/wd4503", # decorated name length exceeded, name was truncated
-]
-
-# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
-ABSL_DEFAULT_COPTS = select({
- "//absl:windows": MSVC_FLAGS,
- "//absl:llvm_compiler": LLVM_FLAGS,
- "//conditions:default": GCC_FLAGS,
-})
-
-# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
-# to their (included header) dependencies and fail to build outside absl
-ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
- "//absl:windows": MSVC_TEST_FLAGS,
- "//absl:llvm_compiler": LLVM_TEST_FLAGS,
- "//conditions:default": GCC_TEST_FLAGS,
-})
-
-ABSL_EXCEPTIONS_FLAG = select({
- "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"],
- "//conditions:default": ["-fexceptions"],
-})
-
-ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({
- "//conditions:default": [],
-})
diff --git a/absl/copts/AbseilConfigureCopts.cmake b/absl/copts/AbseilConfigureCopts.cmake
new file mode 100644
index 00000000..4ece4c6f
--- /dev/null
+++ b/absl/copts/AbseilConfigureCopts.cmake
@@ -0,0 +1,60 @@
+# See absl/copts/copts.py and absl/copts/generate_copts.py
+include(GENERATED_AbseilCopts)
+
+set(ABSL_LSAN_LINKOPTS "")
+set(ABSL_HAVE_LSAN OFF)
+set(ABSL_DEFAULT_LINKOPTS "")
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_GCC_EXCEPTIONS_FLAGS}")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
+elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+ # MATCHES so we get both Clang and AppleClang
+ if(MSVC)
+ # clang-cl is half MSVC, half LLVM
+ set(ABSL_DEFAULT_COPTS "${ABSL_CLANG_CL_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_CLANG_CL_FLAGS};${ABSL_CLANG_CL_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_CLANG_CL_EXCEPTIONS_FLAGS}")
+ set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
+ else()
+ set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_LLVM_EXCEPTIONS_FLAGS}")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
+ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # AppleClang doesn't have lsan
+ # https://developer.apple.com/documentation/code_diagnostics
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
+ set(ABSL_LSAN_LINKOPTS "-fsanitize=leak")
+ set(ABSL_HAVE_LSAN ON)
+ endif()
+ endif()
+ endif()
+elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
+ set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
+ set(ABSL_EXCEPTIONS_FLAG "${ABSL_MSVC_EXCEPTIONS_FLAGS}")
+ set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
+ set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
+else()
+ message(WARNING "Unknown compiler: ${CMAKE_CXX_COMPILER}. Building with no default flags")
+ set(ABSL_DEFAULT_COPTS "")
+ set(ABSL_TEST_COPTS "")
+ set(ABSL_EXCEPTIONS_FLAG "")
+ set(ABSL_RANDOM_RANDEN_COPTS "")
+endif()
+
+# This flag is used internally for Bazel builds and is kept here for consistency
+set(ABSL_EXCEPTIONS_FLAG_LINKOPTS "")
+
+if("${CMAKE_CXX_STANDARD}" EQUAL 98)
+ message(FATAL_ERROR "Abseil requires at least C++11")
+elseif(NOT "${CMAKE_CXX_STANDARD}")
+ message(STATUS "No CMAKE_CXX_STANDARD set, assuming 11")
+ set(ABSL_CXX_STANDARD 11)
+else()
+ set(ABSL_CXX_STANDARD "${CMAKE_CXX_STANDARD}")
+endif()
diff --git a/absl/copts/GENERATED_AbseilCopts.cmake b/absl/copts/GENERATED_AbseilCopts.cmake
new file mode 100644
index 00000000..01bd40b2
--- /dev/null
+++ b/absl/copts/GENERATED_AbseilCopts.cmake
@@ -0,0 +1,236 @@
+# GENERATED! DO NOT MANUALLY EDIT THIS FILE.
+#
+# (1) Edit absl/copts/copts.py.
+# (2) Run `python <path_to_absl>/copts/generate_copts.py`.
+
+list(APPEND ABSL_CLANG_CL_EXCEPTIONS_FLAGS
+ "/U_HAS_EXCEPTIONS"
+ "/D_HAS_EXCEPTIONS=1"
+ "/EHsc"
+)
+
+list(APPEND ABSL_CLANG_CL_FLAGS
+ "/W3"
+ "-Wno-c++98-compat-pedantic"
+ "-Wno-conversion"
+ "-Wno-covered-switch-default"
+ "-Wno-deprecated"
+ "-Wno-disabled-macro-expansion"
+ "-Wno-double-promotion"
+ "-Wno-comma"
+ "-Wno-extra-semi"
+ "-Wno-extra-semi-stmt"
+ "-Wno-packed"
+ "-Wno-padded"
+ "-Wno-sign-compare"
+ "-Wno-float-conversion"
+ "-Wno-float-equal"
+ "-Wno-format-nonliteral"
+ "-Wno-gcc-compat"
+ "-Wno-global-constructors"
+ "-Wno-exit-time-destructors"
+ "-Wno-nested-anon-types"
+ "-Wno-non-modular-include-in-module"
+ "-Wno-old-style-cast"
+ "-Wno-range-loop-analysis"
+ "-Wno-reserved-id-macro"
+ "-Wno-shorten-64-to-32"
+ "-Wno-switch-enum"
+ "-Wno-thread-safety-negative"
+ "-Wno-unknown-warning-option"
+ "-Wno-unreachable-code"
+ "-Wno-unused-macros"
+ "-Wno-weak-vtables"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wbitfield-enum-conversion"
+ "-Wbool-conversion"
+ "-Wconstant-conversion"
+ "-Wenum-conversion"
+ "-Wint-conversion"
+ "-Wliteral-conversion"
+ "-Wnon-literal-null-conversion"
+ "-Wnull-conversion"
+ "-Wobjc-literal-conversion"
+ "-Wno-sign-conversion"
+ "-Wstring-conversion"
+ "/DNOMINMAX"
+ "/DWIN32_LEAN_AND_MEAN"
+ "/D_CRT_SECURE_NO_WARNINGS"
+ "/D_SCL_SECURE_NO_WARNINGS"
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+)
+
+list(APPEND ABSL_CLANG_CL_TEST_FLAGS
+ "-Wno-c99-extensions"
+ "-Wno-deprecated-declarations"
+ "-Wno-missing-noreturn"
+ "-Wno-missing-prototypes"
+ "-Wno-missing-variable-declarations"
+ "-Wno-null-conversion"
+ "-Wno-shadow"
+ "-Wno-shift-sign-overflow"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-member-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+ "-Wno-unused-template"
+ "-Wno-used-but-marked-unused"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wno-gnu-zero-variadic-macro-arguments"
+)
+
+list(APPEND ABSL_GCC_EXCEPTIONS_FLAGS
+ "-fexceptions"
+)
+
+list(APPEND ABSL_GCC_FLAGS
+ "-Wall"
+ "-Wextra"
+ "-Wcast-qual"
+ "-Wconversion-null"
+ "-Wmissing-declarations"
+ "-Woverlength-strings"
+ "-Wpointer-arith"
+ "-Wunused-local-typedefs"
+ "-Wunused-result"
+ "-Wvarargs"
+ "-Wvla"
+ "-Wwrite-strings"
+ "-Wno-missing-field-initializers"
+ "-Wno-sign-compare"
+)
+
+list(APPEND ABSL_GCC_TEST_FLAGS
+ "-Wno-conversion-null"
+ "-Wno-deprecated-declarations"
+ "-Wno-missing-declarations"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+)
+
+list(APPEND ABSL_LLVM_EXCEPTIONS_FLAGS
+ "-fexceptions"
+)
+
+list(APPEND ABSL_LLVM_FLAGS
+ "-Wall"
+ "-Wextra"
+ "-Weverything"
+ "-Wno-c++98-compat-pedantic"
+ "-Wno-conversion"
+ "-Wno-covered-switch-default"
+ "-Wno-deprecated"
+ "-Wno-disabled-macro-expansion"
+ "-Wno-double-promotion"
+ "-Wno-comma"
+ "-Wno-extra-semi"
+ "-Wno-extra-semi-stmt"
+ "-Wno-packed"
+ "-Wno-padded"
+ "-Wno-sign-compare"
+ "-Wno-float-conversion"
+ "-Wno-float-equal"
+ "-Wno-format-nonliteral"
+ "-Wno-gcc-compat"
+ "-Wno-global-constructors"
+ "-Wno-exit-time-destructors"
+ "-Wno-nested-anon-types"
+ "-Wno-non-modular-include-in-module"
+ "-Wno-old-style-cast"
+ "-Wno-range-loop-analysis"
+ "-Wno-reserved-id-macro"
+ "-Wno-shorten-64-to-32"
+ "-Wno-switch-enum"
+ "-Wno-thread-safety-negative"
+ "-Wno-unknown-warning-option"
+ "-Wno-unreachable-code"
+ "-Wno-unused-macros"
+ "-Wno-weak-vtables"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wbitfield-enum-conversion"
+ "-Wbool-conversion"
+ "-Wconstant-conversion"
+ "-Wenum-conversion"
+ "-Wint-conversion"
+ "-Wliteral-conversion"
+ "-Wnon-literal-null-conversion"
+ "-Wnull-conversion"
+ "-Wobjc-literal-conversion"
+ "-Wno-sign-conversion"
+ "-Wstring-conversion"
+)
+
+list(APPEND ABSL_LLVM_TEST_FLAGS
+ "-Wno-c99-extensions"
+ "-Wno-deprecated-declarations"
+ "-Wno-missing-noreturn"
+ "-Wno-missing-prototypes"
+ "-Wno-missing-variable-declarations"
+ "-Wno-null-conversion"
+ "-Wno-shadow"
+ "-Wno-shift-sign-overflow"
+ "-Wno-sign-compare"
+ "-Wno-unused-function"
+ "-Wno-unused-member-function"
+ "-Wno-unused-parameter"
+ "-Wno-unused-private-field"
+ "-Wno-unused-template"
+ "-Wno-used-but-marked-unused"
+ "-Wno-zero-as-null-pointer-constant"
+ "-Wno-gnu-zero-variadic-macro-arguments"
+)
+
+list(APPEND ABSL_MSVC_EXCEPTIONS_FLAGS
+ "/U_HAS_EXCEPTIONS"
+ "/D_HAS_EXCEPTIONS=1"
+ "/EHsc"
+)
+
+list(APPEND ABSL_MSVC_FLAGS
+ "/W3"
+ "/DNOMINMAX"
+ "/DWIN32_LEAN_AND_MEAN"
+ "/D_CRT_SECURE_NO_WARNINGS"
+ "/D_SCL_SECURE_NO_WARNINGS"
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE"
+ "/wd4005"
+ "/wd4068"
+ "/wd4180"
+ "/wd4244"
+ "/wd4267"
+ "/wd4503"
+ "/wd4800"
+)
+
+list(APPEND ABSL_MSVC_LINKOPTS
+ "-ignore:4221"
+)
+
+list(APPEND ABSL_MSVC_TEST_FLAGS
+ "/wd4018"
+ "/wd4101"
+ "/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
+ "/O2"
+ "/Ob2"
+)
+
+list(APPEND ABSL_RANDOM_HWAES_X64_FLAGS
+ "-maes"
+ "-msse4.1"
+)
diff --git a/absl/copts/GENERATED_copts.bzl b/absl/copts/GENERATED_copts.bzl
new file mode 100644
index 00000000..82f332f4
--- /dev/null
+++ b/absl/copts/GENERATED_copts.bzl
@@ -0,0 +1,237 @@
+"""GENERATED! DO NOT MANUALLY EDIT THIS FILE.
+
+(1) Edit absl/copts/copts.py.
+(2) Run `python <path_to_absl>/copts/generate_copts.py`.
+"""
+
+ABSL_CLANG_CL_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS",
+ "/D_HAS_EXCEPTIONS=1",
+ "/EHsc",
+]
+
+ABSL_CLANG_CL_FLAGS = [
+ "/W3",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ "-Wno-sign-compare",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ "-Wno-gcc-compat",
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+ "/DNOMINMAX",
+ "/DWIN32_LEAN_AND_MEAN",
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+]
+
+ABSL_CLANG_CL_TEST_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+ABSL_GCC_EXCEPTIONS_FLAGS = [
+ "-fexceptions",
+]
+
+ABSL_GCC_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion-null",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvarargs",
+ "-Wvla",
+ "-Wwrite-strings",
+ "-Wno-missing-field-initializers",
+ "-Wno-sign-compare",
+]
+
+ABSL_GCC_TEST_FLAGS = [
+ "-Wno-conversion-null",
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-declarations",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+]
+
+ABSL_LLVM_EXCEPTIONS_FLAGS = [
+ "-fexceptions",
+]
+
+ABSL_LLVM_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Weverything",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ "-Wno-sign-compare",
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ "-Wno-gcc-compat",
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+]
+
+ABSL_LLVM_TEST_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+ABSL_MSVC_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS",
+ "/D_HAS_EXCEPTIONS=1",
+ "/EHsc",
+]
+
+ABSL_MSVC_FLAGS = [
+ "/W3",
+ "/DNOMINMAX",
+ "/DWIN32_LEAN_AND_MEAN",
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+ "/wd4005",
+ "/wd4068",
+ "/wd4180",
+ "/wd4244",
+ "/wd4267",
+ "/wd4503",
+ "/wd4800",
+]
+
+ABSL_MSVC_LINKOPTS = [
+ "-ignore:4221",
+]
+
+ABSL_MSVC_TEST_FLAGS = [
+ "/wd4018",
+ "/wd4101",
+ "/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 = [
+ "/O2",
+ "/Ob2",
+]
+
+ABSL_RANDOM_HWAES_X64_FLAGS = [
+ "-maes",
+ "-msse4.1",
+]
diff --git a/absl/copts/configure_copts.bzl b/absl/copts/configure_copts.bzl
new file mode 100644
index 00000000..8c4efe77
--- /dev/null
+++ b/absl/copts/configure_copts.bzl
@@ -0,0 +1,89 @@
+"""absl specific copts.
+
+This file simply selects the correct options from the generated files. To
+change Abseil copts, edit absl/copts/copts.py
+"""
+
+load(
+ "//absl:copts/GENERATED_copts.bzl",
+ "ABSL_GCC_EXCEPTIONS_FLAGS",
+ "ABSL_GCC_FLAGS",
+ "ABSL_GCC_TEST_FLAGS",
+ "ABSL_LLVM_EXCEPTIONS_FLAGS",
+ "ABSL_LLVM_FLAGS",
+ "ABSL_LLVM_TEST_FLAGS",
+ "ABSL_MSVC_EXCEPTIONS_FLAGS",
+ "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:windows": ABSL_MSVC_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_FLAGS,
+ "//conditions:default": ABSL_GCC_FLAGS,
+})
+
+# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts
+# to their (included header) dependencies and fail to build outside absl
+ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({
+ "//absl:windows": ABSL_MSVC_TEST_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_TEST_FLAGS,
+ "//conditions:default": ABSL_GCC_TEST_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG = select({
+ "//absl:windows": ABSL_MSVC_EXCEPTIONS_FLAGS,
+ "//absl:llvm_compiler": ABSL_LLVM_EXCEPTIONS_FLAGS,
+ "//conditions:default": ABSL_GCC_EXCEPTIONS_FLAGS,
+})
+
+ABSL_EXCEPTIONS_FLAG_LINKOPTS = select({
+ "//conditions:default": [],
+})
+
+ABSL_DEFAULT_LINKOPTS = select({
+ "//absl:windows": 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_haswell": ABSL_RANDOM_HWAES_X64_FLAGS,
+ ":cpu_ppc": ["-mcrypto"],
+
+ # 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",
+ "haswell",
+ "darwin_x86_64",
+ "darwin",
+ "x64_windows_msvc",
+ "x64_windows",
+ ]
+ 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
new file mode 100644
index 00000000..068abceb
--- /dev/null
+++ b/absl/copts/copts.py
@@ -0,0 +1,214 @@
+"""Abseil compiler options.
+
+This is the source of truth for Abseil compiler options. To modify Abseil
+compilation options:
+
+ (1) Edit the appropriate list in this file based on the platform the flag is
+ needed on.
+ (2) Run `<path_to_absl>/copts/generate_copts.py`.
+
+The generated copts are consumed by configure_copts.bzl and
+AbseilConfigureCopts.cmake.
+"""
+
+# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ...
+MSVC_BIG_WARNING_FLAGS = [
+ "/W3",
+]
+
+LLVM_BIG_WARNING_FLAGS = [
+ "-Wall",
+ "-Wextra",
+ "-Weverything",
+]
+
+# Docs on single flags is preceded by a comment.
+# Docs on groups of flags is preceded by ###.
+LLVM_DISABLE_WARNINGS_FLAGS = [
+ # Abseil does not support C++98
+ "-Wno-c++98-compat-pedantic",
+ # Turns off all implicit conversion warnings. Most are re-enabled below.
+ "-Wno-conversion",
+ "-Wno-covered-switch-default",
+ "-Wno-deprecated",
+ "-Wno-disabled-macro-expansion",
+ "-Wno-double-promotion",
+ ###
+ # Turned off as they include valid C++ code.
+ "-Wno-comma",
+ "-Wno-extra-semi",
+ "-Wno-extra-semi-stmt",
+ "-Wno-packed",
+ "-Wno-padded",
+ ###
+ # Google style does not use unsigned integers, though STL containers
+ # have unsigned types.
+ "-Wno-sign-compare",
+ ###
+ "-Wno-float-conversion",
+ "-Wno-float-equal",
+ "-Wno-format-nonliteral",
+ # Too aggressive: warns on Clang extensions enclosed in Clang-only
+ # compilation paths.
+ "-Wno-gcc-compat",
+ ###
+ # Some internal globals are necessary. Don't do this at home.
+ "-Wno-global-constructors",
+ "-Wno-exit-time-destructors",
+ ###
+ "-Wno-nested-anon-types",
+ "-Wno-non-modular-include-in-module",
+ "-Wno-old-style-cast",
+ # Warns on preferred usage of non-POD types such as string_view
+ "-Wno-range-loop-analysis",
+ "-Wno-reserved-id-macro",
+ "-Wno-shorten-64-to-32",
+ "-Wno-switch-enum",
+ "-Wno-thread-safety-negative",
+ "-Wno-unknown-warning-option",
+ "-Wno-unreachable-code",
+ # Causes warnings on include guards
+ "-Wno-unused-macros",
+ "-Wno-weak-vtables",
+ # Causes warnings on usage of types/compare.h comparison operators.
+ "-Wno-zero-as-null-pointer-constant",
+ ###
+ # Implicit conversion warnings turned off by -Wno-conversion
+ # which are re-enabled below.
+ "-Wbitfield-enum-conversion",
+ "-Wbool-conversion",
+ "-Wconstant-conversion",
+ "-Wenum-conversion",
+ "-Wint-conversion",
+ "-Wliteral-conversion",
+ "-Wnon-literal-null-conversion",
+ "-Wnull-conversion",
+ "-Wobjc-literal-conversion",
+ "-Wno-sign-conversion",
+ "-Wstring-conversion",
+]
+
+LLVM_TEST_DISABLE_WARNINGS_FLAGS = [
+ "-Wno-c99-extensions",
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-noreturn",
+ "-Wno-missing-prototypes",
+ "-Wno-missing-variable-declarations",
+ "-Wno-null-conversion",
+ "-Wno-shadow",
+ "-Wno-shift-sign-overflow",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-member-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ "-Wno-unused-template",
+ "-Wno-used-but-marked-unused",
+ "-Wno-zero-as-null-pointer-constant",
+ # gtest depends on this GNU extension being offered.
+ "-Wno-gnu-zero-variadic-macro-arguments",
+]
+
+MSVC_STYLE_EXCEPTIONS_FLAGS = [
+ "/U_HAS_EXCEPTIONS",
+ "/D_HAS_EXCEPTIONS=1",
+ "/EHsc"
+]
+
+MSVC_DEFINES = [
+ "/DNOMINMAX", # Don't define min and max macros (windows.h)
+ # Don't bloat namespace with incompatible winsock versions.
+ "/DWIN32_LEAN_AND_MEAN",
+ # Don't warn about usage of insecure C functions.
+ "/D_CRT_SECURE_NO_WARNINGS",
+ "/D_SCL_SECURE_NO_WARNINGS",
+ # Introduced in VS 2017 15.8, allow overaligned types in aligned_storage
+ "/D_ENABLE_EXTENDED_ALIGNED_STORAGE",
+]
+
+COPT_VARS = {
+ "ABSL_GCC_FLAGS": [
+ "-Wall",
+ "-Wextra",
+ "-Wcast-qual",
+ "-Wconversion-null",
+ "-Wmissing-declarations",
+ "-Woverlength-strings",
+ "-Wpointer-arith",
+ "-Wunused-local-typedefs",
+ "-Wunused-result",
+ "-Wvarargs",
+ "-Wvla", # variable-length array
+ "-Wwrite-strings",
+ # gcc-4.x has spurious missing field initializer warnings.
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
+ # Remove when gcc-4.x is no longer supported.
+ "-Wno-missing-field-initializers",
+ # Google style does not use unsigned integers, though STL containers
+ # have unsigned types.
+ "-Wno-sign-compare",
+ ],
+ "ABSL_GCC_TEST_FLAGS": [
+ "-Wno-conversion-null",
+ "-Wno-deprecated-declarations",
+ "-Wno-missing-declarations",
+ "-Wno-sign-compare",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ "-Wno-unused-private-field",
+ ],
+ "ABSL_GCC_EXCEPTIONS_FLAGS": ["-fexceptions"],
+ "ABSL_LLVM_FLAGS":
+ LLVM_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS,
+ "ABSL_LLVM_TEST_FLAGS":
+ LLVM_TEST_DISABLE_WARNINGS_FLAGS,
+ "ABSL_LLVM_EXCEPTIONS_FLAGS": ["-fexceptions"],
+ "ABSL_CLANG_CL_FLAGS":
+ (MSVC_BIG_WARNING_FLAGS + LLVM_DISABLE_WARNINGS_FLAGS + MSVC_DEFINES),
+ "ABSL_CLANG_CL_TEST_FLAGS":
+ LLVM_TEST_DISABLE_WARNINGS_FLAGS,
+ "ABSL_CLANG_CL_EXCEPTIONS_FLAGS":
+ MSVC_STYLE_EXCEPTIONS_FLAGS,
+ "ABSL_MSVC_FLAGS":
+ MSVC_BIG_WARNING_FLAGS + MSVC_DEFINES + [
+ "/wd4005", # macro-redefinition
+ "/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)
+ "/wd4800",
+ ],
+ "ABSL_MSVC_TEST_FLAGS": [
+ "/wd4018", # signed/unsigned mismatch
+ "/wd4101", # unreferenced local variable
+ "/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_EXCEPTIONS_FLAGS":
+ MSVC_STYLE_EXCEPTIONS_FLAGS,
+ "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": [
+ "/O2", # Maximize speed
+ "/Ob2", # Aggressive inlining
+ ],
+}
diff --git a/absl/copts/generate_copts.py b/absl/copts/generate_copts.py
new file mode 100755
index 00000000..0e5dc9fa
--- /dev/null
+++ b/absl/copts/generate_copts.py
@@ -0,0 +1,109 @@
+#!/usr/bin/python
+"""Generate Abseil compile compile option configs.
+
+Usage: <path_to_absl>/copts/generate_copts.py
+
+The configs are generated from copts.py.
+"""
+
+from os import path
+import sys
+from copts import COPT_VARS
+
+
+# Helper functions
+def file_header_lines():
+ return [
+ "GENERATED! DO NOT MANUALLY EDIT THIS FILE.", "",
+ "(1) Edit absl/copts/copts.py.",
+ "(2) Run `python <path_to_absl>/copts/generate_copts.py`."
+ ]
+
+
+def flatten(*lists):
+ return [item for sublist in lists for item in sublist]
+
+
+def relative_filename(filename):
+ return path.join(path.dirname(__file__), filename)
+
+
+# Style classes. These contain all the syntactic styling needed to generate a
+# copt file for different build tools.
+class CMakeStyle(object):
+ """Style object for CMake copts file."""
+
+ def separator(self):
+ return ""
+
+ def list_introducer(self, name):
+ return "list(APPEND " + name
+
+ def list_closer(self):
+ return ")\n"
+
+ def docstring(self):
+ return "\n".join((("# " + line).strip() for line in file_header_lines()))
+
+ def filename(self):
+ return "GENERATED_AbseilCopts.cmake"
+
+
+class StarlarkStyle(object):
+ """Style object for Starlark copts file."""
+
+ def separator(self):
+ return ","
+
+ def list_introducer(self, name):
+ return name + " = ["
+
+ def list_closer(self):
+ return "]\n"
+
+ def docstring(self):
+ docstring_quotes = "\"\"\""
+ return docstring_quotes + "\n".join(
+ flatten(file_header_lines(), [docstring_quotes]))
+
+ def filename(self):
+ return "GENERATED_copts.bzl"
+
+
+def copt_list(name, arg_list, style):
+ """Copt file generation."""
+
+ make_line = lambda s: " \"" + s + "\"" + style.separator()
+ external_str_list = [make_line(s) for s in arg_list]
+
+ return "\n".join(
+ flatten(
+ [style.list_introducer(name)],
+ external_str_list,
+ [style.list_closer()]))
+
+
+def generate_copt_file(style):
+ """Creates a generated copt file using the given style object.
+
+ Args:
+ style: either StarlarkStyle() or CMakeStyle()
+ """
+ with open(relative_filename(style.filename()), "w") as f:
+ f.write(style.docstring())
+ f.write("\n")
+ for var_name, arg_list in sorted(COPT_VARS.items()):
+ f.write("\n")
+ f.write(copt_list(var_name, arg_list, style))
+
+
+def main(argv):
+ if len(argv) > 1:
+ raise RuntimeError("generate_copts needs no command line args")
+
+ generate_copt_file(StarlarkStyle())
+ generate_copt_file(CMakeStyle())
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/absl/debugging/BUILD.bazel b/absl/debugging/BUILD.bazel
index a8ebaea4..913cfafb 100644
--- a/absl/debugging/BUILD.bazel
+++ b/absl/debugging/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -33,6 +34,7 @@ cc_library(
],
hdrs = ["stacktrace.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":debugging_internal",
"//absl/base",
@@ -53,11 +55,13 @@ cc_library(
"symbolize.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":debugging_internal",
":demangle_internal",
"//absl/base",
"//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
"//absl/base:malloc_internal",
],
)
@@ -66,6 +70,7 @@ cc_test(
name = "symbolize_test",
srcs = ["symbolize_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":stack_consumption",
":symbolize",
@@ -85,6 +90,7 @@ cc_library(
"internal/examine_stack.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
":stacktrace",
@@ -99,6 +105,7 @@ cc_library(
srcs = ["failure_signal_handler.cc"],
hdrs = ["failure_signal_handler.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":examine_stack",
":stacktrace",
@@ -115,7 +122,7 @@ cc_test(
linkopts = select({
"//absl:windows": [],
"//conditions:default": ["-pthread"],
- }),
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
":failure_signal_handler",
":stacktrace",
@@ -147,6 +154,7 @@ cc_library(
"internal/vdso_support.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base",
"//absl/base:core_headers",
@@ -169,6 +177,7 @@ cc_test(
name = "demangle_test",
srcs = ["internal/demangle_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":demangle_internal",
":stack_consumption",
@@ -181,22 +190,9 @@ cc_test(
cc_library(
name = "leak_check",
- srcs = select({
- # The leak checking interface depends on weak function
- # declarations that may not necessarily have definitions.
- # Windows doesn't support this, and ios requires
- # guaranteed definitions for weak symbols.
- "//absl:ios": [],
- "//absl:windows": [],
- "//conditions:default": [
- "leak_check.cc",
- ],
- }),
- hdrs = select({
- "//absl:ios": [],
- "//absl:windows": [],
- "//conditions:default": ["leak_check.h"],
- }),
+ srcs = ["leak_check.cc"],
+ hdrs = ["leak_check.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = ["//absl/base:core_headers"],
)
@@ -206,6 +202,7 @@ cc_library(
cc_library(
name = "leak_check_disable",
srcs = ["leak_check_disable.cc"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
linkstatic = 1,
alwayslink = 1,
)
@@ -226,6 +223,7 @@ cc_library(
"//absl:llvm_compiler": ["-DLEAK_SANITIZER"],
"//conditions:default": [],
}),
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
)
@@ -235,6 +233,7 @@ cc_library(
srcs = ["leak_check.cc"],
hdrs = ["leak_check.h"],
copts = ["-ULEAK_SANITIZER"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
)
@@ -245,7 +244,8 @@ cc_test(
"//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"],
"//conditions:default": [],
}),
- linkopts = ABSL_LSAN_LINKOPTS,
+ linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
+ tags = ["notsan"],
deps = [
":leak_check_api_enabled_for_testing",
"//absl/base",
@@ -257,6 +257,8 @@ cc_test(
name = "leak_check_no_lsan_test",
srcs = ["leak_check_test.cc"],
copts = ["-UABSL_EXPECT_LEAK_SANITIZER"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ["noasan"],
deps = [
":leak_check_api_disabled_for_testing",
"//absl/base", # for raw_logging
@@ -271,7 +273,8 @@ cc_test(
cc_test(
name = "disabled_leak_check_test",
srcs = ["leak_check_fail_test.cc"],
- linkopts = ABSL_LSAN_LINKOPTS,
+ linkopts = ABSL_LSAN_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
+ tags = ["notsan"],
deps = [
":leak_check_api_enabled_for_testing",
":leak_check_disable",
@@ -286,6 +289,7 @@ cc_library(
srcs = ["internal/stack_consumption.cc"],
hdrs = ["internal/stack_consumption.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
"//absl/base",
@@ -297,6 +301,7 @@ cc_test(
name = "stack_consumption_test",
srcs = ["internal/stack_consumption_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":stack_consumption",
"//absl/base",
diff --git a/absl/debugging/CMakeLists.txt b/absl/debugging/CMakeLists.txt
index f66688ba..001e2727 100644
--- a/absl/debugging/CMakeLists.txt
+++ b/absl/debugging/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -43,11 +43,14 @@ absl_cc_library(
"symbolize_win32.inc"
COPTS
${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::debugging_internal
absl::demangle_internal
absl::base
absl::core_headers
+ absl::dynamic_annotations
absl::malloc_internal
PUBLIC
)
@@ -181,9 +184,9 @@ absl_cc_library(
NAME
leak_check
HDRS
- "$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.h>"
+ "leak_check.h"
SRCS
- "$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:leak_check.cc>"
+ "leak_check.cc"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
@@ -196,14 +199,11 @@ absl_cc_library(
leak_check_disable
SRCS
"leak_check_disable.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
PUBLIC
)
-# TODO(cohenjon) Move into the copts code.
-if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- set(ABSL_LSAN_LINKOPTS "-fsanitize=leak")
-endif()
-
absl_cc_library(
NAME
leak_check_api_enabled_for_testing
@@ -212,7 +212,8 @@ absl_cc_library(
SRCS
"leak_check.cc"
COPTS
- $<$<BOOL:${ABSL_USING_CLANG}>:-DLEAK_SANITIZER>
+ ${ABSL_DEFAULT_COPTS}
+ $<$<BOOL:${ABSL_HAVE_LSAN}>:-DLEAK_SANITIZER>
TESTONLY
)
@@ -224,6 +225,7 @@ absl_cc_library(
SRCS
"leak_check.cc"
COPTS
+ ${ABSL_DEFAULT_COPTS}
"-ULEAK_SANITIZER"
TESTONLY
)
@@ -234,7 +236,8 @@ absl_cc_test(
SRCS
"leak_check_test.cc"
COPTS
- "$<$<CXX_COMPILER_ID:Clang>:-DABSL_EXPECT_LEAK_SANITIZER>"
+ ${ABSL_DEFAULT_COPTS}
+ "$<$<BOOL:${ABSL_HAVE_LSAN}>:-DABSL_EXPECT_LEAK_SANITIZER>"
LINKOPTS
"${ABSL_LSAN_LINKOPTS}"
DEPS
@@ -249,6 +252,7 @@ absl_cc_test(
SRCS
"leak_check_test.cc"
COPTS
+ ${ABSL_TEST_COPTS}
"-UABSL_EXPECT_LEAK_SANITIZER"
DEPS
absl::leak_check_api_disabled_for_testing
@@ -261,6 +265,8 @@ absl_cc_test(
disabled_leak_check_test
SRCS
"leak_check_fail_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
LINKOPTS
"${ABSL_LSAN_LINKOPTS}"
DEPS
@@ -303,6 +309,8 @@ absl_cc_test(
absl_cc_library(
NAME
debugging
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
DEPS
absl::stacktrace
absl::leak_check
diff --git a/absl/debugging/failure_signal_handler.cc b/absl/debugging/failure_signal_handler.cc
index a3a36f64..af651c72 100644
--- a/absl/debugging/failure_signal_handler.cc
+++ b/absl/debugging/failure_signal_handler.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -47,7 +47,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
@@ -357,5 +357,5 @@ void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
}
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/failure_signal_handler.h b/absl/debugging/failure_signal_handler.h
index 0aeb287f..87b202b0 100644
--- a/absl/debugging/failure_signal_handler.h
+++ b/absl/debugging/failure_signal_handler.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -45,7 +45,7 @@
#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// FailureSignalHandlerOptions
//
@@ -113,7 +113,7 @@ namespace debugging_internal {
const char* FailureSignalToString(int signo);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
diff --git a/absl/debugging/failure_signal_handler_test.cc b/absl/debugging/failure_signal_handler_test.cc
index ba520910..bb2cc48e 100644
--- a/absl/debugging/failure_signal_handler_test.cc
+++ b/absl/debugging/failure_signal_handler_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -133,16 +133,17 @@ constexpr int kFailureSignals[] = {
};
std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
- std::string result = absl::debugging_internal::FailureSignalToString(info.param);
+ std::string result =
+ absl::debugging_internal::FailureSignalToString(info.param);
if (result.empty()) {
result = absl::StrCat(info.param);
}
return result;
}
-INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
- ::testing::ValuesIn(kFailureSignals),
- SignalParamToString);
+INSTANTIATE_TEST_SUITE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
+ ::testing::ValuesIn(kFailureSignals),
+ SignalParamToString);
#endif // GTEST_HAS_DEATH_TEST
diff --git a/absl/debugging/internal/address_is_readable.cc b/absl/debugging/internal/address_is_readable.cc
index 2a83f4c8..64dd285b 100644
--- a/absl/debugging/internal/address_is_readable.cc
+++ b/absl/debugging/internal/address_is_readable.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,14 +20,14 @@
#if !defined(__linux__) || defined(__ANDROID__)
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// On platforms other than Linux, just return true.
bool AddressIsReadable(const void* /* addr */) { return true; }
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else
@@ -42,7 +42,7 @@ bool AddressIsReadable(const void* /* addr */) { return true; }
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Pack a pid and two file descriptors into a 64-bit word,
@@ -131,7 +131,7 @@ bool AddressIsReadable(const void *addr) {
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif
diff --git a/absl/debugging/internal/address_is_readable.h b/absl/debugging/internal/address_is_readable.h
index 3942f44b..dc626e5b 100644
--- a/absl/debugging/internal/address_is_readable.h
+++ b/absl/debugging/internal/address_is_readable.h
@@ -4,20 +4,19 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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_ADDRESS_IS_READABLE_H_
#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Return whether the byte at *addr is readable, without faulting.
@@ -25,7 +24,7 @@ namespace debugging_internal {
bool AddressIsReadable(const void *addr);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index 57b9393f..976e47a6 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include <limits>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
typedef struct {
@@ -750,8 +750,8 @@ static bool ParseSourceName(State *state) {
// <local-source-name> ::= L <source-name> [<discriminator>]
//
// References:
-// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
-// http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+// https://gcc.gnu.org/viewcvs?view=rev&revision=124467
static bool ParseLocalSourceName(State *state) {
ComplexityGuard guard(state);
if (guard.IsTooComplex()) return false;
@@ -1169,6 +1169,12 @@ static bool ParseType(State *state) {
}
state->parse_state = copy;
+ // nullptr_t, i.e. decltype(nullptr).
+ if (ParseTwoCharToken(state, "Dn")) {
+ return true;
+ }
+ state->parse_state = copy;
+
if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
ParseType(state)) {
return true;
@@ -1869,5 +1875,5 @@ bool Demangle(const char *mangled, char *out, int out_size) {
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/internal/demangle.h b/absl/debugging/internal/demangle.h
index 1f8722c7..20adbe9c 100644
--- a/absl/debugging/internal/demangle.h
+++ b/absl/debugging/internal/demangle.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -54,7 +54,7 @@
#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Demangle `mangled`. On success, return true and write the
@@ -63,7 +63,7 @@ namespace debugging_internal {
bool Demangle(const char *mangled, char *out, int out_size);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index fa89fb80..7c50fe3a 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/memory/memory.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
namespace {
@@ -82,8 +82,9 @@ TEST(Demangle, Clones) {
// Tests that verify that Demangle footprint is within some limit.
// They are not to be run under sanitizers as the sanitizers increase
// stack consumption by about 4x.
-#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
- !ADDRESS_SANITIZER && !MEMORY_SANITIZER && !THREAD_SANITIZER
+#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \
+ !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+ !defined(THREAD_SANITIZER)
static const char *g_mangled;
static char g_demangle_buffer[4096];
@@ -177,6 +178,7 @@ static void TestOnInput(const char* input) {
TEST(DemangleRegression, NegativeLength) {
TestOnInput("_ZZn4");
}
+
TEST(DemangleRegression, DeeplyNestedArrayType) {
const int depth = 100000;
std::string data = "_ZStI";
@@ -189,5 +191,5 @@ TEST(DemangleRegression, DeeplyNestedArrayType) {
} // namespace
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/internal/elf_mem_image.cc b/absl/debugging/internal/elf_mem_image.cc
index e7e35e9c..a795117a 100644
--- a/absl/debugging/internal/elf_mem_image.cc
+++ b/absl/debugging/internal/elf_mem_image.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,7 +38,7 @@
#define VERSYM_VERSION 0x7fff
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
namespace {
@@ -376,7 +376,7 @@ void ElfMemImage::SymbolIterator::Update(int increment) {
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/absl/debugging/internal/elf_mem_image.h b/absl/debugging/internal/elf_mem_image.h
index 0adb5f5d..fcd32afe 100644
--- a/absl/debugging/internal/elf_mem_image.h
+++ b/absl/debugging/internal/elf_mem_image.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -34,12 +34,12 @@
#define ABSL_HAVE_ELF_MEM_IMAGE 1
#endif
-#if ABSL_HAVE_ELF_MEM_IMAGE
+#ifdef ABSL_HAVE_ELF_MEM_IMAGE
#include <link.h> // for ElfW
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// An in-memory ELF image (may not exist on disk).
@@ -124,7 +124,7 @@ class ElfMemImage {
};
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/absl/debugging/internal/examine_stack.cc b/absl/debugging/internal/examine_stack.cc
index 4764355a..4739fbc5 100644
--- a/absl/debugging/internal/examine_stack.cc
+++ b/absl/debugging/internal/examine_stack.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,7 +30,7 @@
#include "absl/debugging/symbolize.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Returns the program counter from signal context, nullptr if
@@ -151,5 +151,5 @@ void DumpPCAndFrameSizesAndStackTrace(
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/internal/examine_stack.h b/absl/debugging/internal/examine_stack.h
index 474fdd5e..861db75d 100644
--- a/absl/debugging/internal/examine_stack.h
+++ b/absl/debugging/internal/examine_stack.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Returns the program counter from signal context, or nullptr if
@@ -34,7 +34,7 @@ void DumpPCAndFrameSizesAndStackTrace(
void (*writerfn)(const char*, void*), void* writerfn_arg);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_
diff --git a/absl/debugging/internal/stack_consumption.cc b/absl/debugging/internal/stack_consumption.cc
index 94b43e1d..8dfd94aa 100644
--- a/absl/debugging/internal/stack_consumption.cc
+++ b/absl/debugging/internal/stack_consumption.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,7 +27,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
namespace {
@@ -168,7 +168,7 @@ int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) {
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/absl/debugging/internal/stack_consumption.h b/absl/debugging/internal/stack_consumption.h
index 2defdf0d..1eb37eef 100644
--- a/absl/debugging/internal/stack_consumption.h
+++ b/absl/debugging/internal/stack_consumption.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,7 +27,7 @@
#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Returns the stack consumption in bytes for the code exercised by
@@ -39,7 +39,7 @@ namespace debugging_internal {
int GetSignalHandlerStackConsumption(void (*signal_handler)(int));
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/absl/debugging/internal/stack_consumption_test.cc b/absl/debugging/internal/stack_consumption_test.cc
index 022e508a..1c82d18a 100644
--- a/absl/debugging/internal/stack_consumption_test.cc
+++ b/absl/debugging/internal/stack_consumption_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
namespace {
@@ -44,7 +44,7 @@ TEST(SignalHandlerStackConsumptionTest, MeasuresStackConsumption) {
} // namespace
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION
diff --git a/absl/debugging/internal/stacktrace_aarch64-inl.inc b/absl/debugging/internal/stacktrace_aarch64-inl.inc
index 2ed7ae1f..14b6e6b0 100644
--- a/absl/debugging/internal/stacktrace_aarch64-inl.inc
+++ b/absl/debugging/internal/stacktrace_aarch64-inl.inc
@@ -180,13 +180,13 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_
diff --git a/absl/debugging/internal/stacktrace_arm-inl.inc b/absl/debugging/internal/stacktrace_arm-inl.inc
index eb8ca77c..4f51d180 100644
--- a/absl/debugging/internal/stacktrace_arm-inl.inc
+++ b/absl/debugging/internal/stacktrace_arm-inl.inc
@@ -113,13 +113,13 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_
diff --git a/absl/debugging/internal/stacktrace_config.h b/absl/debugging/internal/stacktrace_config.h
index 578e4968..d4e8480a 100644
--- a/absl/debugging/internal/stacktrace_config.h
+++ b/absl/debugging/internal/stacktrace_config.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
diff --git a/absl/debugging/internal/stacktrace_generic-inl.inc b/absl/debugging/internal/stacktrace_generic-inl.inc
index 823942af..39c47866 100644
--- a/absl/debugging/internal/stacktrace_generic-inl.inc
+++ b/absl/debugging/internal/stacktrace_generic-inl.inc
@@ -12,13 +12,47 @@
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
#include <execinfo.h>
+#include <atomic>
#include <cstring>
#include "absl/debugging/stacktrace.h"
+// 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).
+// That can cause a self-deadlock.
+// Protect against such reentrant call by failing to get a stack trace.
+//
+// We use __thread here because the code here is extremely low level -- it is
+// called while collecting stack traces from within malloc and mmap, and thus
+// can not call anything which might call malloc or mmap itself.
+static __thread int recursive = 0;
+
+// The stack trace function might be invoked very early in the program's
+// execution (e.g. from the very first malloc if using tcmalloc). Also, the
+// glibc implementation itself will trigger malloc the first time it is called.
+// As such, we suppress usage of backtrace during this early stage of execution.
+static std::atomic<bool> disable_stacktraces(true); // Disabled until healthy.
+// Waiting until static initializers run seems to be late enough.
+// This file is included into stacktrace.cc so this will only run once.
+static int stacktraces_enabler = []() {
+ 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
+ // to use backtrace from a signal handler if we crash somewhere later.
+ backtrace(unused_stack, 1);
+ disable_stacktraces.store(false, std::memory_order_relaxed);
+ return 0;
+}();
+
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) {
+ if (recursive || disable_stacktraces.load(std::memory_order_relaxed)) {
+ return 0;
+ }
+ ++recursive;
+
static_cast<void>(ucp); // Unused.
static const int kStackLength = 64;
void * stack[kStackLength];
@@ -46,17 +80,19 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
}
}
+ --recursive;
+
return result_count;
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_powerpc-inl.inc b/absl/debugging/internal/stacktrace_powerpc-inl.inc
index aff2d516..ee6b38ff 100644
--- a/absl/debugging/internal/stacktrace_powerpc-inl.inc
+++ b/absl/debugging/internal/stacktrace_powerpc-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -14,8 +14,8 @@
//
// Produce stack trace. I'm guessing (hoping!) the code is much like
// for x86. For apple machines, at least, it seems to be; see
-// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
-// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
+// https://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html
+// https://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK
// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
@@ -162,7 +162,7 @@ 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) {
void **sp;
- // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
+ // 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
// different asm syntax. I don't know quite the best way to discriminate
// systems using the old as from the new one; I've gone with __APPLE__.
@@ -236,13 +236,13 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_
diff --git a/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
index 65345efc..b49a929a 100644
--- a/absl/debugging/internal/stacktrace_unimplemented-inl.inc
+++ b/absl/debugging/internal/stacktrace_unimplemented-inl.inc
@@ -12,13 +12,13 @@ static int UnwindImpl(void** /* result */, int* /* sizes */,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
index 59e72785..0cd8c339 100644
--- a/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,7 +32,7 @@
// server.
//
// This code is inspired by a patch from David Vitek:
-// http://code.google.com/p/google-perftools/issues/detail?id=83
+// https://code.google.com/p/google-perftools/issues/detail?id=83
#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
@@ -73,13 +73,13 @@ static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return false;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_
diff --git a/absl/debugging/internal/stacktrace_x86-inl.inc b/absl/debugging/internal/stacktrace_x86-inl.inc
index d29cd84b..ff0fd31f 100644
--- a/absl/debugging/internal/stacktrace_x86-inl.inc
+++ b/absl/debugging/internal/stacktrace_x86-inl.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,6 +33,7 @@
#include "absl/debugging/internal/address_is_readable.h"
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
#include "absl/debugging/stacktrace.h"
+
#include "absl/base/internal/raw_logging.h"
#if defined(__linux__) && defined(__i386__)
@@ -327,13 +328,13 @@ static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count,
}
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
bool StackTraceWorksForTest() {
return true;
}
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_
diff --git a/absl/debugging/internal/symbolize.h b/absl/debugging/internal/symbolize.h
index 2791105e..151bc77c 100644
--- a/absl/debugging/internal/symbolize.h
+++ b/absl/debugging/internal/symbolize.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,6 @@
#include <cstddef>
#include <cstdint>
-#include "absl/base/port.h" // Needed for string vs std::string
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
@@ -34,7 +33,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// Iterates over all sections, invoking callback on each with the section name
@@ -43,9 +42,9 @@ namespace debugging_internal {
// Returns true on success; otherwise returns false in case of errors.
//
// This is not async-signal-safe.
-bool ForEachSection(
- int fd, const std::function<bool(const std::string& name, const ElfW(Shdr) &)>&
- callback);
+bool ForEachSection(int fd,
+ const std::function<bool(const std::string& name,
+ const ElfW(Shdr) &)>& callback);
// Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false.
@@ -53,13 +52,13 @@ bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
struct SymbolDecoratorArgs {
@@ -121,7 +120,7 @@ bool GetFileMappingHint(const void** start,
const char** filename);
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_
diff --git a/absl/debugging/internal/vdso_support.cc b/absl/debugging/internal/vdso_support.cc
index 85b52bc8..fa88e1d8 100644
--- a/absl/debugging/internal/vdso_support.cc
+++ b/absl/debugging/internal/vdso_support.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,7 +38,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
ABSL_CONST_INIT
@@ -188,7 +188,7 @@ static class VDSOInitHelper {
} vdso_init_helper;
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_VDSO_SUPPORT
diff --git a/absl/debugging/internal/vdso_support.h b/absl/debugging/internal/vdso_support.h
index 035e5964..bc5fdb11 100644
--- a/absl/debugging/internal/vdso_support.h
+++ b/absl/debugging/internal/vdso_support.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -53,7 +53,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
// NOTE: this class may be used from within tcmalloc, and can not
@@ -150,7 +150,7 @@ class VDSOSupport {
int GetCPU();
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_ELF_MEM_IMAGE
diff --git a/absl/debugging/leak_check.cc b/absl/debugging/leak_check.cc
index cf65280a..63e54ffa 100644
--- a/absl/debugging/leak_check.cc
+++ b/absl/debugging/leak_check.cc
@@ -4,13 +4,14 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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.
+
// Wrappers around lsan_interface functions.
// When lsan is not linked in, these functions are not available,
// therefore Abseil code which depends on these functions is conditioned on the
@@ -20,14 +21,14 @@
#ifndef LEAK_SANITIZER
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
bool HaveLeakSanitizer() { return false; }
void DoIgnoreLeak(const void*) { }
void RegisterLivePointers(const void*, size_t) { }
void UnRegisterLivePointers(const void*, size_t) { }
LeakCheckDisabler::LeakCheckDisabler() { }
LeakCheckDisabler::~LeakCheckDisabler() { }
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else
@@ -35,7 +36,7 @@ LeakCheckDisabler::~LeakCheckDisabler() { }
#include <sanitizer/lsan_interface.h>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
bool HaveLeakSanitizer() { return true; }
void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); }
void RegisterLivePointers(const void* ptr, size_t size) {
@@ -46,7 +47,7 @@ void UnRegisterLivePointers(const void* ptr, size_t size) {
}
LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); }
LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); }
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // LEAK_SANITIZER
diff --git a/absl/debugging/leak_check.h b/absl/debugging/leak_check.h
index f5e4fd87..e1215e38 100644
--- a/absl/debugging/leak_check.h
+++ b/absl/debugging/leak_check.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,7 +33,7 @@
#include <cstddef>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// HaveLeakSanitizer()
//
@@ -105,7 +105,7 @@ void RegisterLivePointers(const void* ptr, size_t size);
// `RegisterLivePointers()`, enabling leak checking of those pointers.
void UnRegisterLivePointers(const void* ptr, size_t size);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_LEAK_CHECK_H_
diff --git a/absl/debugging/leak_check_disable.cc b/absl/debugging/leak_check_disable.cc
index df22c1ca..924d6e3d 100644
--- a/absl/debugging/leak_check_disable.cc
+++ b/absl/debugging/leak_check_disable.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/debugging/leak_check_fail_test.cc b/absl/debugging/leak_check_fail_test.cc
index bf541fe8..2887ceab 100644
--- a/absl/debugging/leak_check_fail_test.cc
+++ b/absl/debugging/leak_check_fail_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/debugging/leak_check_test.cc b/absl/debugging/leak_check_test.cc
index febd1ee4..93a7edd2 100644
--- a/absl/debugging/leak_check_test.cc
+++ b/absl/debugging/leak_check_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/debugging/stacktrace.cc b/absl/debugging/stacktrace.cc
index e991fc59..3052fb97 100644
--- a/absl/debugging/stacktrace.cc
+++ b/absl/debugging/stacktrace.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -46,6 +46,7 @@
#include ABSL_STACKTRACE_INL_HEADER
#else
# error Cannot calculate stack trace: will need to write for your environment
+
# include "absl/debugging/internal/stacktrace_aarch64-inl.inc"
# include "absl/debugging/internal/stacktrace_arm-inl.inc"
# include "absl/debugging/internal/stacktrace_generic-inl.inc"
@@ -56,7 +57,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
typedef int (*Unwinder)(void**, int*, int, int, const void*, int*);
@@ -135,5 +136,5 @@ int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip,
return n;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/stacktrace.h b/absl/debugging/stacktrace.h
index 7baf83bc..d7565aa4 100644
--- a/absl/debugging/stacktrace.h
+++ b/absl/debugging/stacktrace.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,7 +32,7 @@
#define ABSL_DEBUGGING_STACKTRACE_H_
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// GetStackFrames()
//
@@ -221,7 +221,7 @@ namespace debugging_internal {
// working.
extern bool StackTraceWorksForTest();
} // namespace debugging_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_STACKTRACE_H_
diff --git a/absl/debugging/symbolize.cc b/absl/debugging/symbolize.cc
index a35e24cc..24e3a7f0 100644
--- a/absl/debugging/symbolize.cc
+++ b/absl/debugging/symbolize.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/debugging/symbolize.h b/absl/debugging/symbolize.h
index fc606e87..ab5447c4 100644
--- a/absl/debugging/symbolize.h
+++ b/absl/debugging/symbolize.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -55,7 +55,7 @@
#include "absl/debugging/internal/symbolize.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// InitializeSymbolizer()
//
@@ -93,7 +93,7 @@ void InitializeSymbolizer(const char* argv0);
// }
bool Symbolize(const void *pc, char *out, int out_size);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_DEBUGGING_SYMBOLIZE_H_
diff --git a/absl/debugging/symbolize_elf.inc b/absl/debugging/symbolize_elf.inc
index 37f77ca6..2bd7659f 100644
--- a/absl/debugging/symbolize_elf.inc
+++ b/absl/debugging/symbolize_elf.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -76,7 +76,7 @@
#include "absl/debugging/internal/vdso_support.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Value of argv[0]. Used by MaybeInitializeObjFile().
static char *argv0_value = nullptr;
@@ -306,7 +306,7 @@ class Symbolizer {
char *tmp_buf, int tmp_buf_size);
enum {
- SYMBOL_BUF_SIZE = 2048,
+ SYMBOL_BUF_SIZE = 3072,
TMP_BUF_SIZE = 1024,
SYMBOL_CACHE_LINES = 128,
};
@@ -763,37 +763,27 @@ FindSymbolResult Symbolizer::GetSymbolFromObjectFile(
}
}
- // Consult a regular symbol table first.
- if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
- obj.elf_header.e_shoff, SHT_SYMTAB, &symtab,
- tmp_buf, tmp_buf_size)) {
- return SYMBOL_NOT_FOUND;
- }
- if (!ReadFromOffsetExact(
- obj.fd, &strtab, sizeof(strtab),
- obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
- return SYMBOL_NOT_FOUND;
- }
- const FindSymbolResult rc =
- FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
- opd_ptr, tmp_buf, tmp_buf_size);
- if (rc != SYMBOL_NOT_FOUND) {
- return rc; // Found the symbol in a regular symbol table.
+ // Consult a regular symbol table, then fall back to the dynamic symbol table.
+ for (const auto symbol_table_type : {SHT_SYMTAB, SHT_DYNSYM}) {
+ if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
+ obj.elf_header.e_shoff, symbol_table_type,
+ &symtab, tmp_buf, tmp_buf_size)) {
+ continue;
+ }
+ if (!ReadFromOffsetExact(
+ obj.fd, &strtab, sizeof(strtab),
+ obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
+ continue;
+ }
+ const FindSymbolResult rc =
+ FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
+ opd_ptr, tmp_buf, tmp_buf_size);
+ if (rc != SYMBOL_NOT_FOUND) {
+ return rc;
+ }
}
- // If the symbol is not found, then consult a dynamic symbol table.
- if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum,
- obj.elf_header.e_shoff, SHT_DYNSYM, &symtab,
- tmp_buf, tmp_buf_size)) {
- return SYMBOL_NOT_FOUND;
- }
- if (!ReadFromOffsetExact(
- obj.fd, &strtab, sizeof(strtab),
- obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
- return SYMBOL_NOT_FOUND;
- }
- return FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab,
- opd_ptr, tmp_buf, tmp_buf_size);
+ return SYMBOL_NOT_FOUND;
}
namespace {
@@ -926,6 +916,14 @@ static const char *GetHex(const char *start, const char *end,
return p;
}
+// Normally we are only interested in "r?x" maps.
+// On the PowerPC, function pointers point to descriptors in the .opd
+// section. The descriptors themselves are not executable code, so
+// we need to relax the check below to "r??".
+static bool ShouldUseMapping(const char *const flags) {
+ return flags[0] == 'r' && (kPlatformUsesOPDSections || flags[2] == 'x');
+}
+
// Read /proc/self/maps and run "callback" for each mmapped file found. If
// "callback" returns false, stop scanning and return true. Else continue
// scanning /proc/self/maps. Return true if no parse error is found.
@@ -995,12 +993,8 @@ static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap(
return false;
}
- // Check flags. Normally we are only interested in "r-x" maps. On
- // the PowerPC, function pointers point to descriptors in the .opd
- // section. The descriptors themselves are not executable code. So
- // we need to relax the check below to "r**".
- if (memcmp(flags_start, "r-x", 3) != 0 && // Not a "r-x" map.
- !(kPlatformUsesOPDSections && flags_start[0] == 'r')) {
+ // Check flags.
+ if (!ShouldUseMapping(flags_start)) {
continue; // We skip this map.
}
++cursor; // Skip ' '.
@@ -1475,5 +1469,5 @@ bool Symbolize(const void *pc, char *out, int out_size) {
return ok;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/symbolize_test.cc b/absl/debugging/symbolize_test.cc
index 8029fbe9..08068c30 100644
--- a/absl/debugging/symbolize_test.cc
+++ b/absl/debugging/symbolize_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -107,7 +107,8 @@ static const char *TrySymbolizeWithLimit(void *pc, int limit) {
ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit,
"absl::Symbolize() did not properly terminate the string");
strncpy(try_symbolize_buffer, heap_buffer.get(),
- sizeof(try_symbolize_buffer));
+ sizeof(try_symbolize_buffer) - 1);
+ try_symbolize_buffer[sizeof(try_symbolize_buffer) - 1] = '\0';
}
return found ? try_symbolize_buffer : nullptr;
@@ -392,16 +393,20 @@ TEST(Symbolize, ForEachSection) {
extern "C" {
inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() {
void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+ __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+ __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
#endif
return pc;
}
void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() {
void *pc = nullptr;
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
+#if defined(__i386__)
+ __asm__ __volatile__("call 1f;\n 1: pop %[PC]" : [ PC ] "=r"(pc));
+#elif defined(__x86_64__)
+ __asm__ __volatile__("leaq 0(%%rip),%[PC];\n" : [ PC ] "=r"(pc));
#endif
return pc;
}
diff --git a/absl/debugging/symbolize_unimplemented.inc b/absl/debugging/symbolize_unimplemented.inc
index 874a4228..0c1c1951 100644
--- a/absl/debugging/symbolize_unimplemented.inc
+++ b/absl/debugging/symbolize_unimplemented.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace debugging_internal {
@@ -27,11 +27,14 @@ bool RemoveAllSymbolDecorators(void) { return false; }
bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) {
return false;
}
+bool GetFileMappingHint(const void **, const void **, uint64_t *, const char **) {
+ return false;
+}
} // namespace debugging_internal
void InitializeSymbolizer(const char*) {}
bool Symbolize(const void *, char *, int) { return false; }
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index ee8fd55c..498ca2db 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,8 +16,14 @@
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
#include <windows.h>
+
+// MSVC header DbgHelp.h has a warning for an ignored typedef.
+#pragma warning(push)
+#pragma warning(disable:4091)
#include <DbgHelp.h>
-#pragma comment(lib, "DbgHelp")
+#pragma warning(pop)
+
+#pragma comment(lib, "dbghelp.lib")
#include <algorithm>
#include <cstring>
@@ -25,7 +31,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
static HANDLE process = NULL;
@@ -72,5 +78,5 @@ bool Symbolize(const void *pc, char *out, int out_size) {
return true;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
new file mode 100644
index 00000000..2fe61eaa
--- /dev/null
+++ b/absl/flags/BUILD.bazel
@@ -0,0 +1,384 @@
+#
+# 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.
+#
+
+load(
+ "//absl:copts/configure_copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
+ "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "internal",
+ srcs = [
+ "internal/program_name.cc",
+ ],
+ hdrs = [
+ "internal/path_util.h",
+ "internal/program_name.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/flags:__pkg__",
+ ],
+ deps = [
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+cc_library(
+ name = "config",
+ srcs = [
+ "usage_config.cc",
+ ],
+ hdrs = [
+ "config.h",
+ "usage_config.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":internal",
+ "//absl/base:core_headers",
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+cc_library(
+ name = "marshalling",
+ srcs = [
+ "marshalling.cc",
+ ],
+ hdrs = [
+ "marshalling.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:core_headers",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ ],
+)
+
+cc_library(
+ name = "handle",
+ srcs = [
+ "internal/commandlineflag.cc",
+ ],
+ hdrs = [
+ "internal/commandlineflag.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/flags:__pkg__",
+ ],
+ deps = [
+ ":config",
+ ":marshalling",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/strings",
+ "//absl/synchronization",
+ "//absl/types:optional",
+ ],
+)
+
+cc_library(
+ name = "registry",
+ srcs = [
+ "internal/registry.cc",
+ "internal/type_erased.cc",
+ ],
+ hdrs = [
+ "internal/registry.h",
+ "internal/type_erased.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/flags:__pkg__",
+ ],
+ deps = [
+ ":config",
+ ":handle",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/base:dynamic_annotations",
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+cc_library(
+ name = "flag",
+ srcs = [
+ "flag.cc",
+ ],
+ hdrs = [
+ "declare.h",
+ "flag.h",
+ "internal/flag.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":handle",
+ ":marshalling",
+ ":registry",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/strings",
+ ],
+)
+
+cc_library(
+ name = "usage_internal",
+ srcs = [
+ "internal/usage.cc",
+ ],
+ hdrs = [
+ "internal/usage.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/flags:__pkg__",
+ ],
+ deps = [
+ ":config",
+ ":flag",
+ ":handle",
+ ":internal",
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+cc_library(
+ name = "usage",
+ srcs = [
+ "usage.cc",
+ ],
+ hdrs = [
+ "usage.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":usage_internal",
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+cc_library(
+ name = "parse",
+ srcs = ["parse.cc"],
+ hdrs = [
+ "internal/parse.h",
+ "parse.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":flag",
+ ":handle",
+ ":internal",
+ ":registry",
+ ":usage",
+ ":usage_internal",
+ "//absl/strings",
+ "//absl/synchronization",
+ ],
+)
+
+############################################################################
+# Unit tests in alpahabetical order.
+
+cc_test(
+ name = "commandlineflag_test",
+ size = "small",
+ srcs = [
+ "internal/commandlineflag_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":flag",
+ ":handle",
+ ":registry",
+ "//absl/memory",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "config_test",
+ size = "small",
+ srcs = [
+ "config_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "flag_test",
+ size = "small",
+ srcs = [
+ "flag_test.cc",
+ "flag_test_defs.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":flag",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "marshalling_test",
+ size = "small",
+ srcs = [
+ "marshalling_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":marshalling",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "path_util_test",
+ size = "small",
+ srcs = [
+ "internal/path_util_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":internal",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "parse_test",
+ size = "small",
+ srcs = [
+ "parse_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":flag",
+ ":parse",
+ "//absl/base",
+ "//absl/base:scoped_set_env",
+ "//absl/strings",
+ "//absl/types:span",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "program_name_test",
+ size = "small",
+ srcs = [
+ "internal/program_name_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":internal",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "type_erased_test",
+ size = "small",
+ srcs = [
+ "internal/type_erased_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":flag",
+ ":registry",
+ "//absl/memory",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "usage_config_test",
+ size = "small",
+ srcs = [
+ "usage_config_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":internal",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "usage_test",
+ size = "small",
+ srcs = [
+ "internal/usage_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":config",
+ ":flag",
+ ":internal",
+ ":parse",
+ ":usage",
+ ":usage_internal",
+ "//absl/memory",
+ "//absl/strings",
+ "@com_google_googletest//:gtest",
+ ],
+)
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt
new file mode 100644
index 00000000..fa1d4e17
--- /dev/null
+++ b/absl/flags/CMakeLists.txt
@@ -0,0 +1,346 @@
+#
+# 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.
+#
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_internal
+ SRCS
+ "internal/program_name.cc"
+ HDRS
+ "internal/path_util.h"
+ "internal/program_name.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::strings
+ absl::synchronization
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ flags_config
+ SRCS
+ "usage_config.cc"
+ HDRS
+ "config.h"
+ "usage_config.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_internal
+ absl::core_headers
+ absl::strings
+ absl::synchronization
+)
+
+absl_cc_library(
+ NAME
+ flags_marshalling
+ SRCS
+ "marshalling.cc"
+ HDRS
+ "marshalling.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::core_headers
+ absl::strings
+ absl::str_format
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_handle
+ SRCS
+ "internal/commandlineflag.cc"
+ HDRS
+ "internal/commandlineflag.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_config
+ absl::flags_marshalling
+ absl::base
+ absl::core_headers
+ absl::strings
+ absl::synchronization
+ absl::optional
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_registry
+ SRCS
+ "internal/registry.cc"
+ "internal/type_erased.cc"
+ HDRS
+ "internal/registry.h"
+ "internal/type_erased.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_config
+ absl::flags_handle
+ absl::base
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::strings
+ absl::synchronization
+)
+
+absl_cc_library(
+ NAME
+ flags
+ SRCS
+ "flag.cc"
+ HDRS
+ "declare.h"
+ "flag.h"
+ "internal/flag.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_config
+ absl::flags_handle
+ absl::flags_marshalling
+ absl::flags_registry
+ absl::base
+ absl::core_headers
+ absl::strings
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ flags_usage_internal
+ SRCS
+ "internal/usage.cc"
+ HDRS
+ "internal/usage.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_config
+ absl::flags
+ absl::flags_handle
+ absl::flags_internal
+ absl::strings
+ absl::synchronization
+)
+
+absl_cc_library(
+ NAME
+ flags_usage
+ SRCS
+ "usage.cc"
+ HDRS
+ "usage.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_usage_internal
+ absl::strings
+ absl::synchronization
+)
+
+absl_cc_library(
+ NAME
+ flags_parse
+ SRCS
+ "parse.cc"
+ HDRS
+ "internal/parse.h"
+ "parse.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::flags_config
+ absl::flags
+ absl::flags_handle
+ absl::flags_internal
+ absl::flags_registry
+ absl::flags_usage
+ absl::strings
+ absl::synchronization
+)
+
+############################################################################
+# Unit tests in alpahabetical order.
+
+absl_cc_test(
+ NAME
+ flags_commandlineflag_test
+ SRCS
+ "internal/commandlineflag_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags
+ absl::flags_handle
+ absl::flags_registry
+ absl::memory
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_config_test
+ SRCS
+ "config_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_config
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_flag_test
+ SRCS
+ "flag_test.cc"
+ "flag_test_defs.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_marshalling_test
+ SRCS
+ "marshalling_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_marshalling
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_parse_test
+ SRCS
+ "parse_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags
+ absl::base
+ absl::flags_parse
+ absl::scoped_set_env
+ absl::span
+ absl::strings
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ flags_path_util_test
+ SRCS
+ "internal/path_util_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_internal
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_program_name_test
+ SRCS
+ "internal/program_name_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_internal
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_type_erased_test
+ SRCS
+ "internal/type_erased_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags
+ absl::flags_registry
+ absl::memory
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_usage_config_test
+ SRCS
+ "usage_config_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_config
+ absl::flags_internal
+ absl::strings
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ flags_usage_test
+ SRCS
+ "internal/usage_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::flags_config
+ absl::flags
+ absl::flags_internal
+ absl::flags_parse
+ absl::flags_usage
+ absl::memory
+ absl::strings
+ gtest
+)
diff --git a/absl/flags/config.h b/absl/flags/config.h
new file mode 100644
index 00000000..a9fd97ad
--- /dev/null
+++ b/absl/flags/config.h
@@ -0,0 +1,48 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_CONFIG_H_
+#define ABSL_FLAGS_CONFIG_H_
+
+// Determine if we should strip string literals from the Flag objects.
+// By default we strip string literals on mobile platforms.
+#if !defined(ABSL_FLAGS_STRIP_NAMES)
+
+#if defined(__ANDROID__)
+#define ABSL_FLAGS_STRIP_NAMES 1
+
+#elif defined(__APPLE__)
+#include <TargetConditionals.h>
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define ABSL_FLAGS_STRIP_NAMES 1
+#elif defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED
+#define ABSL_FLAGS_STRIP_NAMES 1
+#endif // TARGET_OS_*
+#endif
+
+#endif // !defined(ABSL_FLAGS_STRIP_NAMES)
+
+#if !defined(ABSL_FLAGS_STRIP_NAMES)
+// If ABSL_FLAGS_STRIP_NAMES wasn't set on the command line or above,
+// the default is not to strip.
+#define ABSL_FLAGS_STRIP_NAMES 0
+#endif
+
+#if !defined(ABSL_FLAGS_STRIP_HELP)
+// By default, if we strip names, we also strip help.
+#define ABSL_FLAGS_STRIP_HELP ABSL_FLAGS_STRIP_NAMES
+#endif
+
+#endif // ABSL_FLAGS_CONFIG_H_
diff --git a/absl/flags/config_test.cc b/absl/flags/config_test.cc
new file mode 100644
index 00000000..63899866
--- /dev/null
+++ b/absl/flags/config_test.cc
@@ -0,0 +1,61 @@
+// 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.
+
+#include "absl/flags/config.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include "gtest/gtest.h"
+
+#ifndef ABSL_FLAGS_STRIP_NAMES
+#error ABSL_FLAGS_STRIP_NAMES is not defined
+#endif
+
+#ifndef ABSL_FLAGS_STRIP_HELP
+#error ABSL_FLAGS_STRIP_HELP is not defined
+#endif
+
+namespace {
+
+// Test that ABSL_FLAGS_STRIP_NAMES and ABSL_FLAGS_STRIP_HELP are configured how
+// we expect them to be configured by default. If you override this
+// configuration, this test will fail, but the code should still be safe to use.
+TEST(FlagsConfigTest, Test) {
+#if defined(__ANDROID__)
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
+#elif defined(__myriad2__)
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
+#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
+#elif defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 1);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 1);
+#elif defined(__APPLE__)
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
+#elif defined(_WIN32)
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
+#elif defined(__linux__)
+ EXPECT_EQ(ABSL_FLAGS_STRIP_NAMES, 0);
+ EXPECT_EQ(ABSL_FLAGS_STRIP_HELP, 0);
+#endif
+}
+
+} // namespace
diff --git a/absl/flags/declare.h b/absl/flags/declare.h
new file mode 100644
index 00000000..7ef1d432
--- /dev/null
+++ b/absl/flags/declare.h
@@ -0,0 +1,60 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: declare.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the ABSL_DECLARE_FLAG macro, allowing you to declare an
+// `absl::Flag` for use within a translation unit. You should place this
+// declaration within the header file associated with the .cc file that defines
+// and owns the `Flag`.
+
+#ifndef ABSL_FLAGS_DECLARE_H_
+#define ABSL_FLAGS_DECLARE_H_
+
+#include "absl/strings/string_view.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// absl::Flag<T> represents a flag of type 'T' created by ABSL_FLAG.
+template <typename T>
+class Flag;
+
+} // namespace flags_internal
+
+// Flag
+//
+// Forward declaration of the `absl::Flag` type for use in defining the macro.
+template <typename T>
+using Flag = flags_internal::Flag<T>;
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+// ABSL_DECLARE_FLAG()
+//
+// This macro is a convenience for declaring use of an `absl::Flag` within a
+// translation unit. This macro should be used within a header file to
+// declare usage of the flag within any .cc file including that header file.
+//
+// The ABSL_DECLARE_FLAG(type, name) macro expands to:
+//
+// extern absl::Flag<type> FLAGS_name;
+#define ABSL_DECLARE_FLAG(type, name) extern ::absl::Flag<type> FLAGS_##name
+
+#endif // ABSL_FLAGS_DECLARE_H_
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
new file mode 100644
index 00000000..0858259b
--- /dev/null
+++ b/absl/flags/flag.cc
@@ -0,0 +1,46 @@
+//
+// 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.
+
+#include "absl/flags/flag.h"
+
+#include <cstring>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// We want to validate the type mismatch between type definition and
+// declaration. The lock-free implementation does not allow us to do it,
+// so in debug builds we always use the slower implementation, which always
+// validates the type.
+#ifndef NDEBUG
+#define ABSL_FLAGS_ATOMIC_GET(T) \
+ T GetFlag(const absl::Flag<T>& flag) { return flag.Get(); }
+#else
+#define ABSL_FLAGS_ATOMIC_GET(T) \
+ T GetFlag(const absl::Flag<T>& flag) { \
+ T result; \
+ if (flag.AtomicGet(&result)) { \
+ return result; \
+ } \
+ return flag.Get(); \
+ }
+#endif
+
+ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_ATOMIC_GET)
+
+#undef ABSL_FLAGS_ATOMIC_GET
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
new file mode 100644
index 00000000..28925927
--- /dev/null
+++ b/absl/flags/flag.h
@@ -0,0 +1,259 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: flag.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::Flag<T>` type for holding command-line
+// flag data, and abstractions to create, get and set such flag data.
+//
+// It is important to note that this type is **unspecified** (an implementation
+// detail) and you do not construct or manipulate actual `absl::Flag<T>`
+// instances. Instead, you define and declare flags using the
+// `ABSL_FLAG()` and `ABSL_DECLARE_FLAG()` macros, and get and set flag values
+// using the `absl::GetFlag()` and `absl::SetFlag()` functions.
+
+#ifndef ABSL_FLAGS_FLAG_H_
+#define ABSL_FLAGS_FLAG_H_
+
+#include "absl/base/attributes.h"
+#include "absl/base/casts.h"
+#include "absl/flags/config.h"
+#include "absl/flags/declare.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/flag.h"
+#include "absl/flags/marshalling.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// Flag
+//
+// An `absl::Flag` holds a command-line flag value, providing a runtime
+// parameter to a binary. Such flags should be defined in the global namespace
+// and (preferably) in the module containing the binary's `main()` function.
+//
+// You should not construct and cannot use the `absl::Flag` type directly;
+// instead, you should declare flags using the `ABSL_DECLARE_FLAG()` macro
+// within a header file, and define your flag using `ABSL_FLAG()` within your
+// header's associated `.cc` file. Such flags will be named `FLAGS_name`.
+//
+// Example:
+//
+// .h file
+//
+// // Declares usage of a flag named "FLAGS_count"
+// ABSL_DECLARE_FLAG(int, count);
+//
+// .cc file
+//
+// // Defines a flag named "FLAGS_count" with a default `int` value of 0.
+// ABSL_FLAG(int, count, 0, "Count of items to process");
+//
+// No public methods of `absl::Flag<T>` are part of the Abseil Flags API.
+template <typename T>
+using Flag = flags_internal::Flag<T>;
+
+// GetFlag()
+//
+// Returns the value (of type `T`) of an `absl::Flag<T>` instance, by value. Do
+// not construct an `absl::Flag<T>` directly and call `absl::GetFlag()`;
+// instead, refer to flag's constructed variable name (e.g. `FLAGS_name`).
+// Because this function returns by value and not by reference, it is
+// thread-safe, but note that the operation may be expensive; as a result, avoid
+// `absl::GetFlag()` within any tight loops.
+//
+// Example:
+//
+// // FLAGS_count is a Flag of type `int`
+// int my_count = absl::GetFlag(FLAGS_count);
+//
+// // FLAGS_firstname is a Flag of type `std::string`
+// std::string first_name = absl::GetFlag(FLAGS_firstname);
+template <typename T>
+T GetFlag(const absl::Flag<T>& flag) {
+#define ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE(BIT) \
+ static_assert( \
+ !std::is_same<T, BIT>::value, \
+ "Do not specify explicit template parameters to absl::GetFlag");
+ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE)
+#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_VALIDATE
+
+ return flag.Get();
+}
+
+// Overload for `GetFlag()` for types that support lock-free reads.
+#define ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT(T) \
+ extern T GetFlag(const absl::Flag<T>& flag);
+ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT)
+#undef ABSL_FLAGS_INTERNAL_LOCK_FREE_EXPORT
+
+// SetFlag()
+//
+// Sets the value of an `absl::Flag` to the value `v`. Do not construct an
+// `absl::Flag<T>` directly and call `absl::SetFlag()`; instead, use the
+// flag's variable name (e.g. `FLAGS_name`). This function is
+// 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) {
+ flag->Set(v);
+}
+
+// Overload of `SetFlag()` to allow callers to pass in a value that is
+// 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) {
+ T value(v);
+ flag->Set(value);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+
+// ABSL_FLAG()
+//
+// This macro defines an `absl::Flag<T>` instance of a specified type `T`:
+//
+// ABSL_FLAG(T, name, default_value, help);
+//
+// where:
+//
+// * `T` is a supported flag type (see the list of types in `marshalling.h`),
+// * `name` designates the name of the flag (as a global variable
+// `FLAGS_name`),
+// * `default_value` is an expression holding the default value for this flag
+// (which must be implicitly convertible to `T`),
+// * `help` is the help text, which can also be an expression.
+//
+// This macro expands to a flag named 'FLAGS_name' of type 'T':
+//
+// absl::Flag<T> FLAGS_name = ...;
+//
+// Note that all such instances are created as global variables.
+//
+// For `ABSL_FLAG()` values that you wish to expose to other translation units,
+// it is recommended to define those flags within the `.cc` file associated with
+// the header where the flag is declared.
+//
+// Note: do not construct objects of type `absl::Flag<T>` directly. Only use the
+// `ABSL_FLAG()` macro for such construction.
+#define ABSL_FLAG(Type, name, default_value, help) \
+ ABSL_FLAG_IMPL(Type, name, default_value, help)
+
+// ABSL_FLAG().OnUpdate()
+//
+// Defines a flag of type `T` with a callback attached:
+//
+// ABSL_FLAG(T, name, default_value, help).OnUpdate(callback);
+//
+// After any setting of the flag value, the callback will be called at least
+// once. A rapid sequence of changes may be merged together into the same
+// callback. No concurrent calls to the callback will be made for the same
+// flag. Callbacks are allowed to read the current value of the flag but must
+// not mutate that flag.
+//
+// The update mechanism guarantees "eventual consistency"; if the callback
+// derives an auxiliary data structure from the flag value, it is guaranteed
+// that eventually the flag value and the derived data structure will be
+// consistent.
+//
+// Note: ABSL_FLAG.OnUpdate() does not have a public definition. Hence, this
+// comment serves as its API documentation.
+
+
+// -----------------------------------------------------------------------------
+// Implementation details below this section
+// -----------------------------------------------------------------------------
+
+// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_NAMES
+
+#if ABSL_FLAGS_STRIP_NAMES
+#define ABSL_FLAG_IMPL_FLAGNAME(txt) ""
+#define ABSL_FLAG_IMPL_FILENAME() ""
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
+ absl::flags_internal::FlagRegistrar<T, false>(&flag)
+#else
+#define ABSL_FLAG_IMPL_FLAGNAME(txt) txt
+#define ABSL_FLAG_IMPL_FILENAME() __FILE__
+#define ABSL_FLAG_IMPL_REGISTRAR(T, flag) \
+ absl::flags_internal::FlagRegistrar<T, true>(&flag)
+#endif
+
+// ABSL_FLAG_IMPL macro definition conditional on ABSL_FLAGS_STRIP_HELP
+
+#if ABSL_FLAGS_STRIP_HELP
+#define ABSL_FLAG_IMPL_FLAGHELP(txt) absl::flags_internal::kStrippedFlagHelp
+#else
+#define ABSL_FLAG_IMPL_FLAGHELP(txt) txt
+#endif
+
+#define ABSL_FLAG_IMPL_DECLARE_HELP_WRAPPER(name, txt) \
+ static std::string AbslFlagsWrapHelp##name() { \
+ return ABSL_FLAG_IMPL_FLAGHELP(txt); \
+ }
+
+#define ABSL_FLAG_IMPL_DECLARE_DEF_VAL_WRAPPER(name, Type, default_value) \
+ static void* AbslFlagsInitFlag##name() { \
+ return absl::flags_internal::MakeFromDefaultValue<Type>(default_value); \
+ }
+
+// ABSL_FLAG_IMPL
+//
+// 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) \
+ 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), &AbslFlagsWrapHelp##name, \
+ ABSL_FLAG_IMPL_FILENAME(), \
+ &absl::flags_internal::FlagMarshallingOps<Type>, \
+ &AbslFlagsInitFlag##name); \
+ extern bool FLAGS_no##name; \
+ bool FLAGS_no##name = ABSL_FLAG_IMPL_REGISTRAR(Type, FLAGS_##name)
+
+// ABSL_RETIRED_FLAG
+//
+// Designates the flag (which is usually pre-existing) as "retired." A retired
+// flag is a flag that is now unused by the program, but may still be passed on
+// the command line, usually by production scripts. A retired flag is ignored
+// and code can't access it at runtime.
+//
+// This macro registers a retired flag with given name and type, with a name
+// identical to the name of the original flag you are retiring. The retired
+// flag's type can change over time, so that you can retire code to support a
+// custom flag type.
+//
+// This macro has the same signature as `ABSL_FLAG`. To retire a flag, simply
+// replace an `ABSL_FLAG` definition with `ABSL_RETIRED_FLAG`, leaving the
+// 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.
+// TODO(rogeeff): Return an anonymous struct instead of bool, and place it into
+// the unnamed namespace.
+#define ABSL_RETIRED_FLAG(type, flagname, default_value, explanation) \
+ ABSL_ATTRIBUTE_UNUSED static const bool ignored_##flagname = \
+ ([] { return type(default_value); }, \
+ absl::flags_internal::RetiredFlag<type>(#flagname))
+
+#endif // ABSL_FLAGS_FLAG_H_
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc
new file mode 100644
index 00000000..1bcd7e96
--- /dev/null
+++ b/absl/flags/flag_test.cc
@@ -0,0 +1,482 @@
+//
+// 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.
+
+#include "absl/flags/flag.h"
+
+#include "gtest/gtest.h"
+#include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+
+ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag);
+ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag);
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+std::string TestHelpMsg() { return "help"; }
+template <typename T>
+void* TestMakeDflt() {
+ return new T{};
+}
+void TestCallback() {}
+
+template <typename T>
+bool TestConstructionFor() {
+ constexpr flags::Flag<T> f1("f1", &TestHelpMsg, "file",
+ &absl::flags_internal::FlagMarshallingOps<T>,
+ &TestMakeDflt<T>);
+ EXPECT_EQ(f1.Name(), "f1");
+ EXPECT_EQ(f1.Help(), "help");
+ EXPECT_EQ(f1.Filename(), "file");
+
+ ABSL_CONST_INIT static flags::Flag<T> f2(
+ "f2", &TestHelpMsg, "file", &absl::flags_internal::FlagMarshallingOps<T>,
+ &TestMakeDflt<T>);
+ flags::FlagRegistrar<T, false>(&f2).OnUpdate(TestCallback);
+
+ EXPECT_EQ(f2.Name(), "f2");
+ EXPECT_EQ(f2.Help(), "help");
+ EXPECT_EQ(f2.Filename(), "file");
+
+ return true;
+}
+
+struct UDT {
+ UDT() = default;
+ UDT(const UDT&) = default;
+};
+bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
+std::string AbslUnparseFlag(const UDT&) { return ""; }
+
+TEST(FlagTest, TestConstruction) {
+ TestConstructionFor<bool>();
+ TestConstructionFor<int16_t>();
+ TestConstructionFor<uint16_t>();
+ TestConstructionFor<int32_t>();
+ TestConstructionFor<uint32_t>();
+ TestConstructionFor<int64_t>();
+ TestConstructionFor<uint64_t>();
+ TestConstructionFor<double>();
+ TestConstructionFor<float>();
+ TestConstructionFor<std::string>();
+
+ TestConstructionFor<UDT>();
+}
+
+// --------------------------------------------------------------------
+
+} // namespace
+
+ABSL_DECLARE_FLAG(bool, test_flag_01);
+ABSL_DECLARE_FLAG(int, test_flag_02);
+ABSL_DECLARE_FLAG(int16_t, test_flag_03);
+ABSL_DECLARE_FLAG(uint16_t, test_flag_04);
+ABSL_DECLARE_FLAG(int32_t, test_flag_05);
+ABSL_DECLARE_FLAG(uint32_t, test_flag_06);
+ABSL_DECLARE_FLAG(int64_t, test_flag_07);
+ABSL_DECLARE_FLAG(uint64_t, test_flag_08);
+ABSL_DECLARE_FLAG(double, test_flag_09);
+ABSL_DECLARE_FLAG(float, test_flag_10);
+ABSL_DECLARE_FLAG(std::string, test_flag_11);
+
+namespace {
+
+#if !ABSL_FLAGS_STRIP_NAMES
+
+TEST(FlagTest, TestFlagDeclaration) {
+ // test that we can access flag objects.
+ EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
+ EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
+ EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
+ EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
+ EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
+ EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
+ EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
+ EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
+ EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
+ EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
+ EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+}
+#endif // !ABSL_FLAGS_STRIP_NAMES
+
+// --------------------------------------------------------------------
+
+} // namespace
+
+ABSL_FLAG(bool, test_flag_01, true, "test flag 01");
+ABSL_FLAG(int, test_flag_02, 1234, "test flag 02");
+ABSL_FLAG(int16_t, test_flag_03, -34, "test flag 03");
+ABSL_FLAG(uint16_t, test_flag_04, 189, "test flag 04");
+ABSL_FLAG(int32_t, test_flag_05, 10765, "test flag 05");
+ABSL_FLAG(uint32_t, test_flag_06, 40000, "test flag 06");
+ABSL_FLAG(int64_t, test_flag_07, -1234567, "test flag 07");
+ABSL_FLAG(uint64_t, test_flag_08, 9876543, "test flag 08");
+ABSL_FLAG(double, test_flag_09, -9.876e-50, "test flag 09");
+ABSL_FLAG(float, test_flag_10, 1.234e12f, "test flag 10");
+ABSL_FLAG(std::string, test_flag_11, "", "test flag 11");
+
+namespace {
+
+#if !ABSL_FLAGS_STRIP_NAMES
+TEST(FlagTest, TestFlagDefinition) {
+ absl::string_view expected_file_name = "absl/flags/flag_test.cc";
+
+ EXPECT_EQ(FLAGS_test_flag_01.Name(), "test_flag_01");
+ EXPECT_EQ(FLAGS_test_flag_01.Help(), "test flag 01");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_01.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_02.Name(), "test_flag_02");
+ EXPECT_EQ(FLAGS_test_flag_02.Help(), "test flag 02");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_02.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_03.Name(), "test_flag_03");
+ EXPECT_EQ(FLAGS_test_flag_03.Help(), "test flag 03");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_03.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_04.Name(), "test_flag_04");
+ EXPECT_EQ(FLAGS_test_flag_04.Help(), "test flag 04");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_04.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_05.Name(), "test_flag_05");
+ EXPECT_EQ(FLAGS_test_flag_05.Help(), "test flag 05");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_05.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_06.Name(), "test_flag_06");
+ EXPECT_EQ(FLAGS_test_flag_06.Help(), "test flag 06");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_06.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_07.Name(), "test_flag_07");
+ EXPECT_EQ(FLAGS_test_flag_07.Help(), "test flag 07");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_07.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_08.Name(), "test_flag_08");
+ EXPECT_EQ(FLAGS_test_flag_08.Help(), "test flag 08");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_08.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_09.Name(), "test_flag_09");
+ EXPECT_EQ(FLAGS_test_flag_09.Help(), "test flag 09");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_09.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_10.Name(), "test_flag_10");
+ EXPECT_EQ(FLAGS_test_flag_10.Help(), "test flag 10");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_10.Filename(), expected_file_name));
+
+ EXPECT_EQ(FLAGS_test_flag_11.Name(), "test_flag_11");
+ EXPECT_EQ(FLAGS_test_flag_11.Help(), "test flag 11");
+ EXPECT_TRUE(
+ absl::EndsWith(FLAGS_test_flag_11.Filename(), expected_file_name));
+}
+#endif // !ABSL_FLAGS_STRIP_NAMES
+
+// --------------------------------------------------------------------
+
+TEST(FlagTest, TestDefault) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), true);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 1234);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), -34);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 189);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), 10765);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 40000);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -1234567);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 9876543);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), -9.876e-50, 1e-55);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), 1.234e12f, 1e5f);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "");
+}
+
+// --------------------------------------------------------------------
+
+TEST(FlagTest, TestGetSet) {
+ absl::SetFlag(&FLAGS_test_flag_01, false);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_01), false);
+
+ absl::SetFlag(&FLAGS_test_flag_02, 321);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_02), 321);
+
+ absl::SetFlag(&FLAGS_test_flag_03, 67);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_03), 67);
+
+ absl::SetFlag(&FLAGS_test_flag_04, 1);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_04), 1);
+
+ absl::SetFlag(&FLAGS_test_flag_05, -908);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_05), -908);
+
+ absl::SetFlag(&FLAGS_test_flag_06, 4001);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_06), 4001);
+
+ absl::SetFlag(&FLAGS_test_flag_07, -23456);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_07), -23456);
+
+ absl::SetFlag(&FLAGS_test_flag_08, 975310);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_08), 975310);
+
+ absl::SetFlag(&FLAGS_test_flag_09, 1.00001);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_09), 1.00001, 1e-10);
+
+ absl::SetFlag(&FLAGS_test_flag_10, -3.54f);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_test_flag_10), -3.54f, 1e-6f);
+
+ absl::SetFlag(&FLAGS_test_flag_11, "asdf");
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_11), "asdf");
+}
+
+// --------------------------------------------------------------------
+
+int GetDflt1() { return 1; }
+
+} // namespace
+
+ABSL_FLAG(int, test_flag_12, GetDflt1(), "test flag 12");
+ABSL_FLAG(std::string, test_flag_13, absl::StrCat("AAA", "BBB"),
+ "test flag 13");
+
+namespace {
+
+TEST(FlagTest, TestNonConstexprDefault) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_12), 1);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_13), "AAABBB");
+}
+
+// --------------------------------------------------------------------
+
+} // namespace
+
+ABSL_FLAG(bool, test_flag_14, true, absl::StrCat("test ", "flag ", "14"));
+
+namespace {
+
+#if !ABSL_FLAGS_STRIP_HELP
+TEST(FlagTest, TestNonConstexprHelp) {
+ EXPECT_EQ(FLAGS_test_flag_14.Help(), "test flag 14");
+}
+#endif //! ABSL_FLAGS_STRIP_HELP
+
+// --------------------------------------------------------------------
+
+int cb_test_value = -1;
+void TestFlagCB();
+
+} // namespace
+
+ABSL_FLAG(int, test_flag_with_cb, 100, "").OnUpdate(TestFlagCB);
+
+ABSL_FLAG(int, test_flag_with_lambda_cb, 200, "").OnUpdate([]() {
+ cb_test_value = absl::GetFlag(FLAGS_test_flag_with_lambda_cb) +
+ absl::GetFlag(FLAGS_test_flag_with_cb);
+});
+
+namespace {
+
+void TestFlagCB() { cb_test_value = absl::GetFlag(FLAGS_test_flag_with_cb); }
+
+// Tests side-effects of callback invocation.
+TEST(FlagTest, CallbackInvocation) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_cb), 100);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_with_lambda_cb), 200);
+ EXPECT_EQ(cb_test_value, 300);
+
+ absl::SetFlag(&FLAGS_test_flag_with_cb, 1);
+ EXPECT_EQ(cb_test_value, 1);
+
+ absl::SetFlag(&FLAGS_test_flag_with_lambda_cb, 3);
+ EXPECT_EQ(cb_test_value, 4);
+}
+
+// --------------------------------------------------------------------
+
+struct CustomUDT {
+ CustomUDT() : a(1), b(1) {}
+ CustomUDT(int a_, int b_) : a(a_), b(b_) {}
+
+ friend bool operator==(const CustomUDT& f1, const CustomUDT& f2) {
+ return f1.a == f2.a && f1.b == f2.b;
+ }
+
+ int a;
+ int b;
+};
+bool AbslParseFlag(absl::string_view in, CustomUDT* f, std::string*) {
+ std::vector<absl::string_view> parts =
+ absl::StrSplit(in, ':', absl::SkipWhitespace());
+
+ if (parts.size() != 2) return false;
+
+ if (!absl::SimpleAtoi(parts[0], &f->a)) return false;
+
+ if (!absl::SimpleAtoi(parts[1], &f->b)) return false;
+
+ return true;
+}
+std::string AbslUnparseFlag(const CustomUDT& f) {
+ return absl::StrCat(f.a, ":", f.b);
+}
+
+} // namespace
+
+ABSL_FLAG(CustomUDT, test_flag_15, CustomUDT(), "test flag 15");
+
+namespace {
+
+TEST(FlagTest, TestCustomUDT) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(1, 1));
+ absl::SetFlag(&FLAGS_test_flag_15, CustomUDT(2, 3));
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_15), CustomUDT(2, 3));
+}
+
+// MSVC produces link error on the type mismatch.
+// Linux does not have build errors and validations work as expected.
+#if 0 // !defined(_WIN32) && GTEST_HAS_DEATH_TEST
+
+TEST(Flagtest, TestTypeMismatchValidations) {
+ // For builtin types, GetFlag() only does validation in debug mode.
+ EXPECT_DEBUG_DEATH(
+ absl::GetFlag(FLAGS_mistyped_int_flag),
+ "Flag 'mistyped_int_flag' is defined as one type and declared "
+ "as another");
+ EXPECT_DEATH(absl::SetFlag(&FLAGS_mistyped_int_flag, 0),
+ "Flag 'mistyped_int_flag' is defined as one type and declared "
+ "as another");
+
+ EXPECT_DEATH(absl::GetFlag(FLAGS_mistyped_string_flag),
+ "Flag 'mistyped_string_flag' is defined as one type and "
+ "declared as another");
+ EXPECT_DEATH(
+ absl::SetFlag(&FLAGS_mistyped_string_flag, std::vector<std::string>{}),
+ "Flag 'mistyped_string_flag' is defined as one type and declared as "
+ "another");
+}
+
+#endif
+
+// --------------------------------------------------------------------
+
+// A contrived type that offers implicit and explicit conversion from specific
+// source types.
+struct ConversionTestVal {
+ ConversionTestVal() = default;
+ explicit ConversionTestVal(int a_in) : a(a_in) {}
+
+ enum class ViaImplicitConv { kTen = 10, kEleven };
+ // NOLINTNEXTLINE
+ ConversionTestVal(ViaImplicitConv from) : a(static_cast<int>(from)) {}
+
+ int a;
+};
+
+bool AbslParseFlag(absl::string_view in, ConversionTestVal* val_out,
+ std::string*) {
+ if (!absl::SimpleAtoi(in, &val_out->a)) {
+ return false;
+ }
+ return true;
+}
+std::string AbslUnparseFlag(const ConversionTestVal& val) {
+ return absl::StrCat(val.a);
+}
+
+} // namespace
+
+// Flag default values can be specified with a value that converts to the flag
+// value type implicitly.
+ABSL_FLAG(ConversionTestVal, test_flag_16,
+ ConversionTestVal::ViaImplicitConv::kTen, "test flag 16");
+
+namespace {
+
+TEST(FlagTest, CanSetViaImplicitConversion) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 10);
+ absl::SetFlag(&FLAGS_test_flag_16,
+ ConversionTestVal::ViaImplicitConv::kEleven);
+ EXPECT_EQ(absl::GetFlag(FLAGS_test_flag_16).a, 11);
+}
+
+// --------------------------------------------------------------------
+
+struct NonDfltConstructible {
+ public:
+ // This constructor tests that we can initialize the flag with int value
+ NonDfltConstructible(int i) : value(i) {} // NOLINT
+
+ // This constructor tests that we can't initialize the flag with char value
+ // but can with explicitly constructed NonDfltConstructible.
+ explicit NonDfltConstructible(char c) : value(100 + static_cast<int>(c)) {}
+
+ int value;
+};
+
+bool AbslParseFlag(absl::string_view in, NonDfltConstructible* ndc_out,
+ std::string*) {
+ return absl::SimpleAtoi(in, &ndc_out->value);
+}
+std::string AbslUnparseFlag(const NonDfltConstructible& ndc) {
+ return absl::StrCat(ndc.value);
+}
+
+} // namespace
+
+ABSL_FLAG(NonDfltConstructible, ndc_flag1, NonDfltConstructible('1'),
+ "Flag with non default constructible type");
+ABSL_FLAG(NonDfltConstructible, ndc_flag2, 0,
+ "Flag with non default constructible type");
+
+namespace {
+
+TEST(FlagTest, TestNonDefaultConstructibleType) {
+ EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, '1' + 100);
+ EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 0);
+
+ absl::SetFlag(&FLAGS_ndc_flag1, NonDfltConstructible('A'));
+ absl::SetFlag(&FLAGS_ndc_flag2, 25);
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag1).value, 'A' + 100);
+ EXPECT_EQ(absl::GetFlag(FLAGS_ndc_flag2).value, 25);
+}
+
+// --------------------------------------------------------------------
+
+} // namespace
+
+ABSL_RETIRED_FLAG(bool, old_bool_flag, true, "old descr");
+ABSL_RETIRED_FLAG(int, old_int_flag, (int)std::sqrt(10), "old descr");
+ABSL_RETIRED_FLAG(std::string, old_str_flag, "", absl::StrCat("old ", "descr"));
+
+namespace {
+
+TEST(FlagTest, TestRetiredFlagRegistration) {
+ bool is_bool = false;
+ EXPECT_TRUE(flags::IsRetiredFlag("old_bool_flag", &is_bool));
+ EXPECT_TRUE(is_bool);
+ EXPECT_TRUE(flags::IsRetiredFlag("old_int_flag", &is_bool));
+ EXPECT_FALSE(is_bool);
+ EXPECT_TRUE(flags::IsRetiredFlag("old_str_flag", &is_bool));
+ EXPECT_FALSE(is_bool);
+ EXPECT_FALSE(flags::IsRetiredFlag("some_other_flag", &is_bool));
+}
+
+} // namespace
diff --git a/absl/flags/flag_test_defs.cc b/absl/flags/flag_test_defs.cc
new file mode 100644
index 00000000..3366c580
--- /dev/null
+++ b/absl/flags/flag_test_defs.cc
@@ -0,0 +1,22 @@
+//
+// 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.
+
+// This file is used to test the mismatch of the flag type between definition
+// and declaration. These are definitions. flag_test.cc contains declarations.
+#include <string>
+#include "absl/flags/flag.h"
+
+ABSL_FLAG(int, mistyped_int_flag, 0, "");
+ABSL_FLAG(std::string, mistyped_string_flag, "", "");
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
new file mode 100644
index 00000000..f964165e
--- /dev/null
+++ b/absl/flags/internal/commandlineflag.cc
@@ -0,0 +1,496 @@
+//
+// 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.
+
+#include "absl/flags/internal/commandlineflag.h"
+
+#include <cassert>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/optimization.h"
+#include "absl/flags/config.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// The help message indicating that the commandline flag has been
+// 'stripped'. It will not show up when doing "-help" and its
+// variants. The flag is stripped if ABSL_FLAGS_STRIP_HELP is set to 1
+// before including absl/flags/flag.h
+
+// This is used by this file, and also in commandlineflags_reporting.cc
+const char kStrippedFlagHelp[] = "\001\002\003\004 (unknown) \004\003\002\001";
+
+namespace {
+
+// Currently we only validate flag values for user-defined flag types.
+bool ShouldValidateFlagValue(const CommandLineFlag& flag) {
+#define DONT_VALIDATE(T) \
+ if (flag.IsOfType<T>()) return false;
+ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(DONT_VALIDATE)
+ DONT_VALIDATE(std::string)
+ DONT_VALIDATE(std::vector<std::string>)
+#undef DONT_VALIDATE
+
+ return true;
+}
+
+} // namespace
+
+absl::Mutex* InitFlag(CommandLineFlag* flag) {
+ ABSL_CONST_INIT static absl::Mutex init_lock(absl::kConstInit);
+ absl::Mutex* mu;
+
+ {
+ absl::MutexLock lock(&init_lock);
+
+ if (flag->locks == nullptr) { // Must initialize Mutexes for this flag.
+ flag->locks = new flags_internal::CommandLineFlagLocks;
+ }
+
+ mu = &flag->locks->primary_mu;
+ }
+
+ {
+ absl::MutexLock lock(mu);
+
+ if (!flag->retired && flag->def == nullptr) {
+ // Need to initialize def and cur fields.
+ flag->def = (*flag->make_init_value)();
+ flag->cur = Clone(flag->op, flag->def);
+ UpdateCopy(flag);
+ flag->inited.store(true, std::memory_order_release);
+ flag->InvokeCallback();
+ }
+ }
+
+ flag->inited.store(true, std::memory_order_release);
+ return mu;
+}
+
+// Ensure that the lazily initialized fields of *flag have been initialized,
+// and return &flag->locks->primary_mu.
+absl::Mutex* CommandLineFlag::InitFlagIfNecessary() const
+ LOCK_RETURNED(locks->primary_mu) {
+ if (!this->inited.load(std::memory_order_acquire)) {
+ return InitFlag(const_cast<CommandLineFlag*>(this));
+ }
+
+ // All fields initialized; this->locks is therefore safe to read.
+ return &this->locks->primary_mu;
+}
+
+void CommandLineFlag::Destroy() const {
+ // Values are heap allocated for retired and Abseil Flags.
+ if (IsRetired() || IsAbseilFlag()) {
+ if (this->cur) Delete(this->op, this->cur);
+ if (this->def) Delete(this->op, this->def);
+ }
+
+ delete this->locks;
+}
+
+bool CommandLineFlag::IsModified() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+ return modified;
+}
+
+void CommandLineFlag::SetModified(bool is_modified) {
+ absl::MutexLock l(InitFlagIfNecessary());
+ modified = is_modified;
+}
+
+bool CommandLineFlag::IsSpecifiedOnCommandLine() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+ return on_command_line;
+}
+
+absl::string_view CommandLineFlag::Typename() const {
+ // We do not store/report type in Abseil Flags, so that user do not rely on in
+ // at runtime
+ if (IsAbseilFlag() || IsRetired()) return "";
+
+#define HANDLE_V1_BUILTIN_TYPE(t) \
+ if (IsOfType<t>()) { \
+ return #t; \
+ }
+
+ HANDLE_V1_BUILTIN_TYPE(bool);
+ HANDLE_V1_BUILTIN_TYPE(int32_t);
+ HANDLE_V1_BUILTIN_TYPE(int64_t);
+ HANDLE_V1_BUILTIN_TYPE(uint64_t);
+ HANDLE_V1_BUILTIN_TYPE(double);
+#undef HANDLE_V1_BUILTIN_TYPE
+
+ if (IsOfType<std::string>()) {
+ return "string";
+ }
+
+ return "";
+}
+
+std::string CommandLineFlag::Filename() const {
+ return flags_internal::GetUsageConfig().normalize_filename(this->filename);
+}
+
+std::string CommandLineFlag::DefaultValue() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ return Unparse(this->marshalling_op, this->def);
+}
+
+std::string CommandLineFlag::CurrentValue() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ return Unparse(this->marshalling_op, this->cur);
+}
+
+bool CommandLineFlag::HasValidatorFn() const {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ return this->validator != nullptr;
+}
+
+bool CommandLineFlag::SetValidatorFn(FlagValidator fn) {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ // ok to register the same function over and over again
+ if (fn == this->validator) return true;
+
+ // Can't set validator to a different function, unless reset first.
+ if (fn != nullptr && this->validator != nullptr) {
+ ABSL_INTERNAL_LOG(
+ WARNING, absl::StrCat("Ignoring SetValidatorFn() for flag '", Name(),
+ "': validate-fn already registered"));
+
+ return false;
+ }
+
+ this->validator = fn;
+ return true;
+}
+
+bool CommandLineFlag::InvokeValidator(const void* value) const
+ EXCLUSIVE_LOCKS_REQUIRED(this->locks->primary_mu) {
+ if (!this->validator) {
+ return true;
+ }
+
+ (void)value;
+
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ absl::StrCat("Flag '", Name(),
+ "' of encapsulated type should not have a validator"));
+
+ return false;
+}
+
+void CommandLineFlag::SetCallback(
+ const flags_internal::FlagCallback mutation_callback) {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ callback = mutation_callback;
+
+ InvokeCallback();
+}
+
+// If the flag has a mutation callback this function invokes it. While the
+// callback is being invoked the primary flag's mutex is unlocked and it is
+// re-locked back after call to callback is completed. Callback invocation is
+// guarded by flag's secondary mutex instead which prevents concurrent callback
+// invocation. Note that it is possible for other thread to grab the primary
+// lock and update flag's value at any time during the callback invocation.
+// This is by design. Callback can get a value of the flag if necessary, but it
+// might be different from the value initiated the callback and it also can be
+// different by the time the callback invocation is completed.
+// Requires that *primary_lock be held in exclusive mode; it may be released
+// and reacquired by the implementation.
+void CommandLineFlag::InvokeCallback()
+ EXCLUSIVE_LOCKS_REQUIRED(this->locks->primary_mu) {
+ if (!this->callback) return;
+
+ // The callback lock is guaranteed initialized, because *locks->primary_mu
+ // exists.
+ absl::Mutex* callback_mu = &this->locks->callback_mu;
+
+ // When executing the callback we need the primary flag's mutex to be unlocked
+ // so that callback can retrieve the flag's value.
+ this->locks->primary_mu.Unlock();
+
+ {
+ absl::MutexLock lock(callback_mu);
+ this->callback();
+ }
+
+ this->locks->primary_mu.Lock();
+}
+
+// Attempts to parse supplied `value` string using parsing routine in the `flag`
+// argument. If parsing is successful, it will try to validate that the parsed
+// value is valid for the specified 'flag'. Finally this function stores the
+// parsed value in 'dst' assuming it is a pointer to the flag's value type. In
+// case if any error is encountered in either step, the error message is stored
+// in 'err'
+bool TryParseLocked(CommandLineFlag* flag, void* dst, absl::string_view value,
+ std::string* err)
+ EXCLUSIVE_LOCKS_REQUIRED(flag->locks->primary_mu) {
+ void* tentative_value = Clone(flag->op, flag->def);
+ std::string parse_err;
+ if (!Parse(flag->marshalling_op, value, tentative_value, &parse_err)) {
+ auto type_name = flag->Typename();
+ absl::string_view err_sep = parse_err.empty() ? "" : "; ";
+ absl::string_view typename_sep = type_name.empty() ? "" : " ";
+ *err = absl::StrCat("Illegal value '", value, "' specified for",
+ typename_sep, type_name, " flag '", flag->Name(), "'",
+ err_sep, parse_err);
+ Delete(flag->op, tentative_value);
+ return false;
+ }
+
+ if (!flag->InvokeValidator(tentative_value)) {
+ *err = absl::StrCat("Failed validation of new value '",
+ Unparse(flag->marshalling_op, tentative_value),
+ "' for flag '", flag->Name(), "'");
+ Delete(flag->op, tentative_value);
+ return false;
+ }
+
+ flag->counter++;
+ Copy(flag->op, tentative_value, dst);
+ Delete(flag->op, tentative_value);
+ return true;
+}
+
+// Sets the value of the flag based on specified string `value`. If the flag
+// was successfully set to new value, it returns true. Otherwise, sets `err`
+// to indicate the error, leaves the flag unchanged, and returns false. There
+// are three ways to set the flag's value:
+// * Update the current flag value
+// * Update the flag's default value
+// * Update the current flag value if it was never set before
+// The mode is selected based on 'set_mode' parameter.
+bool CommandLineFlag::SetFromString(absl::string_view value,
+ FlagSettingMode set_mode,
+ ValueSource source, std::string* err) {
+ if (IsRetired()) return false;
+
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ // Direct-access flags can be modified without going through the
+ // flag API. Detect such changes and update the flag->modified bit.
+ if (!IsAbseilFlag()) {
+ if (!this->modified && ChangedDirectly(this, this->cur, this->def)) {
+ this->modified = true;
+ }
+ }
+
+ switch (set_mode) {
+ case SET_FLAGS_VALUE: {
+ // set or modify the flag's value
+ if (!TryParseLocked(this, this->cur, value, err)) return false;
+ this->modified = true;
+ UpdateCopy(this);
+ InvokeCallback();
+
+ if (source == kCommandLine) {
+ this->on_command_line = true;
+ }
+ break;
+ }
+ case SET_FLAG_IF_DEFAULT: {
+ // set the flag's value, but only if it hasn't been set by someone else
+ if (!this->modified) {
+ if (!TryParseLocked(this, this->cur, value, err)) return false;
+ this->modified = true;
+ UpdateCopy(this);
+ InvokeCallback();
+ } else {
+ // TODO(rogeeff): review and fix this semantic. Currently we do not fail
+ // in this case if flag is modified. This is misleading since the flag's
+ // value is not updated even though we return true.
+ // *err = absl::StrCat(this->Name(), " is already set to ",
+ // CurrentValue(), "\n");
+ // return false;
+ return true;
+ }
+ break;
+ }
+ case SET_FLAGS_DEFAULT: {
+ // modify the flag's default-value
+ if (!TryParseLocked(this, this->def, value, err)) return false;
+
+ if (!this->modified) {
+ // Need to set both defvalue *and* current, in this case
+ Copy(this->op, this->def, this->cur);
+ UpdateCopy(this);
+ InvokeCallback();
+ }
+ break;
+ }
+ default: {
+ // unknown set_mode
+ assert(false);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void CommandLineFlag::StoreAtomic(size_t size) {
+ int64_t t = 0;
+ assert(size <= sizeof(int64_t));
+ memcpy(&t, this->cur, size);
+ this->atomic.store(t, std::memory_order_release);
+}
+
+void CommandLineFlag::CheckDefaultValueParsingRoundtrip() const {
+ std::string v = DefaultValue();
+
+ absl::MutexLock lock(InitFlagIfNecessary());
+
+ void* dst = Clone(this->op, this->def);
+ std::string error;
+ if (!flags_internal::Parse(this->marshalling_op, v, dst, &error)) {
+ ABSL_INTERNAL_LOG(
+ FATAL,
+ absl::StrCat("Flag ", Name(), " (from ", Filename(),
+ "): std::string form of default value '", v,
+ "' could not be parsed; error=", error));
+ }
+
+ // We do not compare dst to def since parsing/unparsing may make
+ // small changes, e.g., precision loss for floating point types.
+ Delete(this->op, dst);
+}
+
+bool CommandLineFlag::ValidateDefaultValue() const {
+ absl::MutexLock lock(InitFlagIfNecessary());
+ return InvokeValidator(this->def);
+}
+
+bool CommandLineFlag::ValidateInputValue(absl::string_view value) const {
+ absl::MutexLock l(InitFlagIfNecessary()); // protect default value access
+
+ void* obj = Clone(this->op, this->def);
+ std::string ignored_error;
+ const bool result =
+ flags_internal::Parse(this->marshalling_op, value, obj, &ignored_error) &&
+ InvokeValidator(obj);
+ Delete(this->op, obj);
+ return result;
+}
+
+const int64_t CommandLineFlag::kAtomicInit;
+
+void CommandLineFlag::Read(void* dst,
+ const flags_internal::FlagOpFn dst_op) const {
+ absl::ReaderMutexLock l(InitFlagIfNecessary());
+
+ // `dst_op` is the unmarshaling operation corresponding to the declaration
+ // visibile at the call site. `op` is the Flag's defined unmarshalling
+ // operation. They must match for this operation to be well-defined.
+ if (ABSL_PREDICT_FALSE(dst_op != op)) {
+ ABSL_INTERNAL_LOG(
+ ERROR,
+ absl::StrCat("Flag '", name,
+ "' is defined as one type and declared as another"));
+ }
+ CopyConstruct(op, cur, dst);
+}
+
+void CommandLineFlag::Write(const void* src,
+ const flags_internal::FlagOpFn src_op) {
+ absl::MutexLock l(InitFlagIfNecessary());
+
+ // `src_op` is the marshalling operation corresponding to the declaration
+ // visible at the call site. `op` is the Flag's defined marshalling operation.
+ // They must match for this operation to be well-defined.
+ if (ABSL_PREDICT_FALSE(src_op != op)) {
+ ABSL_INTERNAL_LOG(
+ ERROR,
+ absl::StrCat("Flag '", name,
+ "' is defined as one type and declared as another"));
+ }
+
+ if (ShouldValidateFlagValue(*this)) {
+ void* obj = Clone(op, src);
+ std::string ignored_error;
+ std::string src_as_str = Unparse(marshalling_op, src);
+ if (!Parse(marshalling_op, src_as_str, obj, &ignored_error) ||
+ !InvokeValidator(obj)) {
+ ABSL_INTERNAL_LOG(ERROR, absl::StrCat("Attempt to set flag '", name,
+ "' to invalid value ", src_as_str));
+ }
+ Delete(op, obj);
+ }
+
+ modified = true;
+ counter++;
+ Copy(op, src, cur);
+
+ UpdateCopy(this);
+ InvokeCallback();
+}
+
+std::string HelpText::GetHelpText() const {
+ if (help_function_) return help_function_();
+ if (help_message_) return help_message_;
+
+ return {};
+}
+
+// Update any copy of the flag value that is stored in an atomic word.
+// In addition if flag has a mutation callback this function invokes it.
+void UpdateCopy(CommandLineFlag* flag) {
+#define STORE_ATOMIC(T) \
+ else if (flag->IsOfType<T>()) { \
+ flag->StoreAtomic(sizeof(T)); \
+ }
+
+ if (false) {
+ }
+ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(STORE_ATOMIC)
+#undef STORE_ATOMIC
+}
+
+// Return true iff flag value was changed via direct-access.
+bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b) {
+ if (!flag->IsAbseilFlag()) {
+// Need to compare values for direct-access flags.
+#define CHANGED_FOR_TYPE(T) \
+ if (flag->IsOfType<T>()) { \
+ return *reinterpret_cast<const T*>(a) != *reinterpret_cast<const T*>(b); \
+ }
+
+ CHANGED_FOR_TYPE(bool);
+ CHANGED_FOR_TYPE(int32_t);
+ CHANGED_FOR_TYPE(int64_t);
+ CHANGED_FOR_TYPE(uint64_t);
+ CHANGED_FOR_TYPE(double);
+ CHANGED_FOR_TYPE(std::string);
+#undef CHANGED_FOR_TYPE
+ }
+
+ return false;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
new file mode 100644
index 00000000..382553d2
--- /dev/null
+++ b/absl/flags/internal/commandlineflag.h
@@ -0,0 +1,385 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
+#define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
+
+#include <atomic>
+
+#include "absl/base/macros.h"
+#include "absl/flags/marshalling.h"
+#include "absl/synchronization/mutex.h"
+#include "absl/types/optional.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// Type-specific operations, eg., parsing, copying, etc. are provided
+// by function specific to that type with a signature matching FlagOpFn.
+enum FlagOp {
+ kDelete,
+ kClone,
+ kCopy,
+ kCopyConstruct,
+ kSizeof,
+ kParse,
+ kUnparse
+};
+using FlagOpFn = void* (*)(FlagOp, const void*, void*);
+using FlagMarshallingOpFn = void* (*)(FlagOp, const void*, void*, void*);
+
+// Options that control SetCommandLineOptionWithMode.
+enum FlagSettingMode {
+ // update the flag's value unconditionally (can call this multiple times).
+ SET_FLAGS_VALUE,
+ // update the flag's value, but *only if* it has not yet been updated
+ // with SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef".
+ SET_FLAG_IF_DEFAULT,
+ // set the flag's default value to this. If the flag has not been updated
+ // yet (via SET_FLAGS_VALUE, SET_FLAG_IF_DEFAULT, or "FLAGS_xxx = nondef")
+ // change the flag's current value to the new default value as well.
+ SET_FLAGS_DEFAULT
+};
+
+// Options that control SetFromString: Source of a value.
+enum ValueSource {
+ // Flag is being set by value specified on a command line.
+ kCommandLine,
+ // Flag is being set by value specified in the code.
+ kProgrammaticChange,
+};
+
+// Signature for the help generation function used as an argument for the
+// absl::Flag constructor.
+using HelpGenFunc = std::string (*)();
+
+// Signature for the function generating the initial flag value based (usually
+// based on default value supplied in flag's definition)
+using InitialValGenFunc = void* (*)();
+
+struct CommandLineFlagInfo;
+
+// Signature for the mutation callback used by watched Flags
+// The callback is noexcept.
+// TODO(rogeeff): add noexcept after C++17 support is added.
+using FlagCallback = void (*)();
+
+using FlagValidator = bool (*)();
+
+extern const char kStrippedFlagHelp[];
+
+// The per-type function
+template <typename T>
+void* FlagOps(FlagOp op, const void* v1, void* v2) {
+ switch (op) {
+ case kDelete:
+ delete static_cast<const T*>(v1);
+ return nullptr;
+ case kClone:
+ return new T(*static_cast<const T*>(v1));
+ case kCopy:
+ *static_cast<T*>(v2) = *static_cast<const T*>(v1);
+ return nullptr;
+ case kCopyConstruct:
+ new (v2) T(*static_cast<const T*>(v1));
+ return nullptr;
+ case kSizeof:
+ return reinterpret_cast<void*>(sizeof(T));
+ default:
+ return nullptr;
+ }
+}
+
+template <typename T>
+void* FlagMarshallingOps(FlagOp op, const void* v1, void* v2, void* v3) {
+ switch (op) {
+ case kParse: {
+ // initialize the temporary instance of type T based on current value in
+ // destination (which is going to be flag's default value).
+ T temp(*static_cast<T*>(v2));
+ if (!absl::ParseFlag<T>(*static_cast<const absl::string_view*>(v1), &temp,
+ static_cast<std::string*>(v3))) {
+ return nullptr;
+ }
+ *static_cast<T*>(v2) = std::move(temp);
+ return v2;
+ }
+ case kUnparse:
+ *static_cast<std::string*>(v2) =
+ absl::UnparseFlag<T>(*static_cast<const T*>(v1));
+ return nullptr;
+ default:
+ return nullptr;
+ }
+}
+
+// Functions that invoke flag-type-specific operations.
+inline void Delete(FlagOpFn op, const void* obj) {
+ op(flags_internal::kDelete, obj, nullptr);
+}
+
+inline void* Clone(FlagOpFn op, const void* obj) {
+ return op(flags_internal::kClone, obj, nullptr);
+}
+
+inline void Copy(FlagOpFn op, const void* src, void* dst) {
+ op(flags_internal::kCopy, src, dst);
+}
+
+inline void CopyConstruct(FlagOpFn op, const void* src, void* dst) {
+ op(flags_internal::kCopyConstruct, src, dst);
+}
+
+inline bool Parse(FlagMarshallingOpFn op, absl::string_view text, void* dst,
+ std::string* error) {
+ return op(flags_internal::kParse, &text, dst, error) != nullptr;
+}
+
+inline std::string Unparse(FlagMarshallingOpFn op, const void* val) {
+ std::string result;
+ op(flags_internal::kUnparse, val, &result, nullptr);
+ return result;
+}
+
+inline size_t Sizeof(FlagOpFn op) {
+ // This sequence of casts reverses the sequence from base::internal::FlagOps()
+ return static_cast<size_t>(reinterpret_cast<intptr_t>(
+ op(flags_internal::kSizeof, nullptr, nullptr)));
+}
+
+// The following struct contains the locks in a CommandLineFlag struct.
+// They are in a separate struct that is lazily allocated to avoid problems
+// with static initialization and to avoid multiple allocations.
+struct CommandLineFlagLocks {
+ absl::Mutex primary_mu; // protects several fields in CommandLineFlag
+ absl::Mutex callback_mu; // used to serialize callbacks
+};
+
+// Holds either a pointer to help text or a function which produces it. This is
+// needed for supporting both static initialization of Flags while supporting
+// the legacy registration framework. We can't use absl::variant<const char*,
+// const char*(*)()> since anybody passing 0 or nullptr in to a CommandLineFlag
+// would find an ambiguity.
+class HelpText {
+ public:
+ static constexpr HelpText FromFunctionPointer(const HelpGenFunc fn) {
+ return HelpText(fn, nullptr);
+ }
+ static constexpr HelpText FromStaticCString(const char* msg) {
+ return HelpText(nullptr, msg);
+ }
+
+ std::string GetHelpText() const;
+
+ HelpText() = delete;
+ HelpText(const HelpText&) = default;
+ HelpText(HelpText&&) = default;
+
+ private:
+ explicit constexpr HelpText(const HelpGenFunc fn, const char* msg)
+ : help_function_(fn), help_message_(msg) {}
+
+ HelpGenFunc help_function_;
+ const char* help_message_;
+};
+
+// Holds all information for a flag.
+struct CommandLineFlag {
+ constexpr CommandLineFlag(
+ const char* name_arg, HelpText help_text, const char* filename_arg,
+ const flags_internal::FlagOpFn op_arg,
+ const flags_internal::FlagMarshallingOpFn marshalling_op_arg,
+ const flags_internal::InitialValGenFunc initial_value_gen,
+ const bool retired_arg, void* def_arg, void* cur_arg)
+ : name(name_arg),
+ help(help_text),
+ filename(filename_arg),
+ op(op_arg),
+ marshalling_op(marshalling_op_arg),
+ make_init_value(initial_value_gen),
+ retired(retired_arg),
+ inited(false),
+ modified(false),
+ on_command_line(false),
+ validator(nullptr),
+ callback(nullptr),
+ def(def_arg),
+ cur(cur_arg),
+ counter(0),
+ atomic(kAtomicInit),
+ locks(nullptr) {}
+
+ // Revert the init routine.
+ void Destroy() const;
+
+ // Not copyable/assignable.
+ CommandLineFlag(const CommandLineFlag&) = delete;
+ CommandLineFlag& operator=(const CommandLineFlag&) = delete;
+
+ absl::string_view Name() const { return name; }
+ std::string Help() const { return help.GetHelpText(); }
+ bool IsRetired() const { return this->retired; }
+ bool IsModified() const;
+ void SetModified(bool is_modified);
+ bool IsSpecifiedOnCommandLine() const;
+ // Returns true iff this is a handle to an Abseil Flag.
+ bool IsAbseilFlag() const {
+ // Set to null for V1 flags
+ return this->make_init_value != nullptr;
+ }
+
+ absl::string_view Typename() const;
+ std::string Filename() const;
+ std::string DefaultValue() const;
+ std::string CurrentValue() const;
+
+ bool HasValidatorFn() const;
+ bool SetValidatorFn(FlagValidator fn);
+ bool InvokeValidator(const void* value) const;
+
+ // Return true iff flag has type T.
+ template <typename T>
+ inline bool IsOfType() const {
+ return this->op == &flags_internal::FlagOps<T>;
+ }
+
+ // Attempts to retrieve the flag value. Returns value on success,
+ // absl::nullopt otherwise.
+ template <typename T>
+ absl::optional<T> Get() const {
+ if (IsRetired() || flags_internal::FlagOps<T> != this->op)
+ return absl::nullopt;
+
+ T res;
+ Read(&res, flags_internal::FlagOps<T>);
+
+ return res;
+ }
+
+ void SetCallback(const flags_internal::FlagCallback mutation_callback);
+ void InvokeCallback();
+
+ // Sets the value of the flag based on specified std::string `value`. If the flag
+ // was successfully set to new value, it returns true. Otherwise, sets `error`
+ // to indicate the error, leaves the flag unchanged, and returns false. There
+ // are three ways to set the flag's value:
+ // * Update the current flag value
+ // * Update the flag's default value
+ // * Update the current flag value if it was never set before
+ // The mode is selected based on `set_mode` parameter.
+ bool SetFromString(absl::string_view value,
+ flags_internal::FlagSettingMode set_mode,
+ flags_internal::ValueSource source, std::string* error);
+
+ void StoreAtomic(size_t size);
+
+ void CheckDefaultValueParsingRoundtrip() const;
+ // Invoke the flag validators for old flags.
+ // TODO(rogeeff): implement proper validators for Abseil Flags
+ bool ValidateDefaultValue() const;
+ bool ValidateInputValue(absl::string_view value) const;
+
+ // Constant configuration for a particular flag.
+ private:
+ const char* const name;
+ const HelpText help;
+ const char* const filename;
+
+ protected:
+ const FlagOpFn op; // Type-specific handler
+ const FlagMarshallingOpFn marshalling_op; // Marshalling ops handler
+ const InitialValGenFunc make_init_value; // Makes initial value for the flag
+ const bool retired; // Is the flag retired?
+ std::atomic<bool> inited; // fields have been lazily initialized
+
+ // Mutable state (guarded by locks->primary_mu).
+ bool modified; // Has flag value been modified?
+ bool on_command_line; // Specified on command line.
+ FlagValidator validator; // Validator function, or nullptr
+ FlagCallback callback; // Mutation callback, or nullptr
+ void* def; // Lazily initialized pointer to default value
+ void* cur; // Lazily initialized pointer to current value
+ int64_t counter; // Mutation counter
+
+ // For some types, a copy of the current value is kept in an atomically
+ // accessible field.
+ static const int64_t kAtomicInit = 0xababababababababll;
+ std::atomic<int64_t> atomic;
+
+ // Lazily initialized mutexes for this flag value. We cannot inline a
+ // SpinLock or Mutex here because those have non-constexpr constructors and
+ // so would prevent constant initialization of this type.
+ // TODO(rogeeff): fix it once Mutex has constexpr constructor
+ struct CommandLineFlagLocks* locks; // locks, laziliy allocated.
+
+ // Ensure that the lazily initialized fields of *flag have been initialized,
+ // and return the lock which should be locked when flag's state is mutated.
+ absl::Mutex* InitFlagIfNecessary() const;
+
+ // copy construct new value of flag's type in a memory referenced by dst
+ // based on current flag's value
+ void Read(void* dst, const flags_internal::FlagOpFn dst_op) const;
+ // updates flag's value to *src (locked)
+ void Write(const void* src, const flags_internal::FlagOpFn src_op);
+
+ friend class FlagRegistry;
+ friend class FlagPtrMap;
+ friend class FlagSaverImpl;
+ friend void FillCommandLineFlagInfo(CommandLineFlag* flag,
+ CommandLineFlagInfo* result);
+ friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
+ absl::string_view value, std::string* err);
+ friend absl::Mutex* InitFlag(CommandLineFlag* flag);
+};
+
+// Update any copy of the flag value that is stored in an atomic word.
+// In addition if flag has a mutation callback this function invokes it. While
+// callback is being invoked the primary flag's mutex is unlocked and it is
+// re-locked back after call to callback is completed. Callback invocation is
+// guarded by flag's secondary mutex instead which prevents concurrent callback
+// invocation. Note that it is possible for other thread to grab the primary
+// lock and update flag's value at any time during the callback invocation.
+// This is by design. Callback can get a value of the flag if necessary, but it
+// might be different from the value initiated the callback and it also can be
+// different by the time the callback invocation is completed.
+// Requires that *primary_lock be held in exclusive mode; it may be released
+// and reacquired by the implementation.
+void UpdateCopy(CommandLineFlag* flag);
+// Return true iff flag value was changed via direct-access.
+bool ChangedDirectly(CommandLineFlag* flag, const void* a, const void* b);
+
+// This macro is the "source of truth" for the list of supported flag types we
+// expect to perform lock free operations on. Specifically it generates code,
+// a one argument macro operating on a type, supplied as a macro argument, for
+// each type in the list.
+#define ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(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(double) \
+ A(float)
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
diff --git a/absl/flags/internal/commandlineflag_test.cc b/absl/flags/internal/commandlineflag_test.cc
new file mode 100644
index 00000000..f0d57adb
--- /dev/null
+++ b/absl/flags/internal/commandlineflag_test.cc
@@ -0,0 +1,196 @@
+//
+// 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.
+
+#include "absl/flags/internal/commandlineflag.h"
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
+
+ABSL_FLAG(int, int_flag, 201, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt",
+ absl::StrCat("string_flag", " help"));
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class CommandLineFlagTest : public testing::Test {
+ protected:
+ void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
+ void TearDown() override { flag_saver_.reset(); }
+
+ private:
+ std::unique_ptr<flags::FlagSaver> flag_saver_;
+};
+
+TEST_F(CommandLineFlagTest, TestAttributesAccessMethods) {
+ auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+
+ ASSERT_TRUE(flag_01);
+ EXPECT_EQ(flag_01->Name(), "int_flag");
+ EXPECT_EQ(flag_01->Help(), "int_flag help");
+ EXPECT_EQ(flag_01->Typename(), "");
+ EXPECT_TRUE(!flag_01->IsRetired());
+ EXPECT_TRUE(flag_01->IsOfType<int>());
+ EXPECT_TRUE(absl::EndsWith(
+ flag_01->Filename(),
+ "absl/flags/internal/commandlineflag_test.cc"));
+
+ auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+
+ ASSERT_TRUE(flag_02);
+ EXPECT_EQ(flag_02->Name(), "string_flag");
+ EXPECT_EQ(flag_02->Help(), "string_flag help");
+ EXPECT_EQ(flag_02->Typename(), "");
+ EXPECT_TRUE(!flag_02->IsRetired());
+ EXPECT_TRUE(flag_02->IsOfType<std::string>());
+ EXPECT_TRUE(absl::EndsWith(
+ flag_02->Filename(),
+ "absl/flags/internal/commandlineflag_test.cc"));
+
+ auto* flag_03 = flags::FindRetiredFlag("bool_retired_flag");
+
+ ASSERT_TRUE(flag_03);
+ EXPECT_EQ(flag_03->Name(), "bool_retired_flag");
+ EXPECT_EQ(flag_03->Help(), "");
+ EXPECT_EQ(flag_03->Typename(), "");
+ EXPECT_TRUE(flag_03->IsRetired());
+ EXPECT_TRUE(flag_03->IsOfType<bool>());
+ EXPECT_EQ(flag_03->Filename(), "RETIRED");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestValueAccessMethods) {
+ absl::SetFlag(&FLAGS_int_flag, 301);
+ auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+
+ ASSERT_TRUE(flag_01);
+ EXPECT_EQ(flag_01->CurrentValue(), "301");
+ EXPECT_EQ(flag_01->DefaultValue(), "201");
+
+ absl::SetFlag(&FLAGS_string_flag, "new_str_value");
+ auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+
+ ASSERT_TRUE(flag_02);
+ EXPECT_EQ(flag_02->CurrentValue(), "new_str_value");
+ EXPECT_EQ(flag_02->DefaultValue(), "dflt");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestSetFromStringCurrentValue) {
+ std::string err;
+
+ auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(flag_01->SetFromString("11", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(flag_01->SetFromString("-123", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(!flag_01->SetFromString("xyz", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_EQ(err, "Illegal value 'xyz' specified for flag 'int_flag'");
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(!flag_01->SetFromString("A1", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), -123);
+ EXPECT_EQ(err, "Illegal value 'A1' specified for flag 'int_flag'");
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(flag_01->SetFromString("0x10", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 16);
+ EXPECT_FALSE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(flag_01->SetFromString("011", flags::SET_FLAGS_VALUE,
+ flags::kCommandLine, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 11);
+ EXPECT_TRUE(flag_01->IsSpecifiedOnCommandLine());
+
+ EXPECT_TRUE(!flag_01->SetFromString("", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(err, "Illegal value '' specified for flag 'int_flag'");
+
+ auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+ EXPECT_TRUE(flag_02->SetFromString("xyz", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "xyz");
+
+ EXPECT_TRUE(flag_02->SetFromString("", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestSetFromStringDefaultValue) {
+ std::string err;
+
+ auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+
+ EXPECT_TRUE(flag_01->SetFromString("111", flags::SET_FLAGS_DEFAULT,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(flag_01->DefaultValue(), "111");
+
+ auto* flag_02 = flags::FindCommandLineFlag("string_flag");
+
+ EXPECT_TRUE(flag_02->SetFromString("abc", flags::SET_FLAGS_DEFAULT,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(flag_02->DefaultValue(), "abc");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(CommandLineFlagTest, TestSetFromStringIfDefault) {
+ std::string err;
+
+ auto* flag_01 = flags::FindCommandLineFlag("int_flag");
+
+ EXPECT_TRUE(flag_01->SetFromString("22", flags::SET_FLAG_IF_DEFAULT,
+ flags::kProgrammaticChange, &err))
+ << err;
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+
+ EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 22);
+ // EXPECT_EQ(err, "ERROR: int_flag is already set to 22");
+
+ // Reset back to default value
+ EXPECT_TRUE(flag_01->SetFromString("201", flags::SET_FLAGS_VALUE,
+ flags::kProgrammaticChange, &err));
+
+ EXPECT_TRUE(flag_01->SetFromString("33", flags::SET_FLAG_IF_DEFAULT,
+ flags::kProgrammaticChange, &err));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 201);
+ // EXPECT_EQ(err, "ERROR: int_flag is already set to 201");
+}
+
+} // namespace
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
new file mode 100644
index 00000000..9a5d9b4b
--- /dev/null
+++ b/absl/flags/internal/flag.h
@@ -0,0 +1,123 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_FLAG_H_
+#define ABSL_FLAGS_INTERNAL_FLAG_H_
+
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/registry.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// This is "unspecified" implementation of absl::Flag<T> type.
+template <typename T>
+class Flag : public flags_internal::CommandLineFlag {
+ public:
+ constexpr Flag(const char* name, const flags_internal::HelpGenFunc help_gen,
+ const char* filename,
+ const flags_internal::FlagMarshallingOpFn marshalling_op_arg,
+ const flags_internal::InitialValGenFunc initial_value_gen)
+ : flags_internal::CommandLineFlag(
+ name, flags_internal::HelpText::FromFunctionPointer(help_gen),
+ filename, &flags_internal::FlagOps<T>, marshalling_op_arg,
+ initial_value_gen,
+ /*retired_arg=*/false, /*def_arg=*/nullptr,
+ /*cur_arg=*/nullptr) {}
+
+ T Get() const {
+ // Implementation notes:
+ //
+ // We are wrapping a union around the value of `T` to serve three purposes:
+ //
+ // 1. `U.value` has correct size and alignment for a value of type `T`
+ // 2. The `U.value` constructor is not invoked since U's constructor does
+ // not
+ // do it explicitly.
+ // 3. The `U.value` destructor is invoked since U's destructor does it
+ // explicitly. This makes `U` a kind of RAII wrapper around non default
+ // constructible value of T, which is destructed when we leave the
+ // scope. We do need to destroy U.value, which is constructed by
+ // CommandLineFlag::Read even though we left it in a moved-from state
+ // after std::move.
+ //
+ // All of this serves to avoid requiring `T` being default constructible.
+ union U {
+ T value;
+ U() {}
+ ~U() { value.~T(); }
+ };
+ U u;
+
+ this->Read(&u.value, &flags_internal::FlagOps<T>);
+ return std::move(u.value);
+ }
+
+ bool AtomicGet(T* v) const {
+ const int64_t r = this->atomic.load(std::memory_order_acquire);
+ if (r != flags_internal::CommandLineFlag::kAtomicInit) {
+ memcpy(v, &r, sizeof(T));
+ return true;
+ }
+
+ return false;
+ }
+
+ void Set(const T& v) { this->Write(&v, &flags_internal::FlagOps<T>); }
+};
+
+// This class facilitates Flag object registration and tail expression-based
+// flag definition, for example:
+// ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
+template <typename T, bool do_register>
+class FlagRegistrar {
+ public:
+ explicit FlagRegistrar(Flag<T>* flag) : flag_(flag) {
+ if (do_register) flags_internal::RegisterCommandLineFlag(flag_);
+ }
+
+ FlagRegistrar& OnUpdate(flags_internal::FlagCallback cb) && {
+ flag_->SetCallback(cb);
+ return *this;
+ }
+
+ // Make the registrar "die" gracefully as a bool on a line where registration
+ // happens. Registrar objects are intended to live only as temporary.
+ operator bool() const { return true; } // NOLINT
+
+ private:
+ Flag<T>* flag_; // Flag being registered (not owned).
+};
+
+// This struct and corresponding overload to MakeDefaultValue are used to
+// facilitate usage of {} as default value in ABSL_FLAG macro.
+struct EmptyBraces {};
+
+template <typename T>
+T* MakeFromDefaultValue(T t) {
+ return new T(std::move(t));
+}
+
+template <typename T>
+T* MakeFromDefaultValue(EmptyBraces) {
+ return new T;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_FLAG_H_
diff --git a/absl/flags/internal/parse.h b/absl/flags/internal/parse.h
new file mode 100644
index 00000000..6c79dc87
--- /dev/null
+++ b/absl/flags/internal/parse.h
@@ -0,0 +1,50 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_PARSE_H_
+#define ABSL_FLAGS_INTERNAL_PARSE_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/flags/declare.h"
+
+ABSL_DECLARE_FLAG(std::vector<std::string>, flagfile);
+ABSL_DECLARE_FLAG(std::vector<std::string>, fromenv);
+ABSL_DECLARE_FLAG(std::vector<std::string>, tryfromenv);
+ABSL_DECLARE_FLAG(std::vector<std::string>, undefok);
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+enum class ArgvListAction { kRemoveParsedArgs, kKeepParsedArgs };
+enum class UsageFlagsAction { kHandleUsage, kIgnoreUsage };
+enum class OnUndefinedFlag {
+ kIgnoreUndefined,
+ kReportUndefined,
+ kAbortIfUndefined
+};
+
+std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
+ ArgvListAction arg_list_act,
+ UsageFlagsAction usage_flag_act,
+ OnUndefinedFlag on_undef_flag);
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_PARSE_H_
diff --git a/absl/flags/internal/path_util.h b/absl/flags/internal/path_util.h
new file mode 100644
index 00000000..623a7bc9
--- /dev/null
+++ b/absl/flags/internal/path_util.h
@@ -0,0 +1,62 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
+#define ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// A portable interface that returns the basename of the filename passed as an
+// argument. It is similar to basename(3)
+// <https://linux.die.net/man/3/basename>.
+// For example:
+// flags_internal::Basename("a/b/prog/file.cc")
+// returns "file.cc"
+// flags_internal::Basename("file.cc")
+// returns "file.cc"
+inline absl::string_view Basename(absl::string_view filename) {
+ auto last_slash_pos = filename.find_last_of("/\\");
+
+ return last_slash_pos == absl::string_view::npos
+ ? filename
+ : filename.substr(last_slash_pos + 1);
+}
+
+// A portable interface that returns the directory name of the filename
+// passed as an argument, including the trailing slash.
+// Returns the empty string if a slash is not found in the input file name.
+// For example:
+// flags_internal::Package("a/b/prog/file.cc")
+// returns "a/b/prog/"
+// flags_internal::Package("file.cc")
+// returns ""
+inline absl::string_view Package(absl::string_view filename) {
+ auto last_slash_pos = filename.find_last_of("/\\");
+
+ return last_slash_pos == absl::string_view::npos
+ ? absl::string_view()
+ : filename.substr(0, last_slash_pos + 1);
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_PATH_UTIL_H_
diff --git a/absl/flags/internal/path_util_test.cc b/absl/flags/internal/path_util_test.cc
new file mode 100644
index 00000000..2091373c
--- /dev/null
+++ b/absl/flags/internal/path_util_test.cc
@@ -0,0 +1,46 @@
+//
+// 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.
+
+#include "absl/flags/internal/path_util.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+TEST(FlagsPathUtilTest, TestBasename) {
+ EXPECT_EQ(flags::Basename(""), "");
+ EXPECT_EQ(flags::Basename("a.cc"), "a.cc");
+ EXPECT_EQ(flags::Basename("dir/a.cc"), "a.cc");
+ EXPECT_EQ(flags::Basename("dir1/dir2/a.cc"), "a.cc");
+ EXPECT_EQ(flags::Basename("../dir1/dir2/a.cc"), "a.cc");
+ EXPECT_EQ(flags::Basename("/dir1/dir2/a.cc"), "a.cc");
+ EXPECT_EQ(flags::Basename("/dir1/dir2/../dir3/a.cc"), "a.cc");
+}
+
+// --------------------------------------------------------------------
+
+TEST(FlagsPathUtilTest, TestPackage) {
+ EXPECT_EQ(flags::Package(""), "");
+ EXPECT_EQ(flags::Package("a.cc"), "");
+ EXPECT_EQ(flags::Package("dir/a.cc"), "dir/");
+ EXPECT_EQ(flags::Package("dir1/dir2/a.cc"), "dir1/dir2/");
+ EXPECT_EQ(flags::Package("../dir1/dir2/a.cc"), "../dir1/dir2/");
+ EXPECT_EQ(flags::Package("/dir1/dir2/a.cc"), "/dir1/dir2/");
+ EXPECT_EQ(flags::Package("/dir1/dir2/../dir3/a.cc"), "/dir1/dir2/../dir3/");
+}
+
+} // namespace
diff --git a/absl/flags/internal/program_name.cc b/absl/flags/internal/program_name.cc
new file mode 100644
index 00000000..28b8ed38
--- /dev/null
+++ b/absl/flags/internal/program_name.cc
@@ -0,0 +1,55 @@
+//
+// 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.
+
+#include "absl/flags/internal/program_name.h"
+
+#include <string>
+
+#include "absl/flags/internal/path_util.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+ABSL_CONST_INIT static absl::Mutex program_name_guard(absl::kConstInit);
+ABSL_CONST_INIT static std::string* program_name
+ GUARDED_BY(program_name_guard) = nullptr;
+
+std::string ProgramInvocationName() {
+ absl::MutexLock l(&program_name_guard);
+
+ return program_name ? *program_name : "UNKNOWN";
+}
+
+std::string ShortProgramInvocationName() {
+ absl::MutexLock l(&program_name_guard);
+
+ 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)
+ program_name = new std::string(prog_name_str);
+ else
+ program_name->assign(prog_name_str.data(), prog_name_str.size());
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/internal/program_name.h b/absl/flags/internal/program_name.h
new file mode 100644
index 00000000..a2f0ca10
--- /dev/null
+++ b/absl/flags/internal/program_name.h
@@ -0,0 +1,49 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_PROGRAM_NAME_H_
+#define ABSL_FLAGS_INTERNAL_PROGRAM_NAME_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+// --------------------------------------------------------------------
+// Program name
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// Returns program invocation name or "UNKNOWN" if `SetProgramInvocationName()`
+// is never called. At the moment this is always set to argv[0] as part of
+// library initialization.
+std::string ProgramInvocationName();
+
+// Returns base name for program invocation name. For example, if
+// ProgramInvocationName() == "a/b/mybinary"
+// then
+// ShortProgramInvocationName() == "mybinary"
+std::string ShortProgramInvocationName();
+
+// Sets program invocation name to a new value. Should only be called once
+// during program initialization, before any threads are spawned.
+void SetProgramInvocationName(absl::string_view prog_name_str);
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_PROGRAM_NAME_H_
diff --git a/absl/flags/internal/program_name_test.cc b/absl/flags/internal/program_name_test.cc
new file mode 100644
index 00000000..ed69218b
--- /dev/null
+++ b/absl/flags/internal/program_name_test.cc
@@ -0,0 +1,60 @@
+//
+// 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.
+
+#include "absl/flags/internal/program_name.h"
+
+#include "gtest/gtest.h"
+#include "absl/strings/match.h"
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+TEST(FlagsPathUtilTest, TestInitialProgamName) {
+ flags::SetProgramInvocationName("absl/flags/program_name_test");
+ std::string program_name = flags::ProgramInvocationName();
+ for (char& c : program_name)
+ if (c == '\\') c = '/';
+
+#if !defined(__wasm__) && !defined(__asmjs__)
+ const std::string expect_name = "absl/flags/program_name_test";
+ const std::string expect_basename = "program_name_test";
+#else
+ // For targets that generate javascript or webassembly the invocation name
+ // has the special value below.
+ const std::string expect_name = "this.program";
+ const std::string expect_basename = "this.program";
+#endif
+
+ EXPECT_TRUE(absl::EndsWith(program_name, expect_name)) << program_name;
+ EXPECT_EQ(flags::ShortProgramInvocationName(), expect_basename);
+}
+
+TEST(FlagsPathUtilTest, TestProgamNameInterfaces) {
+ flags::SetProgramInvocationName("a/my_test");
+
+ EXPECT_EQ(flags::ProgramInvocationName(), "a/my_test");
+ EXPECT_EQ(flags::ShortProgramInvocationName(), "my_test");
+
+ absl::string_view not_null_terminated("absl/aaa/bbb");
+ not_null_terminated = not_null_terminated.substr(1, 10);
+
+ flags::SetProgramInvocationName(not_null_terminated);
+
+ EXPECT_EQ(flags::ProgramInvocationName(), "bsl/aaa/bb");
+ EXPECT_EQ(flags::ShortProgramInvocationName(), "bb");
+}
+
+} // namespace
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
new file mode 100644
index 00000000..e39264e5
--- /dev/null
+++ b/absl/flags/internal/registry.cc
@@ -0,0 +1,445 @@
+//
+// 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.
+
+#include "absl/flags/internal/registry.h"
+
+#include "absl/base/dynamic_annotations.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/flags/config.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/string_view.h"
+#include "absl/synchronization/mutex.h"
+
+// --------------------------------------------------------------------
+// FlagRegistry implementation
+// A FlagRegistry holds all flag objects indexed
+// by their names so that if you know a flag's name you can access or
+// set it.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+namespace {
+
+void DestroyFlag(CommandLineFlag* flag) NO_THREAD_SAFETY_ANALYSIS {
+ flag->Destroy();
+
+ // CommandLineFlag handle object is heap allocated for non Abseil Flags.
+ if (!flag->IsAbseilFlag()) {
+ delete flag;
+ }
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+// FlagRegistry
+// A FlagRegistry singleton object holds all flag objects indexed
+// by their names so that if you know a flag's name (as a C
+// string), you can access or set it. If the function is named
+// FooLocked(), you must own the registry lock before calling
+// the function; otherwise, you should *not* hold the lock, and
+// the function will acquire it itself if needed.
+// --------------------------------------------------------------------
+
+class FlagRegistry {
+ public:
+ FlagRegistry() = default;
+ ~FlagRegistry() {
+ for (auto& p : flags_) {
+ DestroyFlag(p.second);
+ }
+ }
+
+ // Store a flag in this registry. Takes ownership of *flag.
+ void RegisterFlag(CommandLineFlag* flag);
+
+ void Lock() EXCLUSIVE_LOCK_FUNCTION(lock_) { lock_.Lock(); }
+ void Unlock() UNLOCK_FUNCTION(lock_) { lock_.Unlock(); }
+
+ // Returns the flag object for the specified name, or nullptr if not found.
+ // Will emit a warning if a 'retired' flag is specified.
+ CommandLineFlag* FindFlagLocked(absl::string_view name);
+
+ // Returns the retired flag object for the specified name, or nullptr if not
+ // found or not retired. Does not emit a warning.
+ CommandLineFlag* FindRetiredFlagLocked(absl::string_view name);
+
+ static FlagRegistry* GlobalRegistry(); // returns a singleton registry
+
+ private:
+ friend class FlagSaverImpl; // reads all the flags in order to copy them
+ friend void ForEachFlagUnlocked(
+ std::function<void(CommandLineFlag*)> visitor);
+
+ // The map from name to flag, for FindFlagLocked().
+ using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
+ using FlagIterator = FlagMap::iterator;
+ using FlagConstIterator = FlagMap::const_iterator;
+ FlagMap flags_;
+
+ absl::Mutex lock_;
+
+ // Disallow
+ FlagRegistry(const FlagRegistry&);
+ FlagRegistry& operator=(const FlagRegistry&);
+};
+
+FlagRegistry* FlagRegistry::GlobalRegistry() {
+ static FlagRegistry* global_registry = new FlagRegistry;
+ return global_registry;
+}
+
+namespace {
+
+class FlagRegistryLock {
+ public:
+ explicit FlagRegistryLock(FlagRegistry* fr) : fr_(fr) { fr_->Lock(); }
+ ~FlagRegistryLock() { fr_->Unlock(); }
+
+ private:
+ FlagRegistry* const fr_;
+};
+
+} // namespace
+
+void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
+ FlagRegistryLock registry_lock(this);
+ std::pair<FlagIterator, bool> ins =
+ flags_.insert(FlagMap::value_type(flag->Name(), flag));
+ if (ins.second == false) { // means the name was already in the map
+ CommandLineFlag* old_flag = ins.first->second;
+ if (flag->IsRetired() != old_flag->IsRetired()) {
+ // All registrations must agree on the 'retired' flag.
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Retired flag '", flag->Name(),
+ "' was defined normally in file '",
+ (flag->IsRetired() ? old_flag->Filename() : flag->Filename()),
+ "'."),
+ true);
+ } else if (flag->op != old_flag->op) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Flag '", flag->Name(),
+ "' was defined more than once but with "
+ "differing types. Defined in files '",
+ old_flag->Filename(), "' and '", flag->Filename(),
+ "' with types '", old_flag->Typename(), "' and '",
+ flag->Typename(), "', respectively."),
+ true);
+ } else if (old_flag->IsRetired()) {
+ // Retired definitions are idempotent. Just keep the old one.
+ DestroyFlag(flag);
+ return;
+ } else if (old_flag->Filename() != flag->Filename()) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Flag '", flag->Name(),
+ "' was defined more than once (in files '",
+ old_flag->Filename(), "' and '", flag->Filename(),
+ "')."),
+ true);
+ } else {
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Something wrong with flag '", flag->Name(), "' in file '",
+ flag->Filename(), "'. One possibility: file '", flag->Filename(),
+ "' is being linked both statically and dynamically into this "
+ "executable. e.g. some files listed as srcs to a test and also "
+ "listed as srcs of some shared lib deps of the same test."),
+ true);
+ }
+ // All cases above are fatal, except for the retired flags.
+ std::exit(1);
+ }
+}
+
+CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end()) {
+ return nullptr;
+ }
+
+ if (i->second->IsRetired()) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Accessing retired flag '", name, "'"), false);
+ }
+
+ return i->second;
+}
+
+CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
+ FlagConstIterator i = flags_.find(name);
+ if (i == flags_.end() || !i->second->IsRetired()) {
+ return nullptr;
+ }
+
+ return i->second;
+}
+
+// --------------------------------------------------------------------
+// FlagSaver
+// FlagSaverImpl
+// This class stores the states of all flags at construct time,
+// and restores all flags to that state at destruct time.
+// Its major implementation challenge is that it never modifies
+// pointers in the 'main' registry, so global FLAG_* vars always
+// point to the right place.
+// --------------------------------------------------------------------
+
+class FlagSaverImpl {
+ public:
+ // Constructs an empty FlagSaverImpl object.
+ FlagSaverImpl() {}
+ ~FlagSaverImpl() {
+ // reclaim memory from each of our CommandLineFlags
+ for (const SavedFlag& src : backup_registry_) {
+ Delete(src.op, src.current);
+ Delete(src.op, src.default_value);
+ }
+ }
+
+ // Saves the flag states from the flag registry into this object.
+ // It's an error to call this more than once.
+ // Must be called when the registry mutex is not held.
+ void SaveFromRegistry() {
+ assert(backup_registry_.empty()); // call only once!
+ SavedFlag saved;
+ flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
+ if (flag->IsRetired()) return;
+
+ saved.name = flag->Name();
+ saved.op = flag->op;
+ saved.marshalling_op = flag->marshalling_op;
+ {
+ absl::MutexLock l(flag->InitFlagIfNecessary());
+ saved.validator = flag->validator;
+ saved.modified = flag->modified;
+ saved.on_command_line = flag->on_command_line;
+ saved.current = Clone(saved.op, flag->cur);
+ saved.default_value = Clone(saved.op, flag->def);
+ saved.counter = flag->counter;
+ }
+ backup_registry_.push_back(saved);
+ });
+ }
+
+ // Restores the saved flag states into the flag registry. We
+ // assume no flags were added or deleted from the registry since
+ // the SaveFromRegistry; if they were, that's trouble! Must be
+ // called when the registry mutex is not held.
+ void RestoreToRegistry() {
+ FlagRegistry* const global_registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(global_registry);
+ for (const SavedFlag& src : backup_registry_) {
+ CommandLineFlag* flag = global_registry->FindFlagLocked(src.name);
+ // If null, flag got deleted from registry.
+ if (!flag) continue;
+
+ bool restored = false;
+ {
+ absl::MutexLock l(flag->InitFlagIfNecessary());
+ flag->validator = src.validator;
+ flag->modified = src.modified;
+ flag->on_command_line = src.on_command_line;
+ if (flag->counter != src.counter ||
+ ChangedDirectly(flag, src.default_value, flag->def)) {
+ restored = true;
+ Copy(src.op, src.default_value, flag->def);
+ }
+ if (flag->counter != src.counter ||
+ ChangedDirectly(flag, src.current, flag->cur)) {
+ restored = true;
+ Copy(src.op, src.current, flag->cur);
+ UpdateCopy(flag);
+ flag->InvokeCallback();
+ }
+ }
+
+ if (restored) {
+ flag->counter++;
+
+ // Revalidate the flag because the validator might store state based
+ // on the flag's value, which just changed due to the restore.
+ // Failing validation is ignored because it's assumed that the flag
+ // was valid previously and there's little that can be done about it
+ // here, anyway.
+ flag->ValidateInputValue(flag->CurrentValue());
+
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrCat("Restore saved value of ", flag->Name(), ": ",
+ Unparse(src.marshalling_op, src.current)));
+ }
+ }
+ }
+
+ private:
+ struct SavedFlag {
+ absl::string_view name;
+ FlagOpFn op;
+ FlagMarshallingOpFn marshalling_op;
+ int64_t counter;
+ bool modified;
+ bool on_command_line;
+ bool (*validator)();
+ const void* current; // nullptr after restore
+ const void* default_value; // nullptr after restore
+ };
+
+ std::vector<SavedFlag> backup_registry_;
+
+ FlagSaverImpl(const FlagSaverImpl&); // no copying!
+ void operator=(const FlagSaverImpl&);
+};
+
+FlagSaver::FlagSaver() : impl_(new FlagSaverImpl()) {
+ impl_->SaveFromRegistry();
+}
+
+void FlagSaver::Ignore() {
+ delete impl_;
+ impl_ = nullptr;
+}
+
+FlagSaver::~FlagSaver() {
+ if (!impl_) return;
+
+ impl_->RestoreToRegistry();
+ delete impl_;
+}
+
+// --------------------------------------------------------------------
+// GetAllFlags()
+// The main way the FlagRegistry class exposes its data. This
+// returns, as strings, all the info about all the flags in
+// the main registry, sorted first by filename they are defined
+// in, and then by flagname.
+// --------------------------------------------------------------------
+
+struct FilenameFlagnameLess {
+ bool operator()(const CommandLineFlagInfo& a,
+ const CommandLineFlagInfo& b) const {
+ int cmp = absl::string_view(a.filename).compare(b.filename);
+ if (cmp != 0) return cmp < 0;
+ return a.name < b.name;
+ }
+};
+
+void FillCommandLineFlagInfo(CommandLineFlag* flag,
+ CommandLineFlagInfo* result) {
+ result->name = std::string(flag->Name());
+ result->type = std::string(flag->Typename());
+ result->description = flag->Help();
+ result->filename = flag->Filename();
+
+ if (!flag->IsAbseilFlag()) {
+ if (!flag->IsModified() && ChangedDirectly(flag, flag->cur, flag->def)) {
+ flag->modified = true;
+ }
+ }
+
+ result->current_value = flag->CurrentValue();
+ result->default_value = flag->DefaultValue();
+ result->is_default = !flag->IsModified();
+ result->has_validator_fn = flag->HasValidatorFn();
+ absl::MutexLock l(flag->InitFlagIfNecessary());
+ result->flag_ptr = flag->IsAbseilFlag() ? nullptr : flag->cur;
+}
+
+// --------------------------------------------------------------------
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name) {
+ if (name.empty()) return nullptr;
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+
+ return registry->FindFlagLocked(name);
+}
+
+CommandLineFlag* FindRetiredFlag(absl::string_view name) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+
+ return registry->FindRetiredFlagLocked(name);
+}
+
+// --------------------------------------------------------------------
+
+void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
+ i != registry->flags_.end(); ++i) {
+ visitor(i->second);
+ }
+}
+
+void ForEachFlag(std::function<void(CommandLineFlag*)> visitor) {
+ FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
+ FlagRegistryLock frl(registry);
+ ForEachFlagUnlocked(visitor);
+}
+
+// --------------------------------------------------------------------
+
+void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT) {
+ flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
+ if (flag->IsRetired()) return;
+
+ CommandLineFlagInfo fi;
+ FillCommandLineFlagInfo(flag, &fi);
+ OUTPUT->push_back(fi);
+ });
+
+ // Now sort the flags, first by filename they occur in, then alphabetically
+ std::sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameLess());
+}
+
+// --------------------------------------------------------------------
+
+bool RegisterCommandLineFlag(CommandLineFlag* flag) {
+ FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
+ return true;
+}
+
+// --------------------------------------------------------------------
+
+bool Retire(FlagOpFn ops, FlagMarshallingOpFn marshalling_ops,
+ const char* name) {
+ auto* flag = new CommandLineFlag(
+ name,
+ /*help_text=*/absl::flags_internal::HelpText::FromStaticCString(nullptr),
+ /*filename_arg=*/"RETIRED", ops, marshalling_ops,
+ /*initial_value_gen=*/nullptr,
+ /*retired_arg=*/true, nullptr, nullptr);
+ FlagRegistry::GlobalRegistry()->RegisterFlag(flag);
+ return true;
+}
+
+// --------------------------------------------------------------------
+
+bool IsRetiredFlag(absl::string_view name, bool* type_is_bool) {
+ assert(!name.empty());
+ CommandLineFlag* flag = flags_internal::FindRetiredFlag(name);
+ if (flag == nullptr) {
+ return false;
+ }
+ assert(type_is_bool);
+ *type_is_bool = flag->IsOfType<bool>();
+ return true;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/internal/registry.h b/absl/flags/internal/registry.h
new file mode 100644
index 00000000..d851d245
--- /dev/null
+++ b/absl/flags/internal/registry.h
@@ -0,0 +1,169 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_REGISTRY_H_
+#define ABSL_FLAGS_INTERNAL_REGISTRY_H_
+
+#include <functional>
+#include <map>
+#include <string>
+
+#include "absl/base/macros.h"
+#include "absl/flags/internal/commandlineflag.h"
+
+// --------------------------------------------------------------------
+// Global flags registry API.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// CommandLineFlagInfo holds all information for a flag.
+struct CommandLineFlagInfo {
+ std::string name; // the name of the flag
+ std::string type; // DO NOT use. Use flag->IsOfType<T>() instead.
+ std::string description; // the "help text" associated with the flag
+ std::string current_value; // the current value, as a std::string
+ std::string default_value; // the default value, as a std::string
+ std::string filename; // 'cleaned' version of filename holding the flag
+ bool has_validator_fn; // true if RegisterFlagValidator called on this flag
+
+ bool is_default; // true if the flag has the default value and
+ // has not been set explicitly from the cmdline
+ // or via SetCommandLineOption.
+
+ // nullptr for ABSL_FLAG. A pointer to the flag's current value
+ // otherwise. E.g., for DEFINE_int32(foo, ...), flag_ptr will be
+ // &FLAGS_foo.
+ const void* flag_ptr;
+};
+
+//-----------------------------------------------------------------------------
+
+void FillCommandLineFlagInfo(CommandLineFlag* flag,
+ CommandLineFlagInfo* result);
+
+//-----------------------------------------------------------------------------
+
+CommandLineFlag* FindCommandLineFlag(absl::string_view name);
+CommandLineFlag* FindRetiredFlag(absl::string_view name);
+
+// Executes specified visitor for each non-retired flag in the registry.
+// Requires the caller hold the registry lock.
+void ForEachFlagUnlocked(std::function<void(CommandLineFlag*)> visitor);
+// Executes specified visitor for each non-retired flag in the registry. While
+// callback are executed, the registry is locked and can't be changed.
+void ForEachFlag(std::function<void(CommandLineFlag*)> visitor);
+
+//-----------------------------------------------------------------------------
+
+// Store the list of all flags in *OUTPUT, sorted by file.
+void GetAllFlags(std::vector<CommandLineFlagInfo>* OUTPUT);
+
+//-----------------------------------------------------------------------------
+
+bool RegisterCommandLineFlag(CommandLineFlag*);
+
+//-----------------------------------------------------------------------------
+// Retired registrations:
+//
+// Retired flag registrations are treated specially. A 'retired' flag is
+// provided only for compatibility with automated invocations that still
+// name it. A 'retired' flag:
+// - is not bound to a C++ FLAGS_ reference.
+// - has a type and a value, but that value is intentionally inaccessible.
+// - does not appear in --help messages.
+// - is fully supported by _all_ flag parsing routines.
+// - consumes args normally, and complains about type mismatches in its
+// argument.
+// - emits a complaint but does not die (e.g. LOG(ERROR)) if it is
+// accessed by name through the flags API for parsing or otherwise.
+//
+// The registrations for a flag happen in an unspecified order as the
+// initializers for the namespace-scope objects of a program are run.
+// Any number of weak registrations for a flag can weakly define the flag.
+// One non-weak registration will upgrade the flag from weak to non-weak.
+// Further weak registrations of a non-weak flag are ignored.
+//
+// This mechanism is designed to support moving dead flags into a
+// 'graveyard' library. An example migration:
+//
+// 0: Remove references to this FLAGS_flagname in the C++ codebase.
+// 1: Register as 'retired' in old_lib.
+// 2: Make old_lib depend on graveyard.
+// 3: Add a redundant 'retired' registration to graveyard.
+// 4: Remove the old_lib 'retired' registration.
+// 5: Eventually delete the graveyard registration entirely.
+//
+// Returns bool to enable use in namespace-scope initializers.
+// For example:
+//
+// static const bool dummy = base::RetiredFlag<int32_t>("myflag");
+//
+// Or to declare several at once:
+//
+// static bool dummies[] = {
+// base::RetiredFlag<std::string>("some_string_flag"),
+// base::RetiredFlag<double>("some_double_flag"),
+// base::RetiredFlag<int32_t>("some_int32_flag")
+// };
+
+// Retire flag with name "name" and type indicated by ops.
+bool Retire(FlagOpFn ops, FlagMarshallingOpFn marshalling_ops,
+ const char* name);
+
+// Registered a retired flag with name 'flag_name' and type 'T'.
+template <typename T>
+inline bool RetiredFlag(const char* flag_name) {
+ return flags_internal::Retire(flags_internal::FlagOps<T>,
+ flags_internal::FlagMarshallingOps<T>,
+ flag_name);
+}
+
+// If the flag is retired, returns true and indicates in |*type_is_bool|
+// whether the type of the retired flag is a bool.
+// Only to be called by code that needs to explicitly ignore retired flags.
+bool IsRetiredFlag(absl::string_view name, bool* type_is_bool);
+
+//-----------------------------------------------------------------------------
+// Saves the states (value, default value, whether the user has set
+// the flag, registered validators, etc) of all flags, and restores
+// them when the FlagSaver is destroyed.
+//
+// This class is thread-safe. However, its destructor writes to
+// exactly the set of flags that have changed value during its
+// lifetime, so concurrent _direct_ access to those flags
+// (i.e. FLAGS_foo instead of {Get,Set}CommandLineOption()) is unsafe.
+
+class FlagSaver {
+ public:
+ FlagSaver();
+ ~FlagSaver();
+
+ FlagSaver(const FlagSaver&) = delete;
+ void operator=(const FlagSaver&) = delete;
+
+ // Prevents saver from restoring the saved state of flags.
+ void Ignore();
+
+ private:
+ class FlagSaverImpl* impl_; // we use pimpl here to keep API steady
+};
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_REGISTRY_H_
diff --git a/absl/flags/internal/type_erased.cc b/absl/flags/internal/type_erased.cc
new file mode 100644
index 00000000..6b91b261
--- /dev/null
+++ b/absl/flags/internal/type_erased.cc
@@ -0,0 +1,108 @@
+//
+// 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.
+
+#include "absl/flags/internal/type_erased.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/flags/config.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+bool GetCommandLineOption(absl::string_view name, std::string* value) {
+ if (name.empty()) return false;
+ assert(value);
+
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+ if (flag == nullptr || flag->IsRetired()) {
+ return false;
+ }
+
+ *value = flag->CurrentValue();
+ return true;
+}
+
+bool GetCommandLineFlagInfo(absl::string_view name,
+ CommandLineFlagInfo* OUTPUT) {
+ if (name.empty()) return false;
+
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+ if (flag == nullptr || flag->IsRetired()) {
+ return false;
+ }
+
+ assert(OUTPUT);
+ FillCommandLineFlagInfo(flag, OUTPUT);
+ return true;
+}
+
+CommandLineFlagInfo GetCommandLineFlagInfoOrDie(absl::string_view name) {
+ CommandLineFlagInfo info;
+ if (!GetCommandLineFlagInfo(name, &info)) {
+ ABSL_INTERNAL_LOG(FATAL, absl::StrCat("Flag '", name, "' does not exist"));
+ }
+ return info;
+}
+
+// --------------------------------------------------------------------
+
+bool SetCommandLineOption(absl::string_view name, absl::string_view value) {
+ return SetCommandLineOptionWithMode(name, value,
+ flags_internal::SET_FLAGS_VALUE);
+}
+
+bool SetCommandLineOptionWithMode(absl::string_view name,
+ absl::string_view value,
+ FlagSettingMode set_mode) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+
+ if (!flag || flag->IsRetired()) return false;
+
+ std::string error;
+ if (!flag->SetFromString(value, set_mode, kProgrammaticChange, &error)) {
+ // Errors here are all of the form: the provided name was a recognized
+ // flag, but the value was invalid (bad type, or validation failed).
+ flags_internal::ReportUsageError(error, false);
+ return false;
+ }
+
+ return true;
+}
+
+// --------------------------------------------------------------------
+
+bool IsValidFlagValue(absl::string_view name, absl::string_view value) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+
+ return flag != nullptr &&
+ (flag->IsRetired() || flag->ValidateInputValue(value));
+}
+
+// --------------------------------------------------------------------
+
+bool SpecifiedOnCommandLine(absl::string_view name) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+ if (flag != nullptr && !flag->IsRetired()) {
+ return flag->IsSpecifiedOnCommandLine();
+ }
+ return false;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/internal/type_erased.h b/absl/flags/internal/type_erased.h
new file mode 100644
index 00000000..c9de6de9
--- /dev/null
+++ b/absl/flags/internal/type_erased.h
@@ -0,0 +1,99 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
+#define ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
+
+#include <string>
+
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/flags/internal/registry.h"
+
+// --------------------------------------------------------------------
+// Registry interfaces operating on type erased handles.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// If a flag named "name" exists, store its current value in *OUTPUT
+// and return true. Else return false without changing *OUTPUT.
+// Thread-safe.
+bool GetCommandLineOption(absl::string_view name, std::string* value);
+
+// If a flag named "name" exists, store its information in *OUTPUT
+// and return true. Else return false without changing *OUTPUT.
+// Thread-safe.
+bool GetCommandLineFlagInfo(absl::string_view name,
+ CommandLineFlagInfo* OUTPUT);
+
+// Returns the CommandLineFlagInfo of the flagname. exit() with an
+// error code if name not found.
+// Thread-safe.
+CommandLineFlagInfo GetCommandLineFlagInfoOrDie(absl::string_view name);
+
+// Set the value of the flag named "name" to value. If successful,
+// returns true. If not successful (e.g., the flag was not found or
+// the value is not a valid value), returns false.
+// Thread-safe.
+bool SetCommandLineOption(absl::string_view name, absl::string_view value);
+
+bool SetCommandLineOptionWithMode(absl::string_view name,
+ absl::string_view value,
+ FlagSettingMode set_mode);
+
+//-----------------------------------------------------------------------------
+
+// Returns true iff all of the following conditions are true:
+// (a) "name" names a registered flag
+// (b) "value" can be parsed succesfully according to the type of the flag
+// (c) parsed value passes any validator associated with the flag
+bool IsValidFlagValue(absl::string_view name, absl::string_view value);
+
+//-----------------------------------------------------------------------------
+
+// Returns true iff a flag named "name" was specified on the command line
+// (either directly, or via one of --flagfile or --fromenv or --tryfromenv).
+//
+// Any non-command-line modification of the flag does not affect the
+// result of this function. So for example, if a flag was passed on
+// the command line but then reset via SET_FLAGS_DEFAULT, this
+// function will still return true.
+bool SpecifiedOnCommandLine(absl::string_view name);
+
+//-----------------------------------------------------------------------------
+
+// If a flag with specified "name" exists and has type T, store
+// its current value in *dst and return true. Else return false
+// without touching *dst. T must obey all of the requirements for
+// types passed to DEFINE_FLAG.
+template <typename T>
+inline bool GetByName(absl::string_view name, T* dst) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(name);
+ if (!flag) return false;
+
+ if (auto val = flag->Get<T>()) {
+ *dst = *val;
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_INTERNAL_TYPE_ERASED_H_
diff --git a/absl/flags/internal/type_erased_test.cc b/absl/flags/internal/type_erased_test.cc
new file mode 100644
index 00000000..ac749a60
--- /dev/null
+++ b/absl/flags/internal/type_erased_test.cc
@@ -0,0 +1,147 @@
+//
+// 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.
+
+#include "absl/flags/internal/type_erased.h"
+
+#include <cmath>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
+
+ABSL_FLAG(int, int_flag, 1, "int_flag help");
+ABSL_FLAG(std::string, string_flag, "dflt", "string_flag help");
+ABSL_RETIRED_FLAG(bool, bool_retired_flag, false, "bool_retired_flag help");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+class TypeErasedTest : public testing::Test {
+ protected:
+ void SetUp() override { flag_saver_ = absl::make_unique<flags::FlagSaver>(); }
+ void TearDown() override { flag_saver_.reset(); }
+
+ private:
+ std::unique_ptr<flags::FlagSaver> flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestGetCommandLineOption) {
+ std::string value;
+ EXPECT_TRUE(flags::GetCommandLineOption("int_flag", &value));
+ EXPECT_EQ(value, "1");
+
+ EXPECT_TRUE(flags::GetCommandLineOption("string_flag", &value));
+ EXPECT_EQ(value, "dflt");
+
+ EXPECT_FALSE(flags::GetCommandLineOption("bool_retired_flag", &value));
+
+ EXPECT_FALSE(flags::GetCommandLineOption("unknown_flag", &value));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestSetCommandLineOption) {
+ EXPECT_TRUE(flags::SetCommandLineOption("int_flag", "101"));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
+
+ EXPECT_TRUE(flags::SetCommandLineOption("string_flag", "asdfgh"));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
+
+ EXPECT_FALSE(flags::SetCommandLineOption("bool_retired_flag", "true"));
+
+ EXPECT_FALSE(flags::SetCommandLineOption("unknown_flag", "true"));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_VALUE) {
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
+ flags::SET_FLAGS_VALUE));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
+
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
+ flags::SET_FLAGS_VALUE));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
+ flags::SET_FLAGS_VALUE));
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
+ flags::SET_FLAGS_VALUE));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAG_IF_DEFAULT) {
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
+ flags::SET_FLAG_IF_DEFAULT));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
+
+ // This semantic is broken. We return true instead of false. Value is not
+ // updated.
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
+ flags::SET_FLAG_IF_DEFAULT));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 101);
+
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
+ flags::SET_FLAG_IF_DEFAULT));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
+ flags::SET_FLAG_IF_DEFAULT));
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
+ flags::SET_FLAG_IF_DEFAULT));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestSetCommandLineOptionWithMode_SET_FLAGS_DEFAULT) {
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "101",
+ flags::SET_FLAGS_DEFAULT));
+
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("string_flag", "asdfgh",
+ flags::SET_FLAGS_DEFAULT));
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "asdfgh");
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("bool_retired_flag", "true",
+ flags::SET_FLAGS_DEFAULT));
+
+ EXPECT_FALSE(flags::SetCommandLineOptionWithMode("unknown_flag", "true",
+ flags::SET_FLAGS_DEFAULT));
+
+ // This should be successfull, since flag is still is not set
+ EXPECT_TRUE(flags::SetCommandLineOptionWithMode("int_flag", "202",
+ flags::SET_FLAG_IF_DEFAULT));
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 202);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(TypeErasedTest, TestIsValidFlagValue) {
+ EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "57"));
+ EXPECT_TRUE(flags::IsValidFlagValue("int_flag", "-101"));
+ EXPECT_FALSE(flags::IsValidFlagValue("int_flag", "1.1"));
+
+ EXPECT_TRUE(flags::IsValidFlagValue("string_flag", "#%^#%^$%DGHDG$W%adsf"));
+
+ EXPECT_TRUE(flags::IsValidFlagValue("bool_retired_flag", "true"));
+}
+
+} // namespace
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
new file mode 100644
index 00000000..a9a8a21e
--- /dev/null
+++ b/absl/flags/internal/usage.cc
@@ -0,0 +1,385 @@
+//
+// 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.
+
+#include "absl/flags/internal/usage.h"
+
+#include <map>
+#include <string>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "absl/synchronization/mutex.h"
+
+ABSL_FLAG(bool, help, false,
+ "show help on important flags for this binary [tip: all flags can "
+ "have two dashes]");
+ABSL_FLAG(bool, helpfull, false, "show help on all flags");
+ABSL_FLAG(bool, helpshort, false,
+ "show help on only the main module for this program");
+ABSL_FLAG(bool, helppackage, false,
+ "show help on all modules in the main package");
+ABSL_FLAG(bool, version, false, "show version and build info and exit");
+ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
+ABSL_FLAG(std::string, helpon, "",
+ "show help on the modules named by this flag value");
+ABSL_FLAG(std::string, helpmatch, "",
+ "show help on modules whose name contains the specified substr");
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+namespace {
+
+// This class is used to emit an XML element with `tag` and `text`.
+// It adds opening and closing tags and escapes special characters in the text.
+// For example:
+// std::cout << XMLElement("title", "Milk & Cookies");
+// prints "<title>Milk &amp; Cookies</title>"
+class XMLElement {
+ public:
+ XMLElement(absl::string_view tag, absl::string_view txt)
+ : tag_(tag), txt_(txt) {}
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const XMLElement& xml_elem) {
+ out << "<" << xml_elem.tag_ << ">";
+
+ for (auto c : xml_elem.txt_) {
+ switch (c) {
+ case '"':
+ out << "&quot;";
+ break;
+ case '\'':
+ out << "&apos;";
+ break;
+ case '&':
+ out << "&amp;";
+ break;
+ case '<':
+ out << "&lt;";
+ break;
+ case '>':
+ out << "&gt;";
+ break;
+ default:
+ out << c;
+ break;
+ }
+ }
+
+ return out << "</" << xml_elem.tag_ << ">";
+ }
+
+ private:
+ absl::string_view tag_;
+ absl::string_view txt_;
+};
+
+// --------------------------------------------------------------------
+// Helper class to pretty-print info about a flag.
+
+class FlagHelpPrettyPrinter {
+ public:
+ // Pretty printer holds on to the std::ostream& reference to direct an output
+ // to that stream.
+ FlagHelpPrettyPrinter(int max_line_len, std::ostream* out)
+ : out_(*out),
+ max_line_len_(max_line_len),
+ line_len_(0),
+ first_line_(true) {}
+
+ void Write(absl::string_view str, bool wrap_line = false) {
+ // Empty std::string - do nothing.
+ if (str.empty()) return;
+
+ std::vector<absl::string_view> tokens;
+ if (wrap_line) {
+ for (auto line : absl::StrSplit(str, absl::ByAnyChar("\n\r"))) {
+ if (!tokens.empty()) {
+ // Keep line separators in the input std::string.
+ tokens.push_back("\n");
+ }
+ for (auto token :
+ absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipEmpty())) {
+ tokens.push_back(token);
+ }
+ }
+ } else {
+ tokens.push_back(str);
+ }
+
+ for (auto token : tokens) {
+ bool new_line = (line_len_ == 0);
+
+ // Respect line separators in the input std::string.
+ if (token == "\n") {
+ EndLine();
+ continue;
+ }
+
+ // Write the token, ending the std::string first if necessary/possible.
+ if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
+ EndLine();
+ new_line = true;
+ }
+
+ if (new_line) {
+ StartLine();
+ } else {
+ out_ << ' ';
+ ++line_len_;
+ }
+
+ out_ << token;
+ line_len_ += token.size();
+ }
+ }
+
+ void StartLine() {
+ if (first_line_) {
+ out_ << " ";
+ line_len_ = 4;
+ first_line_ = false;
+ } else {
+ out_ << " ";
+ line_len_ = 6;
+ }
+ }
+ void EndLine() {
+ out_ << '\n';
+ line_len_ = 0;
+ }
+
+ private:
+ std::ostream& out_;
+ const int max_line_len_;
+ int line_len_;
+ bool first_line_;
+};
+
+void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag,
+ std::ostream* out) {
+ FlagHelpPrettyPrinter printer(80, out); // Max line length is 80.
+
+ // Flag name.
+ printer.Write(absl::StrCat("-", flag.Name()));
+
+ // Flag help.
+ printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
+
+ // Flag data type (for V1 flags only).
+ if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
+ printer.Write(absl::StrCat("type: ", flag.Typename(), ";"));
+ }
+
+ // The listed default value will be the actual default from the flag
+ // definition in the originating source file, unless the value has
+ // subsequently been modified using SetCommandLineOption() with mode
+ // SET_FLAGS_DEFAULT.
+ std::string dflt_val = flag.DefaultValue();
+ if (flag.IsOfType<std::string>()) {
+ dflt_val = absl::StrCat("\"", dflt_val, "\"");
+ }
+ printer.Write(absl::StrCat("default: ", dflt_val, ";"));
+
+ if (flag.IsModified()) {
+ std::string curr_val = flag.CurrentValue();
+ if (flag.IsOfType<std::string>()) {
+ curr_val = absl::StrCat("\"", curr_val, "\"");
+ }
+ printer.Write(absl::StrCat("currently: ", curr_val, ";"));
+ }
+
+ printer.EndLine();
+}
+
+// Shows help for every filename which matches any of the filters
+// If filters are empty, shows help for every file.
+// If a flag's help message has been stripped (e.g. by adding '#define
+// STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
+// and its variants.
+void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
+ HelpFormat format, absl::string_view program_usage_message) {
+ if (format == HelpFormat::kHumanReadable) {
+ out << flags_internal::ShortProgramInvocationName() << ": "
+ << program_usage_message << "\n\n";
+ } else {
+ // XML schema is not a part of our public API for now.
+ out << "<?xml version=\"1.0\"?>\n"
+ // The document.
+ << "<AllFlags>\n"
+ // The program name and usage.
+ << XMLElement("program", flags_internal::ShortProgramInvocationName())
+ << '\n'
+ << XMLElement("usage", program_usage_message) << '\n';
+ }
+
+ // Map of package name to
+ // map of file name to
+ // vector of flags in the file.
+ // This map is used to output matching flags grouped by package and file
+ // name.
+ std::map<std::string,
+ std::map<std::string,
+ std::vector<const flags_internal::CommandLineFlag*>>>
+ matching_flags;
+
+ flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
+ std::string flag_filename = flag->Filename();
+
+ // Ignore retired flags.
+ if (flag->IsRetired()) return;
+
+ // If the flag has been stripped, pretend that it doesn't exist.
+ if (flag->Help() == flags_internal::kStrippedFlagHelp) return;
+
+ // Make sure flag satisfies the filter
+ if (!filter_cb || !filter_cb(flag_filename)) return;
+
+ matching_flags[std::string(flags_internal::Package(flag_filename))]
+ [flag_filename]
+ .push_back(flag);
+ });
+
+ absl::string_view
+ package_separator; // controls blank lines between packages.
+ absl::string_view file_separator; // controls blank lines between files.
+ for (const auto& package : matching_flags) {
+ if (format == HelpFormat::kHumanReadable) {
+ out << package_separator;
+ package_separator = "\n\n";
+ }
+
+ file_separator = "";
+ for (const auto& flags_in_file : package.second) {
+ if (format == HelpFormat::kHumanReadable) {
+ out << file_separator << " Flags from " << flags_in_file.first
+ << ":\n";
+ file_separator = "\n";
+ }
+
+ for (const auto* flag : flags_in_file.second) {
+ flags_internal::FlagHelp(out, *flag, format);
+ }
+ }
+ }
+
+ if (format == HelpFormat::kHumanReadable) {
+ if (filter_cb && matching_flags.empty()) {
+ out << " No modules matched: use -helpfull\n";
+ }
+ } else {
+ // The end of the document.
+ out << "</AllFlags>\n";
+ }
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+// Produces the help message describing specific flag.
+void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+ HelpFormat format) {
+ if (format == HelpFormat::kHumanReadable)
+ flags_internal::FlagHelpHumanReadable(flag, &out);
+}
+
+// --------------------------------------------------------------------
+// Produces the help messages for all flags matching the filter.
+// If filter is empty produces help messages for all flags.
+void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
+ absl::string_view program_usage_message) {
+ flags_internal::FlagKindFilter filter_cb = [&](absl::string_view filename) {
+ return filter.empty() || filename.find(filter) != absl::string_view::npos;
+ };
+ flags_internal::FlagsHelpImpl(out, filter_cb, format, program_usage_message);
+}
+
+// --------------------------------------------------------------------
+// Checks all the 'usage' command line flags to see if any have been set.
+// If so, handles them appropriately.
+int HandleUsageFlags(std::ostream& out,
+ absl::string_view program_usage_message) {
+ if (absl::GetFlag(FLAGS_helpshort)) {
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helpshort_flags,
+ HelpFormat::kHumanReadable, program_usage_message);
+ return 1;
+ }
+
+ if (absl::GetFlag(FLAGS_helpfull)) {
+ // show all options
+ flags_internal::FlagsHelp(out, "", HelpFormat::kHumanReadable,
+ program_usage_message);
+ return 1;
+ }
+
+ if (!absl::GetFlag(FLAGS_helpon).empty()) {
+ flags_internal::FlagsHelp(
+ out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."),
+ HelpFormat::kHumanReadable, program_usage_message);
+ return 1;
+ }
+
+ if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
+ flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch),
+ HelpFormat::kHumanReadable,
+ program_usage_message);
+ return 1;
+ }
+
+ if (absl::GetFlag(FLAGS_help)) {
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_help_flags,
+ HelpFormat::kHumanReadable, program_usage_message);
+
+ out << "\nTry --helpfull to get a list of all flags.\n";
+
+ return 1;
+ }
+
+ if (absl::GetFlag(FLAGS_helppackage)) {
+ flags_internal::FlagsHelpImpl(
+ out, flags_internal::GetUsageConfig().contains_helppackage_flags,
+ HelpFormat::kHumanReadable, program_usage_message);
+
+ out << "\nTry --helpfull to get a list of all flags.\n";
+
+ return 1;
+ }
+
+ if (absl::GetFlag(FLAGS_version)) {
+ if (flags_internal::GetUsageConfig().version_string)
+ out << flags_internal::GetUsageConfig().version_string();
+ // Unlike help, we may be asking for version in a script, so return 0
+ return 0;
+ }
+
+ if (absl::GetFlag(FLAGS_only_check_args)) {
+ return 0;
+ }
+
+ return -1;
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/internal/usage.h b/absl/flags/internal/usage.h
new file mode 100644
index 00000000..f3794afe
--- /dev/null
+++ b/absl/flags/internal/usage.h
@@ -0,0 +1,80 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_INTERNAL_USAGE_H_
+#define ABSL_FLAGS_INTERNAL_USAGE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "absl/flags/declare.h"
+#include "absl/flags/internal/commandlineflag.h"
+#include "absl/strings/string_view.h"
+
+// --------------------------------------------------------------------
+// Usage reporting interfaces
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// The format to report the help messages in.
+enum class HelpFormat {
+ kHumanReadable,
+};
+
+// Outputs the help message describing specific flag.
+void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
+ HelpFormat format = HelpFormat::kHumanReadable);
+
+// Produces the help messages for all flags matching the filter. A flag matches
+// the filter if it is defined in a file with a filename which includes
+// filter string as a substring. You can use '/' and '.' to restrict the
+// matching to a specific file names. For example:
+// FlagsHelp(out, "/path/to/file.");
+// restricts help to only flags which resides in files named like:
+// .../path/to/file.<ext>
+// for any extension 'ext'. If the filter is empty this function produces help
+// messages for all flags.
+void FlagsHelp(std::ostream& out, absl::string_view filter,
+ HelpFormat format, absl::string_view program_usage_message);
+
+// --------------------------------------------------------------------
+
+// If any of the 'usage' related command line flags (listed on the bottom of
+// this file) has been set this routine produces corresponding help message in
+// the specified output stream and returns:
+// 0 - if "version" or "only_check_flags" flags were set and handled.
+// 1 - if some other 'usage' related flag was set and handled.
+// -1 - if no usage flags were set on a commmand line.
+// Non negative return values are expected to be used as an exit code for a
+// binary.
+int HandleUsageFlags(std::ostream& out,
+ absl::string_view program_usage_message);
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+ABSL_DECLARE_FLAG(bool, help);
+ABSL_DECLARE_FLAG(bool, helpfull);
+ABSL_DECLARE_FLAG(bool, helpshort);
+ABSL_DECLARE_FLAG(bool, helppackage);
+ABSL_DECLARE_FLAG(bool, version);
+ABSL_DECLARE_FLAG(bool, only_check_args);
+ABSL_DECLARE_FLAG(std::string, helpon);
+ABSL_DECLARE_FLAG(std::string, helpmatch);
+
+#endif // ABSL_FLAGS_INTERNAL_USAGE_H_
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
new file mode 100644
index 00000000..781e1d2b
--- /dev/null
+++ b/absl/flags/internal/usage_test.cc
@@ -0,0 +1,404 @@
+//
+// 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.
+
+#include "absl/flags/internal/usage.h"
+
+#include <sstream>
+
+#include "gtest/gtest.h"
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/usage.h"
+#include "absl/flags/usage_config.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/match.h"
+
+ABSL_FLAG(int, usage_reporting_test_flag_01, 101,
+ "usage_reporting_test_flag_01 help message");
+ABSL_FLAG(bool, usage_reporting_test_flag_02, false,
+ "usage_reporting_test_flag_02 help message");
+ABSL_FLAG(double, usage_reporting_test_flag_03, 1.03,
+ "usage_reporting_test_flag_03 help message");
+ABSL_FLAG(int64_t, usage_reporting_test_flag_04, 1000000000000004L,
+ "usage_reporting_test_flag_04 help message");
+
+static const char kTestUsageMessage[] = "Custom usage message";
+
+struct UDT {
+ UDT() = default;
+ UDT(const UDT&) = default;
+};
+bool AbslParseFlag(absl::string_view, UDT*, std::string*) { return true; }
+std::string AbslUnparseFlag(const UDT&) { return "UDT{}"; }
+
+ABSL_FLAG(UDT, usage_reporting_test_flag_05, {},
+ "usage_reporting_test_flag_05 help message");
+
+ABSL_FLAG(
+ std::string, usage_reporting_test_flag_06, {},
+ "usage_reporting_test_flag_06 help message.\n"
+ "\n"
+ "Some more help.\n"
+ "Even more long long long long long long long long long long long long "
+ "help message.");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+
+static std::string NormalizeFileName(absl::string_view fname) {
+#ifdef _WIN32
+ std::string normalized(fname);
+ std::replace(normalized.begin(), normalized.end(), '\\', '/');
+ fname = normalized;
+#endif
+
+ auto absl_pos = fname.find("/absl/");
+ if (absl_pos != absl::string_view::npos) {
+ fname = fname.substr(absl_pos + 1);
+ }
+ return std::string(fname);
+}
+
+class UsageReportingTest : public testing::Test {
+ protected:
+ UsageReportingTest() {
+ // Install default config for the use on this unit test.
+ // Binary may install a custom config before tests are run.
+ absl::FlagsUsageConfig default_config;
+ default_config.normalize_filename = &NormalizeFileName;
+ absl::SetFlagsUsageConfig(default_config);
+ }
+
+ private:
+ flags::FlagSaver flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+using UsageReportingDeathTest = UsageReportingTest;
+
+TEST_F(UsageReportingDeathTest, TestSetProgramUsageMessage) {
+ EXPECT_EQ(absl::ProgramUsageMessage(), kTestUsageMessage);
+
+#ifndef _WIN32
+ // TODO(rogeeff): figure out why this does not work on Windows.
+ EXPECT_DEATH(absl::SetProgramUsageMessage("custom usage message"),
+ ".*SetProgramUsageMessage\\(\\) called twice.*");
+#endif
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_01) {
+ const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_01");
+ std::stringstream test_buf;
+
+ flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
+ EXPECT_EQ(
+ test_buf.str(),
+ R"( -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+)");
+}
+
+TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_02) {
+ const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_02");
+ std::stringstream test_buf;
+
+ flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
+ EXPECT_EQ(
+ test_buf.str(),
+ R"( -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+)");
+}
+
+TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_03) {
+ const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_03");
+ std::stringstream test_buf;
+
+ flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
+ EXPECT_EQ(
+ test_buf.str(),
+ R"( -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+)");
+}
+
+TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_04) {
+ const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_04");
+ std::stringstream test_buf;
+
+ flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
+ EXPECT_EQ(
+ test_buf.str(),
+ R"( -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+)");
+}
+
+TEST_F(UsageReportingTest, TestFlagHelpHRF_on_flag_05) {
+ const auto* flag = flags::FindCommandLineFlag("usage_reporting_test_flag_05");
+ std::stringstream test_buf;
+
+ flags::FlagHelp(test_buf, *flag, flags::HelpFormat::kHumanReadable);
+ EXPECT_EQ(
+ test_buf.str(),
+ R"( -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
+ std::string usage_test_flags_out =
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+)";
+
+ std::stringstream test_buf_01;
+ flags::FlagsHelp(test_buf_01, "usage_test.cc",
+ flags::HelpFormat::kHumanReadable, kTestUsageMessage);
+ EXPECT_EQ(test_buf_01.str(), usage_test_flags_out);
+
+ std::stringstream test_buf_02;
+ flags::FlagsHelp(test_buf_02, "flags/internal/usage_test.cc",
+ flags::HelpFormat::kHumanReadable, kTestUsageMessage);
+ EXPECT_EQ(test_buf_02.str(), usage_test_flags_out);
+
+ std::stringstream test_buf_03;
+ flags::FlagsHelp(test_buf_03, "usage_test", flags::HelpFormat::kHumanReadable,
+ kTestUsageMessage);
+ EXPECT_EQ(test_buf_03.str(), usage_test_flags_out);
+
+ std::stringstream test_buf_04;
+ flags::FlagsHelp(test_buf_04, "flags/invalid_file_name.cc",
+ flags::HelpFormat::kHumanReadable, kTestUsageMessage);
+ EXPECT_EQ(test_buf_04.str(),
+ R"(usage_test: Custom usage message
+
+ No modules matched: use -helpfull
+)");
+
+ std::stringstream test_buf_05;
+ flags::FlagsHelp(test_buf_05, "", flags::HelpFormat::kHumanReadable,
+ kTestUsageMessage);
+ std::string test_out = test_buf_05.str();
+ absl::string_view test_out_str(test_out);
+ EXPECT_TRUE(
+ absl::StartsWith(test_out_str, "usage_test: Custom usage message"));
+ EXPECT_TRUE(absl::StrContains(
+ test_out_str, "Flags from absl/flags/internal/usage_test.cc:"));
+ EXPECT_TRUE(absl::StrContains(test_out_str,
+ "Flags from absl/flags/internal/usage.cc:"));
+ EXPECT_TRUE(
+ absl::StrContains(test_out_str, "-usage_reporting_test_flag_01 "));
+ EXPECT_TRUE(absl::StrContains(test_out_str, "-help (show help"))
+ << test_out_str;
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestNoUsageFlags) {
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), -1);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
+ absl::SetFlag(&FLAGS_helpshort, true);
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_help) {
+ absl::SetFlag(&FLAGS_help, true);
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+
+Try --helpfull to get a list of all flags.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
+ absl::SetFlag(&FLAGS_helppackage, true);
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+
+Try --helpfull to get a list of all flags.
+)");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_version) {
+ absl::SetFlag(&FLAGS_version, true);
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
+#ifndef NDEBUG
+ EXPECT_EQ(test_buf.str(), "usage_test\nDebug build (NDEBUG not #defined)\n");
+#else
+ EXPECT_EQ(test_buf.str(), "usage_test\n");
+#endif
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_only_check_args) {
+ absl::SetFlag(&FLAGS_only_check_args, true);
+
+ std::stringstream test_buf;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage), 0);
+ EXPECT_EQ(test_buf.str(), "");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(UsageReportingTest, TestUsageFlag_helpon) {
+ absl::SetFlag(&FLAGS_helpon, "bla-bla");
+
+ std::stringstream test_buf_01;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf_01, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf_01.str(),
+ R"(usage_test: Custom usage message
+
+ No modules matched: use -helpfull
+)");
+
+ absl::SetFlag(&FLAGS_helpon, "usage_test");
+
+ std::stringstream test_buf_02;
+ EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage), 1);
+ EXPECT_EQ(test_buf_02.str(),
+ R"(usage_test: Custom usage message
+
+ Flags from absl/flags/internal/usage_test.cc:
+ -usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
+ default: 101;
+ -usage_reporting_test_flag_02 (usage_reporting_test_flag_02 help message);
+ default: false;
+ -usage_reporting_test_flag_03 (usage_reporting_test_flag_03 help message);
+ default: 1.03;
+ -usage_reporting_test_flag_04 (usage_reporting_test_flag_04 help message);
+ default: 1000000000000004;
+ -usage_reporting_test_flag_05 (usage_reporting_test_flag_05 help message);
+ default: UDT{};
+ -usage_reporting_test_flag_06 (usage_reporting_test_flag_06 help message.
+
+ Some more help.
+ Even more long long long long long long long long long long long long help
+ message.); default: "";
+)");
+}
+
+// --------------------------------------------------------------------
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ absl::GetFlag(FLAGS_undefok); // Force linking of parse.cc
+ flags::SetProgramInvocationName("usage_test");
+ absl::SetProgramUsageMessage(kTestUsageMessage);
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/absl/flags/marshalling.cc b/absl/flags/marshalling.cc
new file mode 100644
index 00000000..71b01d77
--- /dev/null
+++ b/absl/flags/marshalling.cc
@@ -0,0 +1,191 @@
+//
+// 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.
+
+#include "absl/flags/marshalling.h"
+
+#include <limits>
+
+#include "absl/base/macros.h"
+#include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/str_split.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// --------------------------------------------------------------------
+// AbslParseFlag specializations for boolean type.
+
+bool AbslParseFlag(absl::string_view text, bool* dst, std::string*) {
+ const char* kTrue[] = {"1", "t", "true", "y", "yes"};
+ const char* kFalse[] = {"0", "f", "false", "n", "no"};
+ static_assert(sizeof(kTrue) == sizeof(kFalse), "true_false_equal");
+
+ text = absl::StripAsciiWhitespace(text);
+
+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kTrue); ++i) {
+ if (absl::EqualsIgnoreCase(text, kTrue[i])) {
+ *dst = true;
+ return true;
+ } else if (absl::EqualsIgnoreCase(text, kFalse[i])) {
+ *dst = false;
+ return true;
+ }
+ }
+ return false; // didn't match a legal input
+}
+
+// --------------------------------------------------------------------
+// AbslParseFlag for integral types.
+
+// Return the base to use for parsing text as an integer. Leading 0x
+// puts us in base 16. But leading 0 does not put us in base 8. It
+// caused too many bugs when we had that behavior.
+static int NumericBase(absl::string_view text) {
+ const bool hex = (text.size() >= 2 && text[0] == '0' &&
+ (text[1] == 'x' || text[1] == 'X'));
+ return hex ? 16 : 10;
+}
+
+template <typename IntType>
+inline bool ParseFlagImpl(absl::string_view text, IntType* dst) {
+ text = absl::StripAsciiWhitespace(text);
+
+ return absl::numbers_internal::safe_strtoi_base(text, dst, NumericBase(text));
+}
+
+bool AbslParseFlag(absl::string_view text, short* dst, std::string*) {
+ int val;
+ if (!ParseFlagImpl(text, &val)) return false;
+ if (static_cast<short>(val) != val) // worked, but number out of range
+ return false;
+ *dst = static_cast<short>(val);
+ return true;
+}
+
+bool AbslParseFlag(absl::string_view text, unsigned short* dst, std::string*) {
+ unsigned int val;
+ if (!ParseFlagImpl(text, &val)) return false;
+ if (static_cast<unsigned short>(val) !=
+ val) // worked, but number out of range
+ return false;
+ *dst = static_cast<unsigned short>(val);
+ return true;
+}
+
+bool AbslParseFlag(absl::string_view text, int* dst, std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, unsigned int* dst, std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, long* dst, std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, unsigned long* dst, std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, long long* dst, std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, unsigned long long* dst,
+ std::string*) {
+ return ParseFlagImpl(text, dst);
+}
+
+// --------------------------------------------------------------------
+// AbslParseFlag for floating point types.
+
+bool AbslParseFlag(absl::string_view text, float* dst, std::string*) {
+ return absl::SimpleAtof(text, dst);
+}
+
+bool AbslParseFlag(absl::string_view text, double* dst, std::string*) {
+ return absl::SimpleAtod(text, dst);
+}
+
+// --------------------------------------------------------------------
+// AbslParseFlag for strings.
+
+bool AbslParseFlag(absl::string_view text, std::string* dst, std::string*) {
+ dst->assign(text.data(), text.size());
+ return true;
+}
+
+// --------------------------------------------------------------------
+// AbslParseFlag for vector of strings.
+
+bool AbslParseFlag(absl::string_view text, std::vector<std::string>* dst,
+ std::string*) {
+ // An empty flag value corresponds to an empty vector, not a vector
+ // with a single, empty std::string.
+ if (text.empty()) {
+ dst->clear();
+ return true;
+ }
+ *dst = absl::StrSplit(text, ',', absl::AllowEmpty());
+ return true;
+}
+
+// --------------------------------------------------------------------
+// AbslUnparseFlag specializations for various builtin flag types.
+
+std::string Unparse(bool v) { return v ? "true" : "false"; }
+std::string Unparse(short v) { return absl::StrCat(v); }
+std::string Unparse(unsigned short v) { return absl::StrCat(v); }
+std::string Unparse(int v) { return absl::StrCat(v); }
+std::string Unparse(unsigned int v) { return absl::StrCat(v); }
+std::string Unparse(long v) { return absl::StrCat(v); }
+std::string Unparse(unsigned long v) { return absl::StrCat(v); }
+std::string Unparse(long long v) { return absl::StrCat(v); }
+std::string Unparse(unsigned long long v) { return absl::StrCat(v); }
+template <typename T>
+std::string UnparseFloatingPointVal(T v) {
+ // digits10 is guaranteed to roundtrip correctly in std::string -> value -> std::string
+ // conversions, but may not be enough to represent all the values correctly.
+ std::string digit10_str =
+ absl::StrFormat("%.*g", std::numeric_limits<T>::digits10, v);
+ if (std::isnan(v) || std::isinf(v)) return digit10_str;
+
+ T roundtrip_val = 0;
+ std::string err;
+ if (absl::ParseFlag(digit10_str, &roundtrip_val, &err) &&
+ roundtrip_val == v) {
+ return digit10_str;
+ }
+
+ // max_digits10 is the number of base-10 digits that are necessary to uniquely
+ // represent all distinct values.
+ return absl::StrFormat("%.*g", std::numeric_limits<T>::max_digits10, v);
+}
+std::string Unparse(float v) { return UnparseFloatingPointVal(v); }
+std::string Unparse(double v) { return UnparseFloatingPointVal(v); }
+std::string AbslUnparseFlag(absl::string_view v) { return std::string(v); }
+std::string AbslUnparseFlag(const std::vector<std::string>& v) {
+ return absl::StrJoin(v, ",");
+}
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h
new file mode 100644
index 00000000..5598d444
--- /dev/null
+++ b/absl/flags/marshalling.h
@@ -0,0 +1,255 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: marshalling.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the API for extending Abseil flag support to
+// custom types, and defines the set of overloads for fundamental types.
+//
+// Out of the box, the Abseil flags library supports the following types:
+//
+// * `bool`
+// * `int16_t`
+// * `uint16_t`
+// * `int32_t`
+// * `uint32_t`
+// * `int64_t`
+// * `uint64_t`
+// * `float`
+// * `double`
+// * `std::string`
+// * `std::vector<std::string>`
+//
+// Note that support for integral types is implemented using overloads for
+// variable-width fundamental types (`short`, `int`, `long`, etc.). However,
+// you should prefer the fixed-width integral types (`int32_t`, `uint64_t`,
+// etc.) we've noted above within flag definitions.
+
+//
+// In addition, several Abseil libraries provide their own custom support for
+// Abseil flags.
+//
+// The Abseil time library provides the following support for civil time values:
+//
+// * `absl::CivilSecond`
+// * `absl::CivilMinute`
+// * `absl::CivilHour`
+// * `absl::CivilDay`
+// * `absl::CivilMonth`
+// * `absl::CivilYear`
+//
+// and also provides support for the following absolute time values:
+//
+// * `absl::Duration`
+// * `absl::Time`
+//
+// Additional support for Abseil types will be noted here as it is added.
+//
+// You can also provide your own custom flags by adding overloads for
+// `AbslParseFlag()` and `AbslUnparseFlag()` to your type definitions. (See
+// below.)
+//
+// -----------------------------------------------------------------------------
+// Adding Type Support for Abseil Flags
+// -----------------------------------------------------------------------------
+//
+// To add support for your user-defined type, add overloads of `AbslParseFlag()`
+// and `AbslUnparseFlag()` as free (non-member) functions to your type. If `T`
+// is a class type, these functions can be friend function definitions. These
+// overloads must be added to the same namespace where the type is defined, so
+// that they can be discovered by Argument-Dependent Lookup (ADL).
+//
+// Example:
+//
+// namespace foo {
+//
+// enum OutputMode { kPlainText, kHtml };
+//
+// // AbslParseFlag converts from a string to OutputMode.
+// // Must be in same namespace as OutputMode.
+//
+// // Parses an OutputMode from the command line flag value `text. Returns
+// // `true` and sets `*mode` on success; returns `false` and sets `*error`
+// // on failure.
+// bool AbslParseFlag(absl::string_view text,
+// OutputMode* mode,
+// std::string* error) {
+// if (text == "plaintext") {
+// *mode = kPlainText;
+// return true;
+// }
+// if (text == "html") {
+// *mode = kHtml;
+// return true;
+// }
+// *error = "unknown value for enumeration";
+// return false;
+// }
+//
+// // AbslUnparseFlag converts from an OutputMode to a string.
+// // Must be in same namespace as OutputMode.
+//
+// // Returns a textual flag value corresponding to the OutputMode `mode`.
+// std::string AbslUnparseFlag(OutputMode mode) {
+// switch (mode) {
+// case kPlainText: return "plaintext";
+// case kHtml: return "html";
+// }
+// return absl::StrCat(mode);
+// }
+//
+// Notice that neither `AbslParseFlag()` nor `AbslUnparseFlag()` are class
+// members, but free functions. `AbslParseFlag/AbslUnparseFlag()` overloads
+// for a type should only be declared in the same file and namespace as said
+// type. The proper `AbslParseFlag/AbslUnparseFlag()` implementations for a
+// given type will be discovered via Argument-Dependent Lookup (ADL).
+//
+// `AbslParseFlag()` may need, in turn, to parse simpler constituent types
+// using `absl::ParseFlag()`. For example, a custom struct `MyFlagType`
+// consisting of a `std::pair<int, std::string>` would add an `AbslParseFlag()`
+// overload for its `MyFlagType` like so:
+//
+// Example:
+//
+// namespace my_flag_type {
+//
+// struct MyFlagType {
+// std::pair<int, std::string> my_flag_data;
+// };
+//
+// bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
+// std::string* err);
+//
+// std::string AbslUnparseFlag(const MyFlagType&);
+//
+// // Within the implementation, `AbslParseFlag()` will, in turn invoke
+// // `absl::ParseFlag()` on its constituent `int` and `std::string` types
+// // (which have built-in Abseil flag support.
+//
+// bool AbslParseFlag(absl::string_view text, MyFlagType* flag,
+// std::string* err) {
+// std::pair<absl::string_view, absl::string_view> tokens =
+// absl::StrSplit(text, ',');
+// if (!absl::ParseFlag(tokens.first, &flag->my_flag_data.first, err))
+// return false;
+// if (!absl::ParseFlag(tokens.second, &flag->my_flag_data.second, err))
+// return false;
+// return true;
+// }
+//
+// // Similarly, for unparsing, we can simply invoke `absl::UnparseFlag()` on
+// // the constituent types.
+// std::string AbslUnparseFlag(const MyFlagType& flag) {
+// return absl::StrCat(absl::UnparseFlag(flag.my_flag_data.first),
+// ",",
+// absl::UnparseFlag(flag.my_flag_data.second));
+// }
+#ifndef ABSL_FLAGS_MARSHALLING_H_
+#define ABSL_FLAGS_MARSHALLING_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+// Overloads of `AbslParseFlag()` and `AbslUnparseFlag()` for fundamental types.
+bool AbslParseFlag(absl::string_view, bool*, std::string*);
+bool AbslParseFlag(absl::string_view, short*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, unsigned short*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, int*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, unsigned int*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, long*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, unsigned long*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, long long*, std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, unsigned long long*,
+ std::string*); // NOLINT
+bool AbslParseFlag(absl::string_view, float*, std::string*);
+bool AbslParseFlag(absl::string_view, double*, std::string*);
+bool AbslParseFlag(absl::string_view, std::string*, std::string*);
+bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*);
+
+template <typename T>
+bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) {
+ // Comment on next line provides a good compiler error message if T
+ // does not have AbslParseFlag(absl::string_view, T*, std::string*).
+ return AbslParseFlag(input, dst, err); // Is T missing AbslParseFlag?
+}
+
+// Strings and std:: containers do not have the same overload resolution
+// considerations as fundamental types. Naming these 'AbslUnparseFlag' means we
+// can avoid the need for additional specializations of Unparse (below).
+std::string AbslUnparseFlag(absl::string_view v);
+std::string AbslUnparseFlag(const std::vector<std::string>&);
+
+template <typename T>
+std::string Unparse(const T& v) {
+ // Comment on next line provides a good compiler error message if T does not
+ // have UnparseFlag.
+ return AbslUnparseFlag(v); // Is T missing AbslUnparseFlag?
+}
+
+// Overloads for builtin types.
+std::string Unparse(bool v);
+std::string Unparse(short v); // NOLINT
+std::string Unparse(unsigned short v); // NOLINT
+std::string Unparse(int v); // NOLINT
+std::string Unparse(unsigned int v); // NOLINT
+std::string Unparse(long v); // NOLINT
+std::string Unparse(unsigned long v); // NOLINT
+std::string Unparse(long long v); // NOLINT
+std::string Unparse(unsigned long long v); // NOLINT
+std::string Unparse(float v);
+std::string Unparse(double v);
+
+} // namespace flags_internal
+
+// ParseFlag()
+//
+// Parses a string value into a flag value of type `T`. Do not add overloads of
+// this function for your type directly; instead, add an `AbslParseFlag()`
+// free function as documented above.
+//
+// Some implementations of `AbslParseFlag()` for types which consist of other,
+// constituent types which already have Abseil flag support, may need to call
+// `absl::ParseFlag()` on those consituent string values. (See above.)
+template <typename T>
+inline bool ParseFlag(absl::string_view input, T* dst, std::string* error) {
+ return flags_internal::InvokeParseFlag(input, dst, error);
+}
+
+// UnparseFlag()
+//
+// Unparses a flag value of type `T` into a string value. Do not add overloads
+// of this function for your type directly; instead, add an `AbslUnparseFlag()`
+// free function as documented above.
+//
+// Some implementations of `AbslUnparseFlag()` for types which consist of other,
+// constituent types which already have Abseil flag support, may want to call
+// `absl::UnparseFlag()` on those constituent types. (See above.)
+template <typename T>
+inline std::string UnparseFlag(const T& v) {
+ return flags_internal::Unparse(v);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_MARSHALLING_H_
diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc
new file mode 100644
index 00000000..37cd1940
--- /dev/null
+++ b/absl/flags/marshalling_test.cc
@@ -0,0 +1,899 @@
+//
+// 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.
+
+#include "absl/flags/marshalling.h"
+
+#include <cmath>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(MarshallingTest, TestBoolParsing) {
+ std::string err;
+ bool value;
+
+ // True values.
+ EXPECT_TRUE(absl::ParseFlag("True", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("true", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("TRUE", &value, &err));
+ EXPECT_TRUE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("Yes", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("yes", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("YES", &value, &err));
+ EXPECT_TRUE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("t", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("T", &value, &err));
+ EXPECT_TRUE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("y", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("Y", &value, &err));
+ EXPECT_TRUE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_TRUE(value);
+
+ // False values.
+ EXPECT_TRUE(absl::ParseFlag("False", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("false", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("FALSE", &value, &err));
+ EXPECT_FALSE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("No", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("no", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("NO", &value, &err));
+ EXPECT_FALSE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("f", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("F", &value, &err));
+ EXPECT_FALSE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("n", &value, &err));
+ EXPECT_FALSE(value);
+ EXPECT_TRUE(absl::ParseFlag("N", &value, &err));
+ EXPECT_FALSE(value);
+
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_FALSE(value);
+
+ // Whitespace handling.
+ EXPECT_TRUE(absl::ParseFlag(" true", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag("true ", &value, &err));
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(absl::ParseFlag(" true ", &value, &err));
+ EXPECT_TRUE(value);
+
+ // Invalid input.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("11", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("tt", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt16Parsing) {
+ std::string err;
+ int16_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_EQ(value, -1);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("-18765", &value, &err));
+ EXPECT_EQ(value, -18765);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, 3);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("-001", &value, &err));
+ EXPECT_EQ(value, -1);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, 100);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err));
+ EXPECT_EQ(value, 564);
+ // TODO(rogeeff): fix below validations
+ EXPECT_FALSE(absl::ParseFlag("-0x7FFD", &value, &err));
+ EXPECT_NE(value, -3);
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+ EXPECT_TRUE(absl::ParseFlag(" 0x22 ", &value, &err));
+ EXPECT_EQ(value, 34);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("40000", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint16Parsing) {
+ std::string err;
+ uint16_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, 3);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("001", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, 100);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err));
+ EXPECT_EQ(value, 564);
+ // TODO(rogeeff): fix below validations
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+ EXPECT_TRUE(absl::ParseFlag(" 0x22 ", &value, &err));
+ EXPECT_EQ(value, 34);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("70000", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt32Parsing) {
+ std::string err;
+ int32_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_EQ(value, -1);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err));
+ EXPECT_EQ(value, -98765);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, 3);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("-001", &value, &err));
+ EXPECT_EQ(value, -1);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, 100);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err));
+ EXPECT_EQ(value, 564);
+ // TODO(rogeeff): fix below validations
+ EXPECT_FALSE(absl::ParseFlag("-0x7FFFFFFD", &value, &err));
+ EXPECT_NE(value, -3);
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+ EXPECT_TRUE(absl::ParseFlag(" 0x22 ", &value, &err));
+ EXPECT_EQ(value, 34);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("70000000000", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint32Parsing) {
+ std::string err;
+ uint32_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, 3);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, 100);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0X234", &value, &err));
+ EXPECT_EQ(value, 564);
+ EXPECT_TRUE(absl::ParseFlag("0xFFFFFFFD", &value, &err));
+ EXPECT_EQ(value, 4294967293);
+ // TODO(rogeeff): fix below validations
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+ EXPECT_TRUE(absl::ParseFlag(" 0x22 ", &value, &err));
+ EXPECT_EQ(value, 34);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("140000000000", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt64Parsing) {
+ std::string err;
+ int64_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_EQ(value, -1);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("-98765", &value, &err));
+ EXPECT_EQ(value, -98765);
+ EXPECT_TRUE(absl::ParseFlag("+3", &value, &err));
+ EXPECT_EQ(value, 3);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("001", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0000100", &value, &err));
+ EXPECT_EQ(value, 100);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0XFFFAAABBBCCCDDD", &value, &err));
+ EXPECT_EQ(value, 1152827684197027293);
+ // TODO(rogeeff): fix below validation
+ EXPECT_FALSE(absl::ParseFlag("-0x7FFFFFFFFFFFFFFE", &value, &err));
+ EXPECT_NE(value, -2);
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+ EXPECT_TRUE(absl::ParseFlag(" 0x7F ", &value, &err));
+ EXPECT_EQ(value, 127);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("0xFFFFFFFFFFFFFFFFFF", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUInt64Parsing) {
+ std::string err;
+ uint64_t value;
+
+ // Decimal values.
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0", &value, &err));
+ EXPECT_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("123", &value, &err));
+ EXPECT_EQ(value, 123);
+ EXPECT_TRUE(absl::ParseFlag("+13", &value, &err));
+ EXPECT_EQ(value, 13);
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("001", &value, &err));
+ EXPECT_EQ(value, 1);
+ EXPECT_TRUE(absl::ParseFlag("0000300", &value, &err));
+ EXPECT_EQ(value, 300);
+
+ // Hex values.
+ EXPECT_TRUE(absl::ParseFlag("0x10", &value, &err));
+ EXPECT_EQ(value, 16);
+ EXPECT_TRUE(absl::ParseFlag("0XFFFF", &value, &err));
+ EXPECT_EQ(value, 65535);
+ // TODO(rogeeff): fix below validation
+ EXPECT_FALSE(absl::ParseFlag("+0x31", &value, &err));
+ EXPECT_NE(value, 49);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10 ", &value, &err));
+ EXPECT_EQ(value, 10);
+ EXPECT_TRUE(absl::ParseFlag(" 11", &value, &err));
+ EXPECT_EQ(value, 11);
+ EXPECT_TRUE(absl::ParseFlag(" 012 ", &value, &err));
+ EXPECT_EQ(value, 12);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("0xFFFFFFFFFFFFFFFFFF", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("-1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2U", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("FFF", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestFloatParsing) {
+ std::string err;
+ float value;
+
+ // Ordinary values.
+ EXPECT_TRUE(absl::ParseFlag("1.3", &value, &err));
+ EXPECT_FLOAT_EQ(value, 1.3f);
+ EXPECT_TRUE(absl::ParseFlag("-0.1", &value, &err));
+ EXPECT_DOUBLE_EQ(value, -0.1f);
+ EXPECT_TRUE(absl::ParseFlag("+0.01", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.01f);
+
+ // Scientific values.
+ EXPECT_TRUE(absl::ParseFlag("1.2e3", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 1.2e3f);
+ EXPECT_TRUE(absl::ParseFlag("9.8765402e-37", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 9.8765402e-37f);
+ EXPECT_TRUE(absl::ParseFlag("0.11e+3", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.11e+3f);
+ EXPECT_TRUE(absl::ParseFlag("1.e-2300", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.f);
+ EXPECT_TRUE(absl::ParseFlag("1.e+2300", &value, &err));
+ EXPECT_TRUE(std::isinf(value));
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01.6", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 1.6f);
+ EXPECT_TRUE(absl::ParseFlag("000.0001", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.0001f);
+
+ // Trailing zero values.
+ EXPECT_TRUE(absl::ParseFlag("-5.1000", &value, &err));
+ EXPECT_DOUBLE_EQ(value, -5.1f);
+
+ // Exceptional values.
+ EXPECT_TRUE(absl::ParseFlag("NaN", &value, &err));
+ EXPECT_TRUE(std::isnan(value));
+ EXPECT_TRUE(absl::ParseFlag("Inf", &value, &err));
+ EXPECT_TRUE(std::isinf(value));
+
+ // Hex values
+ EXPECT_TRUE(absl::ParseFlag("0x10.23p12", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 66096.f);
+ EXPECT_TRUE(absl::ParseFlag("-0xF1.A3p-2", &value, &err));
+ EXPECT_NEAR(value, -60.4092f, 5e-5f);
+ EXPECT_TRUE(absl::ParseFlag("+0x0.0AAp-12", &value, &err));
+ EXPECT_NEAR(value, 1.01328e-05f, 5e-11f);
+ EXPECT_TRUE(absl::ParseFlag("0x.01p1", &value, &err));
+ EXPECT_NEAR(value, 0.0078125f, 5e-8f);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10.1 ", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 10.1f);
+ EXPECT_TRUE(absl::ParseFlag(" 2.34", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 2.34f);
+ EXPECT_TRUE(absl::ParseFlag(" 5.7 ", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 5.7f);
+ EXPECT_TRUE(absl::ParseFlag(" -0xE0.F3p01 ", &value, &err));
+ EXPECT_NEAR(value, -449.8984375f, 5e-8f);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2.3xxx", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("0x0.1pAA", &value, &err));
+ // TODO(rogeeff): below assertion should fail
+ EXPECT_TRUE(absl::ParseFlag("0x0.1", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestDoubleParsing) {
+ std::string err;
+ double value;
+
+ // Ordinary values.
+ EXPECT_TRUE(absl::ParseFlag("1.3", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 1.3);
+ EXPECT_TRUE(absl::ParseFlag("-0.1", &value, &err));
+ EXPECT_DOUBLE_EQ(value, -0.1);
+ EXPECT_TRUE(absl::ParseFlag("+0.01", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.01);
+
+ // Scientific values.
+ EXPECT_TRUE(absl::ParseFlag("1.2e3", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 1.2e3);
+ EXPECT_TRUE(absl::ParseFlag("9.00000002e-123", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 9.00000002e-123);
+ EXPECT_TRUE(absl::ParseFlag("0.11e+3", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.11e+3);
+ EXPECT_TRUE(absl::ParseFlag("1.e-2300", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0);
+ EXPECT_TRUE(absl::ParseFlag("1.e+2300", &value, &err));
+ EXPECT_TRUE(std::isinf(value));
+
+ // Leading zero values.
+ EXPECT_TRUE(absl::ParseFlag("01.6", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 1.6);
+ EXPECT_TRUE(absl::ParseFlag("000.0001", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 0.0001);
+
+ // Trailing zero values.
+ EXPECT_TRUE(absl::ParseFlag("-5.1000", &value, &err));
+ EXPECT_DOUBLE_EQ(value, -5.1);
+
+ // Exceptional values.
+ EXPECT_TRUE(absl::ParseFlag("NaN", &value, &err));
+ EXPECT_TRUE(std::isnan(value));
+ EXPECT_TRUE(absl::ParseFlag("nan", &value, &err));
+ EXPECT_TRUE(std::isnan(value));
+ EXPECT_TRUE(absl::ParseFlag("Inf", &value, &err));
+ EXPECT_TRUE(std::isinf(value));
+ EXPECT_TRUE(absl::ParseFlag("inf", &value, &err));
+ EXPECT_TRUE(std::isinf(value));
+
+ // Hex values
+ EXPECT_TRUE(absl::ParseFlag("0x10.23p12", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 66096);
+ EXPECT_TRUE(absl::ParseFlag("-0xF1.A3p-2", &value, &err));
+ EXPECT_NEAR(value, -60.4092, 5e-5);
+ EXPECT_TRUE(absl::ParseFlag("+0x0.0AAp-12", &value, &err));
+ EXPECT_NEAR(value, 1.01328e-05, 5e-11);
+ EXPECT_TRUE(absl::ParseFlag("0x.01p1", &value, &err));
+ EXPECT_NEAR(value, 0.0078125, 5e-8);
+
+ // Whitespace handling
+ EXPECT_TRUE(absl::ParseFlag("10.1 ", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 10.1);
+ EXPECT_TRUE(absl::ParseFlag(" 2.34", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 2.34);
+ EXPECT_TRUE(absl::ParseFlag(" 5.7 ", &value, &err));
+ EXPECT_DOUBLE_EQ(value, 5.7);
+ EXPECT_TRUE(absl::ParseFlag(" -0xE0.F3p01 ", &value, &err));
+ EXPECT_NEAR(value, -449.8984375, 5e-8);
+
+ // Invalid values.
+ EXPECT_FALSE(absl::ParseFlag("", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("--1", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("2.3xxx", &value, &err));
+ EXPECT_FALSE(absl::ParseFlag("0x0.1pAA", &value, &err));
+ // TODO(rogeeff): below assertion should fail
+ EXPECT_TRUE(absl::ParseFlag("0x0.1", &value, &err));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestStringParsing) {
+ std::string err;
+ std::string value;
+
+ EXPECT_TRUE(absl::ParseFlag("", &value, &err));
+ EXPECT_EQ(value, "");
+ EXPECT_TRUE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_EQ(value, " ");
+ EXPECT_TRUE(absl::ParseFlag(" ", &value, &err));
+ EXPECT_EQ(value, " ");
+ EXPECT_TRUE(absl::ParseFlag("\n", &value, &err));
+ EXPECT_EQ(value, "\n");
+ EXPECT_TRUE(absl::ParseFlag("\t", &value, &err));
+ EXPECT_EQ(value, "\t");
+ EXPECT_TRUE(absl::ParseFlag("asdfg", &value, &err));
+ EXPECT_EQ(value, "asdfg");
+ EXPECT_TRUE(absl::ParseFlag("asdf ghjk", &value, &err));
+ EXPECT_EQ(value, "asdf ghjk");
+ EXPECT_TRUE(absl::ParseFlag("a\nb\nc", &value, &err));
+ EXPECT_EQ(value, "a\nb\nc");
+ EXPECT_TRUE(absl::ParseFlag("asd\0fgh", &value, &err));
+ EXPECT_EQ(value, "asd");
+ EXPECT_TRUE(absl::ParseFlag("\\\\", &value, &err));
+ EXPECT_EQ(value, "\\\\");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestVectorOfStringParsing) {
+ std::string err;
+ std::vector<std::string> value;
+
+ EXPECT_TRUE(absl::ParseFlag("", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>{});
+ EXPECT_TRUE(absl::ParseFlag("1", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"1"}));
+ EXPECT_TRUE(absl::ParseFlag("a,b", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"a", "b"}));
+ EXPECT_TRUE(absl::ParseFlag("a,b,c,", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"a", "b", "c", ""}));
+ EXPECT_TRUE(absl::ParseFlag("a,,", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"a", "", ""}));
+ EXPECT_TRUE(absl::ParseFlag(",", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"", ""}));
+ EXPECT_TRUE(absl::ParseFlag("a, b,c ", &value, &err));
+ EXPECT_EQ(value, std::vector<std::string>({"a", " b", "c "}));
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestBoolUnparsing) {
+ EXPECT_EQ(absl::UnparseFlag(true), "true");
+ EXPECT_EQ(absl::UnparseFlag(false), "false");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt16Unparsing) {
+ int16_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = -1;
+ EXPECT_EQ(absl::UnparseFlag(value), "-1");
+ value = 9876;
+ EXPECT_EQ(absl::UnparseFlag(value), "9876");
+ value = -987;
+ EXPECT_EQ(absl::UnparseFlag(value), "-987");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint16Unparsing) {
+ uint16_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = 19876;
+ EXPECT_EQ(absl::UnparseFlag(value), "19876");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt32Unparsing) {
+ int32_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = -1;
+ EXPECT_EQ(absl::UnparseFlag(value), "-1");
+ value = 12345;
+ EXPECT_EQ(absl::UnparseFlag(value), "12345");
+ value = -987;
+ EXPECT_EQ(absl::UnparseFlag(value), "-987");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint32Unparsing) {
+ uint32_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = 1234500;
+ EXPECT_EQ(absl::UnparseFlag(value), "1234500");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestInt64Unparsing) {
+ int64_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = -1;
+ EXPECT_EQ(absl::UnparseFlag(value), "-1");
+ value = 123456789L;
+ EXPECT_EQ(absl::UnparseFlag(value), "123456789");
+ value = -987654321L;
+ EXPECT_EQ(absl::UnparseFlag(value), "-987654321");
+ value = 0x7FFFFFFFFFFFFFFF;
+ EXPECT_EQ(absl::UnparseFlag(value), "9223372036854775807");
+ value = 0xFFFFFFFFFFFFFFFF;
+ EXPECT_EQ(absl::UnparseFlag(value), "-1");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestUint64Unparsing) {
+ uint64_t value;
+
+ value = 1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1");
+ value = 0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = 123456789L;
+ EXPECT_EQ(absl::UnparseFlag(value), "123456789");
+ value = 0xFFFFFFFFFFFFFFFF;
+ EXPECT_EQ(absl::UnparseFlag(value), "18446744073709551615");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestFloatUnparsing) {
+ float value;
+
+ value = 1.1f;
+ EXPECT_EQ(absl::UnparseFlag(value), "1.1");
+ value = 0.01f;
+ EXPECT_EQ(absl::UnparseFlag(value), "0.01");
+ value = 1.23e-2f;
+ EXPECT_EQ(absl::UnparseFlag(value), "0.0123");
+ value = -0.71f;
+ EXPECT_EQ(absl::UnparseFlag(value), "-0.71");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestDoubleUnparsing) {
+ double value;
+
+ value = 1.1;
+ EXPECT_EQ(absl::UnparseFlag(value), "1.1");
+ value = 0.01;
+ EXPECT_EQ(absl::UnparseFlag(value), "0.01");
+ value = 1.23e-2;
+ EXPECT_EQ(absl::UnparseFlag(value), "0.0123");
+ value = -0.71;
+ EXPECT_EQ(absl::UnparseFlag(value), "-0.71");
+ value = -0;
+ EXPECT_EQ(absl::UnparseFlag(value), "0");
+ value = std::nan("");
+ EXPECT_EQ(absl::UnparseFlag(value), "nan");
+ value = std::numeric_limits<double>::infinity();
+ EXPECT_EQ(absl::UnparseFlag(value), "inf");
+}
+
+// --------------------------------------------------------------------
+
+TEST(MarshallingTest, TestStringUnparsing) {
+ EXPECT_EQ(absl::UnparseFlag(""), "");
+ EXPECT_EQ(absl::UnparseFlag(" "), " ");
+ EXPECT_EQ(absl::UnparseFlag("qwerty"), "qwerty");
+ EXPECT_EQ(absl::UnparseFlag("ASDFGH"), "ASDFGH");
+ EXPECT_EQ(absl::UnparseFlag("\n\t "), "\n\t ");
+}
+
+// --------------------------------------------------------------------
+
+template <typename T>
+void TestRoundtrip(T v) {
+ T new_v;
+ std::string err;
+ EXPECT_TRUE(absl::ParseFlag(absl::UnparseFlag(v), &new_v, &err));
+ EXPECT_EQ(new_v, v);
+}
+
+TEST(MarshallingTest, TestFloatRoundTrip) {
+ TestRoundtrip(0.1f);
+ TestRoundtrip(0.12f);
+ TestRoundtrip(0.123f);
+ TestRoundtrip(0.1234f);
+ TestRoundtrip(0.12345f);
+ TestRoundtrip(0.123456f);
+ TestRoundtrip(0.1234567f);
+ TestRoundtrip(0.12345678f);
+
+ TestRoundtrip(0.1e20f);
+ TestRoundtrip(0.12e20f);
+ TestRoundtrip(0.123e20f);
+ TestRoundtrip(0.1234e20f);
+ TestRoundtrip(0.12345e20f);
+ TestRoundtrip(0.123456e20f);
+ TestRoundtrip(0.1234567e20f);
+ TestRoundtrip(0.12345678e20f);
+
+ TestRoundtrip(0.1e-20f);
+ TestRoundtrip(0.12e-20f);
+ TestRoundtrip(0.123e-20f);
+ TestRoundtrip(0.1234e-20f);
+ TestRoundtrip(0.12345e-20f);
+ TestRoundtrip(0.123456e-20f);
+ TestRoundtrip(0.1234567e-20f);
+ TestRoundtrip(0.12345678e-20f);
+}
+
+TEST(MarshallingTest, TestDoubleRoundTrip) {
+ TestRoundtrip(0.1);
+ TestRoundtrip(0.12);
+ TestRoundtrip(0.123);
+ TestRoundtrip(0.1234);
+ TestRoundtrip(0.12345);
+ TestRoundtrip(0.123456);
+ TestRoundtrip(0.1234567);
+ TestRoundtrip(0.12345678);
+ TestRoundtrip(0.123456789);
+ TestRoundtrip(0.1234567891);
+ TestRoundtrip(0.12345678912);
+ TestRoundtrip(0.123456789123);
+ TestRoundtrip(0.1234567891234);
+ TestRoundtrip(0.12345678912345);
+ TestRoundtrip(0.123456789123456);
+ TestRoundtrip(0.1234567891234567);
+ TestRoundtrip(0.12345678912345678);
+
+ TestRoundtrip(0.1e50);
+ TestRoundtrip(0.12e50);
+ TestRoundtrip(0.123e50);
+ TestRoundtrip(0.1234e50);
+ TestRoundtrip(0.12345e50);
+ TestRoundtrip(0.123456e50);
+ TestRoundtrip(0.1234567e50);
+ TestRoundtrip(0.12345678e50);
+ TestRoundtrip(0.123456789e50);
+ TestRoundtrip(0.1234567891e50);
+ TestRoundtrip(0.12345678912e50);
+ TestRoundtrip(0.123456789123e50);
+ TestRoundtrip(0.1234567891234e50);
+ TestRoundtrip(0.12345678912345e50);
+ TestRoundtrip(0.123456789123456e50);
+ TestRoundtrip(0.1234567891234567e50);
+ TestRoundtrip(0.12345678912345678e50);
+
+ TestRoundtrip(0.1e-50);
+ TestRoundtrip(0.12e-50);
+ TestRoundtrip(0.123e-50);
+ TestRoundtrip(0.1234e-50);
+ TestRoundtrip(0.12345e-50);
+ TestRoundtrip(0.123456e-50);
+ TestRoundtrip(0.1234567e-50);
+ TestRoundtrip(0.12345678e-50);
+ TestRoundtrip(0.123456789e-50);
+ TestRoundtrip(0.1234567891e-50);
+ TestRoundtrip(0.12345678912e-50);
+ TestRoundtrip(0.123456789123e-50);
+ TestRoundtrip(0.1234567891234e-50);
+ TestRoundtrip(0.12345678912345e-50);
+ TestRoundtrip(0.123456789123456e-50);
+ TestRoundtrip(0.1234567891234567e-50);
+ TestRoundtrip(0.12345678912345678e-50);
+}
+
+} // namespace
diff --git a/absl/flags/parse.cc b/absl/flags/parse.cc
new file mode 100644
index 00000000..fd80a0c8
--- /dev/null
+++ b/absl/flags/parse.cc
@@ -0,0 +1,755 @@
+//
+// 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.
+
+#include "absl/flags/parse.h"
+
+#include <stdlib.h>
+
+#include <fstream>
+#include <iostream>
+#include <tuple>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "absl/flags/flag.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/flags/internal/registry.h"
+#include "absl/flags/internal/usage.h"
+#include "absl/flags/usage.h"
+#include "absl/flags/usage_config.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/strip.h"
+#include "absl/synchronization/mutex.h"
+
+// --------------------------------------------------------------------
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+namespace {
+
+ABSL_CONST_INIT absl::Mutex processing_checks_guard(absl::kConstInit);
+
+ABSL_CONST_INIT bool flagfile_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+ABSL_CONST_INIT bool fromenv_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+ABSL_CONST_INIT bool tryfromenv_needs_processing
+ GUARDED_BY(processing_checks_guard) = false;
+
+} // namespace
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+ABSL_FLAG(std::vector<std::string>, flagfile, {},
+ "comma-separated list of files to load flags from")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_flagfile).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::flagfile_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING, "flagfile set twice before it is handled");
+ }
+
+ absl::flags_internal::flagfile_needs_processing = true;
+ });
+ABSL_FLAG(std::vector<std::string>, fromenv, {},
+ "comma-separated list of flags to set from the environment"
+ " [use 'export FLAGS_flag1=value']")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_fromenv).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::fromenv_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING, "fromenv set twice before it is handled.");
+ }
+
+ absl::flags_internal::fromenv_needs_processing = true;
+ });
+ABSL_FLAG(std::vector<std::string>, tryfromenv, {},
+ "comma-separated list of flags to try to set from the environment if "
+ "present")
+ .OnUpdate([]() {
+ if (absl::GetFlag(FLAGS_tryfromenv).empty()) return;
+
+ absl::MutexLock l(&absl::flags_internal::processing_checks_guard);
+
+ // Setting this flag twice before it is handled most likely an internal
+ // error and should be reviewed by developers.
+ if (absl::flags_internal::tryfromenv_needs_processing) {
+ ABSL_INTERNAL_LOG(WARNING,
+ "tryfromenv set twice before it is handled.");
+ }
+
+ absl::flags_internal::tryfromenv_needs_processing = true;
+ });
+
+ABSL_FLAG(std::vector<std::string>, undefok, {},
+ "comma-separated list of flag names that it is okay to specify "
+ "on the command line even if the program does not define a flag "
+ "with that name");
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+namespace {
+
+class ArgsList {
+ public:
+ ArgsList() : next_arg_(0) {}
+ ArgsList(int argc, char* argv[]) : args_(argv, argv + argc), next_arg_(0) {}
+ explicit ArgsList(const std::vector<std::string>& args)
+ : args_(args), next_arg_(0) {}
+
+ // Returns success status: true if parsing successful, false otherwise.
+ bool ReadFromFlagfile(const std::string& flag_file_name);
+
+ int Size() const { return args_.size() - next_arg_; }
+ int FrontIndex() const { return next_arg_; }
+ absl::string_view Front() const { return args_[next_arg_]; }
+ void PopFront() { next_arg_++; }
+
+ private:
+ std::vector<std::string> args_;
+ int next_arg_;
+};
+
+bool ArgsList::ReadFromFlagfile(const std::string& flag_file_name) {
+ std::ifstream flag_file(flag_file_name);
+
+ if (!flag_file) {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Can't open flagfile ", flag_file_name), true);
+
+ return false;
+ }
+
+ // This argument represents fake argv[0], which should be present in all arg
+ // lists.
+ args_.push_back("");
+
+ std::string line;
+ bool success = true;
+
+ while (std::getline(flag_file, line)) {
+ absl::string_view stripped = absl::StripLeadingAsciiWhitespace(line);
+
+ if (stripped.empty() || stripped[0] == '#') {
+ // Comment or empty line; just ignore.
+ continue;
+ }
+
+ if (stripped[0] == '-') {
+ if (stripped == "--") {
+ flags_internal::ReportUsageError(
+ "Flagfile can't contain position arguments or --", true);
+
+ success = false;
+ break;
+ }
+
+ args_.push_back(std::string(stripped));
+ continue;
+ }
+
+ flags_internal::ReportUsageError(
+ absl::StrCat("Unexpected line in the flagfile ", flag_file_name, ": ",
+ line),
+ true);
+
+ success = false;
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+// Reads the environment variable with name `name` and stores results in
+// `value`. If variable is not present in environment returns false, otherwise
+// returns true.
+bool GetEnvVar(const char* var_name, std::string* var_value) {
+#ifdef _WIN32
+ char buf[1024];
+ auto get_res = GetEnvironmentVariableA(var_name, buf, sizeof(buf));
+ if (get_res >= sizeof(buf)) {
+ return false;
+ }
+
+ if (get_res == 0) {
+ return false;
+ }
+
+ *var_value = std::string(buf, get_res);
+#else
+ const char* val = ::getenv(var_name);
+ if (val == nullptr) {
+ return false;
+ }
+
+ *var_value = val;
+#endif
+
+ return true;
+}
+
+// --------------------------------------------------------------------
+
+// Returns:
+// Flag name or empty if arg= --
+// Flag value after = in --flag=value (empty if --foo)
+// "Is empty value" status. True if arg= --foo=, false otherwise. This is
+// required to separate --foo from --foo=.
+// For example:
+// arg return values
+// "--foo=bar" -> {"foo", "bar", false}.
+// "--foo" -> {"foo", "", false}.
+// "--foo=" -> {"foo", "", true}.
+std::tuple<absl::string_view, absl::string_view, bool> SplitNameAndValue(
+ absl::string_view arg) {
+ // Allow -foo and --foo
+ absl::ConsumePrefix(&arg, "-");
+
+ if (arg.empty()) {
+ return std::make_tuple("", "", false);
+ }
+
+ auto equal_sign_pos = arg.find("=");
+
+ absl::string_view flag_name = arg.substr(0, equal_sign_pos);
+
+ absl::string_view value;
+ bool is_empty_value = false;
+
+ if (equal_sign_pos != absl::string_view::npos) {
+ value = arg.substr(equal_sign_pos + 1);
+ is_empty_value = value.empty();
+ }
+
+ return std::make_tuple(flag_name, value, is_empty_value);
+}
+
+// --------------------------------------------------------------------
+
+// Returns:
+// found flag or nullptr
+// is negative in case of --nofoo
+std::tuple<CommandLineFlag*, bool> LocateFlag(absl::string_view flag_name) {
+ CommandLineFlag* flag = flags_internal::FindCommandLineFlag(flag_name);
+ bool is_negative = false;
+
+ if (!flag && absl::ConsumePrefix(&flag_name, "no")) {
+ flag = flags_internal::FindCommandLineFlag(flag_name);
+ is_negative = true;
+ }
+
+ return std::make_tuple(flag, is_negative);
+}
+
+// --------------------------------------------------------------------
+
+// Verify that default values of typed flags must be convertible to string and
+// back.
+void CheckDefaultValuesParsingRoundtrip() {
+#ifndef NDEBUG
+ flags_internal::ForEachFlag([&](CommandLineFlag* flag) {
+ if (flag->IsRetired()) return;
+
+#define IGNORE_TYPE(T) \
+ if (flag->IsOfType<T>()) return;
+
+ ABSL_FLAGS_INTERNAL_FOR_EACH_LOCK_FREE(IGNORE_TYPE)
+ IGNORE_TYPE(std::string)
+ IGNORE_TYPE(std::vector<std::string>)
+#undef IGNORE_TYPE
+
+ flag->CheckDefaultValueParsingRoundtrip();
+ });
+#endif
+}
+
+// --------------------------------------------------------------------
+
+// Returns success status, which is true if we successfully read all flag files,
+// in which case new ArgLists are appended to the input_args in a reverse order
+// of file names in the input flagfiles list. This order ensures that flags from
+// the first flagfile in the input list are processed before the second flagfile
+// etc.
+bool ReadFlagfiles(const std::vector<std::string>& flagfiles,
+ std::vector<ArgsList>* input_args) {
+ bool success = true;
+ for (auto it = flagfiles.rbegin(); it != flagfiles.rend(); ++it) {
+ ArgsList al;
+
+ if (al.ReadFromFlagfile(*it)) {
+ input_args->push_back(al);
+ } else {
+ success = false;
+ }
+ }
+
+ return success;
+}
+
+// Returns success status, which is true if were able to locate all environment
+// variables correctly or if fail_on_absent_in_env is false. The environment
+// variable names are expected to be of the form `FLAGS_<flag_name>`, where
+// `flag_name` is a string from the input flag_names list. If successful we
+// append a single ArgList at the end of the input_args.
+bool ReadFlagsFromEnv(const std::vector<std::string>& flag_names,
+ std::vector<ArgsList>* input_args,
+ bool fail_on_absent_in_env) {
+ bool success = true;
+ std::vector<std::string> args;
+
+ // This argument represents fake argv[0], which should be present in all arg
+ // lists.
+ args.push_back("");
+
+ for (const auto& flag_name : flag_names) {
+ // Avoid infinite recursion.
+ if (flag_name == "fromenv" || flag_name == "tryfromenv") {
+ flags_internal::ReportUsageError(
+ absl::StrCat("Infinite recursion on flag ", flag_name), true);
+
+ success = false;
+ continue;
+ }
+
+ const std::string envname = absl::StrCat("FLAGS_", flag_name);
+ std::string envval;
+ if (!GetEnvVar(envname.c_str(), &envval)) {
+ if (fail_on_absent_in_env) {
+ flags_internal::ReportUsageError(
+ absl::StrCat(envname, " not found in environment"), true);
+
+ success = false;
+ }
+
+ continue;
+ }
+
+ args.push_back(absl::StrCat("--", flag_name, "=", envval));
+ }
+
+ if (success) {
+ input_args->emplace_back(args);
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+// Returns success status, which is true if were able to handle all generator
+// flags (flagfile, fromenv, tryfromemv) successfully.
+bool HandleGeneratorFlags(std::vector<ArgsList>* input_args,
+ std::vector<std::string>* flagfile_value) {
+ bool success = true;
+
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+
+ // flagfile could have been set either on a command line or
+ // programmatically before invoking ParseCommandLine. Note that we do not
+ // actually process arguments specified in the flagfile, but instead
+ // create a secondary arguments list to be processed along with the rest
+ // of the comamnd line arguments. Since we always the process most recently
+ // created list of arguments first, this will result in flagfile argument
+ // being processed before any other argument in the command line. If
+ // FLAGS_flagfile contains more than one file name we create multiple new
+ // levels of arguments in a reverse order of file names. Thus we always
+ // process arguments from first file before arguments containing in a
+ // second file, etc. If flagfile contains another
+ // --flagfile inside of it, it will produce new level of arguments and
+ // processed before the rest of the flagfile. We are also collecting all
+ // flagfiles set on original command line. Unlike the rest of the flags,
+ // this flag can be set multiple times and is expected to be handled
+ // multiple times. We are collecting them all into a single list and set
+ // the value of FLAGS_flagfile to that value at the end of the parsing.
+ if (flags_internal::flagfile_needs_processing) {
+ auto flagfiles = absl::GetFlag(FLAGS_flagfile);
+
+ if (input_args->size() == 1) {
+ flagfile_value->insert(flagfile_value->end(), flagfiles.begin(),
+ flagfiles.end());
+ }
+
+ success &= ReadFlagfiles(flagfiles, input_args);
+
+ flags_internal::flagfile_needs_processing = false;
+ }
+
+ // Similar to flagfile fromenv/tryfromemv can be set both
+ // programmatically and at runtime on a command line. Unlike flagfile these
+ // can't be recursive.
+ if (flags_internal::fromenv_needs_processing) {
+ auto flags_list = absl::GetFlag(FLAGS_fromenv);
+
+ success &= ReadFlagsFromEnv(flags_list, input_args, true);
+
+ flags_internal::fromenv_needs_processing = false;
+ }
+
+ if (flags_internal::tryfromenv_needs_processing) {
+ auto flags_list = absl::GetFlag(FLAGS_tryfromenv);
+
+ success &= ReadFlagsFromEnv(flags_list, input_args, false);
+
+ flags_internal::tryfromenv_needs_processing = false;
+ }
+
+ return success;
+}
+
+// --------------------------------------------------------------------
+
+void ResetGeneratorFlags(const std::vector<std::string>& flagfile_value) {
+ // Setting flagfile to the value which collates all the values set on a
+ // command line and programmatically. So if command line looked like
+ // --flagfile=f1 --flagfile=f2 the final value of the FLAGS_flagfile flag is
+ // going to be {"f1", "f2"}
+ if (!flagfile_value.empty()) {
+ absl::SetFlag(&FLAGS_flagfile, flagfile_value);
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+ flags_internal::flagfile_needs_processing = false;
+ }
+
+ // fromenv/tryfromenv are set to <undefined> value.
+ if (!absl::GetFlag(FLAGS_fromenv).empty()) {
+ absl::SetFlag(&FLAGS_fromenv, {});
+ }
+ if (!absl::GetFlag(FLAGS_tryfromenv).empty()) {
+ absl::SetFlag(&FLAGS_tryfromenv, {});
+ }
+
+ absl::MutexLock l(&flags_internal::processing_checks_guard);
+ flags_internal::fromenv_needs_processing = false;
+ flags_internal::tryfromenv_needs_processing = false;
+}
+
+// --------------------------------------------------------------------
+
+// Returns:
+// success status
+// deduced value
+// We are also mutating curr_list in case if we need to get a hold of next
+// argument in the input.
+std::tuple<bool, absl::string_view> DeduceFlagValue(const CommandLineFlag& flag,
+ absl::string_view value,
+ bool is_negative,
+ bool is_empty_value,
+ ArgsList* curr_list) {
+ // Value is either an argument suffix after `=` in "--foo=<value>"
+ // or separate argument in case of "--foo" "<value>".
+
+ // boolean flags have these forms:
+ // --foo
+ // --nofoo
+ // --foo=true
+ // --foo=false
+ // --nofoo=<value> is not supported
+ // --foo <value> is not supported
+
+ // non boolean flags have these forms:
+ // --foo=<value>
+ // --foo <value>
+ // --nofoo is not supported
+
+ if (flag.IsOfType<bool>()) {
+ if (value.empty()) {
+ if (is_empty_value) {
+ // "--bool_flag=" case
+ flags_internal::ReportUsageError(
+ absl::StrCat(
+ "Missing the value after assignment for the boolean flag '",
+ flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+
+ // "--bool_flag" case
+ value = is_negative ? "0" : "1";
+ } else if (is_negative) {
+ // "--nobool_flag=Y" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Negative form with assignment is not valid for the "
+ "boolean flag '",
+ flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+ } else if (is_negative) {
+ // "--noint_flag=1" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Negative form is not valid for the flag '", flag.Name(),
+ "'"),
+ true);
+ return std::make_tuple(false, "");
+ } else if (value.empty() && (!is_empty_value)) {
+ if (curr_list->Size() == 1) {
+ // "--int_flag" case
+ flags_internal::ReportUsageError(
+ absl::StrCat("Missing the value for the flag '", flag.Name(), "'"),
+ true);
+ return std::make_tuple(false, "");
+ }
+
+ // "--int_flag" "10" case
+ curr_list->PopFront();
+ value = curr_list->Front();
+
+ // Heuristic to detect the case where someone treats a std::string arg
+ // like a bool or just forgets to pass a value:
+ // --my_string_var --foo=bar
+ // We look for a flag of std::string type, whose value begins with a
+ // dash and corresponds to known flag or standalone --.
+ if (value[0] == '-' && flag.IsOfType<std::string>()) {
+ auto maybe_flag_name = std::get<0>(SplitNameAndValue(value.substr(1)));
+
+ if (maybe_flag_name.empty() ||
+ std::get<0>(LocateFlag(maybe_flag_name)) != nullptr) {
+ // "--string_flag" "--known_flag" case
+ ABSL_INTERNAL_LOG(
+ WARNING,
+ absl::StrCat("Did you really mean to set flag '", flag.Name(),
+ "' to the value '", value, "'?"));
+ }
+ }
+ }
+
+ return std::make_tuple(true, value);
+}
+
+// --------------------------------------------------------------------
+
+bool CanIgnoreUndefinedFlag(absl::string_view flag_name) {
+ auto undefok = absl::GetFlag(FLAGS_undefok);
+ if (std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
+ return true;
+ }
+
+ if (absl::ConsumePrefix(&flag_name, "no") &&
+ std::find(undefok.begin(), undefok.end(), flag_name) != undefok.end()) {
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+// --------------------------------------------------------------------
+
+std::vector<char*> ParseCommandLineImpl(int argc, char* argv[],
+ ArgvListAction arg_list_act,
+ UsageFlagsAction usage_flag_act,
+ OnUndefinedFlag on_undef_flag) {
+ ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
+
+ // This routine does not return anything since we abort on failure.
+ CheckDefaultValuesParsingRoundtrip();
+
+ std::vector<std::string> flagfile_value;
+
+ std::vector<ArgsList> input_args;
+ input_args.push_back(ArgsList(argc, argv));
+
+ std::vector<char*> output_args;
+ std::vector<char*> positional_args;
+ output_args.reserve(argc);
+
+ // This is the list of undefined flags. The element of the list is the pair
+ // consisting of boolean indicating if flag came from command line (vs from
+ // some flag file we've read) and flag name.
+ // TODO(rogeeff): Eliminate the first element in the pair after cleanup.
+ std::vector<std::pair<bool, std::string>> undefined_flag_names;
+
+ // Set program invocation name if it is not set before.
+ if (ProgramInvocationName() == "UNKNOWN") {
+ flags_internal::SetProgramInvocationName(argv[0]);
+ }
+ output_args.push_back(argv[0]);
+
+ // Iterate through the list of the input arguments. First level are arguments
+ // originated from argc/argv. Following levels are arguments originated from
+ // recursive parsing of flagfile(s).
+ bool success = true;
+ while (!input_args.empty()) {
+ // 10. First we process the built-in generator flags.
+ success &= HandleGeneratorFlags(&input_args, &flagfile_value);
+
+ // 30. Select top-most (most recent) arguments list. If it is empty drop it
+ // and re-try.
+ ArgsList& curr_list = input_args.back();
+
+ curr_list.PopFront();
+
+ if (curr_list.Size() == 0) {
+ input_args.pop_back();
+ continue;
+ }
+
+ // 40. Pick up the front remaining argument in the current list. If current
+ // stack of argument lists contains only one element - we are processing an
+ // argument from the original argv.
+ absl::string_view arg(curr_list.Front());
+ bool arg_from_argv = input_args.size() == 1;
+
+ // 50. If argument does not start with - or is just "-" - this is
+ // positional argument.
+ if (!absl::ConsumePrefix(&arg, "-") || arg.empty()) {
+ ABSL_INTERNAL_CHECK(arg_from_argv,
+ "Flagfile cannot contain positional argument");
+
+ positional_args.push_back(argv[curr_list.FrontIndex()]);
+ continue;
+ }
+
+ if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs)) {
+ output_args.push_back(argv[curr_list.FrontIndex()]);
+ }
+
+ // 60. Split the current argument on '=' to figure out the argument
+ // name and value. If flag name is empty it means we've got "--". value
+ // can be empty either if there were no '=' in argument std::string at all or
+ // an argument looked like "--foo=". In a latter case is_empty_value is
+ // true.
+ absl::string_view flag_name;
+ absl::string_view value;
+ bool is_empty_value = false;
+
+ std::tie(flag_name, value, is_empty_value) = SplitNameAndValue(arg);
+
+ // 70. "--" alone means what it does for GNU: stop flags parsing. We do
+ // not support positional arguments in flagfiles, so we just drop them.
+ if (flag_name.empty()) {
+ ABSL_INTERNAL_CHECK(arg_from_argv,
+ "Flagfile cannot contain positional argument");
+
+ curr_list.PopFront();
+ break;
+ }
+
+ // 80. Locate the flag based on flag name. Handle both --foo and --nofoo
+ CommandLineFlag* flag = nullptr;
+ bool is_negative = false;
+ std::tie(flag, is_negative) = LocateFlag(flag_name);
+
+ if (flag == nullptr) {
+ if (on_undef_flag != OnUndefinedFlag::kIgnoreUndefined) {
+ undefined_flag_names.emplace_back(arg_from_argv,
+ std::string(flag_name));
+ }
+ continue;
+ }
+
+ // 90. Deduce flag's value (from this or next argument)
+ auto curr_index = curr_list.FrontIndex();
+ bool value_success = true;
+ std::tie(value_success, value) =
+ DeduceFlagValue(*flag, value, is_negative, is_empty_value, &curr_list);
+ success &= value_success;
+
+ // If above call consumed an argument, it was a standalone value
+ if (arg_from_argv && (arg_list_act == ArgvListAction::kKeepParsedArgs) &&
+ (curr_index != curr_list.FrontIndex())) {
+ output_args.push_back(argv[curr_list.FrontIndex()]);
+ }
+
+ // 100. Set the located flag to a new new value, unless it is retired.
+ // Setting retired flag fails, but we ignoring it here.
+ if (flag->IsRetired()) continue;
+
+ std::string error;
+ if (!flag->SetFromString(value, SET_FLAGS_VALUE, kCommandLine, &error)) {
+ flags_internal::ReportUsageError(error, true);
+ success = false;
+ }
+ }
+
+ for (const auto& flag_name : undefined_flag_names) {
+ if (CanIgnoreUndefinedFlag(flag_name.second)) continue;
+
+ flags_internal::ReportUsageError(
+ absl::StrCat("Unknown command line flag '", flag_name.second, "'"),
+ true);
+
+ success = false;
+ }
+
+#if ABSL_FLAGS_STRIP_NAMES
+ if (!success) {
+ flags_internal::ReportUsageError(
+ "NOTE: command line flags are disabled in this build", true);
+ }
+#endif
+
+ if (!success) {
+ flags_internal::HandleUsageFlags(std::cout,
+ ProgramUsageMessage());
+ std::exit(1);
+ }
+
+ if (usage_flag_act == UsageFlagsAction::kHandleUsage) {
+ int exit_code = flags_internal::HandleUsageFlags(
+ std::cout, ProgramUsageMessage());
+
+ if (exit_code != -1) {
+ std::exit(exit_code);
+ }
+ }
+
+ ResetGeneratorFlags(flagfile_value);
+
+ // Reinstate positional args which were intermixed with flags in the arguments
+ // list.
+ for (auto arg : positional_args) {
+ output_args.push_back(arg);
+ }
+
+ // All the remaining arguments are positional.
+ if (!input_args.empty()) {
+ for (int arg_index = input_args.back().FrontIndex(); arg_index < argc;
+ ++arg_index) {
+ output_args.push_back(argv[arg_index]);
+ }
+ }
+
+ return output_args;
+}
+
+} // namespace flags_internal
+
+// --------------------------------------------------------------------
+
+std::vector<char*> ParseCommandLine(int argc, char* argv[]) {
+ return flags_internal::ParseCommandLineImpl(
+ argc, argv, flags_internal::ArgvListAction::kRemoveParsedArgs,
+ flags_internal::UsageFlagsAction::kHandleUsage,
+ flags_internal::OnUndefinedFlag::kAbortIfUndefined);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/parse.h b/absl/flags/parse.h
new file mode 100644
index 00000000..469bd506
--- /dev/null
+++ b/absl/flags/parse.h
@@ -0,0 +1,60 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: parse.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the main parsing function for Abseil flags:
+// `absl::ParseCommandLine()`.
+
+#ifndef ABSL_FLAGS_PARSE_H_
+#define ABSL_FLAGS_PARSE_H_
+
+#include <string>
+#include <vector>
+
+#include "absl/flags/internal/parse.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// ParseCommandLine()
+//
+// Parses the set of command-line arguments passed in the `argc` (argument
+// count) and `argv[]` (argument vector) parameters from `main()`, assigning
+// values to any defined Abseil flags. (Any arguments passed after the
+// flag-terminating delimiter (`--`) are treated as positional arguments and
+// ignored.)
+//
+// Any command-line flags (and arguments to those flags) are parsed into Abseil
+// Flag values, if those flags are defined. Any undefined flags will either
+// return an error, or be ignored if that flag is designated using `undefok` to
+// indicate "undefined is OK."
+//
+// Any command-line positional arguments not part of any command-line flag (or
+// arguments to a flag) are returned in a vector, with the program invocation
+// name at position 0 of that vector. (Note that this includes positional
+// arguments after the flag-terminating delimiter `--`.)
+//
+// After all flags and flag arguments are parsed, this function looks for any
+// built-in usage flags (e.g. `--help`), and if any were specified, it reports
+// help messages and then exits the program.
+std::vector<char*> ParseCommandLine(int argc, char* argv[]);
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_PARSE_H_
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc
new file mode 100644
index 00000000..447a3bc7
--- /dev/null
+++ b/absl/flags/parse_test.cc
@@ -0,0 +1,858 @@
+//
+// 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.
+
+#include "absl/flags/parse.h"
+
+#include <fstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/internal/scoped_set_env.h"
+#include "absl/flags/flag.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/substitute.h"
+#include "absl/types/span.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace {
+
+using absl::base_internal::ScopedSetEnv;
+
+struct UDT {
+ UDT() = default;
+ UDT(const UDT&) = default;
+ UDT(int v) : value(v) {} // NOLINT
+
+ int value;
+};
+
+bool AbslParseFlag(absl::string_view in, UDT* udt, std::string* err) {
+ if (in == "A") {
+ udt->value = 1;
+ return true;
+ }
+ if (in == "AAA") {
+ udt->value = 10;
+ return true;
+ }
+
+ *err = "Use values A, AAA instead";
+ return false;
+}
+std::string AbslUnparseFlag(const UDT& udt) {
+ return udt.value == 1 ? "A" : "AAA";
+}
+
+std::string GetTestTmpDirEnvVar(const char* const env_var_name) {
+#ifdef _WIN32
+ char buf[MAX_PATH];
+ auto get_res = GetEnvironmentVariableA(env_var_name, buf, sizeof(buf));
+ if (get_res >= sizeof(buf) || get_res == 0) {
+ return "";
+ }
+
+ return std::string(buf, get_res);
+#else
+ const char* val = ::getenv(env_var_name);
+ if (val == nullptr) {
+ return "";
+ }
+
+ return val;
+#endif
+}
+
+const std::string& GetTestTempDir() {
+ static std::string* temp_dir_name = []() -> std::string* {
+ std::string* res = new std::string(GetTestTmpDirEnvVar("TEST_TMPDIR"));
+
+ if (res->empty()) {
+ *res = GetTestTmpDirEnvVar("TMPDIR");
+ }
+
+ if (res->empty()) {
+#ifdef _WIN32
+ char temp_path_buffer[MAX_PATH];
+
+ auto len = GetTempPathA(MAX_PATH, temp_path_buffer);
+ if (len < MAX_PATH && len != 0) {
+ std::string temp_dir_name = absl::StrCat(
+ temp_path_buffer, "\\parse_test.", GetCurrentProcessId());
+ if (CreateDirectoryA(temp_dir_name.c_str(), nullptr)) {
+ *res = temp_dir_name;
+ }
+ }
+#else
+ char temp_dir_template[] = "/tmp/parse_test.XXXXXX";
+ if (auto* unique_name = ::mkdtemp(temp_dir_template)) {
+ *res = unique_name;
+ }
+#endif
+
+ if (res->empty()) {
+ ABSL_INTERNAL_LOG(FATAL,
+ "Failed to make temporary directory for data files");
+ }
+ }
+
+#ifdef _WIN32
+ *res += "\\";
+#else
+ *res += "/";
+#endif
+
+ return res;
+ }();
+
+ return *temp_dir_name;
+}
+
+struct FlagfileData {
+ const absl::string_view file_name;
+ const absl::Span<const char* const> file_lines;
+};
+
+// clang-format off
+constexpr const char* const ff1_data[] = {
+ "# comment ",
+ " # comment ",
+ "",
+ " ",
+ "--int_flag=-1",
+ " --string_flag=q2w2 ",
+ " ## ",
+ " --double_flag=0.1",
+ "--bool_flag=Y "
+};
+
+constexpr const char* const ff2_data[] = {
+ "# Setting legacy flag",
+ "--legacy_int=1111",
+ "--legacy_bool",
+ "--nobool_flag",
+ "--legacy_str=aqsw",
+ "--int_flag=100",
+ " ## ============="
+};
+// clang-format on
+
+// Builds flagfile flag in the flagfile_flag buffer and returns it. This
+// function also creates a temporary flagfile based on FlagfileData input.
+// We create a flagfile in a temporary directory with the name specified in
+// FlagfileData and populate it with lines specifed in FlagfileData. If $0 is
+// referenced in any of the lines in FlagfileData they are replaced with
+// temporary directory location. This way we can test inclusion of one flagfile
+// from another flagfile.
+const char* GetFlagfileFlag(const std::vector<FlagfileData>& ffd,
+ std::string* flagfile_flag) {
+ *flagfile_flag = "--flagfile=";
+ absl::string_view separator;
+ for (const auto& flagfile_data : ffd) {
+ std::string flagfile_name =
+ absl::StrCat(GetTestTempDir(), flagfile_data.file_name);
+
+ std::ofstream flagfile_out(flagfile_name);
+ for (auto line : flagfile_data.file_lines) {
+ flagfile_out << absl::Substitute(line, GetTestTempDir()) << "\n";
+ }
+
+ absl::StrAppend(flagfile_flag, separator, flagfile_name);
+ separator = ",";
+ }
+
+ return flagfile_flag->c_str();
+}
+
+} // namespace
+
+ABSL_FLAG(int, int_flag, 1, "");
+ABSL_FLAG(double, double_flag, 1.1, "");
+ABSL_FLAG(std::string, string_flag, "a", "");
+ABSL_FLAG(bool, bool_flag, false, "");
+ABSL_FLAG(UDT, udt_flag, -1, "");
+ABSL_RETIRED_FLAG(int, legacy_int, 1, "");
+ABSL_RETIRED_FLAG(bool, legacy_bool, false, "");
+ABSL_RETIRED_FLAG(std::string, legacy_str, "l", "");
+
+namespace {
+
+namespace flags = absl::flags_internal;
+using testing::ElementsAreArray;
+
+class ParseTest : public testing::Test {
+ private:
+ flags::FlagSaver flag_saver_;
+};
+
+// --------------------------------------------------------------------
+
+template <int N>
+std::vector<char*> InvokeParse(const char* (&in_argv)[N]) {
+ return absl::ParseCommandLine(N, const_cast<char**>(in_argv));
+}
+
+// --------------------------------------------------------------------
+
+template <int N>
+void TestParse(const char* (&in_argv)[N], int int_flag_value,
+ double double_flag_val, absl::string_view string_flag_val,
+ bool bool_flag_val, int exp_position_args = 0) {
+ auto out_args = InvokeParse(in_argv);
+
+ EXPECT_EQ(out_args.size(), 1 + exp_position_args);
+ EXPECT_STREQ(out_args[0], "testbin");
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), int_flag_value);
+ EXPECT_NEAR(absl::GetFlag(FLAGS_double_flag), double_flag_val, 0.0001);
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), string_flag_val);
+ EXPECT_EQ(absl::GetFlag(FLAGS_bool_flag), bool_flag_val);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestEmptyArgv) {
+ const char* in_argv[] = {"testbin"};
+
+ auto out_args = InvokeParse(in_argv);
+
+ EXPECT_EQ(out_args.size(), 1);
+ EXPECT_STREQ(out_args[0], "testbin");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidIntArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--int_flag=10",
+ };
+ TestParse(in_args1, 10, 1.1, "a", false);
+
+ const char* in_args2[] = {
+ "testbin",
+ "-int_flag=020",
+ };
+ TestParse(in_args2, 20, 1.1, "a", false);
+
+ const char* in_args3[] = {
+ "testbin",
+ "--int_flag",
+ "-30",
+ };
+ TestParse(in_args3, -30, 1.1, "a", false);
+
+ const char* in_args4[] = {
+ "testbin",
+ "-int_flag",
+ "0x21",
+ };
+ TestParse(in_args4, 33, 1.1, "a", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidDoubleArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--double_flag=2.3",
+ };
+ TestParse(in_args1, 1, 2.3, "a", false);
+
+ const char* in_args2[] = {
+ "testbin",
+ "--double_flag=0x1.2",
+ };
+ TestParse(in_args2, 1, 1.125, "a", false);
+
+ const char* in_args3[] = {
+ "testbin",
+ "--double_flag",
+ "99.7",
+ };
+ TestParse(in_args3, 1, 99.7, "a", false);
+
+ const char* in_args4[] = {
+ "testbin",
+ "--double_flag",
+ "0x20.1",
+ };
+ TestParse(in_args4, 1, 32.0625, "a", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidStringArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--string_flag=aqswde",
+ };
+ TestParse(in_args1, 1, 1.1, "aqswde", false);
+
+ const char* in_args2[] = {
+ "testbin",
+ "-string_flag=a=b=c",
+ };
+ TestParse(in_args2, 1, 1.1, "a=b=c", false);
+
+ const char* in_args3[] = {
+ "testbin",
+ "--string_flag",
+ "zaxscd",
+ };
+ TestParse(in_args3, 1, 1.1, "zaxscd", false);
+
+ const char* in_args4[] = {
+ "testbin",
+ "-string_flag",
+ "--int_flag",
+ };
+ TestParse(in_args4, 1, 1.1, "--int_flag", false);
+
+ const char* in_args5[] = {
+ "testbin",
+ "--string_flag",
+ "--no_a_flag=11",
+ };
+ TestParse(in_args5, 1, 1.1, "--no_a_flag=11", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidBoolArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--bool_flag",
+ };
+ TestParse(in_args1, 1, 1.1, "a", true);
+
+ const char* in_args2[] = {
+ "testbin",
+ "--nobool_flag",
+ };
+ TestParse(in_args2, 1, 1.1, "a", false);
+
+ const char* in_args3[] = {
+ "testbin",
+ "--bool_flag=true",
+ };
+ TestParse(in_args3, 1, 1.1, "a", true);
+
+ const char* in_args4[] = {
+ "testbin",
+ "-bool_flag=false",
+ };
+ TestParse(in_args4, 1, 1.1, "a", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidUDTArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--udt_flag=A",
+ };
+ InvokeParse(in_args1);
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 1);
+
+ const char* in_args2[] = {"testbin", "--udt_flag", "AAA"};
+ InvokeParse(in_args2);
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_udt_flag).value, 10);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidMultipleArg) {
+ const char* in_args1[] = {
+ "testbin", "--bool_flag", "--int_flag=2",
+ "--double_flag=0.1", "--string_flag=asd",
+ };
+ TestParse(in_args1, 2, 0.1, "asd", true);
+
+ const char* in_args2[] = {
+ "testbin", "--string_flag=", "--nobool_flag", "--int_flag",
+ "-011", "--double_flag", "-1e-2",
+ };
+ TestParse(in_args2, -11, -0.01, "", false);
+
+ const char* in_args3[] = {
+ "testbin", "--int_flag", "-0", "--string_flag", "\"\"",
+ "--bool_flag=true", "--double_flag=1e18",
+ };
+ TestParse(in_args3, 0, 1e18, "\"\"", true);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestPositionalArgs) {
+ const char* in_args1[] = {
+ "testbin",
+ "p1",
+ "p2",
+ };
+ TestParse(in_args1, 1, 1.1, "a", false, 2);
+
+ auto out_args1 = InvokeParse(in_args1);
+
+ EXPECT_STREQ(out_args1[1], "p1");
+ EXPECT_STREQ(out_args1[2], "p2");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--int_flag=2",
+ "p1",
+ };
+ TestParse(in_args2, 2, 1.1, "a", false, 1);
+
+ auto out_args2 = InvokeParse(in_args2);
+
+ EXPECT_STREQ(out_args2[1], "p1");
+
+ const char* in_args3[] = {"testbin", "p1", "--int_flag=3",
+ "p2", "--bool_flag", "true"};
+ TestParse(in_args3, 3, 1.1, "a", true, 3);
+
+ auto out_args3 = InvokeParse(in_args3);
+
+ EXPECT_STREQ(out_args3[1], "p1");
+ EXPECT_STREQ(out_args3[2], "p2");
+ EXPECT_STREQ(out_args3[3], "true");
+
+ const char* in_args4[] = {
+ "testbin",
+ "--",
+ "p1",
+ "p2",
+ };
+ TestParse(in_args4, 3, 1.1, "a", true, 2);
+
+ auto out_args4 = InvokeParse(in_args4);
+
+ EXPECT_STREQ(out_args4[1], "p1");
+ EXPECT_STREQ(out_args4[2], "p2");
+
+ const char* in_args5[] = {
+ "testbin", "p1", "--int_flag=4", "--", "--bool_flag", "false", "p2",
+ };
+ TestParse(in_args5, 4, 1.1, "a", true, 4);
+
+ auto out_args5 = InvokeParse(in_args5);
+
+ EXPECT_STREQ(out_args5[1], "p1");
+ EXPECT_STREQ(out_args5[2], "--bool_flag");
+ EXPECT_STREQ(out_args5[3], "false");
+ EXPECT_STREQ(out_args5[4], "p2");
+}
+
+// --------------------------------------------------------------------
+
+using ParseDeathTest = ParseTest;
+
+TEST_F(ParseDeathTest, TestUndefinedArg) {
+ const char* in_args1[] = {
+ "testbin",
+ "--undefined_flag",
+ };
+ EXPECT_DEATH(InvokeParse(in_args1),
+ "Unknown command line flag 'undefined_flag'");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--noprefixed_flag",
+ };
+ EXPECT_DEATH(InvokeParse(in_args2),
+ "Unknown command line flag 'noprefixed_flag'");
+
+ const char* in_args3[] = {
+ "testbin",
+ "--Int_flag=1",
+ };
+ EXPECT_DEATH(InvokeParse(in_args3), "Unknown command line flag 'Int_flag'");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestInvalidBoolFlagFormat) {
+ const char* in_args1[] = {
+ "testbin",
+ "--bool_flag=",
+ };
+ EXPECT_DEATH(
+ InvokeParse(in_args1),
+ "Missing the value after assignment for the boolean flag 'bool_flag'");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--nobool_flag=true",
+ };
+ EXPECT_DEATH(InvokeParse(in_args2),
+ "Negative form with assignment is not valid for the boolean "
+ "flag 'bool_flag'");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestInvalidNonBoolFlagFormat) {
+ const char* in_args1[] = {
+ "testbin",
+ "--nostring_flag",
+ };
+ EXPECT_DEATH(InvokeParse(in_args1),
+ "Negative form is not valid for the flag 'string_flag'");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--int_flag",
+ };
+ EXPECT_DEATH(InvokeParse(in_args2),
+ "Missing the value for the flag 'int_flag'");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) {
+ const char* in_args1[] = {
+ "testbin",
+ "--udt_flag=1",
+ };
+ EXPECT_DEATH(InvokeParse(in_args1),
+ "Illegal value '1' specified for flag 'udt_flag'; Use values A, "
+ "AAA instead");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--udt_flag",
+ "AA",
+ };
+ EXPECT_DEATH(InvokeParse(in_args2),
+ "Illegal value 'AA' specified for flag 'udt_flag'; Use values "
+ "A, AAA instead");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestLegacyFlags) {
+ const char* in_args1[] = {
+ "testbin",
+ "--legacy_int=11",
+ };
+ TestParse(in_args1, 1, 1.1, "a", false);
+
+ const char* in_args2[] = {
+ "testbin",
+ "--legacy_bool",
+ };
+ TestParse(in_args2, 1, 1.1, "a", false);
+
+ const char* in_args3[] = {
+ "testbin", "--legacy_int", "22", "--int_flag=2",
+ "--legacy_bool", "true", "--legacy_str", "--string_flag=qwe",
+ };
+ TestParse(in_args3, 2, 1.1, "a", false, 1);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestSimpleValidFlagfile) {
+ std::string flagfile_flag;
+
+ const char* in_args1[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+ &flagfile_flag),
+ };
+ TestParse(in_args1, -1, 0.1, "q2w2 ", true);
+
+ const char* in_args2[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)}},
+ &flagfile_flag),
+ };
+ TestParse(in_args2, 100, 0.1, "q2w2 ", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestValidMultiFlagfile) {
+ std::string flagfile_flag;
+
+ const char* in_args1[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff2", absl::MakeConstSpan(ff2_data)},
+ {"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+ &flagfile_flag),
+ };
+ TestParse(in_args1, -1, 0.1, "q2w2 ", true);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestFlagfileMixedWithRegularFlags) {
+ std::string flagfile_flag;
+
+ const char* in_args1[] = {
+ "testbin", "--int_flag=3",
+ GetFlagfileFlag({{"parse_test.ff1", absl::MakeConstSpan(ff1_data)}},
+ &flagfile_flag),
+ "-double_flag=0.2"};
+ TestParse(in_args1, -1, 0.2, "q2w2 ", true);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestFlagfileInFlagfile) {
+ std::string flagfile_flag;
+
+ constexpr const char* const ff3_data[] = {
+ "--flagfile=$0/parse_test.ff1",
+ "--flagfile=$0/parse_test.ff2",
+ };
+
+ const char* in_args1[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff3", absl::MakeConstSpan(ff3_data)}},
+ &flagfile_flag),
+ };
+ TestParse(in_args1, 100, 0.1, "q2w2 ", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestInvalidFlagfiles) {
+ std::string flagfile_flag;
+
+ constexpr const char* const ff4_data[] = {
+ "--unknown_flag=10"
+ };
+
+ const char* in_args1[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff4",
+ absl::MakeConstSpan(ff4_data)}}, &flagfile_flag),
+ };
+ EXPECT_DEATH(InvokeParse(in_args1),
+ "Unknown command line flag 'unknown_flag'");
+
+ constexpr const char* const ff5_data[] = {
+ "--int_flag 10",
+ };
+
+ const char* in_args2[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff5",
+ absl::MakeConstSpan(ff5_data)}}, &flagfile_flag),
+ };
+ EXPECT_DEATH(InvokeParse(in_args2),
+ "Unknown command line flag 'int_flag 10'");
+
+ constexpr const char* const ff6_data[] = {
+ "--int_flag=10", "--", "arg1", "arg2", "arg3",
+ };
+
+ const char* in_args3[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff6", absl::MakeConstSpan(ff6_data)}},
+ &flagfile_flag),
+ };
+ EXPECT_DEATH(InvokeParse(in_args3),
+ "Flagfile can't contain position arguments or --");
+
+ const char* in_args4[] = {
+ "testbin",
+ "--flagfile=invalid_flag_file",
+ };
+ EXPECT_DEATH(InvokeParse(in_args4), "Can't open flagfile invalid_flag_file");
+
+ constexpr const char* const ff7_data[] = {
+ "--int_flag=10",
+ "*bin*",
+ "--str_flag=aqsw",
+ };
+
+ const char* in_args5[] = {
+ "testbin",
+ GetFlagfileFlag({{"parse_test.ff7", absl::MakeConstSpan(ff7_data)}},
+ &flagfile_flag),
+ };
+ EXPECT_DEATH(InvokeParse(in_args5),
+ "Unexpected line in the flagfile .*: \\*bin\\*");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestReadingRequiredFlagsFromEnv) {
+ const char* in_args1[] = {"testbin",
+ "--fromenv=int_flag,bool_flag,string_flag"};
+
+ ScopedSetEnv set_int_flag("FLAGS_int_flag", "33");
+ ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "True");
+ ScopedSetEnv set_string_flag("FLAGS_string_flag", "AQ12");
+
+ TestParse(in_args1, 33, 1.1, "AQ12", true);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestReadingUnsetRequiredFlagsFromEnv) {
+ const char* in_args1[] = {"testbin", "--fromenv=int_flag"};
+
+ EXPECT_DEATH(InvokeParse(in_args1),
+ "FLAGS_int_flag not found in environment");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestRecursiveFlagsFromEnv) {
+ const char* in_args1[] = {"testbin", "--fromenv=tryfromenv"};
+
+ ScopedSetEnv set_tryfromenv("FLAGS_tryfromenv", "int_flag");
+
+ EXPECT_DEATH(InvokeParse(in_args1), "Infinite recursion on flag tryfromenv");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestReadingOptionalFlagsFromEnv) {
+ const char* in_args1[] = {
+ "testbin", "--tryfromenv=int_flag,bool_flag,string_flag,other_flag"};
+
+ ScopedSetEnv set_int_flag("FLAGS_int_flag", "17");
+ ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "Y");
+
+ TestParse(in_args1, 17, 1.1, "a", true);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) {
+ const char* in_args1[] = {
+ "testbin",
+ "--bool_flag=T",
+ "--tryfromenv=int_flag,bool_flag",
+ "--int_flag=-21",
+ };
+
+ ScopedSetEnv set_int_flag("FLAGS_int_flag", "-15");
+ ScopedSetEnv set_bool_flag("FLAGS_bool_flag", "F");
+
+ TestParse(in_args1, -21, 1.1, "a", false);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestKeepParsedArgs) {
+ const char* in_args1[] = {
+ "testbin", "arg1", "--bool_flag",
+ "--int_flag=211", "arg2", "--double_flag=1.1",
+ "--string_flag", "asd", "--",
+ "arg3", "arg4",
+ };
+
+ auto out_args1 = InvokeParse(in_args1);
+
+ EXPECT_THAT(
+ out_args1,
+ ElementsAreArray({absl::string_view("testbin"), absl::string_view("arg1"),
+ absl::string_view("arg2"), absl::string_view("arg3"),
+ absl::string_view("arg4")}));
+
+ auto out_args2 = flags::ParseCommandLineImpl(
+ 11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs,
+ flags::UsageFlagsAction::kHandleUsage,
+ flags::OnUndefinedFlag::kAbortIfUndefined);
+
+ EXPECT_THAT(
+ out_args2,
+ ElementsAreArray({absl::string_view("testbin"),
+ absl::string_view("--bool_flag"),
+ absl::string_view("--int_flag=211"),
+ absl::string_view("--double_flag=1.1"),
+ absl::string_view("--string_flag"),
+ absl::string_view("asd"), absl::string_view("--"),
+ absl::string_view("arg1"), absl::string_view("arg2"),
+ absl::string_view("arg3"), absl::string_view("arg4")}));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseTest, TestIgnoreUndefinedFlags) {
+ const char* in_args1[] = {
+ "testbin",
+ "arg1",
+ "--undef_flag=aa",
+ "--int_flag=21",
+ };
+
+ auto out_args1 = flags::ParseCommandLineImpl(
+ 4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs,
+ flags::UsageFlagsAction::kHandleUsage,
+ flags::OnUndefinedFlag::kIgnoreUndefined);
+
+ EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"),
+ absl::string_view("arg1")}));
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21);
+
+ const char* in_args2[] = {
+ "testbin",
+ "arg1",
+ "--undef_flag=aa",
+ "--string_flag=AA",
+ };
+
+ auto out_args2 = flags::ParseCommandLineImpl(
+ 4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs,
+ flags::UsageFlagsAction::kHandleUsage,
+ flags::OnUndefinedFlag::kIgnoreUndefined);
+
+ EXPECT_THAT(
+ out_args2,
+ ElementsAreArray(
+ {absl::string_view("testbin"), absl::string_view("--undef_flag=aa"),
+ absl::string_view("--string_flag=AA"), absl::string_view("arg1")}));
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "AA");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(ParseDeathTest, TestHelpFlagHandling) {
+ const char* in_args1[] = {
+ "testbin",
+ "--help",
+ };
+
+ EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), "");
+
+ const char* in_args2[] = {
+ "testbin",
+ "--help",
+ "--int_flag=3",
+ };
+
+ auto out_args2 = flags::ParseCommandLineImpl(
+ 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs,
+ flags::UsageFlagsAction::kIgnoreUsage,
+ flags::OnUndefinedFlag::kAbortIfUndefined);
+
+ EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3);
+}
+
+} // namespace
diff --git a/absl/flags/usage.cc b/absl/flags/usage.cc
new file mode 100644
index 00000000..12c346b7
--- /dev/null
+++ b/absl/flags/usage.cc
@@ -0,0 +1,58 @@
+//
+// 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.
+#include "absl/flags/usage.h"
+
+#include <string>
+
+#include "absl/flags/internal/usage.h"
+#include "absl/synchronization/mutex.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+namespace {
+ABSL_CONST_INIT absl::Mutex usage_message_guard(absl::kConstInit);
+ABSL_CONST_INIT std::string* program_usage_message
+ GUARDED_BY(usage_message_guard) = nullptr;
+} // namespace
+} // namespace flags_internal
+
+// --------------------------------------------------------------------
+// Sets the "usage" message to be used by help reporting routines.
+void SetProgramUsageMessage(absl::string_view new_usage_message) {
+ absl::MutexLock l(&flags_internal::usage_message_guard);
+
+ if (flags_internal::program_usage_message != nullptr) {
+ ABSL_INTERNAL_LOG(FATAL, "SetProgramUsageMessage() called twice.");
+ std::exit(1);
+ }
+
+ flags_internal::program_usage_message = new std::string(new_usage_message);
+}
+
+// --------------------------------------------------------------------
+// Returns the usage message set by SetProgramUsageMessage().
+// Note: We able to return string_view here only because calling
+// SetProgramUsageMessage twice is prohibited.
+absl::string_view ProgramUsageMessage() {
+ absl::MutexLock l(&flags_internal::usage_message_guard);
+
+ return flags_internal::program_usage_message != nullptr
+ ? absl::string_view(*flags_internal::program_usage_message)
+ : "Warning: SetProgramUsageMessage() never called";
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/usage.h b/absl/flags/usage.h
new file mode 100644
index 00000000..c232a7d0
--- /dev/null
+++ b/absl/flags/usage.h
@@ -0,0 +1,42 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_FLAGS_USAGE_H_
+#define ABSL_FLAGS_USAGE_H_
+
+#include "absl/strings/string_view.h"
+
+// --------------------------------------------------------------------
+// Usage reporting interfaces
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// Sets the "usage" message to be used by help reporting routines.
+// For example:
+// absl::SetProgramUsageMessage(
+// absl::StrCat("This program does nothing. Sample usage:\n", argv[0],
+// " <uselessarg1> <uselessarg2>"));
+// Do not include commandline flags in the usage: we do that for you!
+// Note: Calling SetProgramUsageMessage twice will trigger a call to std::exit.
+void SetProgramUsageMessage(absl::string_view new_usage_message);
+
+// Returns the usage message set by SetProgramUsageMessage().
+absl::string_view ProgramUsageMessage();
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_FLAGS_USAGE_H_
diff --git a/absl/flags/usage_config.cc b/absl/flags/usage_config.cc
new file mode 100644
index 00000000..a538acd5
--- /dev/null
+++ b/absl/flags/usage_config.cc
@@ -0,0 +1,154 @@
+//
+// 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.
+
+#include "absl/flags/usage_config.h"
+
+#include <iostream>
+#include <memory>
+
+#include "absl/base/attributes.h"
+#include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/strip.h"
+#include "absl/synchronization/mutex.h"
+
+extern "C" {
+
+// Additional report of fatal usage error message before we std::exit. Error is
+// fatal if is_fatal argument to ReportUsageError is true.
+ABSL_ATTRIBUTE_WEAK void AbslInternalReportFatalUsageError(absl::string_view) {}
+
+} // extern "C"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace flags_internal {
+
+namespace {
+
+// --------------------------------------------------------------------
+// Returns true if flags defined in the filename should be reported with
+// -helpshort flag.
+
+bool ContainsHelpshortFlags(absl::string_view filename) {
+ // By default we only want flags in binary's main. We expect the main
+ // routine to reside in <program>.cc or <program>-main.cc or
+ // <program>_main.cc, where the <program> is the name of the binary.
+ auto suffix = flags_internal::Basename(filename);
+ if (!absl::ConsumePrefix(&suffix,
+ flags_internal::ShortProgramInvocationName()))
+ return false;
+ return absl::StartsWith(suffix, ".") || absl::StartsWith(suffix, "-main.") ||
+ absl::StartsWith(suffix, "_main.");
+}
+
+// --------------------------------------------------------------------
+// Returns true if flags defined in the filename should be reported with
+// -helppackage flag.
+
+bool ContainsHelppackageFlags(absl::string_view filename) {
+ // TODO(rogeeff): implement properly when registry is available.
+ return ContainsHelpshortFlags(filename);
+}
+
+// --------------------------------------------------------------------
+// Generates program version information into supplied output.
+
+std::string VersionString() {
+ std::string version_str(flags_internal::ShortProgramInvocationName());
+
+ version_str += "\n";
+
+#if !defined(NDEBUG)
+ version_str += "Debug build (NDEBUG not #defined)\n";
+#endif
+
+ return version_str;
+}
+
+// --------------------------------------------------------------------
+// Normalizes the filename specific to the build system/filesystem used.
+
+std::string NormalizeFilename(absl::string_view filename) {
+ // Skip any leading slashes
+ auto pos = filename.find_first_not_of("\\/");
+ if (pos == absl::string_view::npos) return "";
+
+ filename.remove_prefix(pos);
+ return std::string(filename);
+}
+
+// --------------------------------------------------------------------
+
+ABSL_CONST_INIT absl::Mutex custom_usage_config_guard(absl::kConstInit);
+ABSL_CONST_INIT FlagsUsageConfig* custom_usage_config
+ GUARDED_BY(custom_usage_config_guard) = nullptr;
+
+} // namespace
+
+FlagsUsageConfig GetUsageConfig() {
+ absl::MutexLock l(&custom_usage_config_guard);
+
+ if (custom_usage_config) return *custom_usage_config;
+
+ FlagsUsageConfig default_config;
+ default_config.contains_helpshort_flags = &ContainsHelpshortFlags;
+ default_config.contains_help_flags = &ContainsHelppackageFlags;
+ default_config.contains_helppackage_flags = &ContainsHelppackageFlags;
+ default_config.version_string = &VersionString;
+ default_config.normalize_filename = &NormalizeFilename;
+
+ return default_config;
+}
+
+void ReportUsageError(absl::string_view msg, bool is_fatal) {
+ std::cerr << "ERROR: " << msg << std::endl;
+
+ if (is_fatal) {
+ AbslInternalReportFatalUsageError(msg);
+ }
+}
+
+} // namespace flags_internal
+
+void SetFlagsUsageConfig(FlagsUsageConfig usage_config) {
+ absl::MutexLock l(&flags_internal::custom_usage_config_guard);
+
+ if (!usage_config.contains_helpshort_flags)
+ usage_config.contains_helpshort_flags =
+ flags_internal::ContainsHelpshortFlags;
+
+ if (!usage_config.contains_help_flags)
+ usage_config.contains_help_flags = flags_internal::ContainsHelppackageFlags;
+
+ if (!usage_config.contains_helppackage_flags)
+ usage_config.contains_helppackage_flags =
+ flags_internal::ContainsHelppackageFlags;
+
+ if (!usage_config.version_string)
+ usage_config.version_string = flags_internal::VersionString;
+
+ if (!usage_config.normalize_filename)
+ usage_config.normalize_filename = flags_internal::NormalizeFilename;
+
+ if (flags_internal::custom_usage_config)
+ *flags_internal::custom_usage_config = usage_config;
+ else
+ flags_internal::custom_usage_config = new FlagsUsageConfig(usage_config);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/flags/usage_config.h b/absl/flags/usage_config.h
new file mode 100644
index 00000000..c6d34e4a
--- /dev/null
+++ b/absl/flags/usage_config.h
@@ -0,0 +1,133 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: usage_config.h
+// -----------------------------------------------------------------------------
+//
+// This file defines the main usage reporting configuration interfaces and
+// documents Abseil's supported built-in usage flags. If these flags are found
+// when parsing a command-line, Abseil will exit the program and display
+// appropriate help messages.
+#ifndef ABSL_FLAGS_USAGE_CONFIG_H_
+#define ABSL_FLAGS_USAGE_CONFIG_H_
+
+#include <functional>
+#include <string>
+
+#include "absl/strings/string_view.h"
+
+// -----------------------------------------------------------------------------
+// Built-in Usage Flags
+// -----------------------------------------------------------------------------
+//
+// Abseil supports the following built-in usage flags. When passed, these flags
+// exit the program and :
+//
+// * --help
+// Shows help on important flags for this binary
+// * --helpfull
+// Shows help on all flags
+// * --helpshort
+// Shows help on only the main module for this program
+// * --helppackage
+// Shows help on all modules in the main package
+// * --version
+// Shows the version and build info for this binary and exits
+// * --only_check_args
+// Exits after checking all flags
+// * --helpon
+// Shows help on the modules named by this flag value
+// * --helpmatch
+// Shows help on modules whose name contains the specified substring
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+namespace flags_internal {
+using FlagKindFilter = std::function<bool (absl::string_view)>;
+} // namespace flags_internal
+
+// FlagsUsageConfig
+//
+// This structure contains the collection of callbacks for changing the behavior
+// of the usage reporting routines in Abseil Flags.
+struct FlagsUsageConfig {
+ // Returns true if flags defined in the given source code file should be
+ // reported with --helpshort flag. For example, if the file
+ // "path/to/my/code.cc" defines the flag "--my_flag", and
+ // contains_helpshort_flags("path/to/my/code.cc") returns true, invoking the
+ // program with --helpshort will include information about --my_flag in the
+ // program output.
+ flags_internal::FlagKindFilter contains_helpshort_flags;
+
+ // Returns true if flags defined in the filename should be reported with
+ // --help flag. For example, if the file
+ // "path/to/my/code.cc" defines the flag "--my_flag", and
+ // contains_help_flags("path/to/my/code.cc") returns true, invoking the
+ // program with --help will include information about --my_flag in the
+ // program output.
+ flags_internal::FlagKindFilter contains_help_flags;
+
+ // Returns true if flags defined in the filename should be reported with
+ // --helppackage flag. For example, if the file
+ // "path/to/my/code.cc" defines the flag "--my_flag", and
+ // contains_helppackage_flags("path/to/my/code.cc") returns true, invoking the
+ // program with --helppackage will include information about --my_flag in the
+ // program output.
+ flags_internal::FlagKindFilter contains_helppackage_flags;
+
+ // Generates std::string containing program version. This is the std::string reported
+ // when user specifies --version in a command line.
+ std::function<std::string()> version_string;
+
+ // Normalizes the filename specific to the build system/filesystem used. This
+ // routine is used when we report the information about the flag definition
+ // location. For instance, if your build resides at some location you do not
+ // want to expose in the usage output, you can trim it to show only relevant
+ // part.
+ // For example:
+ // normalize_filename("/my_company/some_long_path/src/project/file.cc")
+ // might produce
+ // "project/file.cc".
+ std::function<std::string (absl::string_view)> normalize_filename;
+};
+
+// SetFlagsUsageConfig()
+//
+// Sets the usage reporting configuration callbacks. If any of the callbacks are
+// not set in usage_config instance, then the default value of the callback is
+// used.
+void SetFlagsUsageConfig(FlagsUsageConfig usage_config);
+
+namespace flags_internal {
+
+FlagsUsageConfig GetUsageConfig();
+
+void ReportUsageError(absl::string_view msg, bool is_fatal);
+
+} // namespace flags_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+extern "C" {
+
+// Additional report of fatal usage error message before we std::exit. Error is
+// fatal if is_fatal argument to ReportUsageError is true.
+void AbslInternalReportFatalUsageError(absl::string_view);
+
+} // extern "C"
+
+#endif // ABSL_FLAGS_USAGE_CONFIG_H_
diff --git a/absl/flags/usage_config_test.cc b/absl/flags/usage_config_test.cc
new file mode 100644
index 00000000..3bde13af
--- /dev/null
+++ b/absl/flags/usage_config_test.cc
@@ -0,0 +1,198 @@
+//
+// 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.
+
+#include "absl/flags/usage_config.h"
+
+#include "gtest/gtest.h"
+#include "absl/flags/internal/path_util.h"
+#include "absl/flags/internal/program_name.h"
+#include "absl/strings/match.h"
+
+namespace {
+
+class FlagsUsageConfigTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ // Install Default config for the use on this unit test.
+ // Binary may install a custom config before tests are run.
+ absl::FlagsUsageConfig default_config;
+ absl::SetFlagsUsageConfig(default_config);
+ }
+};
+
+namespace flags = absl::flags_internal;
+
+bool TstContainsHelpshortFlags(absl::string_view f) {
+ return absl::StartsWith(flags::Basename(f), "progname.");
+}
+
+bool TstContainsHelppackageFlags(absl::string_view f) {
+ return absl::EndsWith(flags::Package(f), "aaa/");
+}
+
+bool TstContainsHelpFlags(absl::string_view f) {
+ return absl::EndsWith(flags::Package(f), "zzz/");
+}
+
+std::string TstVersionString() { return "program 1.0.0"; }
+
+std::string TstNormalizeFilename(absl::string_view filename) {
+ return std::string(filename.substr(2));
+}
+
+void TstReportUsageMessage(absl::string_view msg) {}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestGetSetFlagsUsageConfig) {
+ EXPECT_TRUE(flags::GetUsageConfig().contains_helpshort_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().contains_helppackage_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().version_string);
+ EXPECT_TRUE(flags::GetUsageConfig().normalize_filename);
+
+ absl::FlagsUsageConfig empty_config;
+ empty_config.contains_helpshort_flags = &TstContainsHelpshortFlags;
+ empty_config.contains_help_flags = &TstContainsHelpFlags;
+ empty_config.contains_helppackage_flags = &TstContainsHelppackageFlags;
+ empty_config.version_string = &TstVersionString;
+ empty_config.normalize_filename = &TstNormalizeFilename;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_TRUE(flags::GetUsageConfig().contains_helpshort_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().contains_helppackage_flags);
+ EXPECT_TRUE(flags::GetUsageConfig().version_string);
+ EXPECT_TRUE(flags::GetUsageConfig().normalize_filename);
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestContainsHelpshortFlags) {
+ flags::SetProgramInvocationName("usage_config_test");
+
+ auto config = flags::GetUsageConfig();
+ EXPECT_TRUE(config.contains_helpshort_flags("adir/cd/usage_config_test.cc"));
+ EXPECT_TRUE(
+ config.contains_helpshort_flags("aaaa/usage_config_test-main.cc"));
+ EXPECT_TRUE(config.contains_helpshort_flags("abc/usage_config_test_main.cc"));
+ EXPECT_FALSE(config.contains_helpshort_flags("usage_config_main.cc"));
+
+ absl::FlagsUsageConfig empty_config;
+ empty_config.contains_helpshort_flags = &TstContainsHelpshortFlags;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_TRUE(
+ flags::GetUsageConfig().contains_helpshort_flags("aaa/progname.cpp"));
+ EXPECT_FALSE(
+ flags::GetUsageConfig().contains_helpshort_flags("aaa/progmane.cpp"));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestContainsHelpFlags) {
+ flags::SetProgramInvocationName("usage_config_test");
+
+ auto config = flags::GetUsageConfig();
+ EXPECT_TRUE(config.contains_help_flags("zzz/usage_config_test.cc"));
+ EXPECT_TRUE(
+ config.contains_help_flags("bdir/a/zzz/usage_config_test-main.cc"));
+ EXPECT_TRUE(
+ config.contains_help_flags("//aqse/zzz/usage_config_test_main.cc"));
+ EXPECT_FALSE(config.contains_help_flags("zzz/aa/usage_config_main.cc"));
+
+ absl::FlagsUsageConfig empty_config;
+ empty_config.contains_help_flags = &TstContainsHelpFlags;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_TRUE(flags::GetUsageConfig().contains_help_flags("zzz/main-body.c"));
+ EXPECT_FALSE(
+ flags::GetUsageConfig().contains_help_flags("zzz/dir/main-body.c"));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestContainsHelppackageFlags) {
+ flags::SetProgramInvocationName("usage_config_test");
+
+ auto config = flags::GetUsageConfig();
+ EXPECT_TRUE(config.contains_helppackage_flags("aaa/usage_config_test.cc"));
+ EXPECT_TRUE(
+ config.contains_helppackage_flags("bbdir/aaa/usage_config_test-main.cc"));
+ EXPECT_TRUE(config.contains_helppackage_flags(
+ "//aqswde/aaa/usage_config_test_main.cc"));
+ EXPECT_FALSE(config.contains_helppackage_flags("aadir/usage_config_main.cc"));
+
+ absl::FlagsUsageConfig empty_config;
+ empty_config.contains_helppackage_flags = &TstContainsHelppackageFlags;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_TRUE(
+ flags::GetUsageConfig().contains_helppackage_flags("aaa/main-body.c"));
+ EXPECT_FALSE(
+ flags::GetUsageConfig().contains_helppackage_flags("aadir/main-body.c"));
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestVersionString) {
+ flags::SetProgramInvocationName("usage_config_test");
+
+#ifdef NDEBUG
+ std::string expected_output = "usage_config_test\n";
+#else
+ std::string expected_output =
+ "usage_config_test\nDebug build (NDEBUG not #defined)\n";
+#endif
+
+ EXPECT_EQ(flags::GetUsageConfig().version_string(), expected_output);
+
+ absl::FlagsUsageConfig empty_config;
+ empty_config.version_string = &TstVersionString;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_EQ(flags::GetUsageConfig().version_string(), "program 1.0.0");
+}
+
+// --------------------------------------------------------------------
+
+TEST_F(FlagsUsageConfigTest, TestNormalizeFilename) {
+ // This tests the default implementation.
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("///a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/"), "");
+
+ // This tests that the custom implementation is called.
+ absl::FlagsUsageConfig empty_config;
+ empty_config.normalize_filename = &TstNormalizeFilename;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("aaa/a.cc"), "a/a.cc");
+
+ // This tests that the default implementation is called.
+ empty_config.normalize_filename = nullptr;
+ absl::SetFlagsUsageConfig(empty_config);
+
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("/a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("///a/a.cc"), "a/a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("\\a\\a.cc"), "a\\a.cc");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("//"), "");
+ EXPECT_EQ(flags::GetUsageConfig().normalize_filename("\\\\"), "");
+}
+
+} // namespace
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel
index 4f7c94ce..8c2daf70 100644
--- a/absl/hash/BUILD.bazel
+++ b/absl/hash/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -32,6 +33,7 @@ cc_library(
],
hdrs = ["hash.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":city",
"//absl/base:core_headers",
@@ -50,6 +52,7 @@ cc_library(
name = "hash_testing",
testonly = 1,
hdrs = ["hash_testing.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":spy_hash_state",
"//absl/meta:type_traits",
@@ -63,6 +66,7 @@ cc_test(
name = "hash_test",
srcs = ["hash_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":hash",
":hash_testing",
@@ -80,6 +84,7 @@ cc_library(
testonly = 1,
hdrs = ["internal/spy_hash_state.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
":hash",
@@ -95,6 +100,7 @@ cc_library(
"internal/city.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/base:core_headers",
@@ -106,6 +112,7 @@ cc_test(
name = "city_test",
srcs = ["internal/city_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":city",
"@com_google_googletest//:gtest_main",
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt
index 8f97d7cc..febc551f 100644
--- a/absl/hash/CMakeLists.txt
+++ b/absl/hash/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -43,6 +43,8 @@ absl_cc_library(
hash_testing
HDRS
"hash_testing.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::spy_hash_state
absl::meta
@@ -56,7 +58,9 @@ absl_cc_test(
NAME
hash_test
SRCS
- "hash_test.cc"
+ "hash_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
DEPS
absl::hash
absl::hash_testing
diff --git a/absl/hash/hash.h b/absl/hash/hash.h
index 2c8982b8..d36f0960 100644
--- a/absl/hash/hash.h
+++ b/absl/hash/hash.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -36,25 +36,34 @@
// framework by simply combining its state with the state of known, hashable
// types. Hashing of that combined state is separately done by `absl::Hash`.
//
+// One should assume that a hash algorithm is chosen randomly at the start of
+// each process. E.g., absl::Hash<int>()(9) in one process and
+// absl::Hash<int>()(9) in another process are likely to differ.
+//
// Example:
//
-// // Suppose we have a class `Circle` for which we want to add hashing
+// // Suppose we have a class `Circle` for which we want to add hashing:
// class Circle {
-// public:
-// ...
-// private:
-// std::pair<int, int> center_;
-// int radius_;
-// };
-//
-// // To add hashing support to `Circle`, we simply need to add an ordinary
-// // function `AbslHashValue()`, and return the combined hash state of the
-// // existing hash state and the class state:
+// public:
+// ...
+// private:
+// std::pair<int, int> center_;
+// int radius_;
+// };
//
+// // To add hashing support to `Circle`, we simply need to add a free
+// // (non-member) function `AbslHashValue()`, and return the combined hash
+// // state of the existing hash state and the class state. You can add such a
+// // free function using a friend declaration within the body of the class:
+// class Circle {
+// public:
+// ...
// template <typename H>
// friend H AbslHashValue(H h, const Circle& c) {
// return H::combine(std::move(h), c.center_, c.radius_);
// }
+// ...
+// };
//
// For more information, see Adding Type Support to `absl::Hash` below.
//
@@ -64,7 +73,7 @@
#include "absl/hash/internal/hash.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// `absl::Hash`
@@ -236,7 +245,7 @@ using Hash = absl::hash_internal::Hash<T>;
// }
// private:
// virtual void HashValue(absl::HashState state) const = 0;
-// };
+// };
//
// class Impl : Interface {
// private:
@@ -244,7 +253,7 @@ using Hash = absl::hash_internal::Hash<T>;
// absl::HashState::combine(std::move(state), v1_, v2_);
// }
// int v1_;
-// string v2_;
+// std::string v2_;
// };
class HashState : public hash_internal::HashStateBase<HashState> {
public:
@@ -309,6 +318,7 @@ class HashState : public hash_internal::HashStateBase<HashState> {
void (*combine_contiguous_)(void*, const unsigned char*, size_t);
};
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_HASH_HASH_H_
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc
index 4a1a98d5..2a4e2262 100644
--- a/absl/hash/hash_test.cc
+++ b/absl/hash/hash_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,6 +15,7 @@
#include "absl/hash/hash.h"
#include <array>
+#include <bitset>
#include <cstring>
#include <deque>
#include <forward_list>
@@ -50,7 +51,7 @@ using absl::hash_internal::SpyHashState;
template <typename T>
class HashValueIntTest : public testing::Test {
};
-TYPED_TEST_CASE_P(HashValueIntTest);
+TYPED_TEST_SUITE_P(HashValueIntTest);
template <typename T>
SpyHashState SpyHash(const T& value) {
@@ -84,11 +85,349 @@ using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint
uint64_t, size_t>;
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
+enum LegacyEnum { kValue1, kValue2, kValue3 };
+
+enum class EnumClass { kValue4, kValue5, kValue6 };
+
+TEST(HashValueTest, EnumAndBool) {
+ EXPECT_TRUE((is_hashable<LegacyEnum>::value));
+ EXPECT_TRUE((is_hashable<EnumClass>::value));
+ EXPECT_TRUE((is_hashable<bool>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ LegacyEnum::kValue1, LegacyEnum::kValue2, LegacyEnum::kValue3)));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ EnumClass::kValue4, EnumClass::kValue5, EnumClass::kValue6)));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(true, false)));
+}
+
+TEST(HashValueTest, FloatingPoint) {
+ EXPECT_TRUE((is_hashable<float>::value));
+ EXPECT_TRUE((is_hashable<double>::value));
+ EXPECT_TRUE((is_hashable<long double>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(42.f, 0.f, -0.f, std::numeric_limits<float>::infinity(),
+ -std::numeric_limits<float>::infinity())));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(42., 0., -0., std::numeric_limits<double>::infinity(),
+ -std::numeric_limits<double>::infinity())));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ // Add some values with small exponent to test that NORMAL values also
+ // append their category.
+ .5L, 1.L, 2.L, 4.L, 42.L, 0.L, -0.L,
+ 17 * static_cast<long double>(std::numeric_limits<double>::max()),
+ std::numeric_limits<long double>::infinity(),
+ -std::numeric_limits<long double>::infinity())));
+}
+
+TEST(HashValueTest, Pointer) {
+ EXPECT_TRUE((is_hashable<int*>::value));
+
+ int i;
+ int* ptr = &i;
+ int* n = nullptr;
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(&i, ptr, nullptr, ptr + 1, n)));
+}
+
+TEST(HashValueTest, PointerAlignment) {
+ // We want to make sure that pointer alignment will not cause bits to be
+ // stuck.
+
+ constexpr size_t kTotalSize = 1 << 20;
+ std::unique_ptr<char[]> data(new char[kTotalSize]);
+ constexpr size_t kLog2NumValues = 5;
+ constexpr size_t kNumValues = 1 << kLog2NumValues;
+
+ for (size_t align = 1; align < kTotalSize / kNumValues;
+ align < 8 ? align += 1 : align < 1024 ? align += 8 : align += 32) {
+ SCOPED_TRACE(align);
+ ASSERT_LE(align * kNumValues, kTotalSize);
+
+ size_t bits_or = 0;
+ size_t bits_and = ~size_t{};
+
+ for (size_t i = 0; i < kNumValues; ++i) {
+ size_t hash = absl::Hash<void*>()(data.get() + i * align);
+ bits_or |= hash;
+ bits_and &= hash;
+ }
+
+ // 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, 0) << "0x" << std::hex << stuck_bits;
+ }
+}
+
+TEST(HashValueTest, PairAndTuple) {
+ EXPECT_TRUE((is_hashable<std::pair<int, int>>::value));
+ EXPECT_TRUE((is_hashable<std::pair<const int&, const int&>>::value));
+ EXPECT_TRUE((is_hashable<std::tuple<int&, int&>>::value));
+ EXPECT_TRUE((is_hashable<std::tuple<int&&, int&&>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::make_pair(0, 42), std::make_pair(0, 42), std::make_pair(42, 0),
+ std::make_pair(0, 0), std::make_pair(42, 42), std::make_pair(1, 42))));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(std::make_tuple(0, 0, 0), std::make_tuple(0, 0, 42),
+ std::make_tuple(0, 23, 0), std::make_tuple(17, 0, 0),
+ std::make_tuple(42, 0, 0), std::make_tuple(3, 9, 9),
+ std::make_tuple(0, 0, -42))));
+
+ // Test that tuples of lvalue references work (so we need a few lvalues):
+ int a = 0, b = 1, c = 17, d = 23;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::tie(a, a), std::tie(a, b), std::tie(b, c), std::tie(c, d))));
+
+ // Test that tuples of rvalue references work:
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::forward_as_tuple(0, 0, 0), std::forward_as_tuple(0, 0, 42),
+ std::forward_as_tuple(0, 23, 0), std::forward_as_tuple(17, 0, 0),
+ std::forward_as_tuple(42, 0, 0), std::forward_as_tuple(3, 9, 9),
+ std::forward_as_tuple(0, 0, -42))));
+}
+
+TEST(HashValueTest, CombineContiguousWorks) {
+ std::vector<std::tuple<int>> v1 = {std::make_tuple(1), std::make_tuple(3)};
+ std::vector<std::tuple<int>> v2 = {std::make_tuple(1), std::make_tuple(2)};
+
+ auto vh1 = SpyHash(v1);
+ auto vh2 = SpyHash(v2);
+ EXPECT_NE(vh1, vh2);
+}
+
+struct DummyDeleter {
+ template <typename T>
+ void operator() (T* ptr) {}
+};
+
+struct SmartPointerEq {
+ template <typename T, typename U>
+ bool operator()(const T& t, const U& u) const {
+ return GetPtr(t) == GetPtr(u);
+ }
+
+ template <typename T>
+ static auto GetPtr(const T& t) -> decltype(&*t) {
+ return t ? &*t : nullptr;
+ }
+
+ static std::nullptr_t GetPtr(std::nullptr_t) { return nullptr; }
+};
+
+TEST(HashValueTest, SmartPointers) {
+ EXPECT_TRUE((is_hashable<std::unique_ptr<int>>::value));
+ EXPECT_TRUE((is_hashable<std::unique_ptr<int, DummyDeleter>>::value));
+ EXPECT_TRUE((is_hashable<std::shared_ptr<int>>::value));
+
+ int i, j;
+ std::unique_ptr<int, DummyDeleter> unique1(&i);
+ std::unique_ptr<int, DummyDeleter> unique2(&i);
+ std::unique_ptr<int, DummyDeleter> unique_other(&j);
+ std::unique_ptr<int, DummyDeleter> unique_null;
+
+ std::shared_ptr<int> shared1(&i, DummyDeleter());
+ std::shared_ptr<int> shared2(&i, DummyDeleter());
+ std::shared_ptr<int> shared_other(&j, DummyDeleter());
+ std::shared_ptr<int> shared_null;
+
+ // Sanity check of the Eq function.
+ ASSERT_TRUE(SmartPointerEq{}(unique1, shared1));
+ ASSERT_FALSE(SmartPointerEq{}(unique1, shared_other));
+ ASSERT_TRUE(SmartPointerEq{}(unique_null, nullptr));
+ ASSERT_FALSE(SmartPointerEq{}(shared2, nullptr));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::forward_as_tuple(&i, nullptr, //
+ unique1, unique2, unique_null, //
+ absl::make_unique<int>(), //
+ shared1, shared2, shared_null, //
+ std::make_shared<int>()),
+ SmartPointerEq{}));
+}
+
+TEST(HashValueTest, FunctionPointer) {
+ using Func = int (*)();
+ EXPECT_TRUE(is_hashable<Func>::value);
+
+ Func p1 = [] { return 2; }, p2 = [] { return 1; };
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(p1, p2, nullptr)));
+}
+
+struct WrapInTuple {
+ template <typename T>
+ std::tuple<int, T, size_t> operator()(const T& t) const {
+ return std::make_tuple(7, t, 0xdeadbeef);
+ }
+};
+
+TEST(HashValueTest, Strings) {
+ EXPECT_TRUE((is_hashable<std::string>::value));
+
+ const std::string small = "foo";
+ const std::string dup = "foofoo";
+ const std::string large = "large";
+ const std::string huge = std::string(5000, 'a');
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ std::string(), absl::string_view(),
+ std::string(""), absl::string_view(""),
+ std::string(small), absl::string_view(small),
+ std::string(dup), absl::string_view(dup),
+ std::string(large), absl::string_view(large),
+ std::string(huge), absl::string_view(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(std::string("")), t(absl::string_view("")),
+ t(std::string(small)), t(absl::string_view(small)),
+ t(std::string(dup)), t(absl::string_view(dup)),
+ t(std::string(large)), t(absl::string_view(large)),
+ t(std::string(huge)), t(absl::string_view(huge)))));
+
+ // Make sure that hashing a `const char*` does not use its std::string-value.
+ EXPECT_NE(SpyHash(static_cast<const char*>("ABC")),
+ SpyHash(absl::string_view("ABC")));
+}
+
+TEST(HashValueTest, StdArray) {
+ EXPECT_TRUE((is_hashable<std::array<int, 3>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(std::array<int, 3>{}, std::array<int, 3>{{0, 23, 42}})));
+}
+
+TEST(HashValueTest, StdBitset) {
+ EXPECT_TRUE((is_hashable<std::bitset<257>>::value));
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<2>("00"), std::bitset<2>("01"), std::bitset<2>("10"),
+ std::bitset<2>("11")}));
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<5>("10101"), std::bitset<5>("10001"), std::bitset<5>()}));
+
+ constexpr int kNumBits = 256;
+ std::array<std::string, 6> bit_strings;
+ bit_strings.fill(std::string(kNumBits, '1'));
+ bit_strings[1][0] = '0';
+ bit_strings[2][1] = '0';
+ bit_strings[3][kNumBits / 3] = '0';
+ bit_strings[4][kNumBits - 2] = '0';
+ bit_strings[5][kNumBits - 1] = '0';
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {std::bitset<kNumBits>(bit_strings[0].c_str()),
+ std::bitset<kNumBits>(bit_strings[1].c_str()),
+ std::bitset<kNumBits>(bit_strings[2].c_str()),
+ std::bitset<kNumBits>(bit_strings[3].c_str()),
+ std::bitset<kNumBits>(bit_strings[4].c_str()),
+ std::bitset<kNumBits>(bit_strings[5].c_str())}));
+} // namespace
+
+template <typename T>
+class HashValueSequenceTest : public testing::Test {
+};
+TYPED_TEST_SUITE_P(HashValueSequenceTest);
+
+TYPED_TEST_P(HashValueSequenceTest, BasicUsage) {
+ EXPECT_TRUE((is_hashable<TypeParam>::value));
+
+ using ValueType = typename TypeParam::value_type;
+ auto a = static_cast<ValueType>(0);
+ auto b = static_cast<ValueType>(23);
+ auto c = static_cast<ValueType>(42);
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(TypeParam(), TypeParam{}, TypeParam{a, b, c},
+ TypeParam{a, b}, TypeParam{b, c})));
+}
+
+REGISTER_TYPED_TEST_CASE_P(HashValueSequenceTest, BasicUsage);
+using IntSequenceTypes =
+ testing::Types<std::deque<int>, std::forward_list<int>, std::list<int>,
+ std::vector<int>, std::vector<bool>, std::set<int>,
+ std::multiset<int>>;
+INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
+
+// Private type that only supports AbslHashValue to make sure our chosen hash
+// implentation is recursive within absl::Hash.
+// It uses std::abs() on the value to provide different bitwise representations
+// of the same logical value.
+struct Private {
+ int i;
+ template <typename H>
+ friend H AbslHashValue(H h, Private p) {
+ return H::combine(std::move(h), std::abs(p.i));
+ }
+
+ friend bool operator==(Private a, Private b) {
+ return std::abs(a.i) == std::abs(b.i);
+ }
+
+ friend std::ostream& operator<<(std::ostream& o, Private p) {
+ return o << p.i;
+ }
+};
+
+TEST(HashValueTest, PrivateSanity) {
+ // Sanity check that Private is working as the tests below expect it to work.
+ EXPECT_TRUE(is_hashable<Private>::value);
+ EXPECT_NE(SpyHash(Private{0}), SpyHash(Private{1}));
+ EXPECT_EQ(SpyHash(Private{1}), SpyHash(Private{1}));
+}
+
+TEST(HashValueTest, Optional) {
+ EXPECT_TRUE(is_hashable<absl::optional<Private>>::value);
+
+ using O = absl::optional<Private>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}})));
+}
+
+TEST(HashValueTest, Variant) {
+ using V = absl::variant<Private, std::string>;
+ EXPECT_TRUE(is_hashable<V>::value);
+
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD"))));
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+ struct S {};
+ EXPECT_FALSE(is_hashable<absl::variant<S>>::value);
+#endif
+}
+
+TEST(HashValueTest, Maps) {
+ EXPECT_TRUE((is_hashable<std::map<int, std::string>>::value));
+
+ using M = std::map<int, std::string>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ M{}, M{{0, "foo"}}, M{{1, "foo"}}, M{{0, "bar"}}, M{{1, "bar"}},
+ M{{0, "foo"}, {42, "bar"}}, M{{1, "foo"}, {42, "bar"}},
+ M{{1, "foo"}, {43, "bar"}}, M{{1, "foo"}, {43, "baz"}})));
+
+ using MM = std::multimap<int, std::string>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple(
+ MM{}, MM{{0, "foo"}}, MM{{1, "foo"}}, MM{{0, "bar"}}, MM{{1, "bar"}},
+ MM{{0, "foo"}, {0, "bar"}}, MM{{0, "bar"}, {0, "foo"}},
+ MM{{0, "foo"}, {42, "bar"}}, MM{{1, "foo"}, {42, "bar"}},
+ MM{{1, "foo"}, {1, "foo"}, {43, "bar"}}, MM{{1, "foo"}, {43, "baz"}})));
+}
+
template <typename T, typename = void>
-struct IsHashCallble : std::false_type {};
+struct IsHashCallable : std::false_type {};
template <typename T>
-struct IsHashCallble<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()(
+struct IsHashCallable<T, absl::void_t<decltype(std::declval<absl::Hash<T>>()(
std::declval<const T&>()))>> : std::true_type {};
template <typename T, typename = void>
@@ -105,10 +444,11 @@ TEST(IsHashableTest, ValidHash) {
EXPECT_TRUE(std::is_move_constructible<absl::Hash<int>>::value);
EXPECT_TRUE(absl::is_copy_assignable<absl::Hash<int>>::value);
EXPECT_TRUE(absl::is_move_assignable<absl::Hash<int>>::value);
- EXPECT_TRUE(IsHashCallble<int>::value);
+ EXPECT_TRUE(IsHashCallable<int>::value);
EXPECT_TRUE(IsAggregateInitializable<absl::Hash<int>>::value);
}
-#if ABSL_HASH_INTERNAL_CAN_POISON_ && !defined(__APPLE__)
+
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
TEST(IsHashableTest, PoisonHash) {
struct X {};
EXPECT_FALSE((is_hashable<X>::value));
@@ -117,10 +457,10 @@ TEST(IsHashableTest, PoisonHash) {
EXPECT_FALSE(std::is_move_constructible<absl::Hash<X>>::value);
EXPECT_FALSE(absl::is_copy_assignable<absl::Hash<X>>::value);
EXPECT_FALSE(absl::is_move_assignable<absl::Hash<X>>::value);
- EXPECT_FALSE(IsHashCallble<X>::value);
+ EXPECT_FALSE(IsHashCallable<X>::value);
EXPECT_FALSE(IsAggregateInitializable<absl::Hash<X>>::value);
}
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
// Hashable types
//
@@ -129,7 +469,7 @@ TEST(IsHashableTest, PoisonHash) {
struct NoOp {
template <typename HashCode>
friend HashCode AbslHashValue(HashCode h, NoOp n) {
- return std::move(h);
+ return h;
}
};
@@ -159,8 +499,16 @@ struct CombineVariadic {
Int(4));
}
};
+enum class InvokeTag {
+ kUniquelyRepresented,
+ kHashValue,
+#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ kLegacyHash,
+#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ kStdHash,
+ kNone
+};
-using InvokeTag = absl::hash_internal::InvokeHashTag;
template <InvokeTag T>
using InvokeTagConstant = std::integral_constant<InvokeTag, T>;
@@ -175,6 +523,7 @@ struct MinTag<a> : InvokeTagConstant<a> {};
template <InvokeTag... Tags>
struct CustomHashType {
+ explicit CustomHashType(size_t val) : value(val) {}
size_t value;
};
@@ -195,7 +544,7 @@ H AbslHashValue(H state, CustomHashType<Tags...> t) {
} // namespace
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
template <InvokeTag... Tags>
struct is_uniquely_represented<
@@ -203,7 +552,7 @@ struct is_uniquely_represented<
typename EnableIfContained<InvokeTag::kUniquelyRepresented, Tags...>::type>
: std::true_type {};
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
@@ -243,17 +592,17 @@ void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>, T...) {
EXPECT_TRUE(is_hashable<const type&>());
const size_t offset = static_cast<int>(std::min({T::value...}));
- EXPECT_EQ(SpyHash(type{7}), SpyHash(size_t{7 + offset}));
+ EXPECT_EQ(SpyHash(type(7)), SpyHash(size_t{7 + offset}));
}
void TestCustomHashType(InvokeTagConstant<InvokeTag::kNone>) {
-#if ABSL_HASH_INTERNAL_CAN_POISON_
+#if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
// is_hashable is false if we don't support any of the hooks.
using type = CustomHashType<>;
EXPECT_FALSE(is_hashable<type>());
EXPECT_FALSE(is_hashable<const type>());
EXPECT_FALSE(is_hashable<const type&>());
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
+#endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
}
template <InvokeTag Tag, typename... T>
@@ -275,7 +624,7 @@ TEST(HashTest, NoOpsAreEquivalent) {
template <typename T>
class HashIntTest : public testing::Test {
};
-TYPED_TEST_CASE_P(HashIntTest);
+TYPED_TEST_SUITE_P(HashIntTest);
TYPED_TEST_P(HashIntTest, BasicUsage) {
EXPECT_NE(Hash<NoOp>()({}), Hash<TypeParam>()(0));
@@ -354,7 +703,8 @@ TEST(HashTest, HashNonUniquelyRepresentedType) {
}
TEST(HashTest, StandardHashContainerUsage) {
- std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"}, { 42, "bar" }};
+ std::unordered_map<int, std::string, Hash<int>> map = {{0, "foo"},
+ {42, "bar"}};
EXPECT_NE(map.find(0), map.end());
EXPECT_EQ(map.find(1), map.end());
@@ -424,4 +774,24 @@ TEST(HashTest, TypeErased) {
SpyHash(std::make_pair(size_t{7}, 17)));
}
+struct ValueWithBoolConversion {
+ operator bool() const { return false; }
+ int i;
+};
+
+} // namespace
+namespace std {
+template <>
+struct hash<ValueWithBoolConversion> {
+ size_t operator()(ValueWithBoolConversion v) { return v.i; }
+};
+} // namespace std
+
+namespace {
+
+TEST(HashTest, DoesNotUseImplicitConversionsToBool) {
+ EXPECT_NE(absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{0}),
+ absl::Hash<ValueWithBoolConversion>()(ValueWithBoolConversion{1}));
+}
+
} // namespace
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h
index 1c4db26a..6e39028f 100644
--- a/absl/hash/hash_testing.h
+++ b/absl/hash/hash_testing.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/types/variant.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Run the absl::Hash algorithm over all the elements passed in and verify that
// their hash expansion is congruent with their `==` operator.
@@ -191,7 +191,9 @@ VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
struct Info {
const V& value;
size_t index;
- std::string ToString() const { return absl::visit(PrintVisitor{index}, value); }
+ std::string ToString() const {
+ return absl::visit(PrintVisitor{index}, value);
+ }
SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); }
};
@@ -370,7 +372,7 @@ VerifyTypeImplementsAbslHashCorrectly(std::initializer_list<T> values,
equals);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HASH_HASH_TESTING_H_
diff --git a/absl/hash/internal/city.cc b/absl/hash/internal/city.cc
index 5c076fb5..c7ad1591 100644
--- a/absl/hash/internal/city.cc
+++ b/absl/hash/internal/city.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,7 +30,7 @@
#include "absl/base/optimization.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
#ifdef ABSL_IS_BIG_ENDIAN
@@ -342,5 +342,5 @@ uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
}
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/hash/internal/city.h b/absl/hash/internal/city.h
index 46c18ffa..7586ba08 100644
--- a/absl/hash/internal/city.h
+++ b/absl/hash/internal/city.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-// http://code.google.com/p/cityhash/
+// https://code.google.com/p/cityhash/
//
// This file provides a few functions for hashing strings. All of them are
// high-quality functions in the sense that they pass standard tests such
@@ -49,9 +49,8 @@
#include <stdlib.h> // for size_t.
#include <utility>
-
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
typedef std::pair<uint64_t, uint64_t> uint128;
@@ -88,7 +87,7 @@ inline uint64_t Hash128to64(const uint128 &x) {
}
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HASH_INTERNAL_CITY_H_
diff --git a/absl/hash/internal/city_test.cc b/absl/hash/internal/city_test.cc
index f305ed9e..1b9373c2 100644
--- a/absl/hash/internal/city_test.cc
+++ b/absl/hash/internal/city_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
@@ -591,5 +591,5 @@ TEST(CityHashTest, Unchanging) {
}
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index 3e553625..087b389b 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,11 +15,11 @@
#include "absl/hash/internal/hash.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
ABSL_CONST_INIT const void* const CityHashState::kSeed = &kSeed;
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h
index a51ca954..81f1edf8 100644
--- a/absl/hash/internal/hash.h
+++ b/absl/hash/internal/hash.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -50,7 +50,7 @@
#include "absl/hash/internal/city.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
// HashStateBase
@@ -222,7 +222,9 @@ typename std::enable_if<std::is_enum<Enum>::value, H>::type AbslHashValue(
}
// AbslHashValue() for hashing floating-point values
template <typename H, typename Float>
-typename std::enable_if<std::is_floating_point<Float>::value, H>::type
+typename std::enable_if<std::is_same<Float, float>::value ||
+ std::is_same<Float, double>::value,
+ H>::type
AbslHashValue(H hash_state, Float value) {
return hash_internal::hash_bytes(std::move(hash_state),
value == 0 ? 0 : value);
@@ -232,8 +234,9 @@ AbslHashValue(H hash_state, Float value) {
// For example, in x86 sizeof(long double)==16 but it only really uses 80-bits
// of it. This means we can't use hash_bytes on a long double and have to
// convert it to something else first.
-template <typename H>
-H AbslHashValue(H hash_state, long double value) {
+template <typename H, typename LongDouble>
+typename std::enable_if<std::is_same<LongDouble, long double>::value, H>::type
+AbslHashValue(H hash_state, LongDouble value) {
const int category = std::fpclassify(value);
switch (category) {
case FP_INFINITE:
@@ -265,7 +268,12 @@ H AbslHashValue(H hash_state, long double value) {
// AbslHashValue() for hashing pointers
template <typename H, typename T>
H AbslHashValue(H hash_state, T* ptr) {
- return hash_internal::hash_bytes(std::move(hash_state), 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.
+ return H::combine(std::move(hash_state), v, v);
}
// AbslHashValue() for hashing nullptr_t
@@ -528,53 +536,22 @@ hash_range_or_bytes(H hash_state, const T* data, size_t size) {
return hash_state;
}
-// InvokeHashTag
-//
-// InvokeHash(H, const T&) invokes the appropriate hash implementation for a
-// hasher of type `H` and a value of type `T`. If `T` is not hashable, there
-// will be no matching overload of InvokeHash().
-// Note: Some platforms (eg MSVC) do not support the detect idiom on
-// std::hash. In those platforms the last fallback will be std::hash and
-// InvokeHash() will always have a valid overload even if std::hash<T> is not
-// valid.
-//
-// We try the following options in order:
-// * If is_uniquely_represented, hash bytes directly.
-// * ADL AbslHashValue(H, const T&) call.
-// * std::hash<T>
-
-// In MSVC we can't probe std::hash or stdext::hash because it triggers a
-// static_assert instead of failing substitution.
-#if defined(_MSC_VER)
-#define ABSL_HASH_INTERNAL_CAN_POISON_ 0
-#else // _MSC_VER
-#define ABSL_HASH_INTERNAL_CAN_POISON_ 1
-#endif // _MSC_VER
-
#if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
- ABSL_HASH_INTERNAL_CAN_POISON_
+ ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
#else
#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
#endif
-enum class InvokeHashTag {
- kUniquelyRepresented,
- kHashValue,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- kLegacyHash,
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- kStdHash,
- kNone
-};
-
// HashSelect
//
// Type trait to select the appropriate hash implementation to use.
-// HashSelect<T>::value is an instance of InvokeHashTag that indicates the best
-// available hashing mechanism.
-// See `Note` above about MSVC.
-template <typename T>
+// HashSelect::type<T> will give the proper hash implementation, to be invoked
+// as:
+// HashSelect::type<T>::Invoke(state, value)
+// Also, HashSelect::type<T>::value is a boolean equal to `true` if there is a
+// valid `Invoke` function. Types that are not hashable will have a ::value of
+// `false`.
struct HashSelect {
private:
struct State : HashStateBase<State> {
@@ -583,95 +560,75 @@ struct HashSelect {
using State::HashStateBase::combine_contiguous;
};
- // `Probe<V, Tag>::value` evaluates to `V<T>::value` if it is a valid
- // expression, and `false` otherwise.
- // `Probe<V, Tag>::tag` always evaluates to `Tag`.
- template <template <typename> class V, InvokeHashTag Tag>
- struct Probe {
- private:
- template <typename U, typename std::enable_if<V<U>::value, int>::type = 0>
- static std::true_type Test(int);
- template <typename U>
- static std::false_type Test(char);
-
- public:
- static constexpr InvokeHashTag kTag = Tag;
- static constexpr bool value = decltype(
- Test<absl::remove_const_t<absl::remove_reference_t<T>>>(0))::value;
+ struct UniquelyRepresentedProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value)
+ -> absl::enable_if_t<is_uniquely_represented<T>::value, H> {
+ return hash_internal::hash_bytes(std::move(state), value);
+ }
};
- template <typename U>
- using ProbeUniquelyRepresented = is_uniquely_represented<U>;
-
- template <typename U>
- using ProbeHashValue =
- std::is_same<State, decltype(AbslHashValue(std::declval<State>(),
- std::declval<const U&>()))>;
+ struct HashValueProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+ std::is_same<H,
+ decltype(AbslHashValue(std::move(state), value))>::value,
+ H> {
+ return AbslHashValue(std::move(state), value);
+ }
+ };
+ struct LegacyHashProbe {
#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- template <typename U>
- using ProbeLegacyHash =
- std::is_convertible<decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<
- U>()(std::declval<const U&>())),
- size_t>;
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value) -> absl::enable_if_t<
+ std::is_convertible<
+ decltype(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>()(value)),
+ size_t>::value,
+ H> {
+ return hash_internal::hash_bytes(
+ std::move(state),
+ ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
+ }
#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
+ };
- template <typename U>
- using ProbeStdHash =
-#if ABSL_HASH_INTERNAL_CAN_POISON_
- std::is_convertible<decltype(std::hash<U>()(std::declval<const U&>())),
- size_t>;
-#else // ABSL_HASH_INTERNAL_CAN_POISON_
- std::true_type;
-#endif // ABSL_HASH_INTERNAL_CAN_POISON_
+ struct StdHashProbe {
+ template <typename H, typename T>
+ static auto Invoke(H state, const T& value)
+ -> absl::enable_if_t<type_traits_internal::IsHashable<T>::value, H> {
+ return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
+ }
+ };
- template <typename U>
- using ProbeNone = std::true_type;
+ template <typename Hash, typename T>
+ struct Probe : Hash {
+ private:
+ template <typename H, typename = decltype(H::Invoke(
+ std::declval<State>(), std::declval<const T&>()))>
+ static std::true_type Test(int);
+ template <typename U>
+ static std::false_type Test(char);
+
+ public:
+ static constexpr bool value = decltype(Test<Hash>(0))::value;
+ };
public:
// Probe each implementation in order.
- // disjunction provides short circuting wrt instantiation.
- static constexpr InvokeHashTag value = absl::disjunction<
- Probe<ProbeUniquelyRepresented, InvokeHashTag::kUniquelyRepresented>,
- Probe<ProbeHashValue, InvokeHashTag::kHashValue>,
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- Probe<ProbeLegacyHash, InvokeHashTag::kLegacyHash>,
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
- Probe<ProbeStdHash, InvokeHashTag::kStdHash>,
- Probe<ProbeNone, InvokeHashTag::kNone>>::kTag;
+ // disjunction provides short circuiting wrt instantiation.
+ template <typename T>
+ using Apply = absl::disjunction< //
+ Probe<UniquelyRepresentedProbe, T>, //
+ Probe<HashValueProbe, T>, //
+ Probe<LegacyHashProbe, T>, //
+ Probe<StdHashProbe, T>, //
+ std::false_type>;
};
template <typename T>
-struct is_hashable : std::integral_constant<bool, HashSelect<T>::value !=
- InvokeHashTag::kNone> {};
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kUniquelyRepresented,
- H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(std::move(state), value);
-}
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kHashValue, H>
-InvokeHash(H state, const T& value) {
- return AbslHashValue(std::move(state), value);
-}
-
-#if ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kLegacyHash, H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(
- std::move(state), ABSL_INTERNAL_LEGACY_HASH_NAMESPACE::hash<T>{}(value));
-}
-#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
-
-template <typename H, typename T>
-absl::enable_if_t<HashSelect<T>::value == InvokeHashTag::kStdHash, H>
-InvokeHash(H state, const T& value) {
- return hash_internal::hash_bytes(std::move(state), std::hash<T>{}(value));
-}
+struct is_hashable
+ : std::integral_constant<bool, HashSelect::template Apply<T>::value> {};
// CityHashState
class CityHashState : public HashStateBase<CityHashState> {
@@ -684,7 +641,8 @@ class CityHashState : public HashStateBase<CityHashState> {
#endif // ABSL_HAVE_INTRINSIC_INT128
static constexpr uint64_t kMul =
- sizeof(size_t) == 4 ? uint64_t{0xcc9e2d51} : uint64_t{0x9ddfea08eb382d69};
+ sizeof(size_t) == 4 ? uint64_t{0xcc9e2d51}
+ : uint64_t{0x9ddfea08eb382d69};
template <typename T>
using IntegralFastPath =
@@ -881,7 +839,8 @@ struct Hash
template <typename H>
template <typename T, typename... Ts>
H HashStateBase<H>::combine(H state, const T& value, const Ts&... values) {
- return H::combine(hash_internal::InvokeHash(std::move(state), value),
+ return H::combine(hash_internal::HashSelect::template Apply<T>::Invoke(
+ std::move(state), value),
values...);
}
@@ -892,7 +851,7 @@ H HashStateBase<H>::combine_contiguous(H state, const T* data, size_t size) {
return hash_internal::hash_range_or_bytes(std::move(state), data, size);
}
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HASH_INTERNAL_HASH_H_
diff --git a/absl/hash/internal/print_hash_of.cc b/absl/hash/internal/print_hash_of.cc
index b6df31cc..c392125a 100644
--- a/absl/hash/internal/print_hash_of.cc
+++ b/absl/hash/internal/print_hash_of.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h
index 1886d2ef..57cd70b2 100644
--- a/absl/hash/internal/spy_hash_state.h
+++ b/absl/hash/internal/spy_hash_state.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/strings/str_join.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace hash_internal {
// SpyHashState is an implementation of the HashState API that simply
@@ -40,8 +40,7 @@ namespace hash_internal {
template <typename T>
class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
public:
- SpyHashStateImpl()
- : error_(std::make_shared<absl::optional<std::string>>()) {
+ SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) {
static_assert(std::is_void<T>::value, "");
}
@@ -171,7 +170,6 @@ class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> {
// AbslHashValue directly (because the hash state type does not match).
static bool direct_absl_hash_value_error_;
-
std::vector<std::string> hash_representation_;
// This is a shared_ptr because we want all instances of the particular
// SpyHashState run to share the field. This way we can set the error for
@@ -201,7 +199,7 @@ bool RunOnStartup<f>::run = (f(), true);
template <
typename T, typename U,
// Only trigger for when (T != U),
- absl::enable_if_t<!std::is_same<T, U>::value, int> = 0,
+ typename = absl::enable_if_t<!std::is_same<T, U>::value>,
// This statement works in two ways:
// - First, it instantiates RunOnStartup and forces the initialization of
// `run`, which set the global variable.
@@ -214,7 +212,7 @@ void AbslHashValue(SpyHashStateImpl<T>, const U&);
using SpyHashState = SpyHashStateImpl<void>;
} // namespace hash_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HASH_INTERNAL_SPY_HASH_STATE_H_
diff --git a/absl/memory/BUILD.bazel b/absl/memory/BUILD.bazel
index 89a312ea..f815ef94 100644
--- a/absl/memory/BUILD.bazel
+++ b/absl/memory/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
@@ -30,6 +31,7 @@ cc_library(
name = "memory",
hdrs = ["memory.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:core_headers",
"//absl/meta:type_traits",
@@ -40,6 +42,7 @@ cc_test(
name = "memory_test",
srcs = ["memory_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":memory",
"//absl/base",
@@ -54,7 +57,7 @@ cc_test(
"memory_exception_safety_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":memory",
"//absl/base:exception_safety_testing",
diff --git a/absl/memory/CMakeLists.txt b/absl/memory/CMakeLists.txt
index 4b494dc0..0a812203 100644
--- a/absl/memory/CMakeLists.txt
+++ b/absl/memory/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
diff --git a/absl/memory/memory.h b/absl/memory/memory.h
index 34cfb285..7f525e4c 100644
--- a/absl/memory/memory.h
+++ b/absl/memory/memory.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -34,7 +34,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// Function Template: WrapUnique()
@@ -48,19 +48,14 @@ inline namespace lts_2018_12_18 {
// X* NewX(int, int);
// auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>.
//
-// The purpose of WrapUnique is to automatically deduce the pointer type. If you
-// wish to make the type explicit, for readability reasons or because you prefer
-// to use a base-class pointer rather than a derived one, just use
+// Do not call WrapUnique with an explicit type, as in
+// `WrapUnique<X>(NewX(1, 2))`. The purpose of WrapUnique is to automatically
+// deduce the pointer type. If you wish to make the type explicit, just use
// `std::unique_ptr` directly.
//
-// Example:
-// X* Factory(int, int);
-// auto x = std::unique_ptr<X>(Factory(1, 2));
+// auto x = std::unique_ptr<X>(NewX(1, 2));
// - or -
-// std::unique_ptr<X> x(Factory(1, 2));
-//
-// This has the added advantage of working whether Factory returns a raw
-// pointer or a `std::unique_ptr`.
+// std::unique_ptr<X> x(NewX(1, 2));
//
// While `absl::WrapUnique` is useful for capturing the output of a raw
// pointer factory, prefer 'absl::make_unique<T>(args...)' over
@@ -121,7 +116,7 @@ using std::make_unique;
//
// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic,
// see Herb Sutter's explanation on
-// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/].
+// (Exception-Safe Function Calls)[https://herbsutter.com/gotw/_102/].
// (In general, reviewers should treat `new T(a,b)` with scrutiny.)
//
// Example usage:
@@ -647,7 +642,7 @@ struct allocator_is_nothrow
: memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
std::false_type> {};
-#if ABSL_ALLOCATOR_NOTHROW
+#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
template <typename T>
struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
struct default_allocator_is_nothrow : std::true_type {};
@@ -693,7 +688,7 @@ void CopyRange(Allocator& alloc, Iterator destination, InputIterator first,
}
}
} // namespace memory_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_MEMORY_MEMORY_H_
diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc
index 9661502d..f5b39b34 100644
--- a/absl/memory/memory_exception_safety_test.cc
+++ b/absl/memory/memory_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
constexpr int kLength = 50;
@@ -50,5 +50,5 @@ TEST(MakeUnique, CheckForLeaks) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc
index 21fe32f9..c47820e5 100644
--- a/absl/memory/memory_test.cc
+++ b/absl/memory/memory_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -620,7 +620,7 @@ TEST(AllocatorTraits, FunctionsFull) {
}
TEST(AllocatorNoThrowTest, DefaultAllocator) {
-#if ABSL_ALLOCATOR_NOTHROW
+#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
EXPECT_TRUE(absl::default_allocator_is_nothrow::value);
#else
EXPECT_FALSE(absl::default_allocator_is_nothrow::value);
@@ -628,7 +628,7 @@ TEST(AllocatorNoThrowTest, DefaultAllocator) {
}
TEST(AllocatorNoThrowTest, StdAllocator) {
-#if ABSL_ALLOCATOR_NOTHROW
+#if defined(ABSL_ALLOCATOR_NOTHROW) && ABSL_ALLOCATOR_NOTHROW
EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value);
#else
EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value);
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel
index dbc9717d..e004b509 100644
--- a/absl/meta/BUILD.bazel
+++ b/absl/meta/BUILD.bazel
@@ -1,6 +1,7 @@
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -12,6 +13,7 @@ cc_library(
name = "type_traits",
hdrs = ["type_traits.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
],
@@ -21,9 +23,9 @@ cc_test(
name = "type_traits_test",
srcs = ["type_traits_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":type_traits",
- "//absl/base:core_headers",
"@com_google_googletest//:gtest_main",
],
)
diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt
index adb0ceb7..672ead2f 100644
--- a/absl/meta/CMakeLists.txt
+++ b/absl/meta/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,39 +14,37 @@
# limitations under the License.
#
-list(APPEND META_PUBLIC_HEADERS
- "type_traits.h"
+absl_cc_library(
+ NAME
+ type_traits
+ HDRS
+ "type_traits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-# test type_traits_test
-list(APPEND TYPE_TRAITS_TEST_SRC
- "type_traits_test.cc"
- ${META_PUBLIC_HEADERS}
+absl_cc_test(
+ NAME
+ type_traits_test
+ SRCS
+ "type_traits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::type_traits
+ gmock_main
)
-absl_header_library(
- TARGET
- absl_meta
- PUBLIC_LIBRARIES
- absl::base
- EXPORT_NAME
+# component target
+absl_cc_library(
+ NAME
meta
- )
-
-absl_test(
- TARGET
- type_traits_test
- SOURCES
- ${TYPE_TRAITS_TEST_SRC}
- PUBLIC_LIBRARIES
- absl::base
- absl::meta
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::type_traits
+ PUBLIC
)
-
-
-
diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h
index 231e08db..ae7130dd 100644
--- a/absl/meta/type_traits.h
+++ b/absl/meta/type_traits.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
// support type inference, classification, and transformation, as well as
// make it easier to write templates based on generic type behavior.
//
-// See http://en.cppreference.com/w/cpp/header/type_traits
+// See https://en.cppreference.com/w/cpp/header/type_traits
//
// WARNING: use of many of the constructs in this header will count as "complex
// template metaprogramming", so before proceeding, please carefully consider
@@ -42,10 +42,41 @@
#include "absl/base/config.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
+
+// Defined and documented later on in this file.
+template <typename T>
+struct is_trivially_move_assignable;
namespace type_traits_internal {
+// Silence MSVC warnings about the destructor being defined as deleted.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(push)
+#pragma warning(disable : 4624)
+#endif // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+union SingleMemberUnion {
+ T t;
+};
+
+// Restore the state of the destructor warning that was silenced above.
+#if defined(_MSC_VER) && !defined(__GNUC__)
+#pragma warning(pop)
+#endif // defined(_MSC_VER) && !defined(__GNUC__)
+
+template <class T>
+struct IsTriviallyMoveAssignableReference : std::false_type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&>
+ : absl::is_trivially_move_assignable<T>::type {};
+
+template <class T>
+struct IsTriviallyMoveAssignableReference<T&&>
+ : absl::is_trivially_move_assignable<T>::type {};
+
template <typename... Ts>
struct VoidTImpl {
using type = void;
@@ -194,6 +225,23 @@ struct disjunction<> : std::false_type {};
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_trivially_destructible()
//
// Determines whether the passed type `T` is trivially destructable.
@@ -247,7 +295,7 @@ struct is_trivially_destructible
// For the purposes of this check, the call to std::declval is considered
// trivial."
//
-// Notes from http://en.cppreference.com/w/cpp/types/is_constructible:
+// Notes from https://en.cppreference.com/w/cpp/types/is_constructible:
// In many implementations, is_nothrow_constructible also checks if the
// destructor throws because it is effectively noexcept(T(arg)). Same
// applies to is_trivially_constructible, which, in these implementations, also
@@ -276,6 +324,40 @@ struct is_trivially_default_constructible
#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
};
+// is_trivially_move_constructible()
+//
+// Determines whether the passed type `T` is trivially move constructible.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_constructible()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `T obj(declval<T>());` needs to be well-formed and not call any
+// nontrivial operation. Nontrivially destructible types will cause the
+// expression to be nontrivial.
+template <typename T>
+struct is_trivially_move_constructible
+ : std::conditional<
+ std::is_object<T>::value && !std::is_array<T>::value,
+ std::is_move_constructible<
+ type_traits_internal::SingleMemberUnion<T>>,
+ std::is_reference<T>>::type::type {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+ private:
+ static constexpr bool compliant =
+ std::is_trivially_move_constructible<T>::value ==
+ is_trivially_move_constructible::value;
+ static_assert(compliant || std::is_trivially_move_constructible<T>::value,
+ "Not compliant with std::is_trivially_move_constructible; "
+ "Standard: false, Implementation: true");
+ static_assert(compliant || !std::is_trivially_move_constructible<T>::value,
+ "Not compliant with std::is_trivially_move_constructible; "
+ "Standard: true, Implementation: false");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
+};
+
// is_trivially_copy_constructible()
//
// Determines whether the passed type `T` is trivially copy constructible.
@@ -291,9 +373,11 @@ struct is_trivially_default_constructible
// expression to be nontrivial.
template <typename T>
struct is_trivially_copy_constructible
- : std::integral_constant<bool, __has_trivial_copy(T) &&
- std::is_copy_constructible<T>::value &&
- is_trivially_destructible<T>::value> {
+ : std::conditional<
+ std::is_object<T>::value && !std::is_array<T>::value,
+ std::is_copy_constructible<
+ type_traits_internal::SingleMemberUnion<T>>,
+ std::is_lvalue_reference<T>>::type::type {
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
private:
static constexpr bool compliant =
@@ -308,6 +392,42 @@ struct is_trivially_copy_constructible
#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
};
+// is_trivially_move_assignable()
+//
+// Determines whether the passed type `T` is trivially move assignable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_move_assignable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do
+// fully support C++11, we check whether this yields the same result as the std
+// implementation.
+//
+// NOTE: `is_assignable<T, U>::value` is `true` if the expression
+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated
+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no
+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply
+// `is_trivially_assignable<T&, T>`.
+template <typename T>
+struct is_trivially_move_assignable
+ : std::conditional<
+ std::is_object<T>::value && !std::is_array<T>::value,
+ std::is_move_assignable<type_traits_internal::SingleMemberUnion<T>>,
+ type_traits_internal::IsTriviallyMoveAssignableReference<T>>::type::
+ type {
+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+ private:
+ static constexpr bool compliant =
+ std::is_trivially_move_assignable<T>::value ==
+ is_trivially_move_assignable::value;
+ static_assert(compliant || std::is_trivially_move_assignable<T>::value,
+ "Not compliant with std::is_trivially_move_assignable; "
+ "Standard: false, Implementation: true");
+ static_assert(compliant || !std::is_trivially_move_assignable<T>::value,
+ "Not compliant with std::is_trivially_move_assignable; "
+ "Standard: true, Implementation: false");
+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
+};
+
// is_trivially_copy_assignable()
//
// Determines whether the passed type `T` is trivially copy assignable.
@@ -342,6 +462,49 @@ struct is_trivially_copy_assignable
#endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
};
+namespace type_traits_internal {
+// is_trivially_copyable()
+//
+// Determines whether the passed type `T` is trivially copyable.
+//
+// This metafunction is designed to be a drop-in replacement for the C++11
+// `std::is_trivially_copyable()` metafunction for platforms that have
+// incomplete C++11 support (such as libstdc++ 4.x). We use the C++17 definition
+// of TriviallyCopyable.
+//
+// NOTE: `is_trivially_copyable<T>::value` is `true` if all of T's copy/move
+// constructors/assignment operators are trivial or deleted, T has at least
+// one non-deleted copy/move constructor/assignment operator, and T is trivially
+// destructible. Arrays of trivially copyable types are trivially copyable.
+//
+// We expose this metafunction only for internal use within absl.
+template <typename T>
+class is_trivially_copyable_impl {
+ using ExtentsRemoved = typename std::remove_all_extents<T>::type;
+ static constexpr bool kIsCopyOrMoveConstructible =
+ std::is_copy_constructible<ExtentsRemoved>::value ||
+ std::is_move_constructible<ExtentsRemoved>::value;
+ static constexpr bool kIsCopyOrMoveAssignable =
+ absl::is_copy_assignable<ExtentsRemoved>::value ||
+ absl::is_move_assignable<ExtentsRemoved>::value;
+
+ public:
+ static constexpr bool kValue =
+ (__has_trivial_copy(ExtentsRemoved) || !kIsCopyOrMoveConstructible) &&
+ (__has_trivial_assign(ExtentsRemoved) || !kIsCopyOrMoveAssignable) &&
+ (kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) &&
+ is_trivially_destructible<ExtentsRemoved>::value &&
+ // We need to check for this explicitly because otherwise we'll say
+ // references are trivial copyable when compiled by MSVC.
+ !std::is_reference<ExtentsRemoved>::value;
+};
+
+template <typename T>
+struct is_trivially_copyable
+ : std::integral_constant<
+ bool, type_traits_internal::is_trivially_copyable_impl<T>::kValue> {};
+} // namespace type_traits_internal
+
// -----------------------------------------------------------------------------
// C++14 "_t" trait aliases
// -----------------------------------------------------------------------------
@@ -414,25 +577,140 @@ template <typename T>
using result_of_t = typename std::result_of<T>::type;
namespace type_traits_internal {
+// In MSVC we can't probe std::hash or stdext::hash because it triggers a
+// static_assert instead of failing substitution. Libc++ prior to 4.0
+// also used a static_assert.
+//
+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
+ _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
+#else
+#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
+#endif
+
+#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = size_t>
+struct IsHashable : std::true_type {};
+#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+template <typename Key, typename = void>
struct IsHashable : std::false_type {};
template <typename Key>
-struct IsHashable<Key,
- decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))>
- : std::true_type {};
+struct IsHashable<
+ Key,
+ absl::enable_if_t<std::is_convertible<
+ decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
+ std::size_t>::value>> : std::true_type {};
+#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
+
+struct AssertHashEnabledHelper {
+ private:
+ static void Sink(...) {}
+ struct NAT {};
+
+ template <class Key>
+ static auto GetReturnType(int)
+ -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
+ template <class Key>
+ static NAT GetReturnType(...);
+
+ template <class Key>
+ static std::nullptr_t DoIt() {
+ static_assert(IsHashable<Key>::value,
+ "std::hash<Key> does not provide a call operator");
+ static_assert(
+ std::is_default_constructible<std::hash<Key>>::value,
+ "std::hash<Key> must be default constructible when it is enabled");
+ static_assert(
+ std::is_copy_constructible<std::hash<Key>>::value,
+ "std::hash<Key> must be copy constructible when it is enabled");
+ static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
+ "std::hash<Key> must be copy assignable when it is enabled");
+ // is_destructible is unchecked as it's implied by each of the
+ // is_constructible checks.
+ using ReturnType = decltype(GetReturnType<Key>(0));
+ static_assert(std::is_same<ReturnType, NAT>::value ||
+ std::is_same<ReturnType, size_t>::value,
+ "std::hash<Key> must return size_t");
+ return nullptr;
+ }
+
+ template <class... Ts>
+ friend void AssertHashEnabled();
+};
-template <typename Key>
-struct IsHashEnabled
- : absl::conjunction<std::is_default_constructible<std::hash<Key>>,
- std::is_copy_constructible<std::hash<Key>>,
- std::is_destructible<std::hash<Key>>,
- absl::is_copy_assignable<std::hash<Key>>,
- IsHashable<Key>> {};
+template <class... Ts>
+inline void AssertHashEnabled() {
+ using Helper = AssertHashEnabledHelper;
+ Helper::Sink(Helper::DoIt<Ts>()...);
+}
} // namespace type_traits_internal
-} // inline namespace lts_2018_12_18
+// An internal namespace that is required to implement the C++17 swap traits.
+// It is not further nested in type_traits_internal to avoid long symbol names.
+namespace swap_internal {
+
+// Necessary for the traits.
+using std::swap;
+
+// This declaration prevents global `swap` and `absl::swap` overloads from being
+// considered unless ADL picks them up.
+void swap();
+
+template <class T>
+using IsSwappableImpl = decltype(swap(std::declval<T&>(), std::declval<T&>()));
+
+// NOTE: This dance with the default template parameter is for MSVC.
+template <class T,
+ class IsNoexcept = std::integral_constant<
+ bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))>>
+using IsNothrowSwappableImpl = typename std::enable_if<IsNoexcept::value>::type;
+
+// IsSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T`.
+template <class T>
+struct IsSwappable
+ : absl::type_traits_internal::is_detected<IsSwappableImpl, T> {};
+
+// IsNothrowSwappable
+//
+// Determines whether the standard swap idiom is a valid expression for
+// arguments of type `T` and is noexcept.
+template <class T>
+struct IsNothrowSwappable
+ : absl::type_traits_internal::is_detected<IsNothrowSwappableImpl, T> {};
+
+// Swap()
+//
+// Performs the swap idiom from a namespace where valid candidates may only be
+// found in `std` or via ADL.
+template <class T, absl::enable_if_t<IsSwappable<T>::value, int> = 0>
+void Swap(T& lhs, T& rhs) noexcept(IsNothrowSwappable<T>::value) {
+ swap(lhs, rhs);
+}
+
+// StdSwapIsUnconstrained
+//
+// Some standard library implementations are broken in that they do not
+// constrain `std::swap`. This will effectively tell us if we are dealing with
+// one of those implementations.
+using StdSwapIsUnconstrained = IsSwappable<void()>;
+
+} // namespace swap_internal
+
+namespace type_traits_internal {
+
+// Make the swap-related traits/function accessible from this namespace.
+using swap_internal::IsNothrowSwappable;
+using swap_internal::IsSwappable;
+using swap_internal::Swap;
+using swap_internal::StdSwapIsUnconstrained;
+
+} // namespace type_traits_internal
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_META_TYPE_TRAITS_H_
diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc
index f51f5ded..a7a9c5c9 100644
--- a/absl/meta/type_traits_test.cc
+++ b/absl/meta/type_traits_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -214,6 +214,29 @@ class DeletedDefaultCtor {
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) {}
@@ -247,6 +270,29 @@ class DeletedCopyCtor {
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) {}
@@ -280,10 +326,20 @@ class DeletedCopyAssign {
int n_;
};
-struct NonCopyable {
- NonCopyable() = default;
- NonCopyable(const NonCopyable&) = delete;
- NonCopyable& operator=(const NonCopyable&) = delete;
+struct MovableNonCopyable {
+ MovableNonCopyable() = default;
+ MovableNonCopyable(const MovableNonCopyable&) = delete;
+ MovableNonCopyable(MovableNonCopyable&&) = default;
+ MovableNonCopyable& operator=(const MovableNonCopyable&) = delete;
+ MovableNonCopyable& operator=(MovableNonCopyable&&) = default;
+};
+
+struct NonCopyableOrMovable {
+ NonCopyableOrMovable() = default;
+ NonCopyableOrMovable(const NonCopyableOrMovable&) = delete;
+ NonCopyableOrMovable(NonCopyableOrMovable&&) = delete;
+ NonCopyableOrMovable& operator=(const NonCopyableOrMovable&) = delete;
+ NonCopyableOrMovable& operator=(NonCopyableOrMovable&&) = delete;
};
class Base {
@@ -329,6 +385,22 @@ class Base {
#define ABSL_GCC_BUG_TRIVIALLY_CONSTRUCTIBLE_ON_ARRAY_OF_NONTRIVIAL 1
#endif
+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, TestTrivialDestructor) {
// Verify that arithmetic types and pointers have trivial destructors.
EXPECT_TRUE(absl::is_trivially_destructible<bool>::value);
@@ -474,6 +546,79 @@ TEST(TypeTraitsTest, TestTrivialDefaultCtor) {
#endif
}
+TEST(TypeTraitsTest, TestTrivialMoveCtor) {
+ // Verify that arithmetic types and pointers have trivial move
+ // constructors.
+ EXPECT_TRUE(absl::is_trivially_move_constructible<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<int>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<float>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<double>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<const std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<const Trivial*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<std::string**>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial**>::value);
+
+ // Reference types
+ EXPECT_TRUE(absl::is_trivially_move_constructible<int&>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<int&&>::value);
+
+ // types with compiler generated move ctors
+ EXPECT_TRUE(absl::is_trivially_move_constructible<Trivial>::value);
+ EXPECT_TRUE(absl::is_trivially_move_constructible<TrivialMoveCtor>::value);
+
+ // Verify that types without them (i.e. nontrivial or deleted) are not.
+ EXPECT_FALSE(
+ absl::is_trivially_move_constructible<NontrivialCopyCtor>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<DeletedCopyCtor>::value);
+ EXPECT_FALSE(
+ absl::is_trivially_move_constructible<NonCopyableOrMovable>::value);
+
+#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
+ // type with nontrivial destructor are nontrivial move construbtible
+ EXPECT_FALSE(
+ absl::is_trivially_move_constructible<NontrivialDestructor>::value);
+#endif
+
+ // types with vtables
+ EXPECT_FALSE(absl::is_trivially_move_constructible<Base>::value);
+
+ // Verify that simple_pair of such types is trivially move constructible
+ EXPECT_TRUE(
+ (absl::is_trivially_move_constructible<simple_pair<int, char*>>::value));
+ EXPECT_TRUE((
+ absl::is_trivially_move_constructible<simple_pair<int, Trivial>>::value));
+ EXPECT_TRUE((absl::is_trivially_move_constructible<
+ simple_pair<int, TrivialMoveCtor>>::value));
+
+ // Verify that types without trivial move constructors are
+ // correctly marked as such.
+ EXPECT_FALSE(absl::is_trivially_move_constructible<std::string>::value);
+ EXPECT_FALSE(absl::is_trivially_move_constructible<std::vector<int>>::value);
+
+ // Verify that simple_pairs of types without trivial move constructors
+ // are not marked as trivial.
+ EXPECT_FALSE((absl::is_trivially_move_constructible<
+ simple_pair<int, std::string>>::value));
+ EXPECT_FALSE((absl::is_trivially_move_constructible<
+ simple_pair<std::string, int>>::value));
+
+ // Verify that arrays are not
+ using int10 = int[10];
+ EXPECT_FALSE(absl::is_trivially_move_constructible<int10>::value);
+}
+
TEST(TypeTraitsTest, TestTrivialCopyCtor) {
// Verify that arithmetic types and pointers have trivial copy
// constructors.
@@ -498,6 +643,10 @@ TEST(TypeTraitsTest, TestTrivialCopyCtor) {
EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string**>::value);
EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial**>::value);
+ // Reference types
+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int&>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_constructible<int&&>::value);
+
// types with compiler generated copy ctors
EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial>::value);
EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor>::value);
@@ -507,7 +656,9 @@ TEST(TypeTraitsTest, TestTrivialCopyCtor) {
absl::is_trivially_copy_constructible<NontrivialCopyCtor>::value);
EXPECT_FALSE(absl::is_trivially_copy_constructible<DeletedCopyCtor>::value);
EXPECT_FALSE(
- absl::is_trivially_copy_constructible<NonCopyable>::value);
+ absl::is_trivially_copy_constructible<MovableNonCopyable>::value);
+ EXPECT_FALSE(
+ absl::is_trivially_copy_constructible<NonCopyableOrMovable>::value);
#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE
// type with nontrivial destructor are nontrivial copy construbtible
@@ -543,6 +694,74 @@ TEST(TypeTraitsTest, TestTrivialCopyCtor) {
EXPECT_FALSE(absl::is_trivially_copy_constructible<int10>::value);
}
+TEST(TypeTraitsTest, TestTrivialMoveAssign) {
+ // Verify that arithmetic types and pointers have trivial move
+ // assignment operators.
+ EXPECT_TRUE(absl::is_trivially_move_assignable<bool>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<unsigned char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<signed char>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<wchar_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<int>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<unsigned int>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<int16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<uint16_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<int64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<uint64_t>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<float>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<double>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<long double>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<const std::string*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<const Trivial*>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<std::string**>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial**>::value);
+
+ // const qualified types are not assignable
+ EXPECT_FALSE(absl::is_trivially_move_assignable<const int>::value);
+
+ // types with compiler generated move assignment
+ EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<TrivialMoveAssign>::value);
+
+ // Verify that types without them (i.e. nontrivial or deleted) are not.
+ EXPECT_FALSE(absl::is_trivially_move_assignable<NontrivialCopyAssign>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<DeletedCopyAssign>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<NonCopyableOrMovable>::value);
+
+ // types with vtables
+ EXPECT_FALSE(absl::is_trivially_move_assignable<Base>::value);
+
+ // Verify that simple_pair is trivially assignable
+ EXPECT_TRUE(
+ (absl::is_trivially_move_assignable<simple_pair<int, char*>>::value));
+ EXPECT_TRUE(
+ (absl::is_trivially_move_assignable<simple_pair<int, Trivial>>::value));
+ EXPECT_TRUE((absl::is_trivially_move_assignable<
+ simple_pair<int, TrivialMoveAssign>>::value));
+
+ // Verify that types not trivially move assignable are
+ // correctly marked as such.
+ EXPECT_FALSE(absl::is_trivially_move_assignable<std::string>::value);
+ EXPECT_FALSE(absl::is_trivially_move_assignable<std::vector<int>>::value);
+
+ // Verify that simple_pairs of types not trivially move assignable
+ // are not marked as trivial.
+ EXPECT_FALSE((absl::is_trivially_move_assignable<
+ simple_pair<int, std::string>>::value));
+ EXPECT_FALSE((absl::is_trivially_move_assignable<
+ simple_pair<std::string, int>>::value));
+
+ // Verify that arrays are not trivially move assignable
+ using int10 = int[10];
+ EXPECT_FALSE(absl::is_trivially_move_assignable<int10>::value);
+
+ // Verify that references are handled correctly
+ EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial&&>::value);
+ EXPECT_TRUE(absl::is_trivially_move_assignable<Trivial&>::value);
+}
+
TEST(TypeTraitsTest, TestTrivialCopyAssign) {
// Verify that arithmetic types and pointers have trivial copy
// assignment operators.
@@ -577,7 +796,8 @@ TEST(TypeTraitsTest, TestTrivialCopyAssign) {
// Verify that types without them (i.e. nontrivial or deleted) are not.
EXPECT_FALSE(absl::is_trivially_copy_assignable<NontrivialCopyAssign>::value);
EXPECT_FALSE(absl::is_trivially_copy_assignable<DeletedCopyAssign>::value);
- EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyable>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<MovableNonCopyable>::value);
+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyableOrMovable>::value);
// types with vtables
EXPECT_FALSE(absl::is_trivially_copy_assignable<Base>::value);
@@ -611,6 +831,116 @@ TEST(TypeTraitsTest, TestTrivialCopyAssign) {
EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&>::value);
}
+TEST(TypeTraitsTest, TestTriviallyCopyable) {
+ // Verify that arithmetic types and pointers are trivially copyable.
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<bool>::value);
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<char>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<unsigned char>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<signed char>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<wchar_t>::value);
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<int>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<unsigned int>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<int16_t>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<uint16_t>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<int64_t>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<uint64_t>::value);
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<float>::value);
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<double>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<long double>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<std::string*>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<Trivial*>::value);
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<
+ const std::string*>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<const Trivial*>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<std::string**>::value);
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<Trivial**>::value);
+
+ // const qualified types are not assignable but are constructible
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<const int>::value);
+
+ // Trivial copy constructor/assignment and destructor.
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<Trivial>::value);
+ // Trivial copy assignment, but non-trivial copy constructor/destructor.
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ TrivialCopyAssign>::value);
+ // Trivial copy constructor, but non-trivial assignment.
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ TrivialCopyCtor>::value);
+
+ // Types with a non-trivial copy constructor/assignment
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ NontrivialCopyCtor>::value);
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ NontrivialCopyAssign>::value);
+
+ // Types without copy constructor/assignment, but with move
+ // MSVC disagrees with other compilers about this:
+ // EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<
+ // MovableNonCopyable>::value);
+
+ // Types without copy/move constructor/assignment
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ NonCopyableOrMovable>::value);
+
+ // No copy assign, but has trivial copy constructor.
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<
+ DeletedCopyAssign>::value);
+
+ // types with vtables
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<Base>::value);
+
+ // Verify that simple_pair is trivially copyable if members are
+ EXPECT_TRUE((absl::type_traits_internal::is_trivially_copyable<
+ simple_pair<int, char*>>::value));
+ EXPECT_TRUE((absl::type_traits_internal::is_trivially_copyable<
+ simple_pair<int, Trivial>>::value));
+
+ // Verify that types not trivially copyable are
+ // correctly marked as such.
+ EXPECT_FALSE(
+ absl::type_traits_internal::is_trivially_copyable<std::string>::value);
+ EXPECT_FALSE(absl::type_traits_internal::is_trivially_copyable<
+ std::vector<int>>::value);
+
+ // Verify that simple_pairs of types not trivially copyable
+ // are not marked as trivial.
+ EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable<
+ simple_pair<int, std::string>>::value));
+ EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable<
+ simple_pair<std::string, int>>::value));
+ EXPECT_FALSE((absl::type_traits_internal::is_trivially_copyable<
+ simple_pair<int, TrivialCopyAssign>>::value));
+
+ // Verify that arrays of trivially copyable types are trivially copyable
+ using int10 = int[10];
+ EXPECT_TRUE(absl::type_traits_internal::is_trivially_copyable<int10>::value);
+ using int10x10 = int[10][10];
+ EXPECT_TRUE(
+ absl::type_traits_internal::is_trivially_copyable<int10x10>::value);
+
+ // Verify that references are handled correctly
+ EXPECT_FALSE(
+ absl::type_traits_internal::is_trivially_copyable<Trivial&&>::value);
+ EXPECT_FALSE(
+ absl::type_traits_internal::is_trivially_copyable<Trivial&>::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))
@@ -953,4 +1283,85 @@ TEST(TypeTraitsTest, IsMoveAssignable) {
#endif // _LIBCPP_VERSION
}
+namespace adl_namespace {
+
+struct DeletedSwap {
+};
+
+void swap(DeletedSwap&, DeletedSwap&) = delete;
+
+struct SpecialNoexceptSwap {
+ SpecialNoexceptSwap(SpecialNoexceptSwap&&) {}
+ SpecialNoexceptSwap& operator=(SpecialNoexceptSwap&&) { return *this; }
+ ~SpecialNoexceptSwap() = default;
+};
+
+void swap(SpecialNoexceptSwap&, SpecialNoexceptSwap&) noexcept {}
+
+} // namespace adl_namespace
+
+TEST(TypeTraitsTest, IsSwappable) {
+ using absl::type_traits_internal::IsSwappable;
+ using absl::type_traits_internal::StdSwapIsUnconstrained;
+
+ EXPECT_TRUE(IsSwappable<int>::value);
+
+ struct S {};
+ EXPECT_TRUE(IsSwappable<S>::value);
+
+ struct NoConstruct {
+ NoConstruct(NoConstruct&&) = delete;
+ NoConstruct& operator=(NoConstruct&&) { return *this; }
+ ~NoConstruct() = default;
+ };
+
+ EXPECT_EQ(IsSwappable<NoConstruct>::value, StdSwapIsUnconstrained::value);
+ struct NoAssign {
+ NoAssign(NoAssign&&) {}
+ NoAssign& operator=(NoAssign&&) = delete;
+ ~NoAssign() = default;
+ };
+
+ EXPECT_EQ(IsSwappable<NoAssign>::value, StdSwapIsUnconstrained::value);
+
+ EXPECT_FALSE(IsSwappable<adl_namespace::DeletedSwap>::value);
+
+ EXPECT_TRUE(IsSwappable<adl_namespace::SpecialNoexceptSwap>::value);
+}
+
+TEST(TypeTraitsTest, IsNothrowSwappable) {
+ using absl::type_traits_internal::IsNothrowSwappable;
+ using absl::type_traits_internal::StdSwapIsUnconstrained;
+
+ EXPECT_TRUE(IsNothrowSwappable<int>::value);
+
+ struct NonNoexceptMoves {
+ NonNoexceptMoves(NonNoexceptMoves&&) {}
+ NonNoexceptMoves& operator=(NonNoexceptMoves&&) { return *this; }
+ ~NonNoexceptMoves() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NonNoexceptMoves>::value);
+
+ struct NoConstruct {
+ NoConstruct(NoConstruct&&) = delete;
+ NoConstruct& operator=(NoConstruct&&) { return *this; }
+ ~NoConstruct() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NoConstruct>::value);
+
+ struct NoAssign {
+ NoAssign(NoAssign&&) {}
+ NoAssign& operator=(NoAssign&&) = delete;
+ ~NoAssign() = default;
+ };
+
+ EXPECT_FALSE(IsNothrowSwappable<NoAssign>::value);
+
+ EXPECT_FALSE(IsNothrowSwappable<adl_namespace::DeletedSwap>::value);
+
+ EXPECT_TRUE(IsNothrowSwappable<adl_namespace::SpecialNoexceptSwap>::value);
+}
+
} // namespace
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index 324ce669..d9b561df 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -13,8 +13,9 @@
# limitations under the License.
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -31,6 +32,7 @@ cc_library(
],
hdrs = ["int128.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:config",
"//absl/base:core_headers",
@@ -45,6 +47,7 @@ cc_test(
"int128_test.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":int128",
"//absl/base",
@@ -59,6 +62,7 @@ cc_test(
name = "int128_benchmark",
srcs = ["int128_benchmark.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
deps = [
":int128",
diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt
index 3360b2ee..242889f0 100644
--- a/absl/numeric/CMakeLists.txt
+++ b/absl/numeric/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,49 +14,47 @@
# limitations under the License.
#
-list(APPEND NUMERIC_PUBLIC_HEADERS
- "int128.h"
-)
-
-
-# library 128
-list(APPEND INT128_SRC
- "int128.cc"
- ${NUMERIC_PUBLIC_HEADERS}
-)
-absl_library(
- TARGET
- absl_int128
- SOURCES
- ${INT128_SRC}
- PUBLIC_LIBRARIES
- ${INT128_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
int128
+ HDRS
+ "int128.h"
+ SRCS
+ "int128.cc"
+ "int128_have_intrinsic.inc"
+ "int128_no_intrinsic.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::config
+ absl::core_headers
+ PUBLIC
)
-
-absl_header_library(
- TARGET
- absl_numeric
- PUBLIC_LIBRARIES
+absl_cc_test(
+ NAME
+ int128_test
+ SRCS
+ "int128_stream_test.cc"
+ "int128_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
absl::int128
- EXPORT_NAME
- numeric
+ absl::base
+ absl::core_headers
+ absl::hash_testing
+ absl::type_traits
+ gmock_main
)
-# test int128_test
-set(INT128_TEST_SRC "int128_test.cc")
-set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base)
-
-absl_test(
- TARGET
- int128_test
- SOURCES
- ${INT128_TEST_SRC}
- PUBLIC_LIBRARIES
- ${INT128_TEST_PUBLIC_LIBRARIES}
+# component target
+absl_cc_library(
+ NAME
+ numeric
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::int128
+ PUBLIC
)
-
-
-
diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc
index 98af84b7..a22f1e3e 100644
--- a/absl/numeric/int128.cc
+++ b/absl/numeric/int128.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include <type_traits>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
@@ -66,7 +66,7 @@ static inline int Fls128(uint128 n) {
// Long division/modulo for uint128 implemented using the shift-subtract
// division algorithm adapted from:
-// http://stackoverflow.com/questions/5386377/division-without-using
+// https://stackoverflow.com/questions/5386377/division-without-using
void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret,
uint128* remainder_ret) {
assert(divisor != 0);
@@ -124,6 +124,28 @@ uint128 MakeUint128FromFloat(T v) {
return MakeUint128(0, static_cast<uint64_t>(v));
}
+
+#if defined(__clang__) && !defined(__SSE3__)
+// Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289
+// Casting from long double to uint64_t is miscompiled and drops bits.
+// It is more work, so only use when we need the workaround.
+uint128 MakeUint128FromFloat(long double v) {
+ // Go 50 bits at a time, that fits in a double
+ static_assert(std::numeric_limits<double>::digits >= 50, "");
+ static_assert(std::numeric_limits<long double>::digits <= 150, "");
+ // Undefined behavior if v is not finite or cannot fit into uint128.
+ assert(std::isfinite(v) && v > -1 && v < std::ldexp(1.0L, 128));
+
+ v = std::ldexp(v, -100);
+ uint64_t w0 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ v = std::ldexp(v - static_cast<double>(w0), 50);
+ uint64_t w1 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ v = std::ldexp(v - static_cast<double>(w1), 50);
+ uint64_t w2 = static_cast<uint64_t>(static_cast<double>(std::trunc(v)));
+ return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) |
+ static_cast<uint128>(w2);
+}
+#endif // __clang__ && !__SSE3__
} // namespace
uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {}
@@ -223,7 +245,7 @@ std::ostream& operator<<(std::ostream& os, uint128 v) {
return os << rep;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace std {
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index cb4776f1..a9693a27 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,8 +19,8 @@
//
// This header file defines 128-bit integer types.
//
-// Currently, this file defines `uint128`, an unsigned 128-bit integer; a signed
-// 128-bit integer is forthcoming.
+// Currently, this file defines `uint128`, an unsigned 128-bit integer;
+// a signed 128-bit integer is forthcoming.
#ifndef ABSL_NUMERIC_INT128_H_
#define ABSL_NUMERIC_INT128_H_
@@ -37,14 +37,22 @@
#include "absl/base/macros.h"
#include "absl/base/port.h"
-#if defined(_MSC_VER) && defined(_WIN64)
+#if defined(_MSC_VER)
+// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
+// a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t
+// builtin type. We need to make sure not to define operator wchar_t()
+// alongside operator unsigned short() in these instances.
+#define ABSL_INTERNAL_WCHAR_T __wchar_t
+#if defined(_M_X64)
#include <intrin.h>
#pragma intrinsic(_umul128)
-#endif // defined(_MSC_VER) && defined(_WIN64)
+#endif // defined(_M_X64)
+#else // defined(_MSC_VER)
+#define ABSL_INTERNAL_WCHAR_T wchar_t
+#endif // defined(_MSC_VER)
namespace absl {
-inline namespace lts_2018_12_18 {
-
+inline namespace lts_2019_08_08 {
// uint128
//
@@ -132,7 +140,7 @@ class
constexpr explicit operator unsigned char() const;
constexpr explicit operator char16_t() const;
constexpr explicit operator char32_t() const;
- constexpr explicit operator wchar_t() const;
+ constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const;
constexpr explicit operator short() const; // NOLINT(runtime/int)
// NOLINTNEXTLINE(runtime/int)
constexpr explicit operator unsigned short() const;
@@ -237,7 +245,7 @@ constexpr uint128 Uint128Max() {
(std::numeric_limits<uint64_t>::max)());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// Specialized numeric_limits for uint128.
@@ -273,9 +281,9 @@ class numeric_limits<absl::uint128> {
#endif // ABSL_HAVE_INTRINSIC_INT128
static constexpr bool tinyness_before = false;
- static constexpr absl::uint128 min() { return 0; }
+ static constexpr absl::uint128 (min)() { return 0; }
static constexpr absl::uint128 lowest() { return 0; }
- static constexpr absl::uint128 max() { return absl::Uint128Max(); }
+ static constexpr absl::uint128 (max)() { return absl::Uint128Max(); }
static constexpr absl::uint128 epsilon() { return 0; }
static constexpr absl::uint128 round_error() { return 0; }
static constexpr absl::uint128 infinity() { return 0; }
@@ -291,7 +299,7 @@ class numeric_limits<absl::uint128> {
// Implementation details follow
// --------------------------------------------------------------------------
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
constexpr uint128 MakeUint128(uint64_t high, uint64_t low) {
return uint128(high, low);
@@ -471,8 +479,8 @@ constexpr uint128::operator char32_t() const {
return static_cast<char32_t>(lo_);
}
-constexpr uint128::operator wchar_t() const {
- return static_cast<wchar_t>(lo_);
+constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const {
+ return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_);
}
// NOLINTNEXTLINE(runtime/int)
@@ -669,7 +677,7 @@ inline uint128 operator*(uint128 lhs, uint128 rhs) {
// can be used for uint128 storage.
return static_cast<unsigned __int128>(lhs) *
static_cast<unsigned __int128>(rhs);
-#elif defined(_MSC_VER) && defined(_WIN64)
+#elif defined(_MSC_VER) && defined(_M_X64)
uint64_t carry;
uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry);
return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) +
@@ -720,7 +728,9 @@ inline uint128& uint128::operator--() {
#include "absl/numeric/int128_no_intrinsic.inc"
#endif // ABSL_HAVE_INTRINSIC_INT128
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+#undef ABSL_INTERNAL_WCHAR_T
+
#endif // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
index 1cb7d0ed..a5502d92 100644
--- a/absl/numeric/int128_benchmark.cc
+++ b/absl/numeric/int128_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index ee2a0930..c7ea6834 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
-// included by int128.h.
+// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 0d0b3cfd..046cb9b3 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
-// is included by int128.h.
+// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc
index 09efaad4..3cfa9dc1 100644
--- a/absl/numeric/int128_stream_test.cc
+++ b/absl/numeric/int128_stream_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc
index dfe3475a..5e1b5ec3 100644
--- a/absl/numeric/int128_test.cc
+++ b/absl/numeric/int128_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -51,7 +51,7 @@ template <typename T>
class Uint128FloatTraitsTest : public ::testing::Test {};
typedef ::testing::Types<float, double, long double> FloatingPointTypes;
-TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes);
+TYPED_TEST_SUITE(Uint128IntegerTraitsTest, IntegerTypes);
TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) {
static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
@@ -62,7 +62,7 @@ TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) {
"TypeParam must not be assignable from absl::uint128");
}
-TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes);
+TYPED_TEST_SUITE(Uint128FloatTraitsTest, FloatingPointTypes);
TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) {
static_assert(std::is_constructible<absl::uint128, TypeParam>::value,
@@ -271,6 +271,20 @@ TEST(Uint128, ConversionTests) {
EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0);
EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5);
EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9);
+
+ absl::uint128 highest_precision_in_long_double =
+ ~absl::uint128{} >> (128 - std::numeric_limits<long double>::digits);
+ EXPECT_EQ(highest_precision_in_long_double,
+ static_cast<absl::uint128>(
+ static_cast<long double>(highest_precision_in_long_double)));
+ // Apply a mask just to make sure all the bits are the right place.
+ const absl::uint128 arbitrary_mask =
+ absl::MakeUint128(0xa29f622677ded751, 0xf8ca66add076f468);
+ EXPECT_EQ(highest_precision_in_long_double & arbitrary_mask,
+ static_cast<absl::uint128>(static_cast<long double>(
+ highest_precision_in_long_double & arbitrary_mask)));
+
+ EXPECT_EQ(static_cast<absl::uint128>(-0.1L), 0);
}
TEST(Uint128, OperatorAssignReturnRef) {
@@ -440,4 +454,29 @@ TEST(Uint128, NumericLimitsTest) {
EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max());
}
+TEST(Uint128, Hash) {
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly({
+ // Some simple values
+ 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,
+ // Keeping low same
+ 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(),
+ }));
+}
+
} // namespace
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
new file mode 100644
index 00000000..f7587bf9
--- /dev/null
+++ b/absl/random/BUILD.bazel
@@ -0,0 +1,390 @@
+# ABSL random-number generation libraries.
+
+load(
+ "//absl:copts/configure_copts.bzl",
+ "ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
+ "ABSL_EXCEPTIONS_FLAG",
+ "ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
+)
+
+package(default_visibility = ["//visibility:public"])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "random",
+ hdrs = ["random.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":seed_sequences",
+ "//absl/random/internal:nonsecure_base",
+ "//absl/random/internal:pcg_engine",
+ "//absl/random/internal:pool_urbg",
+ "//absl/random/internal:randen_engine",
+ ],
+)
+
+cc_library(
+ name = "distributions",
+ srcs = [
+ "discrete_distribution.cc",
+ "gaussian_distribution.cc",
+ ],
+ hdrs = [
+ "bernoulli_distribution.h",
+ "beta_distribution.h",
+ "discrete_distribution.h",
+ "distribution_format_traits.h",
+ "distributions.h",
+ "exponential_distribution.h",
+ "gaussian_distribution.h",
+ "log_uniform_int_distribution.h",
+ "poisson_distribution.h",
+ "uniform_int_distribution.h",
+ "uniform_real_distribution.h",
+ "zipf_distribution.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:base_internal",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ "//absl/random/internal:distribution_impl",
+ "//absl/random/internal:distributions",
+ "//absl/random/internal:fast_uniform_bits",
+ "//absl/random/internal:fastmath",
+ "//absl/random/internal:iostream_state_saver",
+ "//absl/random/internal:traits",
+ "//absl/random/internal:uniform_helper",
+ "//absl/strings",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "seed_gen_exception",
+ srcs = ["seed_gen_exception.cc"],
+ hdrs = ["seed_gen_exception.h"],
+ copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:config"],
+)
+
+cc_library(
+ name = "seed_sequences",
+ srcs = ["seed_sequences.cc"],
+ hdrs = [
+ "seed_sequences.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":seed_gen_exception",
+ "//absl/container:inlined_vector",
+ "//absl/random/internal:nonsecure_base",
+ "//absl/random/internal:pool_urbg",
+ "//absl/random/internal:salted_seed_seq",
+ "//absl/random/internal:seed_material",
+ "//absl/types:span",
+ ],
+)
+
+cc_test(
+ name = "bernoulli_distribution_test",
+ size = "small",
+ timeout = "eternal", # Android can take a very long time
+ srcs = ["bernoulli_distribution_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/random/internal:sequence_urbg",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "beta_distribution_test",
+ size = "small",
+ timeout = "eternal", # Android can take a very long time
+ srcs = ["beta_distribution_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "distributions_test",
+ size = "small",
+ srcs = [
+ "distributions_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/random/internal:distribution_test_util",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "generators_test",
+ size = "small",
+ srcs = ["generators_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "log_uniform_int_distribution_test",
+ size = "medium",
+ srcs = [
+ "log_uniform_int_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "discrete_distribution_test",
+ size = "medium",
+ srcs = [
+ "discrete_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "poisson_distribution_test",
+ size = "small",
+ timeout = "eternal", # Android can take a very long time
+ srcs = [
+ "poisson_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = [
+ # Too Slow.
+ "no_test_android_arm",
+ "no_test_loonix",
+ ],
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/container:flat_hash_map",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "exponential_distribution_test",
+ size = "small",
+ srcs = ["exponential_distribution_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "gaussian_distribution_test",
+ size = "small",
+ timeout = "eternal", # Android can take a very long time
+ srcs = [
+ "gaussian_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "uniform_int_distribution_test",
+ size = "medium",
+ timeout = "long",
+ srcs = [
+ "uniform_int_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "uniform_real_distribution_test",
+ size = "medium",
+ srcs = [
+ "uniform_real_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = [
+ "no_test_android_arm",
+ "no_test_android_arm64",
+ "no_test_android_x86",
+ ],
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "zipf_distribution_test",
+ size = "medium",
+ srcs = [
+ "zipf_distribution_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distributions",
+ ":random",
+ "//absl/base",
+ "//absl/random/internal:distribution_test_util",
+ "//absl/random/internal:sequence_urbg",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "examples_test",
+ size = "small",
+ srcs = ["examples_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":random",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "seed_sequences_test",
+ size = "small",
+ srcs = ["seed_sequences_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":random",
+ ":seed_sequences",
+ "//absl/random/internal:nonsecure_base",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+BENCHMARK_TAGS = [
+ "benchmark",
+ "no_test_android_arm",
+ "no_test_android_arm64",
+ "no_test_android_x86",
+ "no_test_darwin_x86_64",
+ "no_test_ios_x86_64",
+ "no_test_loonix",
+ "no_test_msvc_x64",
+ "no_test_wasm",
+]
+
+# Benchmarks for various methods / test utilities
+cc_binary(
+ name = "benchmarks",
+ testonly = 1,
+ srcs = [
+ "benchmarks.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = BENCHMARK_TAGS,
+ 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",
+ ],
+)
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
new file mode 100644
index 00000000..2d5c0658
--- /dev/null
+++ b/absl/random/CMakeLists.txt
@@ -0,0 +1,1034 @@
+#
+# 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.
+#
+
+absl_cc_library(
+ NAME
+ random_random
+ HDRS
+ "random.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ 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
+)
+
+absl_cc_library(
+ NAME
+ random_distributions
+ SRCS
+ "discrete_distribution.cc"
+ "gaussian_distribution.cc"
+ HDRS
+ "bernoulli_distribution.h"
+ "beta_distribution.h"
+ "discrete_distribution.h"
+ "distribution_format_traits.h"
+ "distributions.h"
+ "exponential_distribution.h"
+ "gaussian_distribution.h"
+ "log_uniform_int_distribution.h"
+ "poisson_distribution.h"
+ "uniform_int_distribution.h"
+ "uniform_real_distribution.h"
+ "zipf_distribution.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base_internal
+ absl::core_headers
+ absl::random_internal_distribution_impl
+ absl::random_internal_distributions
+ absl::random_internal_fast_uniform_bits
+ absl::random_internal_fastmath
+ absl::random_internal_iostream_state_saver
+ absl::random_internal_traits
+ absl::random_internal_uniform_helper
+ absl::strings
+ absl::span
+ absl::type_traits
+)
+
+absl_cc_library(
+ NAME
+ random_seed_gen_exception
+ SRCS
+ "seed_gen_exception.cc"
+ HDRS
+ "seed_gen_exception.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+)
+
+absl_cc_library(
+ NAME
+ random_seed_sequences
+ SRCS
+ "seed_sequences.cc"
+ HDRS
+ "seed_sequences.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::inlined_vector
+ absl::random_internal_nonsecure_base
+ absl::random_internal_pool_urbg
+ absl::random_internal_salted_seed_seq
+ absl::random_internal_seed_material
+ absl::random_seed_gen_exception
+ absl::span
+)
+
+absl_cc_test(
+ NAME
+ random_bernoulli_distribution_test
+ SRCS
+ "bernoulli_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_distributions
+ absl::random_random
+ absl::random_internal_sequence_urbg
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_beta_distribution_test
+ SRCS
+ "beta_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_distributions
+ absl::random_random
+ absl::base
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::strings
+ absl::str_format
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_distributions_test
+ SRCS
+ "distributions_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_distributions
+ absl::random_random
+ absl::random_internal_distribution_test_util
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_generators_test
+ SRCS
+ "generators_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ absl::random_distributions
+ absl::random_random
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_log_uniform_int_distribution_test
+ SRCS
+ "log_uniform_int_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ absl::base
+ absl::core_headers
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ absl::str_format
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_discrete_distribution_test
+ SRCS
+ "discrete_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_poisson_distribution_test
+ SRCS
+ "poisson_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_distributions
+ absl::random_random
+ absl::base
+ absl::core_headers
+ absl::flat_hash_map
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::strings
+ absl::str_format
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_exponential_distribution_test
+ SRCS
+ "exponential_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ absl::str_format
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_gaussian_distribution_test
+ SRCS
+ "gaussian_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ absl::str_format
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_uniform_int_distribution_test
+ SRCS
+ "uniform_int_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_uniform_real_distribution_test
+ SRCS
+ "uniform_real_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_zipf_distribution_test
+ SRCS
+ "zipf_distribution_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_distributions
+ absl::random_internal_distribution_test_util
+ absl::random_internal_sequence_urbg
+ absl::random_random
+ absl::strings
+ gmock
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_examples_test
+ SRCS
+ "examples_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_random
+ gtest_main
+)
+
+absl_cc_test(
+ NAME
+ random_seed_sequences_test
+ SRCS
+ "seed_sequences_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_seed_sequences
+ absl::random_internal_nonsecure_base
+ absl::random_random
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_traits
+ HDRS
+ "internal/traits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_distribution_caller
+ HDRS
+ "internal/distribution_caller.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_distributions
+ HDRS
+ "internal/distributions.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_distribution_caller
+ absl::random_internal_fast_uniform_bits
+ absl::random_internal_fastmath
+ absl::random_internal_traits
+ absl::random_internal_uniform_helper
+ absl::span
+ absl::strings
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_fast_uniform_bits
+ HDRS
+ "internal/fast_uniform_bits.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_seed_material
+ SRCS
+ "internal/seed_material.cc"
+ HDRS
+ "internal/seed_material.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::optional
+ absl::random_internal_fast_uniform_bits
+ absl::span
+ absl::strings
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_pool_urbg
+ SRCS
+ "internal/pool_urbg.cc"
+ HDRS
+ "internal/pool_urbg.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::endian
+ absl::random_internal_randen
+ absl::random_internal_seed_material
+ absl::random_internal_traits
+ absl::random_seed_gen_exception
+ absl::span
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_explicit_seed_seq
+ HDRS
+ "internal/random_internal_explicit_seed_seq.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ TESTONLY
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_sequence_urbg
+ HDRS
+ "internal/sequence_urbg.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ TESTONLY
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_salted_seed_seq
+ HDRS
+ "internal/salted_seed_seq.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::inlined_vector
+ absl::optional
+ absl::span
+ absl::random_internal_seed_material
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_iostream_state_saver
+ HDRS
+ "internal/iostream_state_saver.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::int128
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_distribution_impl
+ HDRS
+ "internal/distribution_impl.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::bits
+ absl::config
+ absl::int128
+ absl::random_internal_fastmath
+ absl::random_internal_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_fastmath
+ HDRS
+ "internal/fastmath.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::bits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_nonsecure_base
+ HDRS
+ "internal/nonsecure_base.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::core_headers
+ absl::optional
+ absl::random_internal_pool_urbg
+ absl::random_internal_salted_seed_seq
+ absl::random_internal_seed_material
+ absl::span
+ absl::strings
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_pcg_engine
+ HDRS
+ "internal/pcg_engine.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::config
+ absl::int128
+ absl::random_internal_fastmath
+ absl::random_internal_iostream_state_saver
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_randen_engine
+ HDRS
+ "internal/randen_engine.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_iostream_state_saver
+ absl::random_internal_randen
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_platform
+ HDRS
+ "internal/randen_traits.h"
+ "internal/randen-keys.inc"
+ "internal/platform.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_randen
+ SRCS
+ "internal/randen.cc"
+ HDRS
+ "internal/randen.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_internal_platform
+ absl::random_internal_randen_hwaes
+ absl::random_internal_randen_slow
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_randen_slow
+ SRCS
+ "internal/randen_slow.cc"
+ HDRS
+ "internal/randen_slow.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_platform
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_randen_hwaes
+ SRCS
+ "internal/randen_detect.cc"
+ HDRS
+ "internal/randen_detect.h"
+ "internal/randen_hwaes.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_RANDOM_RANDEN_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_platform
+ absl::random_internal_randen_hwaes_impl
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_randen_hwaes_impl
+ SRCS
+ "internal/randen_hwaes.cc"
+ "internal/randen_hwaes.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ ${ABSL_RANDOM_RANDEN_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_platform
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_distribution_test_util
+ SRCS
+ "internal/chi_square.cc"
+ "internal/distribution_test_util.cc"
+ HDRS
+ "internal/chi_square.h"
+ "internal/distribution_test_util.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::strings
+ absl::str_format
+ absl::span
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_traits_test
+ SRCS
+ "internal/traits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_traits
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_distribution_impl_test
+ SRCS
+ "internal/distribution_impl_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::bits
+ absl::flags
+ absl::int128
+ absl::random_internal_distribution_impl
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_distribution_test_util_test
+ SRCS
+ "internal/distribution_test_util_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_distribution_test_util
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_fastmath_test
+ SRCS
+ "internal/fastmath_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_fastmath
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_explicit_seed_seq_test
+ SRCS
+ "internal/explicit_seed_seq_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_explicit_seed_seq
+ absl::random_seed_sequences
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_salted_seed_seq_test
+ SRCS
+ "internal/salted_seed_seq_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_salted_seed_seq
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_chi_square_test
+ SRCS
+ "internal/chi_square_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::core_headers
+ absl::random_internal_distribution_test_util
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_fast_uniform_bits_test
+ SRCS
+ "internal/fast_uniform_bits_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_fast_uniform_bits
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_nonsecure_base_test
+ SRCS
+ "internal/nonsecure_base_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_nonsecure_base
+ absl::random_random
+ absl::random_distributions
+ absl::random_seed_sequences
+ absl::strings
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_seed_material_test
+ SRCS
+ "internal/seed_material_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_seed_material
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_pool_urbg_test
+ SRCS
+ "internal/pool_urbg_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_pool_urbg
+ absl::span
+ absl::type_traits
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_pcg_engine_test
+ SRCS
+ "internal/pcg_engine_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_explicit_seed_seq
+ absl::random_internal_pcg_engine
+ absl::time
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_randen_engine_test
+ SRCS
+ "internal/randen_engine_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::random_internal_explicit_seed_seq
+ absl::random_internal_randen_engine
+ absl::strings
+ absl::time
+ gmock
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_randen_test
+ SRCS
+ "internal/randen_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_randen
+ absl::type_traits
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_randen_slow_test
+ SRCS
+ "internal/randen_slow_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_randen_slow
+ gtest_main
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_randen_hwaes_test
+ SRCS
+ "internal/randen_hwaes_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_platform
+ absl::random_internal_randen_hwaes
+ absl::random_internal_randen_hwaes_impl
+ absl::base
+ absl::str_format
+ gmock
+ gtest
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_library(
+ NAME
+ random_internal_uniform_helper
+ HDRS
+ "internal/uniform_helper.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::core_headers
+ absl::random_internal_distribution_impl
+ absl::random_internal_fast_uniform_bits
+ absl::random_internal_iostream_state_saver
+ absl::random_internal_traits
+ absl::type_traits
+)
+
+# Internal-only target, do not depend on directly.
+absl_cc_test(
+ NAME
+ random_internal_iostream_state_saver_test
+ SRCS
+ "internal/iostream_state_saver_test.cc"
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::random_internal_iostream_state_saver
+ gtest_main
+)
diff --git a/absl/random/benchmarks.cc b/absl/random/benchmarks.cc
new file mode 100644
index 00000000..87bbb981
--- /dev/null
+++ b/absl/random/benchmarks.cc
@@ -0,0 +1,383 @@
+// 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.
+
+// Benchmarks for absl random distributions as well as a selection of the
+// C++ standard library random distributions.
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <random>
+#include <type_traits>
+#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"
+#include "absl/random/gaussian_distribution.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/randen_engine.h"
+#include "absl/random/log_uniform_int_distribution.h"
+#include "absl/random/poisson_distribution.h"
+#include "absl/random/random.h"
+#include "absl/random/uniform_int_distribution.h"
+#include "absl/random/uniform_real_distribution.h"
+#include "absl/random/zipf_distribution.h"
+#include "benchmark/benchmark.h"
+
+namespace {
+
+// Seed data to avoid reading random_device() for benchmarks.
+uint32_t kSeedData[] = {
+ 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+ 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6,
+ 0xFF34052E, 0xC5855664, 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A,
+ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D,
+ 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71, 0x699A18FF, 0x5664526C, 0xC2B19EE1,
+ 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65,
+ 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+ 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, 0x09686B3F, 0x3EBAEFC9,
+ 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0x13198A2E, 0x03707344,
+};
+
+// PrecompiledSeedSeq provides kSeedData to a conforming
+// random engine to speed initialization in the benchmarks.
+class PrecompiledSeedSeq {
+ public:
+ using result_type = uint32_t;
+
+ PrecompiledSeedSeq() {}
+
+ template <typename Iterator>
+ PrecompiledSeedSeq(Iterator begin, Iterator end) {}
+
+ template <typename T>
+ PrecompiledSeedSeq(std::initializer_list<T> il) {}
+
+ template <typename OutIterator>
+ void generate(OutIterator begin, OutIterator end) {
+ static size_t idx = 0;
+ for (; begin != end; begin++) {
+ *begin = kSeedData[idx++];
+ if (idx >= ABSL_ARRAYSIZE(kSeedData)) {
+ idx = 0;
+ }
+ }
+ }
+
+ size_t size() const { return ABSL_ARRAYSIZE(kSeedData); }
+
+ template <typename OutIterator>
+ void param(OutIterator out) const {
+ std::copy(std::begin(kSeedData), std::end(kSeedData), out);
+ }
+};
+
+// 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;
+
+// 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>
+void BM_Construct(benchmark::State& state) {
+ for (auto _ : state) {
+ auto rng = make_engine<Engine, SSeq>();
+ benchmark::DoNotOptimize(rng());
+ }
+}
+
+template <typename Engine>
+void BM_Direct(benchmark::State& state) {
+ using value_type = typename Engine::result_type;
+ // Direct use of the URBG.
+ auto rng = make_engine<Engine>();
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(rng());
+ }
+ state.SetBytesProcessed(sizeof(value_type) * state.iterations());
+}
+
+template <typename Engine>
+void BM_Generate(benchmark::State& state) {
+ // std::generate makes a copy of the RNG; thus this tests the
+ // copy-constructor efficiency.
+ using value_type = typename Engine::result_type;
+ std::vector<value_type> v(64);
+ auto rng = make_engine<Engine>();
+ while (state.KeepRunningBatch(64)) {
+ std::generate(std::begin(v), std::end(v), rng);
+ }
+}
+
+template <typename Engine, size_t elems>
+void BM_Shuffle(benchmark::State& state) {
+ // Direct use of the Engine.
+ std::vector<uint32_t> v(elems);
+ while (state.KeepRunningBatch(elems)) {
+ auto rng = make_engine<Engine>();
+ std::shuffle(std::begin(v), std::end(v), rng);
+ }
+}
+
+template <typename Engine, size_t elems>
+void BM_ShuffleReuse(benchmark::State& state) {
+ // Direct use of the Engine.
+ std::vector<uint32_t> v(elems);
+ auto rng = make_engine<Engine>();
+ while (state.KeepRunningBatch(elems)) {
+ std::shuffle(std::begin(v), std::end(v), rng);
+ }
+}
+
+template <typename Engine, typename Dist, typename... Args>
+void BM_Dist(benchmark::State& state, Args&&... args) {
+ using value_type = typename Dist::result_type;
+ auto rng = make_engine<Engine>();
+ Dist dis{std::forward<Args>(args)...};
+ // Compare the following loop performance:
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(dis(rng));
+ }
+ state.SetBytesProcessed(sizeof(value_type) * state.iterations());
+}
+
+template <typename Engine, typename Dist>
+void BM_Large(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ volatile value_type kMin = 0;
+ volatile value_type kMax = std::numeric_limits<value_type>::max() / 2 + 1;
+ BM_Dist<Engine, Dist>(state, kMin, kMax);
+}
+
+template <typename Engine, typename Dist>
+void BM_Small(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ volatile value_type kMin = 0;
+ volatile value_type kMax = std::numeric_limits<value_type>::max() / 64 + 1;
+ BM_Dist<Engine, Dist>(state, kMin, kMax);
+}
+
+template <typename Engine, typename Dist, int A>
+void BM_Bernoulli(benchmark::State& state) {
+ volatile double a = static_cast<double>(A) / 1000000;
+ BM_Dist<Engine, Dist>(state, a);
+}
+
+template <typename Engine, typename Dist, int A, int B>
+void BM_Beta(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ volatile value_type a = static_cast<value_type>(A) / 100;
+ volatile value_type b = static_cast<value_type>(B) / 100;
+ BM_Dist<Engine, Dist>(state, a, b);
+}
+
+template <typename Engine, typename Dist, int A>
+void BM_Gamma(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ volatile value_type a = static_cast<value_type>(A) / 100;
+ BM_Dist<Engine, Dist>(state, a);
+}
+
+template <typename Engine, typename Dist, int A = 100>
+void BM_Poisson(benchmark::State& state) {
+ volatile double a = static_cast<double>(A) / 100;
+ BM_Dist<Engine, Dist>(state, a);
+}
+
+template <typename Engine, typename Dist, int Q = 2, int V = 1>
+void BM_Zipf(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ volatile double q = Q;
+ volatile double v = V;
+ BM_Dist<Engine, Dist>(state, std::numeric_limits<value_type>::max(), q, v);
+}
+
+template <typename Engine, typename Dist>
+void BM_Thread(benchmark::State& state) {
+ using value_type = typename Dist::result_type;
+ auto rng = make_engine<Engine>();
+ Dist dis{};
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(dis(rng));
+ }
+ state.SetBytesProcessed(sizeof(value_type) * state.iterations());
+}
+
+// NOTES:
+//
+// std::geometric_distribution is similar to the zipf distributions.
+// The algorithm for the geometric_distribution is, basically,
+// floor(log(1-X) / log(1-p))
+
+// Normal benchmark suite
+#define BM_BASIC(Engine) \
+ BENCHMARK_TEMPLATE(BM_Construct, Engine, PrecompiledSeedSeq); \
+ BENCHMARK_TEMPLATE(BM_Construct, Engine, std::seed_seq); \
+ BENCHMARK_TEMPLATE(BM_Direct, Engine); \
+ BENCHMARK_TEMPLATE(BM_Shuffle, Engine, 10); \
+ BENCHMARK_TEMPLATE(BM_Shuffle, Engine, 100); \
+ BENCHMARK_TEMPLATE(BM_Shuffle, Engine, 1000); \
+ BENCHMARK_TEMPLATE(BM_ShuffleReuse, Engine, 100); \
+ BENCHMARK_TEMPLATE(BM_ShuffleReuse, Engine, 1000); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::random_internal::FastUniformBits<uint32_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::random_internal::FastUniformBits<uint64_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Large, Engine, \
+ std::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Large, Engine, \
+ std::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Large, Engine, \
+ absl::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Large, Engine, \
+ absl::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::uniform_real_distribution<float>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::uniform_real_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, absl::uniform_real_distribution<float>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, absl::uniform_real_distribution<double>)
+
+#define BM_COPY(Engine) BENCHMARK_TEMPLATE(BM_Generate, Engine)
+
+#define BM_THREAD(Engine) \
+ BENCHMARK_TEMPLATE(BM_Thread, Engine, \
+ absl::uniform_int_distribution<int64_t>) \
+ ->ThreadPerCpu(); \
+ BENCHMARK_TEMPLATE(BM_Thread, Engine, \
+ absl::uniform_real_distribution<double>) \
+ ->ThreadPerCpu(); \
+ BENCHMARK_TEMPLATE(BM_Shuffle, Engine, 100)->ThreadPerCpu(); \
+ BENCHMARK_TEMPLATE(BM_Shuffle, Engine, 1000)->ThreadPerCpu(); \
+ BENCHMARK_TEMPLATE(BM_ShuffleReuse, Engine, 100)->ThreadPerCpu(); \
+ BENCHMARK_TEMPLATE(BM_ShuffleReuse, Engine, 1000)->ThreadPerCpu();
+
+#define BM_EXTENDED(Engine) \
+ /* -------------- Extended Uniform -----------------------*/ \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ std::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ std::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ absl::uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ absl::uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, std::uniform_real_distribution<float>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ std::uniform_real_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ absl::uniform_real_distribution<float>); \
+ BENCHMARK_TEMPLATE(BM_Small, Engine, \
+ absl::uniform_real_distribution<double>); \
+ /* -------------- Other -----------------------*/ \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::normal_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, absl::gaussian_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::exponential_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, absl::exponential_distribution<double>); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, std::poisson_distribution<int64_t>, \
+ 100); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, absl::poisson_distribution<int64_t>, \
+ 100); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, std::poisson_distribution<int64_t>, \
+ 10 * 100); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, absl::poisson_distribution<int64_t>, \
+ 10 * 100); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, std::poisson_distribution<int64_t>, \
+ 13 * 100); \
+ BENCHMARK_TEMPLATE(BM_Poisson, Engine, absl::poisson_distribution<int64_t>, \
+ 13 * 100); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::log_uniform_int_distribution<int32_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, \
+ absl::log_uniform_int_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Dist, Engine, std::geometric_distribution<int64_t>); \
+ BENCHMARK_TEMPLATE(BM_Zipf, Engine, absl::zipf_distribution<uint64_t>); \
+ BENCHMARK_TEMPLATE(BM_Zipf, Engine, absl::zipf_distribution<uint64_t>, 2, \
+ 3); \
+ BENCHMARK_TEMPLATE(BM_Bernoulli, Engine, std::bernoulli_distribution, \
+ 257305); \
+ BENCHMARK_TEMPLATE(BM_Bernoulli, Engine, absl::bernoulli_distribution, \
+ 257305); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<double>, 65, \
+ 41); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<double>, 99, \
+ 330); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<double>, 150, \
+ 150); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<double>, 410, \
+ 580); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<float>, 65, 41); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<float>, 99, \
+ 330); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<float>, 150, \
+ 150); \
+ BENCHMARK_TEMPLATE(BM_Beta, Engine, absl::beta_distribution<float>, 410, \
+ 580); \
+ BENCHMARK_TEMPLATE(BM_Gamma, Engine, std::gamma_distribution<float>, 199); \
+ BENCHMARK_TEMPLATE(BM_Gamma, Engine, std::gamma_distribution<double>, 199);
+
+// ABSL Recommended interfaces.
+BM_BASIC(absl::InsecureBitGen); // === pcg64_2018_engine
+BM_BASIC(absl::BitGen); // === randen_engine<uint64_t>.
+BM_THREAD(absl::BitGen);
+BM_EXTENDED(absl::BitGen);
+
+// Instantiate benchmarks for multiple engines.
+using randen_engine_64 = absl::random_internal::randen_engine<uint64_t>;
+using randen_engine_32 = absl::random_internal::randen_engine<uint32_t>;
+
+// Comparison interfaces.
+BM_BASIC(std::mt19937_64);
+BM_COPY(std::mt19937_64);
+BM_EXTENDED(std::mt19937_64);
+BM_BASIC(randen_engine_64);
+BM_COPY(randen_engine_64);
+BM_EXTENDED(randen_engine_64);
+
+BM_BASIC(std::mt19937);
+BM_COPY(std::mt19937);
+BM_BASIC(randen_engine_32);
+BM_COPY(randen_engine_32);
+
+} // namespace
diff --git a/absl/random/bernoulli_distribution.h b/absl/random/bernoulli_distribution.h
new file mode 100644
index 00000000..0afc2c14
--- /dev/null
+++ b/absl/random/bernoulli_distribution.h
@@ -0,0 +1,200 @@
+// 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_BERNOULLI_DISTRIBUTION_H_
+#define ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_
+
+#include <cstdint>
+#include <istream>
+#include <limits>
+
+#include "absl/base/optimization.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::bernoulli_distribution is a drop in replacement for
+// std::bernoulli_distribution. It guarantees that (given a perfect
+// UniformRandomBitGenerator) the acceptance probability is *exactly* equal to
+// the given double.
+//
+// The implementation assumes that double is IEEE754
+class bernoulli_distribution {
+ public:
+ using result_type = bool;
+
+ class param_type {
+ public:
+ using distribution_type = bernoulli_distribution;
+
+ explicit param_type(double p = 0.5) : prob_(p) {
+ assert(p >= 0.0 && p <= 1.0);
+ }
+
+ double p() const { return prob_; }
+
+ friend bool operator==(const param_type& p1, const param_type& p2) {
+ return p1.p() == p2.p();
+ }
+ friend bool operator!=(const param_type& p1, const param_type& p2) {
+ return p1.p() != p2.p();
+ }
+
+ private:
+ double prob_;
+ };
+
+ bernoulli_distribution() : bernoulli_distribution(0.5) {}
+
+ explicit bernoulli_distribution(double p) : param_(p) {}
+
+ explicit bernoulli_distribution(param_type p) : param_(p) {}
+
+ // no-op
+ void reset() {}
+
+ template <typename URBG>
+ bool operator()(URBG& g) { // NOLINT(runtime/references)
+ return Generate(param_.p(), g);
+ }
+
+ template <typename URBG>
+ bool operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& param) {
+ return Generate(param.p(), g);
+ }
+
+ param_type param() const { return param_; }
+ void param(const param_type& param) { param_ = param; }
+
+ double p() const { return param_.p(); }
+
+ result_type(min)() const { return false; }
+ result_type(max)() const { return true; }
+
+ friend bool operator==(const bernoulli_distribution& d1,
+ const bernoulli_distribution& d2) {
+ return d1.param_ == d2.param_;
+ }
+
+ friend bool operator!=(const bernoulli_distribution& d1,
+ const bernoulli_distribution& d2) {
+ return d1.param_ != d2.param_;
+ }
+
+ private:
+ static constexpr uint64_t kP32 = static_cast<uint64_t>(1) << 32;
+
+ template <typename URBG>
+ static bool Generate(double p, URBG& g); // NOLINT(runtime/references)
+
+ param_type param_;
+};
+
+template <typename CharT, typename Traits>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const bernoulli_distribution& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<double>::kPrecision);
+ os << x.p();
+ return os;
+}
+
+template <typename CharT, typename Traits>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ bernoulli_distribution& x) { // NOLINT(runtime/references)
+ auto saver = random_internal::make_istream_state_saver(is);
+ auto p = random_internal::read_floating_point<double>(is);
+ if (!is.fail()) {
+ x.param(bernoulli_distribution::param_type(p));
+ }
+ return is;
+}
+
+template <typename URBG>
+bool bernoulli_distribution::Generate(double p,
+ URBG& g) { // NOLINT(runtime/references)
+ random_internal::FastUniformBits<uint32_t> fast_u32;
+
+ while (true) {
+ // There are two aspects of the definition of `c` below that are worth
+ // commenting on. First, because `p` is in the range [0, 1], `c` is in the
+ // range [0, 2^32] which does not fit in a uint32_t and therefore requires
+ // 64 bits.
+ //
+ // Second, `c` is constructed by first casting explicitly to a signed
+ // integer and then converting implicitly to an unsigned integer of the same
+ // size. This is done because the hardware conversion instructions produce
+ // signed integers from double; if taken as a uint64_t the conversion would
+ // be wrong for doubles greater than 2^63 (not relevant in this use-case).
+ // If converted directly to an unsigned integer, the compiler would end up
+ // emitting code to handle such large values that are not relevant due to
+ // the known bounds on `c`. To avoid these extra instructions this
+ // implementation converts first to the signed type and then use the
+ // implicit conversion to unsigned (which is a no-op).
+ const uint64_t c = static_cast<int64_t>(p * kP32);
+ const uint32_t v = fast_u32(g);
+ // FAST PATH: this path fails with probability 1/2^32. Note that simply
+ // returning v <= c would approximate P very well (up to an absolute error
+ // of 1/2^32); the slow path (taken in that range of possible error, in the
+ // case of equality) eliminates the remaining error.
+ if (ABSL_PREDICT_TRUE(v != c)) return v < c;
+
+ // It is guaranteed that `q` is strictly less than 1, because if `q` were
+ // greater than or equal to 1, the same would be true for `p`. Certainly `p`
+ // cannot be greater than 1, and if `p == 1`, then the fast path would
+ // necessary have been taken already.
+ const double q = static_cast<double>(c) / kP32;
+
+ // The probability of acceptance on the fast path is `q` and so the
+ // probability of acceptance here should be `p - q`.
+ //
+ // Note that `q` is obtained from `p` via some shifts and conversions, the
+ // upshot of which is that `q` is simply `p` with some of the
+ // least-significant bits of its mantissa set to zero. This means that the
+ // difference `p - q` will not have any rounding errors. To see why, pretend
+ // that double has 10 bits of resolution and q is obtained from `p` in such
+ // a way that the 4 least-significant bits of its mantissa are set to zero.
+ // For example:
+ // p = 1.1100111011 * 2^-1
+ // q = 1.1100110000 * 2^-1
+ // p - q = 1.011 * 2^-8
+ // The difference `p - q` has exactly the nonzero mantissa bits that were
+ // "lost" in `q` producing a number which is certainly representable in a
+ // double.
+ const double left = p - q;
+
+ // By construction, the probability of being on this slow path is 1/2^32, so
+ // P(accept in slow path) = P(accept| in slow path) * P(slow path),
+ // which means the probability of acceptance here is `1 / (left * kP32)`:
+ const double here = left * kP32;
+
+ // The simplest way to compute the result of this trial is to repeat the
+ // whole algorithm with the new probability. This terminates because even
+ // given arbitrarily unfriendly "random" bits, each iteration either
+ // multiplies a tiny probability by 2^32 (if c == 0) or strips off some
+ // number of nonzero mantissa bits. That process is bounded.
+ if (here == 0) return false;
+ p = here;
+ }
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_BERNOULLI_DISTRIBUTION_H_
diff --git a/absl/random/bernoulli_distribution_test.cc b/absl/random/bernoulli_distribution_test.cc
new file mode 100644
index 00000000..f2c3b99c
--- /dev/null
+++ b/absl/random/bernoulli_distribution_test.cc
@@ -0,0 +1,213 @@
+// 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/bernoulli_distribution.h"
+
+#include <cmath>
+#include <cstddef>
+#include <random>
+#include <sstream>
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+
+namespace {
+
+class BernoulliTest : public testing::TestWithParam<std::pair<double, size_t>> {
+};
+
+TEST_P(BernoulliTest, Serialize) {
+ const double d = GetParam().first;
+ absl::bernoulli_distribution before(d);
+
+ {
+ absl::bernoulli_distribution via_param{
+ absl::bernoulli_distribution::param_type(d)};
+ EXPECT_EQ(via_param, before);
+ }
+
+ std::stringstream ss;
+ ss << before;
+ absl::bernoulli_distribution after(0.6789);
+
+ EXPECT_NE(before.p(), after.p());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.p(), after.p());
+ EXPECT_EQ(before.param(), after.param());
+ EXPECT_EQ(before, after);
+}
+
+TEST_P(BernoulliTest, Accuracy) {
+ // Sadly, the claim to fame for this implementation is precise accuracy, which
+ // is very, very hard to measure, the improvements come as trials approach the
+ // limit of double accuracy; thus the outcome differs from the
+ // std::bernoulli_distribution with a probability of approximately 1 in 2^-53.
+ const std::pair<double, size_t> para = GetParam();
+ size_t trials = para.second;
+ double p = para.first;
+
+ absl::InsecureBitGen rng;
+
+ size_t yes = 0;
+ absl::bernoulli_distribution dist(p);
+ for (size_t i = 0; i < trials; ++i) {
+ if (dist(rng)) yes++;
+ }
+
+ // Compute the distribution parameters for a binomial test, using a normal
+ // approximation for the confidence interval, as there are a sufficiently
+ // large number of trials that the central limit theorem applies.
+ const double stddev_p = std::sqrt((p * (1.0 - p)) / trials);
+ const double expected = trials * p;
+ const double stddev = trials * stddev_p;
+
+ // 5 sigma, approved by Richard Feynman
+ EXPECT_NEAR(yes, expected, 5 * stddev)
+ << "@" << p << ", "
+ << std::abs(static_cast<double>(yes) - expected) / stddev << " stddev";
+}
+
+// There must be many more trials to make the mean approximately normal for `p`
+// closes to 0 or 1.
+INSTANTIATE_TEST_SUITE_P(
+ All, BernoulliTest,
+ ::testing::Values(
+ // Typical values.
+ std::make_pair(0, 30000), std::make_pair(1e-3, 30000000),
+ std::make_pair(0.1, 3000000), std::make_pair(0.5, 3000000),
+ std::make_pair(0.9, 30000000), std::make_pair(0.999, 30000000),
+ std::make_pair(1, 30000),
+ // Boundary cases.
+ std::make_pair(std::nextafter(1.0, 0.0), 1), // ~1 - epsilon
+ std::make_pair(std::numeric_limits<double>::epsilon(), 1),
+ std::make_pair(std::nextafter(std::numeric_limits<double>::min(),
+ 1.0), // min + epsilon
+ 1),
+ std::make_pair(std::numeric_limits<double>::min(), // smallest normal
+ 1),
+ std::make_pair(
+ std::numeric_limits<double>::denorm_min(), // smallest denorm
+ 1),
+ std::make_pair(std::numeric_limits<double>::min() / 2, 1), // denorm
+ std::make_pair(std::nextafter(std::numeric_limits<double>::min(),
+ 0.0), // denorm_max
+ 1)));
+
+// NOTE: absl::bernoulli_distribution is not guaranteed to be stable.
+TEST(BernoulliTest, StabilityTest) {
+ // absl::bernoulli_distribution stability relies on FastUniformBits and
+ // integer arithmetic.
+ absl::random_internal::sequence_urbg urbg({
+ 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
+ 0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
+ 0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
+ 0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
+ 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
+ 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
+ 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
+ 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
+ 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
+ 0xe3fd722dc65ad09eull, 0x5a14fd21ea2a5705ull, 0x14e6ea4d6edb0c73ull,
+ 0x275b0dc7e0a18acfull, 0x36cebe0d2653682eull, 0x0361e9b23861596bull,
+ });
+
+ // Generate a std::string of '0' and '1' for the distribution output.
+ auto generate = [&urbg](absl::bernoulli_distribution& dist) {
+ std::string output;
+ output.reserve(36);
+ urbg.reset();
+ for (int i = 0; i < 35; i++) {
+ output.append(dist(urbg) ? "1" : "0");
+ }
+ return output;
+ };
+
+ const double kP = 0.0331289862362;
+ {
+ absl::bernoulli_distribution dist(kP);
+ auto v = generate(dist);
+ EXPECT_EQ(35, urbg.invocations());
+ EXPECT_EQ(v, "00000000000010000000000010000000000") << dist;
+ }
+ {
+ absl::bernoulli_distribution dist(kP * 10.0);
+ auto v = generate(dist);
+ EXPECT_EQ(35, urbg.invocations());
+ EXPECT_EQ(v, "00000100010010010010000011000011010") << dist;
+ }
+ {
+ absl::bernoulli_distribution dist(kP * 20.0);
+ auto v = generate(dist);
+ EXPECT_EQ(35, urbg.invocations());
+ EXPECT_EQ(v, "00011110010110110011011111110111011") << dist;
+ }
+ {
+ absl::bernoulli_distribution dist(1.0 - kP);
+ auto v = generate(dist);
+ EXPECT_EQ(35, urbg.invocations());
+ EXPECT_EQ(v, "11111111111111111111011111111111111") << dist;
+ }
+}
+
+TEST(BernoulliTest, StabilityTest2) {
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ // Generate a std::string of '0' and '1' for the distribution output.
+ auto generate = [&urbg](absl::bernoulli_distribution& dist) {
+ std::string output;
+ output.reserve(13);
+ urbg.reset();
+ for (int i = 0; i < 12; i++) {
+ output.append(dist(urbg) ? "1" : "0");
+ }
+ return output;
+ };
+
+ constexpr double b0 = 1.0 / 13.0 / 0.2;
+ constexpr double b1 = 2.0 / 13.0 / 0.2;
+ constexpr double b3 = (5.0 / 13.0 / 0.2) - ((1 - b0) + (1 - b1) + (1 - b1));
+ {
+ absl::bernoulli_distribution dist(b0);
+ auto v = generate(dist);
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_EQ(v, "000011100101") << dist;
+ }
+ {
+ absl::bernoulli_distribution dist(b1);
+ auto v = generate(dist);
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_EQ(v, "001111101101") << dist;
+ }
+ {
+ absl::bernoulli_distribution dist(b3);
+ auto v = generate(dist);
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_EQ(v, "001111101111") << dist;
+ }
+}
+
+} // namespace
diff --git a/absl/random/beta_distribution.h b/absl/random/beta_distribution.h
new file mode 100644
index 00000000..ff1eba80
--- /dev/null
+++ b/absl/random/beta_distribution.h
@@ -0,0 +1,416 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_BETA_DISTRIBUTION_H_
+#define ABSL_RANDOM_BETA_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::beta_distribution:
+// Generate a floating-point variate conforming to a Beta distribution:
+// pdf(x) \propto x^(alpha-1) * (1-x)^(beta-1),
+// where the params alpha and beta are both strictly positive real values.
+//
+// The support is the open interval (0, 1), but the return value might be equal
+// to 0 or 1, due to numerical errors when alpha and beta are very different.
+//
+// Usage note: One usage is that alpha and beta are counts of number of
+// successes and failures. When the total number of trials are large, consider
+// approximating a beta distribution with a Gaussian distribution with the same
+// mean and variance. One could use the skewness, which depends only on the
+// smaller of alpha and beta when the number of trials are sufficiently large,
+// to quantify how far a beta distribution is from the normal distribution.
+template <typename RealType = double>
+class beta_distribution {
+ public:
+ using result_type = RealType;
+
+ class param_type {
+ public:
+ using distribution_type = beta_distribution;
+
+ explicit param_type(result_type alpha, result_type beta)
+ : alpha_(alpha), beta_(beta) {
+ assert(alpha >= 0);
+ assert(beta >= 0);
+ assert(alpha <= (std::numeric_limits<result_type>::max)());
+ assert(beta <= (std::numeric_limits<result_type>::max)());
+ if (alpha == 0 || beta == 0) {
+ method_ = DEGENERATE_SMALL;
+ x_ = (alpha >= beta) ? 1 : 0;
+ return;
+ }
+ // a_ = min(beta, alpha), b_ = max(beta, alpha).
+ if (beta < alpha) {
+ inverted_ = true;
+ a_ = beta;
+ b_ = alpha;
+ } else {
+ inverted_ = false;
+ a_ = alpha;
+ b_ = beta;
+ }
+ if (a_ <= 1 && b_ >= ThresholdForLargeA()) {
+ method_ = DEGENERATE_SMALL;
+ x_ = inverted_ ? result_type(1) : result_type(0);
+ return;
+ }
+ // For threshold values, see also:
+ // Evaluation of Beta Generation Algorithms, Ying-Chao Hung, et. al.
+ // February, 2009.
+ if ((b_ < 1.0 && a_ + b_ <= 1.2) || a_ <= ThresholdForSmallA()) {
+ // Choose Joehnk over Cheng when it's faster or when Cheng encounters
+ // numerical issues.
+ method_ = JOEHNK;
+ a_ = result_type(1) / alpha_;
+ b_ = result_type(1) / beta_;
+ if (std::isinf(a_) || std::isinf(b_)) {
+ method_ = DEGENERATE_SMALL;
+ x_ = inverted_ ? result_type(1) : result_type(0);
+ }
+ return;
+ }
+ if (a_ >= ThresholdForLargeA()) {
+ method_ = DEGENERATE_LARGE;
+ // Note: on PPC for long double, evaluating
+ // `std::numeric_limits::max() / ThresholdForLargeA` results in NaN.
+ result_type r = a_ / b_;
+ x_ = (inverted_ ? result_type(1) : r) / (1 + r);
+ return;
+ }
+ x_ = a_ + b_;
+ log_x_ = std::log(x_);
+ if (a_ <= 1) {
+ method_ = CHENG_BA;
+ y_ = result_type(1) / a_;
+ gamma_ = a_ + a_;
+ return;
+ }
+ method_ = CHENG_BB;
+ result_type r = (a_ - 1) / (b_ - 1);
+ y_ = std::sqrt((1 + r) / (b_ * r * 2 - r + 1));
+ gamma_ = a_ + result_type(1) / y_;
+ }
+
+ result_type alpha() const { return alpha_; }
+ result_type beta() const { return beta_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.alpha_ == b.alpha_ && a.beta_ == b.beta_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class beta_distribution;
+
+#ifdef COMPILER_MSVC
+ // MSVC does not have constexpr implementations for std::log and std::exp
+ // so they are computed at runtime.
+#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR
+#else
+#define ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR constexpr
+#endif
+
+ // The threshold for whether std::exp(1/a) is finite.
+ // Note that this value is quite large, and a smaller a_ is NOT abnormal.
+ static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type
+ ThresholdForSmallA() {
+ return result_type(1) /
+ std::log((std::numeric_limits<result_type>::max)());
+ }
+
+ // The threshold for whether a * std::log(a) is finite.
+ static ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR result_type
+ ThresholdForLargeA() {
+ return std::exp(
+ std::log((std::numeric_limits<result_type>::max)()) -
+ std::log(std::log((std::numeric_limits<result_type>::max)())) -
+ ThresholdPadding());
+ }
+
+#undef ABSL_RANDOM_INTERNAL_LOG_EXP_CONSTEXPR
+
+ // Pad the threshold for large A for long double on PPC. This is done via a
+ // template specialization below.
+ static constexpr result_type ThresholdPadding() { return 0; }
+
+ enum Method {
+ JOEHNK, // Uses algorithm Joehnk
+ CHENG_BA, // Uses algorithm BA in Cheng
+ CHENG_BB, // Uses algorithm BB in Cheng
+
+ // Note: See also:
+ // Hung et al. Evaluation of beta generation algorithms. Communications
+ // in Statistics-Simulation and Computation 38.4 (2009): 750-770.
+ // especially:
+ // Zechner, Heinz, and Ernst Stadlober. Generating beta variates via
+ // patchwork rejection. Computing 50.1 (1993): 1-18.
+
+ DEGENERATE_SMALL, // a_ is abnormally small.
+ DEGENERATE_LARGE, // a_ is abnormally large.
+ };
+
+ result_type alpha_;
+ result_type beta_;
+
+ result_type a_; // the smaller of {alpha, beta}, or 1.0/alpha_ in JOEHNK
+ result_type b_; // the larger of {alpha, beta}, or 1.0/beta_ in JOEHNK
+ result_type x_; // alpha + beta, or the result in degenerate cases
+ result_type log_x_; // log(x_)
+ result_type y_; // "beta" in Cheng
+ result_type gamma_; // "gamma" in Cheng
+
+ Method method_;
+
+ // Placing this last for optimal alignment.
+ // Whether alpha_ != a_, i.e. true iff alpha_ > beta_.
+ bool inverted_;
+
+ static_assert(std::is_floating_point<RealType>::value,
+ "Class-template absl::beta_distribution<> must be "
+ "parameterized using a floating-point type.");
+ };
+
+ beta_distribution() : beta_distribution(1) {}
+
+ explicit beta_distribution(result_type alpha, result_type beta = 1)
+ : param_(alpha, beta) {}
+
+ explicit beta_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ // Generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const { return 0; }
+ result_type(max)() const { return 1; }
+
+ result_type alpha() const { return param_.alpha(); }
+ result_type beta() const { return param_.beta(); }
+
+ friend bool operator==(const beta_distribution& a,
+ const beta_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const beta_distribution& a,
+ const beta_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ template <typename URBG>
+ result_type AlgorithmJoehnk(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ template <typename URBG>
+ result_type AlgorithmCheng(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ template <typename URBG>
+ result_type DegenerateCase(URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ if (p.method_ == param_type::DEGENERATE_SMALL && p.alpha_ == p.beta_) {
+ // Returns 0 or 1 with equal probability.
+ random_internal::FastUniformBits<uint8_t> fast_u8;
+ return static_cast<result_type>((fast_u8(g) & 0x10) !=
+ 0); // pick any single bit.
+ }
+ return p.x_;
+ }
+
+ param_type param_;
+ random_internal::FastUniformBits<uint64_t> fast_u64_;
+};
+
+#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
+ defined(__ppc__) || defined(__PPC__)
+// PPC needs a more stringent boundary for long double.
+template <>
+constexpr long double
+beta_distribution<long double>::param_type::ThresholdPadding() {
+ return 10;
+}
+#endif
+
+template <typename RealType>
+template <typename URBG>
+typename beta_distribution<RealType>::result_type
+beta_distribution<RealType>::AlgorithmJoehnk(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ // Based on Joehnk, M. D. Erzeugung von betaverteilten und gammaverteilten
+ // Zufallszahlen. Metrika 8.1 (1964): 5-15.
+ // This method is described in Knuth, Vol 2 (Third Edition), pp 134.
+ using RandU64ToReal = typename random_internal::RandU64ToReal<result_type>;
+ using random_internal::PositiveValueT;
+ result_type u, v, x, y, z;
+ for (;;) {
+ u = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+ v = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+
+ // Direct method. std::pow is slow for float, so rely on the optimizer to
+ // remove the std::pow() path for that case.
+ if (!std::is_same<float, result_type>::value) {
+ x = std::pow(u, p.a_);
+ y = std::pow(v, p.b_);
+ z = x + y;
+ if (z > 1) {
+ // Reject if and only if `x + y > 1.0`
+ continue;
+ }
+ if (z > 0) {
+ // When both alpha and beta are small, x and y are both close to 0, so
+ // divide by (x+y) directly may result in nan.
+ return x / z;
+ }
+ }
+
+ // Log transform.
+ // x = log( pow(u, p.a_) ), y = log( pow(v, p.b_) )
+ // since u, v <= 1.0, x, y < 0.
+ x = std::log(u) * p.a_;
+ y = std::log(v) * p.b_;
+ if (!std::isfinite(x) || !std::isfinite(y)) {
+ continue;
+ }
+ // z = log( pow(u, a) + pow(v, b) )
+ z = x > y ? (x + std::log(1 + std::exp(y - x)))
+ : (y + std::log(1 + std::exp(x - y)));
+ // Reject iff log(x+y) > 0.
+ if (z > 0) {
+ continue;
+ }
+ return std::exp(x - z);
+ }
+}
+
+template <typename RealType>
+template <typename URBG>
+typename beta_distribution<RealType>::result_type
+beta_distribution<RealType>::AlgorithmCheng(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ // Based on Cheng, Russell CH. Generating beta variates with nonintegral
+ // shape parameters. Communications of the ACM 21.4 (1978): 317-322.
+ // (https://dl.acm.org/citation.cfm?id=359482).
+ using RandU64ToReal = typename random_internal::RandU64ToReal<result_type>;
+ using random_internal::PositiveValueT;
+
+ static constexpr result_type kLogFour =
+ result_type(1.3862943611198906188344642429163531361); // log(4)
+ static constexpr result_type kS =
+ result_type(2.6094379124341003746007593332261876); // 1+log(5)
+
+ const bool use_algorithm_ba = (p.method_ == param_type::CHENG_BA);
+ result_type u1, u2, v, w, z, r, s, t, bw_inv, lhs;
+ for (;;) {
+ u1 = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+ u2 = RandU64ToReal::template Value<PositiveValueT, false>(fast_u64_(g));
+ v = p.y_ * std::log(u1 / (1 - u1));
+ w = p.a_ * std::exp(v);
+ bw_inv = result_type(1) / (p.b_ + w);
+ r = p.gamma_ * v - kLogFour;
+ s = p.a_ + r - w;
+ z = u1 * u1 * u2;
+ if (!use_algorithm_ba && s + kS >= 5 * z) {
+ break;
+ }
+ t = std::log(z);
+ if (!use_algorithm_ba && s >= t) {
+ break;
+ }
+ lhs = p.x_ * (p.log_x_ + std::log(bw_inv)) + r;
+ if (lhs >= t) {
+ break;
+ }
+ }
+ return p.inverted_ ? (1 - w * bw_inv) : w * bw_inv;
+}
+
+template <typename RealType>
+template <typename URBG>
+typename beta_distribution<RealType>::result_type
+beta_distribution<RealType>::operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ switch (p.method_) {
+ case param_type::JOEHNK:
+ return AlgorithmJoehnk(g, p);
+ case param_type::CHENG_BA:
+ ABSL_FALLTHROUGH_INTENDED;
+ case param_type::CHENG_BB:
+ return AlgorithmCheng(g, p);
+ default:
+ return DegenerateCase(g, p);
+ }
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const beta_distribution<RealType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
+ os << x.alpha() << os.fill() << x.beta();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ beta_distribution<RealType>& x) { // NOLINT(runtime/references)
+ using result_type = typename beta_distribution<RealType>::result_type;
+ using param_type = typename beta_distribution<RealType>::param_type;
+ result_type alpha, beta;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ alpha = random_internal::read_floating_point<result_type>(is);
+ if (is.fail()) return is;
+ beta = random_internal::read_floating_point<result_type>(is);
+ if (!is.fail()) {
+ x.param(param_type(alpha, beta));
+ }
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_BETA_DISTRIBUTION_H_
diff --git a/absl/random/beta_distribution_test.cc b/absl/random/beta_distribution_test.cc
new file mode 100644
index 00000000..966ad08b
--- /dev/null
+++ b/absl/random/beta_distribution_test.cc
@@ -0,0 +1,614 @@
+// 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/beta_distribution.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+template <typename IntType>
+class BetaDistributionInterfaceTest : public ::testing::Test {};
+
+using RealTypes = ::testing::Types<float, double, long double>;
+TYPED_TEST_CASE(BetaDistributionInterfaceTest, RealTypes);
+
+TYPED_TEST(BetaDistributionInterfaceTest, SerializeTest) {
+ // The threshold for whether std::exp(1/a) is finite.
+ const TypeParam kSmallA =
+ 1.0f / std::log((std::numeric_limits<TypeParam>::max)());
+ // The threshold for whether a * std::log(a) is finite.
+ const TypeParam kLargeA =
+ std::exp(std::log((std::numeric_limits<TypeParam>::max)()) -
+ std::log(std::log((std::numeric_limits<TypeParam>::max)())));
+ const TypeParam kLargeAPPC = std::exp(
+ std::log((std::numeric_limits<TypeParam>::max)()) -
+ std::log(std::log((std::numeric_limits<TypeParam>::max)())) - 10.0f);
+ using param_type = typename absl::beta_distribution<TypeParam>::param_type;
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ const TypeParam kValues[] = {
+ TypeParam(1e-20), TypeParam(1e-12), TypeParam(1e-8), TypeParam(1e-4),
+ TypeParam(1e-3), TypeParam(0.1), TypeParam(0.25),
+ std::nextafter(TypeParam(0.5), TypeParam(0)), // 0.5 - epsilon
+ std::nextafter(TypeParam(0.5), TypeParam(1)), // 0.5 + epsilon
+ TypeParam(0.5), TypeParam(1.0), //
+ std::nextafter(TypeParam(1), TypeParam(0)), // 1 - epsilon
+ std::nextafter(TypeParam(1), TypeParam(2)), // 1 + epsilon
+ TypeParam(12.5), TypeParam(1e2), TypeParam(1e8), TypeParam(1e12),
+ TypeParam(1e20), //
+ kSmallA, //
+ std::nextafter(kSmallA, TypeParam(0)), //
+ std::nextafter(kSmallA, TypeParam(1)), //
+ kLargeA, //
+ std::nextafter(kLargeA, TypeParam(0)), //
+ std::nextafter(kLargeA, std::numeric_limits<TypeParam>::max()),
+ kLargeAPPC, //
+ std::nextafter(kLargeAPPC, TypeParam(0)),
+ std::nextafter(kLargeAPPC, std::numeric_limits<TypeParam>::max()),
+ // Boundary cases.
+ std::numeric_limits<TypeParam>::max(),
+ std::numeric_limits<TypeParam>::epsilon(),
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(1)), // min + epsilon
+ std::numeric_limits<TypeParam>::min(), // smallest normal
+ std::numeric_limits<TypeParam>::denorm_min(), // smallest denorm
+ std::numeric_limits<TypeParam>::min() / 2, // denorm
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(0)), // denorm_max
+ };
+ for (TypeParam alpha : kValues) {
+ for (TypeParam beta : kValues) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("Smoke test for Beta(%f, %f)", alpha, beta));
+
+ param_type param(alpha, beta);
+ absl::beta_distribution<TypeParam> before(alpha, beta);
+ EXPECT_EQ(before.alpha(), param.alpha());
+ EXPECT_EQ(before.beta(), param.beta());
+
+ {
+ absl::beta_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ EXPECT_EQ(via_param.param(), before.param());
+ }
+
+ // Smoke test.
+ for (int i = 0; i < kCount; ++i) {
+ auto sample = before(gen);
+ EXPECT_TRUE(std::isfinite(sample));
+ EXPECT_GE(sample, before.min());
+ EXPECT_LE(sample, before.max());
+ }
+
+ // Validate stream serialization.
+ std::stringstream ss;
+ ss << before;
+ absl::beta_distribution<TypeParam> after(3.8f, 1.43f);
+ EXPECT_NE(before.alpha(), after.alpha());
+ EXPECT_NE(before.beta(), after.beta());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
+ defined(__ppc__) || defined(__PPC__)
+ if (std::is_same<TypeParam, long double>::value) {
+ // Roundtripping floating point values requires sufficient precision
+ // to reconstruct the exact value. It turns out that long double
+ // has some errors doing this on ppc.
+ if (alpha <= std::numeric_limits<double>::max() &&
+ alpha >= std::numeric_limits<double>::lowest()) {
+ EXPECT_EQ(static_cast<double>(before.alpha()),
+ static_cast<double>(after.alpha()))
+ << ss.str();
+ }
+ if (beta <= std::numeric_limits<double>::max() &&
+ beta >= std::numeric_limits<double>::lowest()) {
+ EXPECT_EQ(static_cast<double>(before.beta()),
+ static_cast<double>(after.beta()))
+ << ss.str();
+ }
+ continue;
+ }
+#endif
+
+ EXPECT_EQ(before.alpha(), after.alpha());
+ EXPECT_EQ(before.beta(), after.beta());
+ EXPECT_EQ(before, after) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+ }
+ }
+}
+
+TYPED_TEST(BetaDistributionInterfaceTest, DegenerateCases) {
+ // Extreme cases when the params are abnormal.
+ absl::InsecureBitGen gen;
+ constexpr int kCount = 1000;
+ const TypeParam kSmallValues[] = {
+ std::numeric_limits<TypeParam>::min(),
+ std::numeric_limits<TypeParam>::denorm_min(),
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(0)), // denorm_max
+ std::numeric_limits<TypeParam>::epsilon(),
+ };
+ const TypeParam kLargeValues[] = {
+ std::numeric_limits<TypeParam>::max() * static_cast<TypeParam>(0.9999),
+ std::numeric_limits<TypeParam>::max() - 1,
+ std::numeric_limits<TypeParam>::max(),
+ };
+ {
+ // Small alpha and beta.
+ // Useful WolframAlpha plots:
+ // * plot InverseBetaRegularized[x, 0.0001, 0.0001] from 0.495 to 0.505
+ // * Beta[1.0, 0.0000001, 0.0000001]
+ // * Beta[0.9999, 0.0000001, 0.0000001]
+ for (TypeParam alpha : kSmallValues) {
+ for (TypeParam beta : kSmallValues) {
+ int zeros = 0;
+ int ones = 0;
+ absl::beta_distribution<TypeParam> d(alpha, beta);
+ for (int i = 0; i < kCount; ++i) {
+ TypeParam x = d(gen);
+ if (x == 0.0) {
+ zeros++;
+ } else if (x == 1.0) {
+ ones++;
+ }
+ }
+ EXPECT_EQ(ones + zeros, kCount);
+ if (alpha == beta) {
+ EXPECT_NE(ones, 0);
+ EXPECT_NE(zeros, 0);
+ }
+ }
+ }
+ }
+ {
+ // Small alpha, large beta.
+ // Useful WolframAlpha plots:
+ // * plot InverseBetaRegularized[x, 0.0001, 10000] from 0.995 to 1
+ // * Beta[0, 0.0000001, 1000000]
+ // * Beta[0.001, 0.0000001, 1000000]
+ // * Beta[1, 0.0000001, 1000000]
+ for (TypeParam alpha : kSmallValues) {
+ for (TypeParam beta : kLargeValues) {
+ absl::beta_distribution<TypeParam> d(alpha, beta);
+ for (int i = 0; i < kCount; ++i) {
+ EXPECT_EQ(d(gen), 0.0);
+ }
+ }
+ }
+ }
+ {
+ // Large alpha, small beta.
+ // Useful WolframAlpha plots:
+ // * plot InverseBetaRegularized[x, 10000, 0.0001] from 0 to 0.001
+ // * Beta[0.99, 1000000, 0.0000001]
+ // * Beta[1, 1000000, 0.0000001]
+ for (TypeParam alpha : kLargeValues) {
+ for (TypeParam beta : kSmallValues) {
+ absl::beta_distribution<TypeParam> d(alpha, beta);
+ for (int i = 0; i < kCount; ++i) {
+ EXPECT_EQ(d(gen), 1.0);
+ }
+ }
+ }
+ }
+ {
+ // Large alpha and beta.
+ absl::beta_distribution<TypeParam> d(std::numeric_limits<TypeParam>::max(),
+ std::numeric_limits<TypeParam>::max());
+ for (int i = 0; i < kCount; ++i) {
+ EXPECT_EQ(d(gen), 0.5);
+ }
+ }
+ {
+ // Large alpha and beta but unequal.
+ absl::beta_distribution<TypeParam> d(
+ std::numeric_limits<TypeParam>::max(),
+ std::numeric_limits<TypeParam>::max() * 0.9999);
+ for (int i = 0; i < kCount; ++i) {
+ TypeParam x = d(gen);
+ EXPECT_NE(x, 0.5f);
+ EXPECT_FLOAT_EQ(x, 0.500025f);
+ }
+ }
+}
+
+class BetaDistributionModel {
+ public:
+ explicit BetaDistributionModel(::testing::tuple<double, double> p)
+ : alpha_(::testing::get<0>(p)), beta_(::testing::get<1>(p)) {}
+
+ double Mean() const { return alpha_ / (alpha_ + beta_); }
+
+ double Variance() const {
+ return alpha_ * beta_ / (alpha_ + beta_ + 1) / (alpha_ + beta_) /
+ (alpha_ + beta_);
+ }
+
+ double Kurtosis() const {
+ return 3 + 6 *
+ ((alpha_ - beta_) * (alpha_ - beta_) * (alpha_ + beta_ + 1) -
+ alpha_ * beta_ * (2 + alpha_ + beta_)) /
+ alpha_ / beta_ / (alpha_ + beta_ + 2) / (alpha_ + beta_ + 3);
+ }
+
+ protected:
+ const double alpha_;
+ const double beta_;
+};
+
+class BetaDistributionTest
+ : public ::testing::TestWithParam<::testing::tuple<double, double>>,
+ public BetaDistributionModel {
+ public:
+ BetaDistributionTest() : BetaDistributionModel(GetParam()) {}
+
+ protected:
+ template <class D>
+ bool SingleZTestOnMeanAndVariance(double p, size_t samples);
+
+ template <class D>
+ bool SingleChiSquaredTest(double p, size_t samples, size_t buckets);
+
+ absl::InsecureBitGen rng_;
+};
+
+template <class D>
+bool BetaDistributionTest::SingleZTestOnMeanAndVariance(double p,
+ size_t samples) {
+ D dis(alpha_, beta_);
+
+ std::vector<double> data;
+ data.reserve(samples);
+ for (size_t i = 0; i < samples; i++) {
+ const double variate = dis(rng_);
+ EXPECT_FALSE(std::isnan(variate));
+ // Note that equality is allowed on both sides.
+ EXPECT_GE(variate, 0.0);
+ EXPECT_LE(variate, 1.0);
+ data.push_back(variate);
+ }
+
+ // We validate that the sample mean and sample variance are indeed from a
+ // Beta distribution with the given shape parameters.
+ const auto m = absl::random_internal::ComputeDistributionMoments(data);
+
+ // The variance of the sample mean is variance / n.
+ const double mean_stddev = std::sqrt(Variance() / static_cast<double>(m.n));
+
+ // The variance of the sample variance is (approximately):
+ // (kurtosis - 1) * variance^2 / n
+ const double variance_stddev = std::sqrt(
+ (Kurtosis() - 1) * Variance() * Variance() / static_cast<double>(m.n));
+ // z score for the sample variance.
+ const double z_variance = (m.variance - Variance()) / variance_stddev;
+
+ const double max_err = absl::random_internal::MaxErrorTolerance(p);
+ const double z_mean = absl::random_internal::ZScore(Mean(), m);
+ const bool pass =
+ absl::random_internal::Near("z", z_mean, 0.0, max_err) &&
+ absl::random_internal::Near("z_variance", z_variance, 0.0, max_err);
+ if (!pass) {
+ ABSL_INTERNAL_LOG(
+ INFO,
+ absl::StrFormat(
+ "Beta(%f, %f), "
+ "mean: sample %f, expect %f, which is %f stddevs away, "
+ "variance: sample %f, expect %f, which is %f stddevs away.",
+ alpha_, beta_, m.mean, Mean(),
+ std::abs(m.mean - Mean()) / mean_stddev, m.variance, Variance(),
+ std::abs(m.variance - Variance()) / variance_stddev));
+ }
+ return pass;
+}
+
+template <class D>
+bool BetaDistributionTest::SingleChiSquaredTest(double p, size_t samples,
+ size_t buckets) {
+ constexpr double kErr = 1e-7;
+ std::vector<double> cutoffs, expected;
+ const double bucket_width = 1.0 / static_cast<double>(buckets);
+ int i = 1;
+ int unmerged_buckets = 0;
+ for (; i < buckets; ++i) {
+ const double p = bucket_width * static_cast<double>(i);
+ const double boundary =
+ absl::random_internal::BetaIncompleteInv(alpha_, beta_, p);
+ // The intention is to add `boundary` to the list of `cutoffs`. It becomes
+ // problematic, however, when the boundary values are not monotone, due to
+ // numerical issues when computing the inverse regularized incomplete
+ // Beta function. In these cases, we merge that bucket with its previous
+ // neighbor and merge their expected counts.
+ if ((cutoffs.empty() && boundary < kErr) ||
+ (!cutoffs.empty() && boundary <= cutoffs.back())) {
+ unmerged_buckets++;
+ continue;
+ }
+ if (boundary >= 1.0 - 1e-10) {
+ break;
+ }
+ cutoffs.push_back(boundary);
+ expected.push_back(static_cast<double>(1 + unmerged_buckets) *
+ bucket_width * static_cast<double>(samples));
+ unmerged_buckets = 0;
+ }
+ cutoffs.push_back(std::numeric_limits<double>::infinity());
+ // Merge all remaining buckets.
+ expected.push_back(static_cast<double>(buckets - i + 1) * bucket_width *
+ static_cast<double>(samples));
+ // Make sure that we don't merge all the buckets, making this test
+ // meaningless.
+ EXPECT_GE(cutoffs.size(), 3) << alpha_ << ", " << beta_;
+
+ D dis(alpha_, beta_);
+
+ std::vector<int32_t> counts(cutoffs.size(), 0);
+ for (int i = 0; i < samples; i++) {
+ const double x = dis(rng_);
+ auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(), x);
+ counts[std::distance(cutoffs.begin(), it)]++;
+ }
+
+ // Null-hypothesis is that the distribution is beta distributed with the
+ // provided alpha, beta params (not estimated from the data).
+ const int dof = cutoffs.size() - 1;
+
+ const double chi_square = absl::random_internal::ChiSquare(
+ counts.begin(), counts.end(), expected.begin(), expected.end());
+ const bool pass =
+ (absl::random_internal::ChiSquarePValue(chi_square, dof) >= p);
+ if (!pass) {
+ for (int i = 0; i < cutoffs.size(); i++) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("cutoff[%d] = %f, actual count %d, expected %d",
+ i, cutoffs[i], counts[i],
+ static_cast<int>(expected[i])));
+ }
+
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat(
+ "Beta(%f, %f) %s %f, p = %f", alpha_, beta_,
+ absl::random_internal::kChiSquared, chi_square,
+ absl::random_internal::ChiSquarePValue(chi_square, dof)));
+ }
+ return pass;
+}
+
+TEST_P(BetaDistributionTest, TestSampleStatistics) {
+ static constexpr int kRuns = 20;
+ static constexpr double kPFail = 0.02;
+ const double p =
+ absl::random_internal::RequiredSuccessProbability(kPFail, kRuns);
+ static constexpr int kSampleCount = 10000;
+ static constexpr int kBucketCount = 100;
+ int failed = 0;
+ for (int i = 0; i < kRuns; ++i) {
+ if (!SingleZTestOnMeanAndVariance<absl::beta_distribution<double>>(
+ p, kSampleCount)) {
+ failed++;
+ }
+ if (!SingleChiSquaredTest<absl::beta_distribution<double>>(
+ 0.005, kSampleCount, kBucketCount)) {
+ failed++;
+ }
+ }
+ // Set so that the test is not flaky at --runs_per_test=10000
+ EXPECT_LE(failed, 5);
+}
+
+std::string ParamName(
+ const ::testing::TestParamInfo<::testing::tuple<double, double>>& info) {
+ std::string name = absl::StrCat("alpha_", ::testing::get<0>(info.param),
+ "__beta_", ::testing::get<1>(info.param));
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_CASE_P(
+ TestSampleStatisticsCombinations, BetaDistributionTest,
+ ::testing::Combine(::testing::Values(0.1, 0.2, 0.9, 1.1, 2.5, 10.0, 123.4),
+ ::testing::Values(0.1, 0.2, 0.9, 1.1, 2.5, 10.0, 123.4)),
+ ParamName);
+
+INSTANTIATE_TEST_CASE_P(
+ TestSampleStatistics_SelectedPairs, BetaDistributionTest,
+ ::testing::Values(std::make_pair(0.5, 1000), std::make_pair(1000, 0.5),
+ std::make_pair(900, 1000), std::make_pair(10000, 20000),
+ std::make_pair(4e5, 2e7), std::make_pair(1e7, 1e5)),
+ ParamName);
+
+// NOTE: absl::beta_distribution is not guaranteed to be stable.
+TEST(BetaDistributionTest, StabilityTest) {
+ // absl::beta_distribution stability relies on the stability of
+ // absl::random_interna::RandU64ToDouble, std::exp, std::log, std::pow,
+ // and std::sqrt.
+ //
+ // This test also depends on the stability of std::frexp.
+ using testing::ElementsAre;
+ absl::random_internal::sequence_urbg urbg({
+ 0xffff00000000e6c8ull, 0xffff0000000006c8ull, 0x800003766295CFA9ull,
+ 0x11C819684E734A41ull, 0x832603766295CFA9ull, 0x7fbe76c8b4395800ull,
+ 0xB3472DCA7B14A94Aull, 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull,
+ 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull, 0x00035C904C70A239ull,
+ 0x00009E0BCBAADE14ull, 0x0000000000622CA7ull, 0x4864f22c059bf29eull,
+ 0x247856d8b862665cull, 0xe46e86e9a1337e10ull, 0xd8c8541f3519b133ull,
+ 0xffe75b52c567b9e4ull, 0xfffff732e5709c5bull, 0xff1f7f0b983532acull,
+ 0x1ec2e8986d2362caull, 0xC332DDEFBE6C5AA5ull, 0x6558218568AB9702ull,
+ 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull, 0xECDD4775619F1510ull,
+ 0x814c8e35fe9a961aull, 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull,
+ 0x1224e62c978bbc7full, 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull,
+ 0x1bbc23cfa8fac721ull, 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull,
+ 0x836d794457c08849ull, 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull,
+ 0xb12d74fdd718c8c5ull, 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull,
+ 0x5738341045ba0d85ull, 0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull,
+ 0xffe6ea4d6edb0c73ull, 0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull,
+ 0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull,
+ 0x8FF6E2FBF2122B64ull, 0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull,
+ 0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull,
+ });
+
+ // Convert the real-valued result into a unit64 where we compare
+ // 5 (float) or 10 (double) decimal digits plus the base-2 exponent.
+ auto float_to_u64 = [](float d) {
+ int exp = 0;
+ auto f = std::frexp(d, &exp);
+ return (static_cast<uint64_t>(1e5 * f) * 10000) + std::abs(exp);
+ };
+ auto double_to_u64 = [](double d) {
+ int exp = 0;
+ auto f = std::frexp(d, &exp);
+ return (static_cast<uint64_t>(1e10 * f) * 10000) + std::abs(exp);
+ };
+
+ std::vector<uint64_t> output(20);
+ {
+ // Algorithm Joehnk (float)
+ absl::beta_distribution<float> dist(0.1f, 0.2f);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return float_to_u64(dist(urbg)); });
+ EXPECT_EQ(44, urbg.invocations());
+ EXPECT_THAT(output, //
+ testing::ElementsAre(
+ 998340000, 619030004, 500000001, 999990000, 996280000,
+ 500000001, 844740004, 847210001, 999970000, 872320000,
+ 585480007, 933280000, 869080042, 647670031, 528240004,
+ 969980004, 626050008, 915930002, 833440033, 878040015));
+ }
+
+ urbg.reset();
+ {
+ // Algorithm Joehnk (double)
+ absl::beta_distribution<double> dist(0.1, 0.2);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return double_to_u64(dist(urbg)); });
+ EXPECT_EQ(44, urbg.invocations());
+ EXPECT_THAT(
+ output, //
+ testing::ElementsAre(
+ 99834713000000, 61903356870004, 50000000000001, 99999721170000,
+ 99628374770000, 99999999990000, 84474397860004, 84721276240001,
+ 99997407490000, 87232528120000, 58548364780007, 93328932910000,
+ 86908237770042, 64767917930031, 52824581970004, 96998544140004,
+ 62605946270008, 91593604380002, 83345031740033, 87804397230015));
+ }
+
+ urbg.reset();
+ {
+ // Algorithm Cheng 1
+ absl::beta_distribution<double> dist(0.9, 2.0);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return double_to_u64(dist(urbg)); });
+ EXPECT_EQ(62, urbg.invocations());
+ EXPECT_THAT(
+ output, //
+ testing::ElementsAre(
+ 62069004780001, 64433204450001, 53607416560000, 89644295430008,
+ 61434586310019, 55172615890002, 62187161490000, 56433684810003,
+ 80454622050005, 86418558710003, 92920514700001, 64645184680001,
+ 58549183380000, 84881283650005, 71078728590002, 69949694970000,
+ 73157461710001, 68592191300001, 70747623900000, 78584696930005));
+ }
+
+ urbg.reset();
+ {
+ // Algorithm Cheng 2
+ absl::beta_distribution<double> dist(1.5, 2.5);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return double_to_u64(dist(urbg)); });
+ EXPECT_EQ(54, urbg.invocations());
+ EXPECT_THAT(
+ output, //
+ testing::ElementsAre(
+ 75000029250001, 76751482860001, 53264575220000, 69193133650005,
+ 78028324470013, 91573587560002, 59167523770000, 60658618560002,
+ 80075870540000, 94141320460004, 63196592770003, 78883906300002,
+ 96797992590001, 76907587800001, 56645167560000, 65408302280003,
+ 53401156320001, 64731238570000, 83065573750001, 79788333820001));
+ }
+}
+
+// This is an implementation-specific test. If any part of the implementation
+// changes, then it is likely that this test will change as well. Also, if
+// dependencies of the distribution change, such as RandU64ToDouble, then this
+// is also likely to change.
+TEST(BetaDistributionTest, AlgorithmBounds) {
+ {
+ absl::random_internal::sequence_urbg urbg(
+ {0x7fbe76c8b4395800ull, 0x8000000000000000ull});
+ // u=0.499, v=0.5
+ absl::beta_distribution<double> dist(1e-4, 1e-4);
+ double a = dist(urbg);
+ EXPECT_EQ(a, 2.0202860861567108529e-09);
+ EXPECT_EQ(2, urbg.invocations());
+ }
+
+ // Test that both the float & double algorithms appropriately reject the
+ // initial draw.
+ {
+ // 1/alpha = 1/beta = 2.
+ absl::beta_distribution<float> dist(0.5, 0.5);
+
+ // first two outputs are close to 1.0 - epsilon,
+ // thus: (u ^ 2 + v ^ 2) > 1.0
+ absl::random_internal::sequence_urbg urbg(
+ {0xffff00000006e6c8ull, 0xffff00000007c7c8ull, 0x800003766295CFA9ull,
+ 0x11C819684E734A41ull});
+ {
+ double y = absl::beta_distribution<double>(0.5, 0.5)(urbg);
+ EXPECT_EQ(4, urbg.invocations());
+ EXPECT_EQ(y, 0.9810668952633862) << y;
+ }
+
+ // ...and: log(u) * a ~= log(v) * b ~= -0.02
+ // thus z ~= -0.02 + log(1 + e(~0))
+ // ~= -0.02 + 0.69
+ // thus z > 0
+ urbg.reset();
+ {
+ float x = absl::beta_distribution<float>(0.5, 0.5)(urbg);
+ EXPECT_EQ(4, urbg.invocations());
+ EXPECT_NEAR(0.98106688261032104, x, 0.0000005) << x << "f";
+ }
+ }
+}
+
+} // namespace
diff --git a/absl/random/discrete_distribution.cc b/absl/random/discrete_distribution.cc
new file mode 100644
index 00000000..13a2dbe4
--- /dev/null
+++ b/absl/random/discrete_distribution.cc
@@ -0,0 +1,98 @@
+// 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/discrete_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Initializes the distribution table for Walker's Aliasing algorithm, described
+// in Knuth, Vol 2. as well as in https://en.wikipedia.org/wiki/Alias_method
+std::vector<std::pair<double, size_t>> InitDiscreteDistribution(
+ std::vector<double>* probabilities) {
+ // The empty-case should already be handled by the constructor.
+ assert(probabilities);
+ assert(!probabilities->empty());
+
+ // Step 1. Normalize the input probabilities to 1.0.
+ double sum = std::accumulate(std::begin(*probabilities),
+ std::end(*probabilities), 0.0);
+ if (std::fabs(sum - 1.0) > 1e-6) {
+ // Scale `probabilities` only when the sum is too far from 1.0. Scaling
+ // unconditionally will alter the probabilities slightly.
+ for (double& item : *probabilities) {
+ item = item / sum;
+ }
+ }
+
+ // Step 2. At this point `probabilities` is set to the conditional
+ // probabilities of each element which sum to 1.0, to within reasonable error.
+ // These values are used to construct the proportional probability tables for
+ // the selection phases of Walker's Aliasing algorithm.
+ //
+ // To construct the table, pick an element which is under-full (i.e., an
+ // element for which `(*probabilities)[i] < 1.0/n`), and pair it with an
+ // element which is over-full (i.e., an element for which
+ // `(*probabilities)[i] > 1.0/n`). The smaller value can always be retired.
+ // The larger may still be greater than 1.0/n, or may now be less than 1.0/n,
+ // and put back onto the appropriate collection.
+ const size_t n = probabilities->size();
+ std::vector<std::pair<double, size_t>> q;
+ q.reserve(n);
+
+ std::vector<size_t> over;
+ std::vector<size_t> under;
+ size_t idx = 0;
+ for (const double item : *probabilities) {
+ assert(item >= 0);
+ const double v = item * n;
+ q.emplace_back(v, 0);
+ if (v < 1.0) {
+ under.push_back(idx++);
+ } else {
+ over.push_back(idx++);
+ }
+ }
+ while (!over.empty() && !under.empty()) {
+ auto lo = under.back();
+ under.pop_back();
+ auto hi = over.back();
+ over.pop_back();
+
+ q[lo].second = hi;
+ const double r = q[hi].first - (1.0 - q[lo].first);
+ q[hi].first = r;
+ if (r < 1.0) {
+ under.push_back(hi);
+ } else {
+ over.push_back(hi);
+ }
+ }
+
+ // Due to rounding errors, there may be un-paired elements in either
+ // collection; these should all be values near 1.0. For these values, set `q`
+ // to 1.0 and set the alternate to the identity.
+ for (auto i : over) {
+ q[i] = {1.0, i};
+ }
+ for (auto i : under) {
+ q[i] = {1.0, i};
+ }
+ return q;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/discrete_distribution.h b/absl/random/discrete_distribution.h
new file mode 100644
index 00000000..5866fb23
--- /dev/null
+++ b/absl/random/discrete_distribution.h
@@ -0,0 +1,247 @@
+// 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_DISCRETE_DISTRIBUTION_H_
+#define ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <numeric>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "absl/random/bernoulli_distribution.h"
+#include "absl/random/internal/iostream_state_saver.h"
+#include "absl/random/uniform_int_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::discrete_distribution
+//
+// A discrete distribution produces random integers i, where 0 <= i < n
+// distributed according to the discrete probability function:
+//
+// P(i|p0,...,pn−1)=pi
+//
+// This class is an implementation of discrete_distribution (see
+// [rand.dist.samp.discrete]).
+//
+// The algorithm used is Walker's Aliasing algorithm, described in Knuth, Vol 2.
+// absl::discrete_distribution takes O(N) time to precompute the probabilities
+// (where N is the number of possible outcomes in the distribution) at
+// construction, and then takes O(1) time for each variate generation. Many
+// other implementations also take O(N) time to construct an ordered sequence of
+// partial sums, plus O(log N) time per variate to binary search.
+//
+template <typename IntType = int>
+class discrete_distribution {
+ public:
+ using result_type = IntType;
+
+ class param_type {
+ public:
+ using distribution_type = discrete_distribution;
+
+ param_type() { init(); }
+
+ template <typename InputIterator>
+ explicit param_type(InputIterator begin, InputIterator end)
+ : p_(begin, end) {
+ init();
+ }
+
+ explicit param_type(std::initializer_list<double> weights) : p_(weights) {
+ init();
+ }
+
+ template <class UnaryOperation>
+ explicit param_type(size_t nw, double xmin, double xmax,
+ UnaryOperation fw) {
+ if (nw > 0) {
+ p_.reserve(nw);
+ double delta = (xmax - xmin) / static_cast<double>(nw);
+ assert(delta > 0);
+ double t = delta * 0.5;
+ for (size_t i = 0; i < nw; ++i) {
+ p_.push_back(fw(xmin + i * delta + t));
+ }
+ }
+ init();
+ }
+
+ const std::vector<double>& probabilities() const { return p_; }
+ size_t n() const { return p_.size() - 1; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.probabilities() == b.probabilities();
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class discrete_distribution;
+
+ void init();
+
+ std::vector<double> p_; // normalized probabilities
+ std::vector<std::pair<double, size_t>> q_; // (acceptance, alternate) pairs
+
+ static_assert(std::is_integral<result_type>::value,
+ "Class-template absl::discrete_distribution<> must be "
+ "parameterized using an integral type.");
+ };
+
+ discrete_distribution() : param_() {}
+
+ explicit discrete_distribution(const param_type& p) : param_(p) {}
+
+ template <typename InputIterator>
+ explicit discrete_distribution(InputIterator begin, InputIterator end)
+ : param_(begin, end) {}
+
+ explicit discrete_distribution(std::initializer_list<double> weights)
+ : param_(weights) {}
+
+ template <class UnaryOperation>
+ explicit discrete_distribution(size_t nw, double xmin, double xmax,
+ UnaryOperation fw)
+ : param_(nw, xmin, xmax, std::move(fw)) {}
+
+ void reset() {}
+
+ // generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ const param_type& param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const { return 0; }
+ result_type(max)() const {
+ return static_cast<result_type>(param_.n());
+ } // inclusive
+
+ // NOTE [rand.dist.sample.discrete] returns a std::vector<double> not a
+ // const std::vector<double>&.
+ const std::vector<double>& probabilities() const {
+ return param_.probabilities();
+ }
+
+ friend bool operator==(const discrete_distribution& a,
+ const discrete_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const discrete_distribution& a,
+ const discrete_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+};
+
+// --------------------------------------------------------------------------
+// Implementation details only below
+// --------------------------------------------------------------------------
+
+namespace random_internal {
+
+// Using the vector `*probabilities`, whose values are the weights or
+// probabilities of an element being selected, constructs the proportional
+// probabilities used by the discrete distribution. `*probabilities` will be
+// scaled, if necessary, so that its entries sum to a value sufficiently close
+// to 1.0.
+std::vector<std::pair<double, size_t>> InitDiscreteDistribution(
+ std::vector<double>* probabilities);
+
+} // namespace random_internal
+
+template <typename IntType>
+void discrete_distribution<IntType>::param_type::init() {
+ if (p_.empty()) {
+ p_.push_back(1.0);
+ q_.emplace_back(1.0, 0);
+ } else {
+ assert(n() <= (std::numeric_limits<IntType>::max)());
+ q_ = random_internal::InitDiscreteDistribution(&p_);
+ }
+}
+
+template <typename IntType>
+template <typename URBG>
+typename discrete_distribution<IntType>::result_type
+discrete_distribution<IntType>::operator()(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ const auto idx = absl::uniform_int_distribution<result_type>(0, p.n())(g);
+ const auto& q = p.q_[idx];
+ const bool selected = absl::bernoulli_distribution(q.first)(g);
+ return selected ? idx : static_cast<result_type>(q.second);
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const discrete_distribution<IntType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ const auto& probabilities = x.param().probabilities();
+ os << probabilities.size();
+
+ os.precision(random_internal::stream_precision_helper<double>::kPrecision);
+ for (const auto& p : probabilities) {
+ os << os.fill() << p;
+ }
+ return os;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ discrete_distribution<IntType>& x) { // NOLINT(runtime/references)
+ using param_type = typename discrete_distribution<IntType>::param_type;
+ auto saver = random_internal::make_istream_state_saver(is);
+
+ size_t n;
+ std::vector<double> p;
+
+ is >> n;
+ if (is.fail()) return is;
+ if (n > 0) {
+ p.reserve(n);
+ for (IntType i = 0; i < n && !is.fail(); ++i) {
+ auto tmp = random_internal::read_floating_point<double>(is);
+ if (is.fail()) return is;
+ p.push_back(tmp);
+ }
+ }
+ x.param(param_type(p.begin(), p.end()));
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_DISCRETE_DISTRIBUTION_H_
diff --git a/absl/random/discrete_distribution_test.cc b/absl/random/discrete_distribution_test.cc
new file mode 100644
index 00000000..7296f0ac
--- /dev/null
+++ b/absl/random/discrete_distribution_test.cc
@@ -0,0 +1,246 @@
+// 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/discrete_distribution.h"
+
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <numeric>
+#include <random>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+template <typename IntType>
+class DiscreteDistributionTypeTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<int8_t, uint8_t, int16_t, uint16_t, int32_t,
+ uint32_t, int64_t, uint64_t>;
+TYPED_TEST_SUITE(DiscreteDistributionTypeTest, IntTypes);
+
+TYPED_TEST(DiscreteDistributionTypeTest, ParamSerializeTest) {
+ using param_type =
+ typename absl::discrete_distribution<TypeParam>::param_type;
+
+ absl::discrete_distribution<TypeParam> empty;
+ EXPECT_THAT(empty.probabilities(), testing::ElementsAre(1.0));
+
+ absl::discrete_distribution<TypeParam> before({1.0, 2.0, 1.0});
+
+ // Validate that the probabilities sum to 1.0. We picked values which
+ // can be represented exactly to avoid floating-point roundoff error.
+ double s = 0;
+ for (const auto& x : before.probabilities()) {
+ s += x;
+ }
+ EXPECT_EQ(s, 1.0);
+ EXPECT_THAT(before.probabilities(), testing::ElementsAre(0.25, 0.5, 0.25));
+
+ // Validate the same data via an initializer list.
+ {
+ std::vector<double> data({1.0, 2.0, 1.0});
+
+ absl::discrete_distribution<TypeParam> via_param{
+ param_type(std::begin(data), std::end(data))};
+
+ EXPECT_EQ(via_param, before);
+ }
+
+ std::stringstream ss;
+ ss << before;
+ absl::discrete_distribution<TypeParam> after;
+
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before, after);
+}
+
+TYPED_TEST(DiscreteDistributionTypeTest, Constructor) {
+ auto fn = [](double x) { return x; };
+ {
+ absl::discrete_distribution<int> unary(0, 1.0, 9.0, fn);
+ EXPECT_THAT(unary.probabilities(), testing::ElementsAre(1.0));
+ }
+
+ {
+ absl::discrete_distribution<int> unary(2, 1.0, 9.0, fn);
+ // => fn(1.0 + 0 * 4 + 2) => 3
+ // => fn(1.0 + 1 * 4 + 2) => 7
+ EXPECT_THAT(unary.probabilities(), testing::ElementsAre(0.3, 0.7));
+ }
+}
+
+TEST(DiscreteDistributionTest, InitDiscreteDistribution) {
+ using testing::Pair;
+
+ {
+ std::vector<double> p({1.0, 2.0, 3.0});
+ std::vector<std::pair<double, size_t>> q =
+ absl::random_internal::InitDiscreteDistribution(&p);
+
+ EXPECT_THAT(p, testing::ElementsAre(1 / 6.0, 2 / 6.0, 3 / 6.0));
+
+ // Each bucket is p=1/3, so bucket 0 will send half it's traffic
+ // to bucket 2, while the rest will retain all of their traffic.
+ EXPECT_THAT(q, testing::ElementsAre(Pair(0.5, 2), //
+ Pair(1.0, 1), //
+ Pair(1.0, 2)));
+ }
+
+ {
+ std::vector<double> p({1.0, 2.0, 3.0, 5.0, 2.0});
+
+ std::vector<std::pair<double, size_t>> q =
+ absl::random_internal::InitDiscreteDistribution(&p);
+
+ EXPECT_THAT(p, testing::ElementsAre(1 / 13.0, 2 / 13.0, 3 / 13.0, 5 / 13.0,
+ 2 / 13.0));
+
+ // A more complex bucketing solution: Each bucket has p=0.2
+ // So buckets 0, 1, 4 will send their alternate traffic elsewhere, which
+ // happens to be bucket 3.
+ // However, summing up that alternate traffic gives bucket 3 too much
+ // traffic, so it will send some traffic to bucket 2.
+ constexpr double b0 = 1.0 / 13.0 / 0.2;
+ constexpr double b1 = 2.0 / 13.0 / 0.2;
+ constexpr double b3 = (5.0 / 13.0 / 0.2) - ((1 - b0) + (1 - b1) + (1 - b1));
+
+ EXPECT_THAT(q, testing::ElementsAre(Pair(b0, 3), //
+ Pair(b1, 3), //
+ Pair(1.0, 2), //
+ Pair(b3, 2), //
+ Pair(b1, 3)));
+ }
+}
+
+TEST(DiscreteDistributionTest, ChiSquaredTest50) {
+ using absl::random_internal::kChiSquared;
+
+ constexpr size_t kTrials = 10000;
+ constexpr int kBuckets = 50; // inclusive, so actally +1
+
+ // 1-in-100000 threshold, but remember, there are about 8 tests
+ // in this file. And the test could fail for other reasons.
+ // Empirically validated with --runs_per_test=10000.
+ const int kThreshold =
+ absl::random_internal::ChiSquareValue(kBuckets, 0.99999);
+
+ std::vector<double> weights(kBuckets, 0);
+ std::iota(std::begin(weights), std::end(weights), 1);
+ absl::discrete_distribution<int> dist(std::begin(weights), std::end(weights));
+
+ absl::InsecureBitGen rng;
+
+ std::vector<int32_t> counts(kBuckets, 0);
+ for (size_t i = 0; i < kTrials; i++) {
+ auto x = dist(rng);
+ counts[x]++;
+ }
+
+ // Scale weights.
+ double sum = 0;
+ for (double x : weights) {
+ sum += x;
+ }
+ for (double& x : weights) {
+ x = kTrials * (x / sum);
+ }
+
+ double chi_square =
+ absl::random_internal::ChiSquare(std::begin(counts), std::end(counts),
+ std::begin(weights), std::end(weights));
+
+ if (chi_square > kThreshold) {
+ double p_value =
+ absl::random_internal::ChiSquarePValue(chi_square, kBuckets);
+
+ // Chi-squared test failed. Output does not appear to be uniform.
+ std::string msg;
+ for (size_t i = 0; i < counts.size(); i++) {
+ absl::StrAppend(&msg, i, ": ", counts[i], " vs ", weights[i], "\n");
+ }
+ absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n");
+ absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ",
+ kThreshold);
+ ABSL_RAW_LOG(INFO, "%s", msg.c_str());
+ FAIL() << msg;
+ }
+}
+
+TEST(DiscreteDistributionTest, StabilityTest) {
+ // absl::discrete_distribution stabilitiy relies on
+ // absl::uniform_int_distribution and absl::bernoulli_distribution.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(6);
+
+ {
+ absl::discrete_distribution<int32_t> dist({1.0, 2.0, 3.0, 5.0, 2.0});
+ EXPECT_EQ(0, dist.min());
+ EXPECT_EQ(4, dist.max());
+ for (auto& v : output) {
+ v = dist(urbg);
+ }
+ EXPECT_EQ(12, urbg.invocations());
+ }
+
+ // With 12 calls to urbg, each call into discrete_distribution consumes
+ // precisely 2 values: one for the uniform call, and a second for the
+ // bernoulli.
+ //
+ // Given the alt mapping: 0=>3, 1=>3, 2=>2, 3=>2, 4=>3, we can
+ //
+ // uniform: 443210143131
+ // bernoulli: b0 000011100101
+ // bernoulli: b1 001111101101
+ // bernoulli: b2 111111111111
+ // bernoulli: b3 001111101111
+ // bernoulli: b4 001111101101
+ // ...
+ EXPECT_THAT(output, testing::ElementsAre(3, 3, 1, 3, 3, 3));
+
+ {
+ urbg.reset();
+ absl::discrete_distribution<int64_t> dist({1.0, 2.0, 3.0, 5.0, 2.0});
+ EXPECT_EQ(0, dist.min());
+ EXPECT_EQ(4, dist.max());
+ for (auto& v : output) {
+ v = dist(urbg);
+ }
+ EXPECT_EQ(12, urbg.invocations());
+ }
+ EXPECT_THAT(output, testing::ElementsAre(3, 3, 0, 3, 0, 4));
+}
+
+} // namespace
diff --git a/absl/random/distribution_format_traits.h b/absl/random/distribution_format_traits.h
new file mode 100644
index 00000000..838271c7
--- /dev/null
+++ b/absl/random/distribution_format_traits.h
@@ -0,0 +1,251 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
+#define ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
+
+#include <string>
+#include <tuple>
+#include <typeinfo>
+
+#include "absl/meta/type_traits.h"
+#include "absl/random/bernoulli_distribution.h"
+#include "absl/random/beta_distribution.h"
+#include "absl/random/exponential_distribution.h"
+#include "absl/random/gaussian_distribution.h"
+#include "absl/random/log_uniform_int_distribution.h"
+#include "absl/random/poisson_distribution.h"
+#include "absl/random/uniform_int_distribution.h"
+#include "absl/random/uniform_real_distribution.h"
+#include "absl/random/zipf_distribution.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// ScalarTypeName defines a preferred hierarchy of preferred type names for
+// scalars, and is evaluated at compile time for the specific type
+// specialization.
+template <typename T>
+constexpr const char* ScalarTypeName() {
+ static_assert(std::is_integral<T>() || std::is_floating_point<T>(), "");
+ // clang-format off
+ return
+ std::is_same<T, float>::value ? "float" :
+ std::is_same<T, double>::value ? "double" :
+ std::is_same<T, long double>::value ? "long double" :
+ std::is_same<T, bool>::value ? "bool" :
+ std::is_signed<T>::value && sizeof(T) == 1 ? "int8_t" :
+ std::is_signed<T>::value && sizeof(T) == 2 ? "int16_t" :
+ std::is_signed<T>::value && sizeof(T) == 4 ? "int32_t" :
+ std::is_signed<T>::value && sizeof(T) == 8 ? "int64_t" :
+ std::is_unsigned<T>::value && sizeof(T) == 1 ? "uint8_t" :
+ std::is_unsigned<T>::value && sizeof(T) == 2 ? "uint16_t" :
+ std::is_unsigned<T>::value && sizeof(T) == 4 ? "uint32_t" :
+ std::is_unsigned<T>::value && sizeof(T) == 8 ? "uint64_t" :
+ "undefined";
+ // clang-format on
+
+ // NOTE: It would be nice to use typeid(T).name(), but that's an
+ // implementation-defined attribute which does not necessarily
+ // correspond to a name. We could potentially demangle it
+ // using, e.g. abi::__cxa_demangle.
+}
+
+// Distribution traits used by DistributionCaller and internal implementation
+// details of the mocking framework.
+/*
+struct DistributionFormatTraits {
+ // Returns the parameterized name of the distribution function.
+ static constexpr const char* FunctionName()
+ // Format DistrT parameters.
+ static std::string FormatArgs(DistrT& dist);
+ // Format DistrT::result_type results.
+ static std::string FormatResults(DistrT& dist);
+};
+*/
+template <typename DistrT>
+struct DistributionFormatTraits;
+
+template <typename R>
+struct DistributionFormatTraits<absl::uniform_int_distribution<R>> {
+ using distribution_t = absl::uniform_int_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Uniform"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat("absl::IntervalClosedClosed, ", (d.min)(), ", ",
+ (d.max)());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::uniform_real_distribution<R>> {
+ using distribution_t = absl::uniform_real_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Uniform"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat((d.min)(), ", ", (d.max)());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::exponential_distribution<R>> {
+ using distribution_t = absl::exponential_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Exponential"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat(d.lambda());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::poisson_distribution<R>> {
+ using distribution_t = absl::poisson_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Poisson"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat(d.mean());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <>
+struct DistributionFormatTraits<absl::bernoulli_distribution> {
+ using distribution_t = absl::bernoulli_distribution;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Bernoulli"; }
+
+ static constexpr const char* FunctionName() { return Name(); }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat(d.p());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::beta_distribution<R>> {
+ using distribution_t = absl::beta_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Beta"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat(d.alpha(), ", ", d.beta());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::zipf_distribution<R>> {
+ using distribution_t = absl::zipf_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Zipf"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrCat(d.k(), ", ", d.v(), ", ", d.q());
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::gaussian_distribution<R>> {
+ using distribution_t = absl::gaussian_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "Gaussian"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrJoin(std::make_tuple(d.mean(), d.stddev()), ", ");
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+template <typename R>
+struct DistributionFormatTraits<absl::log_uniform_int_distribution<R>> {
+ using distribution_t = absl::log_uniform_int_distribution<R>;
+ using result_t = typename distribution_t::result_type;
+
+ static constexpr const char* Name() { return "LogUniform"; }
+
+ static std::string FunctionName() {
+ return absl::StrCat(Name(), "<", ScalarTypeName<R>(), ">");
+ }
+ static std::string FormatArgs(const distribution_t& d) {
+ return absl::StrJoin(std::make_tuple((d.min)(), (d.max)(), d.base()), ", ");
+ }
+ static std::string FormatResults(absl::Span<const result_t> results) {
+ return absl::StrJoin(results, ", ");
+ }
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_DISTRIBUTION_FORMAT_TRAITS_H_
diff --git a/absl/random/distributions.h b/absl/random/distributions.h
new file mode 100644
index 00000000..f2ebfc2d
--- /dev/null
+++ b/absl/random/distributions.h
@@ -0,0 +1,444 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: distributions.h
+// -----------------------------------------------------------------------------
+//
+// This header defines functions representing distributions, which you use in
+// combination with an Abseil random bit generator to produce random values
+// according to the rules of that distribution.
+//
+// The Abseil random library defines the following distributions within this
+// file:
+//
+// * `absl::Uniform` for uniform (constant) distributions having constant
+// probability
+// * `absl::Bernoulli` for discrete distributions having exactly two outcomes
+// * `absl::Beta` for continuous distributions parameterized through two
+// free parameters
+// * `absl::Exponential` for discrete distributions of events occurring
+// continuously and independently at a constant average rate
+// * `absl::Gaussian` (also known as "normal distributions") for continuous
+// distributions using an associated quadratic function
+// * `absl::LogUniform` for continuous uniform distributions where the log
+// to the given base of all values is uniform
+// * `absl::Poisson` for discrete probability distributions that express the
+// probability of a given number of events occurring within a fixed interval
+// * `absl::Zipf` for discrete probability distributions commonly used for
+// modelling of rare events
+//
+// Prefer use of these distribution function classes over manual construction of
+// your own distribution classes, as it allows library maintainers greater
+// flexibility to change the underlying implementation in the future.
+
+#ifndef ABSL_RANDOM_DISTRIBUTIONS_H_
+#define ABSL_RANDOM_DISTRIBUTIONS_H_
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <random>
+#include <type_traits>
+
+#include "absl/base/internal/inline_variable.h"
+#include "absl/random/bernoulli_distribution.h"
+#include "absl/random/beta_distribution.h"
+#include "absl/random/distribution_format_traits.h"
+#include "absl/random/exponential_distribution.h"
+#include "absl/random/gaussian_distribution.h"
+#include "absl/random/internal/distributions.h" // IWYU pragma: export
+#include "absl/random/internal/uniform_helper.h" // IWYU pragma: export
+#include "absl/random/log_uniform_int_distribution.h"
+#include "absl/random/poisson_distribution.h"
+#include "absl/random/uniform_int_distribution.h"
+#include "absl/random/uniform_real_distribution.h"
+#include "absl/random/zipf_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalClosedClosedT,
+ IntervalClosedClosed, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalClosedClosedT,
+ IntervalClosed, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalClosedOpenT,
+ IntervalClosedOpen, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalOpenOpenT,
+ IntervalOpenOpen, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalOpenOpenT,
+ IntervalOpen, {});
+ABSL_INTERNAL_INLINE_CONSTEXPR(random_internal::IntervalOpenClosedT,
+ IntervalOpenClosed, {});
+
+// -----------------------------------------------------------------------------
+// absl::Uniform<T>(tag, bitgen, lo, hi)
+// -----------------------------------------------------------------------------
+//
+// `absl::Uniform()` produces random values of type `T` uniformly distributed in
+// a defined interval {lo, hi}. The interval `tag` defines the type of interval
+// which should be one of the following possible values:
+//
+// * `absl::IntervalOpenOpen`
+// * `absl::IntervalOpenClosed`
+// * `absl::IntervalClosedOpen`
+// * `absl::IntervalClosedClosed`
+//
+// where "open" refers to an exclusive value (excluded) from the output, while
+// "closed" refers to an inclusive value (included) from the output.
+//
+// In the absence of an explicit return type `T`, `absl::Uniform()` will deduce
+// the return type based on the provided endpoint arguments {A lo, B hi}.
+// Given these endpoints, one of {A, B} will be chosen as the return type, if
+// a type can be implicitly converted into the other in a lossless way. The
+// lack of any such implcit conversion between {A, B} will produce a
+// compile-time error
+//
+// See https://en.wikipedia.org/wiki/Uniform_distribution_(continuous)
+//
+// Example:
+//
+// absl::BitGen bitgen;
+//
+// // Produce a random float value between 0.0 and 1.0, inclusive
+// auto x = absl::Uniform(absl::IntervalClosedClosed, bitgen, 0.0f, 1.0f);
+//
+// // The most common interval of `absl::IntervalClosedOpen` is available by
+// // default:
+//
+// auto x = absl::Uniform(bitgen, 0.0f, 1.0f);
+//
+// // Return-types are typically inferred from the arguments, however callers
+// // can optionally provide an explicit return-type to the template.
+//
+// auto x = absl::Uniform<float>(bitgen, 0, 1);
+//
+template <typename R = void, typename TagType, typename URBG>
+typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
+Uniform(TagType tag,
+ URBG&& urbg, // NOLINT(runtime/references)
+ R lo, R hi) {
+ using gen_t = absl::decay_t<URBG>;
+ return random_internal::UniformImpl<R, TagType, gen_t>(tag, urbg, lo, hi);
+}
+
+// absl::Uniform<T>(bitgen, lo, hi)
+//
+// Overload of `Uniform()` using the default closed-open interval of [lo, hi),
+// and returning values of type `T`
+template <typename R = void, typename URBG>
+typename absl::enable_if_t<!std::is_same<R, void>::value, R> //
+Uniform(URBG&& urbg, // NOLINT(runtime/references)
+ R lo, R hi) {
+ constexpr auto tag = absl::IntervalClosedOpen;
+ using tag_t = decltype(tag);
+ using gen_t = absl::decay_t<URBG>;
+
+ return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+}
+
+// absl::Uniform(tag, bitgen, lo, hi)
+//
+// Overload of `Uniform()` using different (but compatible) lo, hi types. Note
+// that a compile-error will result if the return type cannot be deduced
+// correctly from the passed types.
+template <typename R = void, typename TagType, typename URBG, typename A,
+ typename B>
+typename absl::enable_if_t<std::is_same<R, void>::value,
+ random_internal::uniform_inferred_return_t<A, B>>
+Uniform(TagType tag,
+ URBG&& urbg, // NOLINT(runtime/references)
+ A lo, B hi) {
+ using gen_t = absl::decay_t<URBG>;
+ using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+
+ return random_internal::UniformImpl<return_t, TagType, gen_t>(tag, urbg, lo,
+ hi);
+}
+
+// absl::Uniform(bitgen, lo, hi)
+//
+// Overload of `Uniform()` using different (but compatible) lo, hi types and the
+// default closed-open interval of [lo, hi). Note that a compile-error will
+// result if the return type cannot be deduced correctly from the passed types.
+template <typename R = void, typename URBG, typename A, typename B>
+typename absl::enable_if_t<std::is_same<R, void>::value,
+ random_internal::uniform_inferred_return_t<A, B>>
+Uniform(URBG&& urbg, // NOLINT(runtime/references)
+ A lo, B hi) {
+ constexpr auto tag = absl::IntervalClosedOpen;
+ using tag_t = decltype(tag);
+ using gen_t = absl::decay_t<URBG>;
+ using return_t = typename random_internal::uniform_inferred_return_t<A, B>;
+
+ return random_internal::UniformImpl<return_t, tag_t, gen_t>(tag, urbg, lo,
+ hi);
+}
+
+// absl::Uniform<unsigned T>(bitgen)
+//
+// Overload of Uniform() using the minimum and maximum values of a given type
+// `T` (which must be unsigned), returning a value of type `unsigned T`
+template <typename R, typename URBG>
+typename absl::enable_if_t<!std::is_signed<R>::value, R> //
+Uniform(URBG&& urbg) { // NOLINT(runtime/references)
+ constexpr auto tag = absl::IntervalClosedClosed;
+ constexpr auto lo = std::numeric_limits<R>::lowest();
+ constexpr auto hi = (std::numeric_limits<R>::max)();
+ using tag_t = decltype(tag);
+ using gen_t = absl::decay_t<URBG>;
+
+ return random_internal::UniformImpl<R, tag_t, gen_t>(tag, urbg, lo, hi);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Bernoulli(bitgen, p)
+// -----------------------------------------------------------------------------
+//
+// `absl::Bernoulli` produces a random boolean value, with probability `p`
+// (where 0.0 <= p <= 1.0) equaling `true`.
+//
+// Prefer `absl::Bernoulli` to produce boolean values over other alternatives
+// such as comparing an `absl::Uniform()` value to a specific output.
+//
+// See https://en.wikipedia.org/wiki/Bernoulli_distribution
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// if (absl::Bernoulli(bitgen, 1.0/3721.0)) {
+// std::cout << "Asteroid field navigation successful.";
+// }
+//
+template <typename URBG>
+bool Bernoulli(URBG&& urbg, // NOLINT(runtime/references)
+ double p) {
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = absl::bernoulli_distribution;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, p);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Beta<T>(bitgen, alpha, beta)
+// -----------------------------------------------------------------------------
+//
+// `absl::Beta` produces a floating point number distributed in the closed
+// interval [0,1] and parameterized by two values `alpha` and `beta` as per a
+// Beta distribution. `T` must be a floating point type, but may be inferred
+// from the types of `alpha` and `beta`.
+//
+// See https://en.wikipedia.org/wiki/Beta_distribution.
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// double sample = absl::Beta(bitgen, 3.0, 2.0);
+//
+template <typename RealType, typename URBG>
+RealType Beta(URBG&& urbg, // NOLINT(runtime/references)
+ RealType alpha, RealType beta) {
+ static_assert(
+ std::is_floating_point<RealType>::value,
+ "Template-argument 'RealType' must be a floating-point type, in "
+ "absl::Beta<RealType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::beta_distribution<RealType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, alpha, beta);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Exponential<T>(bitgen, lambda = 1)
+// -----------------------------------------------------------------------------
+//
+// `absl::Exponential` produces a floating point number for discrete
+// distributions of events occurring continuously and independently at a
+// constant average rate. `T` must be a floating point type, but may be inferred
+// from the type of `lambda`.
+//
+// See https://en.wikipedia.org/wiki/Exponential_distribution.
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// double call_length = absl::Exponential(bitgen, 7.0);
+//
+template <typename RealType, typename URBG>
+RealType Exponential(URBG&& urbg, // NOLINT(runtime/references)
+ RealType lambda = 1) {
+ static_assert(
+ std::is_floating_point<RealType>::value,
+ "Template-argument 'RealType' must be a floating-point type, in "
+ "absl::Exponential<RealType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::exponential_distribution<RealType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, lambda);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Gaussian<T>(bitgen, mean = 0, stddev = 1)
+// -----------------------------------------------------------------------------
+//
+// `absl::Gaussian` produces a floating point number selected from the Gaussian
+// (ie. "Normal") distribution. `T` must be a floating point type, but may be
+// inferred from the types of `mean` and `stddev`.
+//
+// See https://en.wikipedia.org/wiki/Normal_distribution
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// double giraffe_height = absl::Gaussian(bitgen, 16.3, 3.3);
+//
+template <typename RealType, typename URBG>
+RealType Gaussian(URBG&& urbg, // NOLINT(runtime/references)
+ RealType mean = 0, RealType stddev = 1) {
+ static_assert(
+ std::is_floating_point<RealType>::value,
+ "Template-argument 'RealType' must be a floating-point type, in "
+ "absl::Gaussian<RealType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::gaussian_distribution<RealType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, mean, stddev);
+}
+
+// -----------------------------------------------------------------------------
+// absl::LogUniform<T>(bitgen, lo, hi, base = 2)
+// -----------------------------------------------------------------------------
+//
+// `absl::LogUniform` produces random values distributed where the log to a
+// given base of all values is uniform in a closed interval [lo, hi]. `T` must
+// be an integral type, but may be inferred from the types of `lo` and `hi`.
+//
+// I.e., `LogUniform(0, n, b)` is uniformly distributed across buckets
+// [0], [1, b-1], [b, b^2-1] .. [b^(k-1), (b^k)-1] .. [b^floor(log(n, b)), n]
+// and is uniformly distributed within each bucket.
+//
+// The resulting probability density is inversely related to bucket size, though
+// values in the final bucket may be more likely than previous values. (In the
+// extreme case where n = b^i the final value will be tied with zero as the most
+// probable result.
+//
+// If `lo` is nonzero then this distribution is shifted to the desired interval,
+// so LogUniform(lo, hi, b) is equivalent to LogUniform(0, hi-lo, b)+lo.
+//
+// See http://ecolego.facilia.se/ecolego/show/Log-Uniform%20Distribution
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// int v = absl::LogUniform(bitgen, 0, 1000);
+//
+template <typename IntType, typename URBG>
+IntType LogUniform(URBG&& urbg, // NOLINT(runtime/references)
+ IntType lo, IntType hi, IntType base = 2) {
+ static_assert(std::is_integral<IntType>::value,
+ "Template-argument 'IntType' must be an integral type, in "
+ "absl::LogUniform<IntType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::log_uniform_int_distribution<IntType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, lo, hi, base);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Poisson<T>(bitgen, mean = 1)
+// -----------------------------------------------------------------------------
+//
+// `absl::Poisson` produces discrete probabilities for a given number of events
+// occurring within a fixed interval within the closed interval [0, max]. `T`
+// must be an integral type.
+//
+// See https://en.wikipedia.org/wiki/Poisson_distribution
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// int requests_per_minute = absl::Poisson<int>(bitgen, 3.2);
+//
+template <typename IntType, typename URBG>
+IntType Poisson(URBG&& urbg, // NOLINT(runtime/references)
+ double mean = 1.0) {
+ static_assert(std::is_integral<IntType>::value,
+ "Template-argument 'IntType' must be an integral type, in "
+ "absl::Poisson<IntType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::poisson_distribution<IntType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, mean);
+}
+
+// -----------------------------------------------------------------------------
+// absl::Zipf<T>(bitgen, hi = max, q = 2, v = 1)
+// -----------------------------------------------------------------------------
+//
+// `absl::Zipf` produces discrete probabilities commonly used for modelling of
+// rare events over the closed interval [0, hi]. The parameters `v` and `q`
+// determine the skew of the distribution. `T` must be an integral type, but
+// may be inferred from the type of `hi`.
+//
+// See http://mathworld.wolfram.com/ZipfDistribution.html
+//
+// Example:
+//
+// absl::BitGen bitgen;
+// ...
+// int term_rank = absl::Zipf<int>(bitgen);
+//
+template <typename IntType, typename URBG>
+IntType Zipf(URBG&& urbg, // NOLINT(runtime/references)
+ IntType hi = (std::numeric_limits<IntType>::max)(), double q = 2.0,
+ double v = 1.0) {
+ static_assert(std::is_integral<IntType>::value,
+ "Template-argument 'IntType' must be an integral type, in "
+ "absl::Zipf<IntType, URBG>(...)");
+
+ using gen_t = absl::decay_t<URBG>;
+ using distribution_t = typename absl::zipf_distribution<IntType>;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ return random_internal::DistributionCaller<gen_t>::template Call<
+ distribution_t, format_t>(&urbg, hi, q, v);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_DISTRIBUTIONS_H_
diff --git a/absl/random/distributions_test.cc b/absl/random/distributions_test.cc
new file mode 100644
index 00000000..eb82868d
--- /dev/null
+++ b/absl/random/distributions_test.cc
@@ -0,0 +1,494 @@
+// 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/distributions.h"
+
+#include <cmath>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/random.h"
+
+namespace {
+
+constexpr int kSize = 400000;
+
+class RandomDistributionsTest : public testing::Test {};
+
+TEST_F(RandomDistributionsTest, UniformBoundFunctions) {
+ using absl::IntervalClosedClosed;
+ using absl::IntervalClosedOpen;
+ using absl::IntervalOpenClosed;
+ using absl::IntervalOpenOpen;
+ using absl::random_internal::uniform_lower_bound;
+ using absl::random_internal::uniform_upper_bound;
+
+ // absl::uniform_int_distribution natively assumes IntervalClosedClosed
+ // absl::uniform_real_distribution natively assumes IntervalClosedOpen
+
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, 0, 100), 1);
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, 0, 100), 1);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, 0, 1.0), 0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, 0, 1.0), 0);
+
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, 0, 100), 0);
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, 0, 100), 0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, 0, 1.0), 0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, 0, 1.0), 0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, 0, 100), 99);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, 0, 100), 99);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, 0, 1.0), 1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, 0, 1.0), 1.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, 0, 100), 100);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0, 100), 100);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, 0, 1.0), 1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, 0, 1.0), 1.0);
+
+ // Negative value tests
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, -100, -1), -99);
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenOpen, -100, -1), -99);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<float>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenClosed, -2.0, -1.0), -2.0);
+ EXPECT_GT(uniform_lower_bound<double>(IntervalOpenOpen, -2.0, -1.0), -2.0);
+
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedClosed, -100, -1), -100);
+ EXPECT_EQ(uniform_lower_bound(IntervalClosedOpen, -100, -1), -100);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedClosed, -2.0, -1.0), -2.0);
+ EXPECT_EQ(uniform_lower_bound<float>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+ -2.0);
+ EXPECT_EQ(uniform_lower_bound<double>(IntervalClosedOpen, -2.0, -1.0), -2.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenOpen, -100, -1), -2);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedOpen, -100, -1), -2);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<float>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalOpenOpen, -2.0, -1.0), -1.0);
+ EXPECT_EQ(uniform_upper_bound<double>(IntervalClosedOpen, -2.0, -1.0), -1.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalOpenClosed, -100, -1), -1);
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, -100, -1), -1);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<float>(IntervalClosedClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalOpenClosed, -2.0, -1.0), -1.0);
+ EXPECT_GT(uniform_upper_bound<double>(IntervalClosedClosed, -2.0, -1.0),
+ -1.0);
+
+ // Edge cases: the next value toward itself is itself.
+ const double d = 1.0;
+ const float f = 1.0;
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, d, d), d);
+ EXPECT_EQ(uniform_lower_bound(IntervalOpenClosed, f, f), f);
+
+ EXPECT_GT(uniform_lower_bound(IntervalOpenClosed, 1.0, 2.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, +0.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -0.0), 1.0);
+ EXPECT_LT(uniform_lower_bound(IntervalOpenClosed, 1.0, -1.0), 1.0);
+
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0f,
+ std::numeric_limits<float>::max()),
+ std::numeric_limits<float>::max());
+ EXPECT_EQ(uniform_upper_bound(IntervalClosedClosed, 0.0,
+ std::numeric_limits<double>::max()),
+ std::numeric_limits<double>::max());
+}
+
+struct Invalid {};
+
+template <typename A, typename B>
+auto InferredUniformReturnT(int)
+ -> decltype(absl::Uniform(std::declval<absl::InsecureBitGen&>(),
+ std::declval<A>(), std::declval<B>()));
+
+template <typename, typename>
+Invalid InferredUniformReturnT(...);
+
+template <typename TagType, typename A, typename B>
+auto InferredTaggedUniformReturnT(int)
+ -> decltype(absl::Uniform(std::declval<TagType>(),
+ std::declval<absl::InsecureBitGen&>(),
+ std::declval<A>(), std::declval<B>()));
+
+template <typename, typename, typename>
+Invalid InferredTaggedUniformReturnT(...);
+
+// Given types <A, B, Expect>, CheckArgsInferType() verifies that
+//
+// absl::Uniform(gen, A{}, B{})
+//
+// returns the type "Expect".
+//
+// This interface can also be used to assert that a given absl::Uniform()
+// overload does not exist / will not compile. Given types <A, B>, the
+// expression
+//
+// decltype(absl::Uniform(..., std::declval<A>(), std::declval<B>()))
+//
+// will not compile, leaving the definition of InferredUniformReturnT<A, B> to
+// resolve (via SFINAE) to the overload which returns type "Invalid". This
+// allows tests to assert that an invocation such as
+//
+// absl::Uniform(gen, 1.23f, std::numeric_limits<int>::max() - 1)
+//
+// should not compile, since neither type, float nor int, can precisely
+// represent both endpoint-values. Writing:
+//
+// CheckArgsInferType<float, int, Invalid>()
+//
+// will assert that this overload does not exist.
+template <typename A, typename B, typename Expect>
+void CheckArgsInferType() {
+ static_assert(
+ absl::conjunction<
+ std::is_same<Expect, decltype(InferredUniformReturnT<A, B>(0))>,
+ std::is_same<Expect,
+ decltype(InferredUniformReturnT<B, A>(0))>>::value,
+ "");
+ static_assert(
+ absl::conjunction<
+ std::is_same<Expect,
+ decltype(InferredTaggedUniformReturnT<
+ absl::random_internal::IntervalOpenOpenT, A, B>(
+ 0))>,
+ std::is_same<Expect,
+ decltype(InferredTaggedUniformReturnT<
+ absl::random_internal::IntervalOpenOpenT, B, A>(
+ 0))>>::value,
+ "");
+}
+
+template <typename A, typename B, typename ExplicitRet>
+auto ExplicitUniformReturnT(int) -> decltype(
+ absl::Uniform<ExplicitRet>(*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>()));
+
+template <typename, typename, typename, typename ExplicitRet>
+Invalid ExplicitTaggedUniformReturnT(...);
+
+// Given types <A, B, Expect>, CheckArgsReturnExpectedType() verifies that
+//
+// absl::Uniform<Expect>(gen, A{}, B{})
+//
+// returns the type "Expect", and that the function-overload has the signature
+//
+// Expect(URBG&, Expect, Expect)
+template <typename A, typename B, typename Expect>
+void CheckArgsReturnExpectedType() {
+ static_assert(
+ absl::conjunction<
+ std::is_same<Expect,
+ decltype(ExplicitUniformReturnT<A, B, Expect>(0))>,
+ std::is_same<Expect, decltype(ExplicitUniformReturnT<B, A, Expect>(
+ 0))>>::value,
+ "");
+ static_assert(
+ absl::conjunction<
+ std::is_same<Expect,
+ decltype(ExplicitTaggedUniformReturnT<
+ absl::random_internal::IntervalOpenOpenT, A, B,
+ Expect>(0))>,
+ std::is_same<Expect,
+ decltype(ExplicitTaggedUniformReturnT<
+ absl::random_internal::IntervalOpenOpenT, B, A,
+ Expect>(0))>>::value,
+ "");
+}
+
+TEST_F(RandomDistributionsTest, UniformTypeInference) {
+ // Infers common types.
+ CheckArgsInferType<uint16_t, uint16_t, uint16_t>();
+ CheckArgsInferType<uint32_t, uint32_t, uint32_t>();
+ CheckArgsInferType<uint64_t, uint64_t, uint64_t>();
+ CheckArgsInferType<int16_t, int16_t, int16_t>();
+ CheckArgsInferType<int32_t, int32_t, int32_t>();
+ CheckArgsInferType<int64_t, int64_t, int64_t>();
+ CheckArgsInferType<float, float, float>();
+ CheckArgsInferType<double, double, double>();
+
+ // Explicitly-specified return-values override inferences.
+ CheckArgsReturnExpectedType<int16_t, int16_t, int32_t>();
+ CheckArgsReturnExpectedType<uint16_t, uint16_t, int32_t>();
+ CheckArgsReturnExpectedType<int16_t, int16_t, int64_t>();
+ CheckArgsReturnExpectedType<int16_t, int32_t, int64_t>();
+ CheckArgsReturnExpectedType<int16_t, int32_t, double>();
+ CheckArgsReturnExpectedType<float, float, double>();
+ CheckArgsReturnExpectedType<int, int, int16_t>();
+
+ // Properly promotes uint16_t.
+ CheckArgsInferType<uint16_t, uint32_t, uint32_t>();
+ CheckArgsInferType<uint16_t, uint64_t, uint64_t>();
+ CheckArgsInferType<uint16_t, int32_t, int32_t>();
+ CheckArgsInferType<uint16_t, int64_t, int64_t>();
+ CheckArgsInferType<uint16_t, float, float>();
+ CheckArgsInferType<uint16_t, double, double>();
+
+ // Properly promotes int16_t.
+ CheckArgsInferType<int16_t, int32_t, int32_t>();
+ CheckArgsInferType<int16_t, int64_t, int64_t>();
+ CheckArgsInferType<int16_t, float, float>();
+ CheckArgsInferType<int16_t, double, double>();
+
+ // Invalid (u)int16_t-pairings do not compile.
+ // See "CheckArgsInferType" comments above, for how this is achieved.
+ CheckArgsInferType<uint16_t, int16_t, Invalid>();
+ CheckArgsInferType<int16_t, uint32_t, Invalid>();
+ CheckArgsInferType<int16_t, uint64_t, Invalid>();
+
+ // Properly promotes uint32_t.
+ CheckArgsInferType<uint32_t, uint64_t, uint64_t>();
+ CheckArgsInferType<uint32_t, int64_t, int64_t>();
+ CheckArgsInferType<uint32_t, double, double>();
+
+ // Properly promotes int32_t.
+ CheckArgsInferType<int32_t, int64_t, int64_t>();
+ CheckArgsInferType<int32_t, double, double>();
+
+ // Invalid (u)int32_t-pairings do not compile.
+ CheckArgsInferType<uint32_t, int32_t, Invalid>();
+ CheckArgsInferType<int32_t, uint64_t, Invalid>();
+ CheckArgsInferType<int32_t, float, Invalid>();
+ CheckArgsInferType<uint32_t, float, Invalid>();
+
+ // Invalid (u)int64_t-pairings do not compile.
+ CheckArgsInferType<uint64_t, int64_t, Invalid>();
+ CheckArgsInferType<int64_t, float, Invalid>();
+ CheckArgsInferType<int64_t, double, Invalid>();
+
+ // Properly promotes float.
+ CheckArgsInferType<float, double, double>();
+
+ // Examples.
+ absl::InsecureBitGen gen;
+ EXPECT_NE(1, absl::Uniform(gen, static_cast<uint16_t>(0), 1.0f));
+ EXPECT_NE(1, absl::Uniform(gen, 0, 1.0));
+ EXPECT_NE(1, absl::Uniform(absl::IntervalOpenOpen, gen,
+ static_cast<uint16_t>(0), 1.0f));
+ EXPECT_NE(1, absl::Uniform(absl::IntervalOpenOpen, gen, 0, 1.0));
+ EXPECT_NE(1, absl::Uniform(absl::IntervalOpenOpen, gen, -1, 1.0));
+ EXPECT_NE(1, absl::Uniform<double>(absl::IntervalOpenOpen, gen, -1, 1));
+ EXPECT_NE(1, absl::Uniform<float>(absl::IntervalOpenOpen, gen, 0, 1));
+ EXPECT_NE(1, absl::Uniform<float>(gen, 0, 1));
+}
+
+TEST_F(RandomDistributionsTest, UniformNoBounds) {
+ absl::InsecureBitGen gen;
+
+ absl::Uniform<uint8_t>(gen);
+ absl::Uniform<uint16_t>(gen);
+ absl::Uniform<uint32_t>(gen);
+ absl::Uniform<uint64_t>(gen);
+}
+
+// TODO(lar): Validate properties of non-default interval-semantics.
+TEST_F(RandomDistributionsTest, UniformReal) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Uniform(gen, 0, 1.0);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(0.5, moments.mean, 0.02);
+ EXPECT_NEAR(1 / 12.0, moments.variance, 0.02);
+ EXPECT_NEAR(0.0, moments.skewness, 0.02);
+ EXPECT_NEAR(9 / 5.0, moments.kurtosis, 0.02);
+}
+
+TEST_F(RandomDistributionsTest, UniformInt) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ const int64_t kMax = 1000000000000ll;
+ int64_t j = absl::Uniform(absl::IntervalClosedClosed, gen, 0, kMax);
+ // convert to double.
+ values[i] = static_cast<double>(j) / static_cast<double>(kMax);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(0.5, moments.mean, 0.02);
+ EXPECT_NEAR(1 / 12.0, moments.variance, 0.02);
+ EXPECT_NEAR(0.0, moments.skewness, 0.02);
+ EXPECT_NEAR(9 / 5.0, moments.kurtosis, 0.02);
+
+ /*
+ // NOTE: These are not supported by absl::Uniform, which is specialized
+ // on integer and real valued types.
+
+ enum E { E0, E1 }; // enum
+ enum S : int { S0, S1 }; // signed enum
+ enum U : unsigned int { U0, U1 }; // unsigned enum
+
+ absl::Uniform(gen, E0, E1);
+ absl::Uniform(gen, S0, S1);
+ absl::Uniform(gen, U0, U1);
+ */
+}
+
+TEST_F(RandomDistributionsTest, Exponential) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Exponential<double>(gen);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(1.0, moments.mean, 0.02);
+ EXPECT_NEAR(1.0, moments.variance, 0.025);
+ EXPECT_NEAR(2.0, moments.skewness, 0.1);
+ EXPECT_LT(5.0, moments.kurtosis);
+}
+
+TEST_F(RandomDistributionsTest, PoissonDefault) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Poisson<int64_t>(gen);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(1.0, moments.mean, 0.02);
+ EXPECT_NEAR(1.0, moments.variance, 0.02);
+ EXPECT_NEAR(1.0, moments.skewness, 0.025);
+ EXPECT_LT(2.0, moments.kurtosis);
+}
+
+TEST_F(RandomDistributionsTest, PoissonLarge) {
+ constexpr double kMean = 100000000.0;
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Poisson<int64_t>(gen, kMean);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(kMean, moments.mean, kMean * 0.015);
+ EXPECT_NEAR(kMean, moments.variance, kMean * 0.015);
+ EXPECT_NEAR(std::sqrt(kMean), moments.skewness, kMean * 0.02);
+ EXPECT_LT(2.0, moments.kurtosis);
+}
+
+TEST_F(RandomDistributionsTest, Bernoulli) {
+ constexpr double kP = 0.5151515151;
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Bernoulli(gen, kP);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(kP, moments.mean, 0.01);
+}
+
+TEST_F(RandomDistributionsTest, Beta) {
+ constexpr double kAlpha = 2.0;
+ constexpr double kBeta = 3.0;
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Beta(gen, kAlpha, kBeta);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(0.4, moments.mean, 0.01);
+}
+
+TEST_F(RandomDistributionsTest, Zipf) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Zipf<int64_t>(gen, 100);
+ }
+
+ // The mean of a zipf distribution is: H(N, s-1) / H(N,s).
+ // Given the parameter v = 1, this gives the following function:
+ // (Hn(100, 1) - Hn(1,1)) / (Hn(100,2) - Hn(1,2)) = 6.5944
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(6.5944, moments.mean, 2000) << moments;
+}
+
+TEST_F(RandomDistributionsTest, Gaussian) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::Gaussian<double>(gen);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(0.0, moments.mean, 0.02);
+ EXPECT_NEAR(1.0, moments.variance, 0.04);
+ EXPECT_NEAR(0, moments.skewness, 0.2);
+ EXPECT_NEAR(3.0, moments.kurtosis, 0.5);
+}
+
+TEST_F(RandomDistributionsTest, LogUniform) {
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen gen;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = absl::LogUniform<int64_t>(gen, 0, (1 << 10) - 1);
+ }
+
+ // The mean is the sum of the fractional means of the uniform distributions:
+ // [0..0][1..1][2..3][4..7][8..15][16..31][32..63]
+ // [64..127][128..255][256..511][512..1023]
+ const double mean = (0 + 1 + 1 + 2 + 3 + 4 + 7 + 8 + 15 + 16 + 31 + 32 + 63 +
+ 64 + 127 + 128 + 255 + 256 + 511 + 512 + 1023) /
+ (2.0 * 11.0);
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(mean, moments.mean, 2) << moments;
+}
+
+} // namespace
diff --git a/absl/random/examples_test.cc b/absl/random/examples_test.cc
new file mode 100644
index 00000000..1dcb5146
--- /dev/null
+++ b/absl/random/examples_test.cc
@@ -0,0 +1,99 @@
+// 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 <cinttypes>
+#include <random>
+#include <sstream>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/random/random.h"
+
+template <typename T>
+void Use(T) {}
+
+TEST(Examples, Basic) {
+ absl::BitGen gen;
+ std::vector<int> objs = {10, 20, 30, 40, 50};
+
+ // Choose an element from a set.
+ auto elem = objs[absl::Uniform(gen, 0u, objs.size())];
+ Use(elem);
+
+ // Generate a uniform value between 1 and 6.
+ auto dice_roll = absl::Uniform<int>(absl::IntervalClosedClosed, gen, 1, 6);
+ Use(dice_roll);
+
+ // Generate a random byte.
+ auto byte = absl::Uniform<uint8_t>(gen);
+ Use(byte);
+
+ // Generate a fractional value from [0f, 1f).
+ auto fraction = absl::Uniform<float>(gen, 0, 1);
+ Use(fraction);
+
+ // Toss a fair coin; 50/50 probability.
+ bool coin_toss = absl::Bernoulli(gen, 0.5);
+ Use(coin_toss);
+
+ // Select a file size between 1k and 10MB, biased towards smaller file sizes.
+ auto file_size = absl::LogUniform<size_t>(gen, 1000, 10 * 1000 * 1000);
+ Use(file_size);
+
+ // Randomize (shuffle) a collection.
+ std::shuffle(std::begin(objs), std::end(objs), gen);
+}
+
+TEST(Examples, CreateingCorrelatedVariateSequences) {
+ // Unexpected PRNG correlation is often a source of bugs,
+ // so when using absl::BitGen it must be an intentional choice.
+ // NOTE: All of these only exhibit process-level stability.
+
+ // Create a correlated sequence from system entropy.
+ {
+ auto my_seed = absl::MakeSeedSeq();
+
+ absl::BitGen gen_1(my_seed);
+ absl::BitGen gen_2(my_seed); // Produces same variates as gen_1.
+
+ EXPECT_EQ(absl::Bernoulli(gen_1, 0.5), absl::Bernoulli(gen_2, 0.5));
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen_1), absl::Uniform<uint32_t>(gen_2));
+ }
+
+ // Create a correlated sequence from an existing URBG.
+ {
+ absl::BitGen gen;
+
+ auto my_seed = absl::CreateSeedSeqFrom(&gen);
+ absl::BitGen gen_1(my_seed);
+ absl::BitGen gen_2(my_seed);
+
+ EXPECT_EQ(absl::Bernoulli(gen_1, 0.5), absl::Bernoulli(gen_2, 0.5));
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen_1), absl::Uniform<uint32_t>(gen_2));
+ }
+
+ // An alternate construction which uses user-supplied data
+ // instead of a random seed.
+ {
+ const char kData[] = "A simple seed string";
+ std::seed_seq my_seed(std::begin(kData), std::end(kData));
+
+ absl::BitGen gen_1(my_seed);
+ absl::BitGen gen_2(my_seed);
+
+ EXPECT_EQ(absl::Bernoulli(gen_1, 0.5), absl::Bernoulli(gen_2, 0.5));
+ 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
new file mode 100644
index 00000000..ed5551ae
--- /dev/null
+++ b/absl/random/exponential_distribution.h
@@ -0,0 +1,159 @@
+// 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_EXPONENTIAL_DISTRIBUTION_H_
+#define ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::exponential_distribution:
+// Generates a number conforming to an exponential distribution and is
+// equivalent to the standard [rand.dist.pois.exp] distribution.
+template <typename RealType = double>
+class exponential_distribution {
+ public:
+ using result_type = RealType;
+
+ class param_type {
+ public:
+ using distribution_type = exponential_distribution;
+
+ explicit param_type(result_type lambda = 1) : lambda_(lambda) {
+ assert(lambda > 0);
+ neg_inv_lambda_ = -result_type(1) / lambda_;
+ }
+
+ result_type lambda() const { return lambda_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.lambda_ == b.lambda_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class exponential_distribution;
+
+ result_type lambda_;
+ result_type neg_inv_lambda_;
+
+ static_assert(
+ std::is_floating_point<RealType>::value,
+ "Class-template absl::exponential_distribution<> must be parameterized "
+ "using a floating-point type.");
+ };
+
+ exponential_distribution() : exponential_distribution(1) {}
+
+ explicit exponential_distribution(result_type lambda) : param_(lambda) {}
+
+ explicit exponential_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ // Generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const { return 0; }
+ result_type(max)() const {
+ return std::numeric_limits<result_type>::infinity();
+ }
+
+ result_type lambda() const { return param_.lambda(); }
+
+ friend bool operator==(const exponential_distribution& a,
+ const exponential_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const exponential_distribution& a,
+ const exponential_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+ random_internal::FastUniformBits<uint64_t> fast_u64_;
+};
+
+// --------------------------------------------------------------------------
+// Implementation details follow
+// --------------------------------------------------------------------------
+
+template <typename RealType>
+template <typename URBG>
+typename exponential_distribution<RealType>::result_type
+exponential_distribution<RealType>::operator()(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ using random_internal::NegativeValueT;
+ const result_type u = random_internal::RandU64ToReal<
+ result_type>::template Value<NegativeValueT, false>(fast_u64_(g));
+ // log1p(-x) is mathematically equivalent to log(1 - x) but has more
+ // accuracy for x near zero.
+ return p.neg_inv_lambda_ * std::log1p(u);
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const exponential_distribution<RealType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
+ os << x.lambda();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ exponential_distribution<RealType>& x) { // NOLINT(runtime/references)
+ using result_type = typename exponential_distribution<RealType>::result_type;
+ using param_type = typename exponential_distribution<RealType>::param_type;
+ result_type lambda;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ lambda = random_internal::read_floating_point<result_type>(is);
+ if (!is.fail()) {
+ x.param(param_type(lambda));
+ }
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_EXPONENTIAL_DISTRIBUTION_H_
diff --git a/absl/random/exponential_distribution_test.cc b/absl/random/exponential_distribution_test.cc
new file mode 100644
index 00000000..6f8865c2
--- /dev/null
+++ b/absl/random/exponential_distribution_test.cc
@@ -0,0 +1,422 @@
+// 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/exponential_distribution.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <random>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+using absl::random_internal::kChiSquared;
+
+template <typename RealType>
+class ExponentialDistributionTypedTest : public ::testing::Test {};
+
+using RealTypes = ::testing::Types<float, double, long double>;
+TYPED_TEST_CASE(ExponentialDistributionTypedTest, RealTypes);
+
+TYPED_TEST(ExponentialDistributionTypedTest, SerializeTest) {
+ using param_type =
+ typename absl::exponential_distribution<TypeParam>::param_type;
+
+ const TypeParam kParams[] = {
+ // Cases around 1.
+ 1, //
+ std::nextafter(TypeParam(1), TypeParam(0)), // 1 - epsilon
+ std::nextafter(TypeParam(1), TypeParam(2)), // 1 + epsilon
+ // Typical cases.
+ TypeParam(1e-8), TypeParam(1e-4), TypeParam(1), TypeParam(2),
+ TypeParam(1e4), TypeParam(1e8), TypeParam(1e20), TypeParam(2.5),
+ // Boundary cases.
+ std::numeric_limits<TypeParam>::max(),
+ std::numeric_limits<TypeParam>::epsilon(),
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(1)), // min + epsilon
+ std::numeric_limits<TypeParam>::min(), // smallest normal
+ // There are some errors dealing with denorms on apple platforms.
+ std::numeric_limits<TypeParam>::denorm_min(), // smallest denorm
+ std::numeric_limits<TypeParam>::min() / 2, // denorm
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(0)), // denorm_max
+ };
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+
+ for (const TypeParam lambda : kParams) {
+ // Some values may be invalid; skip those.
+ if (!std::isfinite(lambda)) continue;
+ ABSL_ASSERT(lambda > 0);
+
+ const param_type param(lambda);
+
+ absl::exponential_distribution<TypeParam> before(lambda);
+ EXPECT_EQ(before.lambda(), param.lambda());
+
+ {
+ absl::exponential_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ EXPECT_EQ(via_param.param(), before.param());
+ }
+
+ // Smoke test.
+ auto sample_min = before.max();
+ auto sample_max = before.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = before(gen);
+ EXPECT_GE(sample, before.min()) << before;
+ EXPECT_LE(sample, before.max()) << before;
+ if (sample > sample_max) sample_max = sample;
+ if (sample < sample_min) sample_min = sample;
+ }
+ if (!std::is_same<TypeParam, long double>::value) {
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrFormat("Range {%f}: %f, %f, lambda=%f", lambda,
+ sample_min, sample_max, lambda));
+ }
+
+ std::stringstream ss;
+ ss << before;
+
+ if (!std::isfinite(lambda)) {
+ // Streams do not deserialize inf/nan correctly.
+ continue;
+ }
+ // Validate stream serialization.
+ absl::exponential_distribution<TypeParam> after(34.56f);
+
+ EXPECT_NE(before.lambda(), after.lambda());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
+ defined(__ppc__) || defined(__PPC__)
+ if (std::is_same<TypeParam, long double>::value) {
+ // Roundtripping floating point values requires sufficient precision to
+ // reconstruct the exact value. It turns out that long double has some
+ // errors doing this on ppc, particularly for values
+ // near {1.0 +/- epsilon}.
+ if (lambda <= std::numeric_limits<double>::max() &&
+ lambda >= std::numeric_limits<double>::lowest()) {
+ EXPECT_EQ(static_cast<double>(before.lambda()),
+ static_cast<double>(after.lambda()))
+ << ss.str();
+ }
+ continue;
+ }
+#endif
+
+ EXPECT_EQ(before.lambda(), after.lambda()) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+ }
+}
+
+// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3667.htm
+
+class ExponentialModel {
+ public:
+ explicit ExponentialModel(double lambda)
+ : lambda_(lambda), beta_(1.0 / lambda) {}
+
+ double lambda() const { return lambda_; }
+
+ double mean() const { return beta_; }
+ double variance() const { return beta_ * beta_; }
+ double stddev() const { return std::sqrt(variance()); }
+ double skew() const { return 2; }
+ double kurtosis() const { return 6.0; }
+
+ double CDF(double x) { return 1.0 - std::exp(-lambda_ * x); }
+
+ // The inverse CDF, or PercentPoint function of the distribution
+ double InverseCDF(double p) {
+ ABSL_ASSERT(p >= 0.0);
+ ABSL_ASSERT(p < 1.0);
+ return -beta_ * std::log(1.0 - p);
+ }
+
+ private:
+ const double lambda_;
+ const double beta_;
+};
+
+struct Param {
+ double lambda;
+ double p_fail;
+ int trials;
+};
+
+class ExponentialDistributionTests : public testing::TestWithParam<Param>,
+ public ExponentialModel {
+ public:
+ ExponentialDistributionTests() : ExponentialModel(GetParam().lambda) {}
+
+ // SingleZTest provides a basic z-squared test of the mean vs. expected
+ // mean for data generated by the poisson distribution.
+ template <typename D>
+ bool SingleZTest(const double p, const size_t samples);
+
+ // SingleChiSquaredTest provides a basic chi-squared test of the normal
+ // distribution.
+ template <typename D>
+ double SingleChiSquaredTest();
+
+ absl::InsecureBitGen rng_;
+};
+
+template <typename D>
+bool ExponentialDistributionTests::SingleZTest(const double p,
+ const size_t samples) {
+ D dis(lambda());
+
+ std::vector<double> data;
+ data.reserve(samples);
+ for (size_t i = 0; i < samples; i++) {
+ const double x = dis(rng_);
+ data.push_back(x);
+ }
+
+ const auto m = absl::random_internal::ComputeDistributionMoments(data);
+ const double max_err = absl::random_internal::MaxErrorTolerance(p);
+ const double z = absl::random_internal::ZScore(mean(), m);
+ const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
+
+ if (!pass) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("p=%f max_err=%f\n"
+ " lambda=%f\n"
+ " mean=%f vs. %f\n"
+ " stddev=%f vs. %f\n"
+ " skewness=%f vs. %f\n"
+ " kurtosis=%f vs. %f\n"
+ " z=%f vs. 0",
+ p, max_err, lambda(), m.mean, mean(),
+ std::sqrt(m.variance), stddev(), m.skewness,
+ skew(), m.kurtosis, kurtosis(), z));
+ }
+ return pass;
+}
+
+template <typename D>
+double ExponentialDistributionTests::SingleChiSquaredTest() {
+ const size_t kSamples = 10000;
+ const int kBuckets = 50;
+
+ // The InverseCDF is the percent point function of the distribution, and can
+ // be used to assign buckets roughly uniformly.
+ std::vector<double> cutoffs;
+ const double kInc = 1.0 / static_cast<double>(kBuckets);
+ for (double p = kInc; p < 1.0; p += kInc) {
+ cutoffs.push_back(InverseCDF(p));
+ }
+ if (cutoffs.back() != std::numeric_limits<double>::infinity()) {
+ cutoffs.push_back(std::numeric_limits<double>::infinity());
+ }
+
+ D dis(lambda());
+
+ std::vector<int32_t> counts(cutoffs.size(), 0);
+ for (int j = 0; j < kSamples; j++) {
+ const double x = dis(rng_);
+ auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(), x);
+ counts[std::distance(cutoffs.begin(), it)]++;
+ }
+
+ // Null-hypothesis is that the distribution is exponentially distributed
+ // with the provided lambda (not estimated from the data).
+ const int dof = static_cast<int>(counts.size()) - 1;
+
+ // Our threshold for logging is 1-in-50.
+ const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
+
+ const double expected =
+ static_cast<double>(kSamples) / static_cast<double>(counts.size());
+
+ double chi_square = absl::random_internal::ChiSquareWithExpected(
+ std::begin(counts), std::end(counts), expected);
+ double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
+
+ if (chi_square > threshold) {
+ for (int i = 0; i < cutoffs.size(); i++) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("%d : (%f) = %d", i, cutoffs[i], counts[i]));
+ }
+
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("lambda ", lambda(), "\n", //
+ " expected ", expected, "\n", //
+ kChiSquared, " ", chi_square, " (", p, ")\n",
+ kChiSquared, " @ 0.98 = ", threshold));
+ }
+ return p;
+}
+
+TEST_P(ExponentialDistributionTests, ZTest) {
+ const size_t kSamples = 10000;
+ const auto& param = GetParam();
+ const int expected_failures =
+ std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
+ const double p = absl::random_internal::RequiredSuccessProbability(
+ param.p_fail, param.trials);
+
+ int failures = 0;
+ for (int i = 0; i < param.trials; i++) {
+ failures += SingleZTest<absl::exponential_distribution<double>>(p, kSamples)
+ ? 0
+ : 1;
+ }
+ EXPECT_LE(failures, expected_failures);
+}
+
+TEST_P(ExponentialDistributionTests, ChiSquaredTest) {
+ const int kTrials = 20;
+ int failures = 0;
+
+ for (int i = 0; i < kTrials; i++) {
+ double p_value =
+ SingleChiSquaredTest<absl::exponential_distribution<double>>();
+ if (p_value < 0.005) { // 1/200
+ failures++;
+ }
+ }
+
+ // There is a 0.10% chance of producing at least one failure, so raise the
+ // failure threshold high enough to allow for a flake rate < 10,000.
+ EXPECT_LE(failures, 4);
+}
+
+std::vector<Param> GenParams() {
+ return {
+ Param{1.0, 0.02, 100},
+ Param{2.5, 0.02, 100},
+ Param{10, 0.02, 100},
+ // large
+ Param{1e4, 0.02, 100},
+ Param{1e9, 0.02, 100},
+ // small
+ Param{0.1, 0.02, 100},
+ Param{1e-3, 0.02, 100},
+ Param{1e-5, 0.02, 100},
+ };
+}
+
+std::string ParamName(const ::testing::TestParamInfo<Param>& info) {
+ const auto& p = info.param;
+ std::string name = absl::StrCat("lambda_", absl::SixDigits(p.lambda));
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_CASE_P(, ExponentialDistributionTests,
+ ::testing::ValuesIn(GenParams()), ParamName);
+
+// NOTE: absl::exponential_distribution is not guaranteed to be stable.
+TEST(ExponentialDistributionTest, StabilityTest) {
+ // absl::exponential_distribution stability relies on std::log1p and
+ // absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(14);
+
+ {
+ absl::exponential_distribution<double> dist;
+ std::generate(std::begin(output), std::end(output),
+ [&] { return static_cast<int>(10000.0 * dist(urbg)); });
+
+ EXPECT_EQ(14, urbg.invocations());
+ EXPECT_THAT(output,
+ testing::ElementsAre(0, 71913, 14375, 5039, 1835, 861, 25936,
+ 804, 126, 12337, 17984, 27002, 0, 71913));
+ }
+
+ urbg.reset();
+ {
+ absl::exponential_distribution<float> dist;
+ std::generate(std::begin(output), std::end(output),
+ [&] { return static_cast<int>(10000.0f * dist(urbg)); });
+
+ EXPECT_EQ(14, urbg.invocations());
+ EXPECT_THAT(output,
+ testing::ElementsAre(0, 71913, 14375, 5039, 1835, 861, 25936,
+ 804, 126, 12337, 17984, 27002, 0, 71913));
+ }
+}
+
+TEST(ExponentialDistributionTest, AlgorithmBounds) {
+ // Relies on absl::uniform_real_distribution, so some of these comments
+ // reference that.
+ absl::exponential_distribution<double> dist;
+
+ {
+ // This returns the smallest value >0 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0x0000000000000001ull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 5.42101086242752217004e-20);
+ }
+
+ {
+ // This returns a value very near 0.5 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0x7fffffffffffffefull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 0.693147180559945175204);
+ }
+
+ {
+ // This returns the largest value <1 from absl::uniform_real_distribution.
+ // WolframAlpha: ~39.1439465808987766283058547296341915292187253
+ absl::random_internal::sequence_urbg urbg({0xFFFFFFFFFFFFFFeFull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 36.7368005696771007251);
+ }
+ {
+ // This *ALSO* returns the largest value <1.
+ absl::random_internal::sequence_urbg urbg({0xFFFFFFFFFFFFFFFFull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 36.7368005696771007251);
+ }
+}
+
+} // namespace
diff --git a/absl/random/gaussian_distribution.cc b/absl/random/gaussian_distribution.cc
new file mode 100644
index 00000000..dbc2d848
--- /dev/null
+++ b/absl/random/gaussian_distribution.cc
@@ -0,0 +1,104 @@
+// BEGIN GENERATED CODE; DO NOT EDIT
+// clang-format off
+
+#include "absl/random/gaussian_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+const gaussian_distribution_base::Tables
+ gaussian_distribution_base::zg_ = {
+ {3.7130862467425505, 3.442619855899000214, 3.223084984581141565,
+ 3.083228858216868318, 2.978696252647779819, 2.894344007021528942,
+ 2.82312535054891045, 2.761169372387176857, 2.706113573121819549,
+ 2.656406411261359679, 2.610972248431847387, 2.56903362592493778,
+ 2.530009672388827457, 2.493454522095372106, 2.459018177411830486,
+ 2.426420645533749809, 2.395434278011062457, 2.365871370117638595,
+ 2.337575241339236776, 2.310413683698762988, 2.284274059677471769,
+ 2.25905957386919809, 2.234686395590979036, 2.21108140887870297,
+ 2.188180432076048731, 2.165926793748921497, 2.144270182360394905,
+ 2.123165708673976138, 2.102573135189237608, 2.082456237992015957,
+ 2.062782274508307978, 2.043521536655067194, 2.02464697337738464,
+ 2.006133869963471206, 1.987959574127619033, 1.970103260854325633,
+ 1.952545729553555764, 1.935269228296621957, 1.918257300864508963,
+ 1.901494653105150423, 1.884967035707758143, 1.868661140994487768,
+ 1.852564511728090002, 1.836665460258444904, 1.820952996596124418,
+ 1.805416764219227366, 1.790046982599857506, 1.77483439558606837,
+ 1.759770224899592339, 1.744846128113799244, 1.730054160563729182,
+ 1.71538674071366648, 1.700836618569915748, 1.686396846779167014,
+ 1.6720607540975998, 1.657821920954023254, 1.643674156862867441,
+ 1.629611479470633562, 1.615628095043159629, 1.601718380221376581,
+ 1.587876864890574558, 1.574098216022999264, 1.560377222366167382,
+ 1.546708779859908844, 1.533087877674041755, 1.519509584765938559,
+ 1.505969036863201937, 1.492461423781352714, 1.478981976989922842,
+ 1.465525957342709296, 1.452088642889222792, 1.438665316684561546,
+ 1.425251254514058319, 1.411841712447055919, 1.398431914131003539,
+ 1.385017037732650058, 1.371592202427340812, 1.358152454330141534,
+ 1.34469275175354519, 1.331207949665625279, 1.317692783209412299,
+ 1.304141850128615054, 1.290549591926194894, 1.27691027356015363,
+ 1.263217961454619287, 1.249466499573066436, 1.23564948326336066,
+ 1.221760230539994385, 1.207791750415947662, 1.193736707833126465,
+ 1.17958738466398616, 1.165335636164750222, 1.150972842148865416,
+ 1.136489852013158774, 1.121876922582540237, 1.107123647534034028,
+ 1.092218876907275371, 1.077150624892893482, 1.061905963694822042,
+ 1.046470900764042922, 1.030830236068192907, 1.014967395251327842,
+ 0.9988642334929808131, 0.9825008035154263464, 0.9658550794011470098,
+ 0.9489026255113034436, 0.9316161966151479401, 0.9139652510230292792,
+ 0.8959153525809346874, 0.8774274291129204872, 0.8584568431938099931,
+ 0.8389522142975741614, 0.8188539067003538507, 0.7980920606440534693,
+ 0.7765839878947563557, 0.7542306644540520688, 0.7309119106424850631,
+ 0.7064796113354325779, 0.6807479186691505202, 0.6534786387399710295,
+ 0.6243585973360461505, 0.5929629424714434327, 0.5586921784081798625,
+ 0.5206560387620546848, 0.4774378372966830431, 0.4265479863554152429,
+ 0.3628714310970211909, 0.2723208648139477384, 0},
+ {0.001014352564120377413, 0.002669629083880922793, 0.005548995220771345792,
+ 0.008624484412859888607, 0.01183947865788486861, 0.01516729801054656976,
+ 0.01859210273701129151, 0.02210330461592709475, 0.02569329193593428151,
+ 0.02935631744000685023, 0.03308788614622575758, 0.03688438878665621645,
+ 0.04074286807444417458, 0.04466086220049143157, 0.04863629585986780496,
+ 0.05266740190305100461, 0.05675266348104984759, 0.06089077034804041277,
+ 0.06508058521306804567, 0.06932111739357792179, 0.07361150188411341722,
+ 0.07795098251397346301, 0.08233889824223575293, 0.08677467189478028919,
+ 0.09125780082683036809, 0.095787849121731522, 0.1003644410286559929,
+ 0.1049872554094214289, 0.1096560210148404546, 0.1143705124488661323,
+ 0.1191305467076509556, 0.1239359802028679736, 0.1287867061959434012,
+ 0.1336826525834396151, 0.1386237799845948804, 0.1436100800906280339,
+ 0.1486415742423425057, 0.1537183122081819397, 0.1588403711394795748,
+ 0.1640078546834206341, 0.1692208922373653057, 0.1744796383307898324,
+ 0.1797842721232958407, 0.1851349970089926078, 0.1905320403191375633,
+ 0.1959756531162781534, 0.2014661100743140865, 0.2070037094399269362,
+ 0.2125887730717307134, 0.2182216465543058426, 0.2239026993850088965,
+ 0.229632325232116602, 0.2354109422634795556, 0.2412389935454402889,
+ 0.2471169475123218551, 0.2530452985073261551, 0.2590245673962052742,
+ 0.2650553022555897087, 0.271138079138385224, 0.2772735029191887857,
+ 0.2834622082232336471, 0.2897048604429605656, 0.2960021568469337061,
+ 0.3023548277864842593, 0.3087636380061818397, 0.3152293880650116065,
+ 0.3217529158759855901, 0.3283350983728509642, 0.3349768533135899506,
+ 0.3416791412315512977, 0.3484429675463274756, 0.355269384847918035,
+ 0.3621594953693184626, 0.3691144536644731522, 0.376135469510563536,
+ 0.3832238110559021416, 0.3903808082373155797, 0.3976078564938743676,
+ 0.404906420807223999, 0.4122780401026620578, 0.4197243320495753771,
+ 0.4272469983049970721, 0.4348478302499918513, 0.4425287152754694975,
+ 0.4502916436820402768, 0.458138716267873114, 0.4660721526894572309,
+ 0.4740943006930180559, 0.4822076463294863724, 0.4904148252838453348,
+ 0.4987186354709807201, 0.5071220510755701794, 0.5156282382440030565,
+ 0.5242405726729852944, 0.5329626593838373561, 0.5417983550254266145,
+ 0.5507517931146057588, 0.5598274127040882009, 0.5690299910679523787,
+ 0.5783646811197646898, 0.5878370544347081283, 0.5974531509445183408,
+ 0.6072195366251219584, 0.6171433708188825973, 0.6272324852499290282,
+ 0.6374954773350440806, 0.6479418211102242475, 0.6585820000500898219,
+ 0.6694276673488921414, 0.6804918409973358395, 0.6917891434366769676,
+ 0.7033360990161600101, 0.7151515074105005976, 0.7272569183441868201,
+ 0.7396772436726493094, 0.7524415591746134169, 0.7655841738977066102,
+ 0.7791460859296898134, 0.7931770117713072832, 0.8077382946829627652,
+ 0.8229072113814113187, 0.8387836052959920519, 0.8555006078694531446,
+ 0.873243048910072206, 0.8922816507840289901, 0.9130436479717434217,
+ 0.9362826816850632339, 0.9635996931270905952, 1}};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+// clang-format on
+// END GENERATED CODE
diff --git a/absl/random/gaussian_distribution.h b/absl/random/gaussian_distribution.h
new file mode 100644
index 00000000..8ee95148
--- /dev/null
+++ b/absl/random/gaussian_distribution.h
@@ -0,0 +1,262 @@
+// 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_GAUSSIAN_DISTRIBUTION_H_
+#define ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
+
+// absl::gaussian_distribution implements the Ziggurat algorithm
+// for generating random gaussian numbers.
+//
+// Implementation based on "The Ziggurat Method for Generating Random Variables"
+// by George Marsaglia and Wai Wan Tsang: http://www.jstatsoft.org/v05/i08/
+//
+
+#include <cmath>
+#include <cstdint>
+#include <istream>
+#include <limits>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// absl::gaussian_distribution_base implements the underlying ziggurat algorithm
+// using the ziggurat tables generated by the gaussian_distribution_gentables
+// binary.
+//
+// The specific algorithm has some of the improvements suggested by the
+// 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples",
+// Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf)
+class gaussian_distribution_base {
+ public:
+ template <typename URBG>
+ inline double zignor(URBG& g); // NOLINT(runtime/references)
+
+ private:
+ friend class TableGenerator;
+
+ template <typename URBG>
+ inline double zignor_fallback(URBG& g, // NOLINT(runtime/references)
+ bool neg);
+
+ // Constants used for the gaussian distribution.
+ 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;
+
+ // The ziggurat tables store the pdf(f) and inverse-pdf(x) for equal-area
+ // points on one-half of the normal distribution, where the pdf function,
+ // pdf = e ^ (-1/2 *x^2), assumes that the mean = 0 & stddev = 1.
+ //
+ // These tables are just over 2kb in size; larger tables might improve the
+ // distributions, but also lead to more cache pollution.
+ //
+ // x = {3.71308, 3.44261, 3.22308, ..., 0}
+ // f = {0.00101, 0.00266, 0.00554, ..., 1}
+ struct Tables {
+ double x[kMask + 2];
+ double f[kMask + 2];
+ };
+ static const Tables zg_;
+ random_internal::FastUniformBits<uint64_t> fast_u64_;
+};
+
+} // namespace random_internal
+
+// absl::gaussian_distribution:
+// Generates a number conforming to a Gaussian distribution.
+template <typename RealType = double>
+class gaussian_distribution : random_internal::gaussian_distribution_base {
+ public:
+ using result_type = RealType;
+
+ class param_type {
+ public:
+ using distribution_type = gaussian_distribution;
+
+ explicit param_type(result_type mean = 0, result_type stddev = 1)
+ : mean_(mean), stddev_(stddev) {}
+
+ // Returns the mean distribution parameter. The mean specifies the location
+ // of the peak. The default value is 0.0.
+ result_type mean() const { return mean_; }
+
+ // Returns the deviation distribution parameter. The default value is 1.0.
+ result_type stddev() const { return stddev_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.mean_ == b.mean_ && a.stddev_ == b.stddev_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ result_type mean_;
+ result_type stddev_;
+
+ static_assert(
+ std::is_floating_point<RealType>::value,
+ "Class-template absl::gaussian_distribution<> must be parameterized "
+ "using a floating-point type.");
+ };
+
+ gaussian_distribution() : gaussian_distribution(0) {}
+
+ explicit gaussian_distribution(result_type mean, result_type stddev = 1)
+ : param_(mean, stddev) {}
+
+ explicit gaussian_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ // Generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const {
+ return -std::numeric_limits<result_type>::infinity();
+ }
+ result_type(max)() const {
+ return std::numeric_limits<result_type>::infinity();
+ }
+
+ result_type mean() const { return param_.mean(); }
+ result_type stddev() const { return param_.stddev(); }
+
+ friend bool operator==(const gaussian_distribution& a,
+ const gaussian_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const gaussian_distribution& a,
+ const gaussian_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+};
+
+// --------------------------------------------------------------------------
+// Implementation details only below
+// --------------------------------------------------------------------------
+
+template <typename RealType>
+template <typename URBG>
+typename gaussian_distribution<RealType>::result_type
+gaussian_distribution<RealType>::operator()(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ return p.mean() + p.stddev() * static_cast<result_type>(zignor(g));
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const gaussian_distribution<RealType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
+ os << x.mean() << os.fill() << x.stddev();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ gaussian_distribution<RealType>& x) { // NOLINT(runtime/references)
+ using result_type = typename gaussian_distribution<RealType>::result_type;
+ using param_type = typename gaussian_distribution<RealType>::param_type;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ auto mean = random_internal::read_floating_point<result_type>(is);
+ if (is.fail()) return is;
+ auto stddev = random_internal::read_floating_point<result_type>(is);
+ if (!is.fail()) {
+ x.param(param_type(mean, stddev));
+ }
+ return is;
+}
+
+namespace random_internal {
+
+template <typename URBG>
+inline double gaussian_distribution_base::zignor_fallback(URBG& g, bool neg) {
+ // This fallback path happens approximately 0.05% of the time.
+ double x, y;
+ do {
+ // kRInv = 1/r, U(0, 1)
+ x = kRInv * std::log(RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)));
+ y = -std::log(RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)));
+ } while ((y + y) < (x * x));
+ return neg ? (x - kR) : (kR - x);
+}
+
+template <typename URBG>
+inline double gaussian_distribution_base::zignor(
+ URBG& g) { // NOLINT(runtime/references)
+ while (true) {
+ // We use a single uint64_t to generate both a double and a strip.
+ // These bits are unused when the generated double is > 1/2^5.
+ // This may introduce some bias from the duplicated low bits of small
+ // values (those smaller than 1/2^5, which all end up on the left tail).
+ uint64_t bits = fast_u64_(g);
+ int i = static_cast<int>(bits & kMask); // pick a random strip
+ double j = RandU64ToDouble<SignedValueT, false>(bits); // U(-1, 1)
+ const double x = j * zg_.x[i];
+
+ // Retangular 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]) {
+ return x;
+ }
+
+ // i == 0: Base box. Sample using a ratio of uniforms.
+ if (i == 0) {
+ // This path happens about 0.05% of the time.
+ return zignor_fallback(g, j < 0);
+ }
+
+ // i > 0: Wedge samples using precomputed values.
+ double v = RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)); // U(0, 1)
+ if ((zg_.f[i + 1] + v * (zg_.f[i] - zg_.f[i + 1])) <
+ std::exp(-0.5 * x * x)) {
+ return x;
+ }
+
+ // The wedge was missed; reject the value and try again.
+ }
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
diff --git a/absl/random/gaussian_distribution_test.cc b/absl/random/gaussian_distribution_test.cc
new file mode 100644
index 00000000..47c2989d
--- /dev/null
+++ b/absl/random/gaussian_distribution_test.cc
@@ -0,0 +1,573 @@
+// 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/gaussian_distribution.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <ios>
+#include <iterator>
+#include <random>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+using absl::random_internal::kChiSquared;
+
+template <typename RealType>
+class GaussianDistributionInterfaceTest : public ::testing::Test {};
+
+using RealTypes = ::testing::Types<float, double, long double>;
+TYPED_TEST_CASE(GaussianDistributionInterfaceTest, RealTypes);
+
+TYPED_TEST(GaussianDistributionInterfaceTest, SerializeTest) {
+ using param_type =
+ typename absl::gaussian_distribution<TypeParam>::param_type;
+
+ const TypeParam kParams[] = {
+ // Cases around 1.
+ 1, //
+ std::nextafter(TypeParam(1), TypeParam(0)), // 1 - epsilon
+ std::nextafter(TypeParam(1), TypeParam(2)), // 1 + epsilon
+ // Arbitrary values.
+ TypeParam(1e-8), TypeParam(1e-4), TypeParam(2), TypeParam(1e4),
+ TypeParam(1e8), TypeParam(1e20), TypeParam(2.5),
+ // Boundary cases.
+ std::numeric_limits<TypeParam>::infinity(),
+ std::numeric_limits<TypeParam>::max(),
+ std::numeric_limits<TypeParam>::epsilon(),
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(1)), // min + epsilon
+ std::numeric_limits<TypeParam>::min(), // smallest normal
+ // There are some errors dealing with denorms on apple platforms.
+ std::numeric_limits<TypeParam>::denorm_min(), // smallest denorm
+ std::numeric_limits<TypeParam>::min() / 2,
+ std::nextafter(std::numeric_limits<TypeParam>::min(),
+ TypeParam(0)), // denorm_max
+ };
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+
+ // Use a loop to generate the combinations of {+/-x, +/-y}, and assign x, y to
+ // all values in kParams,
+ for (const auto mod : {0, 1, 2, 3}) {
+ for (const auto x : kParams) {
+ if (!std::isfinite(x)) continue;
+ for (const auto y : kParams) {
+ const TypeParam mean = (mod & 0x1) ? -x : x;
+ const TypeParam stddev = (mod & 0x2) ? -y : y;
+ const param_type param(mean, stddev);
+
+ absl::gaussian_distribution<TypeParam> before(mean, stddev);
+ EXPECT_EQ(before.mean(), param.mean());
+ EXPECT_EQ(before.stddev(), param.stddev());
+
+ {
+ absl::gaussian_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ EXPECT_EQ(via_param.param(), before.param());
+ }
+
+ // Smoke test.
+ auto sample_min = before.max();
+ auto sample_max = before.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = before(gen);
+ if (sample > sample_max) sample_max = sample;
+ if (sample < sample_min) sample_min = sample;
+ EXPECT_GE(sample, before.min()) << before;
+ EXPECT_LE(sample, before.max()) << before;
+ }
+ if (!std::is_same<TypeParam, long double>::value) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("Range{%f, %f}: %f, %f", mean, stddev,
+ sample_min, sample_max));
+ }
+
+ std::stringstream ss;
+ ss << before;
+
+ if (!std::isfinite(mean) || !std::isfinite(stddev)) {
+ // Streams do not parse inf/nan.
+ continue;
+ }
+
+ // Validate stream serialization.
+ absl::gaussian_distribution<TypeParam> after(-0.53f, 2.3456f);
+
+ EXPECT_NE(before.mean(), after.mean());
+ EXPECT_NE(before.stddev(), after.stddev());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+#if defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
+ defined(__ppc__) || defined(__PPC__)
+ if (std::is_same<TypeParam, long double>::value) {
+ // Roundtripping floating point values requires sufficient precision
+ // to reconstruct the exact value. It turns out that long double
+ // has some errors doing this on ppc, particularly for values
+ // near {1.0 +/- epsilon}.
+ if (mean <= std::numeric_limits<double>::max() &&
+ mean >= std::numeric_limits<double>::lowest()) {
+ EXPECT_EQ(static_cast<double>(before.mean()),
+ static_cast<double>(after.mean()))
+ << ss.str();
+ }
+ if (stddev <= std::numeric_limits<double>::max() &&
+ stddev >= std::numeric_limits<double>::lowest()) {
+ EXPECT_EQ(static_cast<double>(before.stddev()),
+ static_cast<double>(after.stddev()))
+ << ss.str();
+ }
+ continue;
+ }
+#endif
+
+ EXPECT_EQ(before.mean(), after.mean());
+ EXPECT_EQ(before.stddev(), after.stddev()) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+ }
+ }
+ }
+}
+
+// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
+
+class GaussianModel {
+ public:
+ GaussianModel(double mean, double stddev) : mean_(mean), stddev_(stddev) {}
+
+ double mean() const { return mean_; }
+ double variance() const { return stddev() * stddev(); }
+ double stddev() const { return stddev_; }
+ double skew() const { return 0; }
+ double kurtosis() const { return 3.0; }
+
+ // The inverse CDF, or PercentPoint function.
+ double InverseCDF(double p) {
+ ABSL_ASSERT(p >= 0.0);
+ ABSL_ASSERT(p < 1.0);
+ return mean() + stddev() * -absl::random_internal::InverseNormalSurvival(p);
+ }
+
+ private:
+ const double mean_;
+ const double stddev_;
+};
+
+struct Param {
+ double mean;
+ double stddev;
+ double p_fail; // Z-Test probability of failure.
+ int trials; // Z-Test trials.
+};
+
+// GaussianDistributionTests implements a z-test for the gaussian
+// distribution.
+class GaussianDistributionTests : public testing::TestWithParam<Param>,
+ public GaussianModel {
+ public:
+ GaussianDistributionTests()
+ : GaussianModel(GetParam().mean, GetParam().stddev) {}
+
+ // SingleZTest provides a basic z-squared test of the mean vs. expected
+ // mean for data generated by the poisson distribution.
+ template <typename D>
+ bool SingleZTest(const double p, const size_t samples);
+
+ // SingleChiSquaredTest provides a basic chi-squared test of the normal
+ // distribution.
+ template <typename D>
+ double SingleChiSquaredTest();
+
+ absl::InsecureBitGen rng_;
+};
+
+template <typename D>
+bool GaussianDistributionTests::SingleZTest(const double p,
+ const size_t samples) {
+ D dis(mean(), stddev());
+
+ std::vector<double> data;
+ data.reserve(samples);
+ for (size_t i = 0; i < samples; i++) {
+ const double x = dis(rng_);
+ data.push_back(x);
+ }
+
+ const double max_err = absl::random_internal::MaxErrorTolerance(p);
+ const auto m = absl::random_internal::ComputeDistributionMoments(data);
+ const double z = absl::random_internal::ZScore(mean(), m);
+ const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
+
+ // NOTE: Informational statistical test:
+ //
+ // Compute the Jarque-Bera test statistic given the excess skewness
+ // and kurtosis. The statistic is drawn from a chi-square(2) distribution.
+ // https://en.wikipedia.org/wiki/Jarque%E2%80%93Bera_test
+ //
+ // The null-hypothesis (normal distribution) is rejected when
+ // (p = 0.05 => jb > 5.99)
+ // (p = 0.01 => jb > 9.21)
+ // NOTE: JB has a large type-I error rate, so it will reject the
+ // null-hypothesis even when it is true more often than the z-test.
+ //
+ const double jb =
+ static_cast<double>(m.n) / 6.0 *
+ (std::pow(m.skewness, 2.0) + std::pow(m.kurtosis - 3.0, 2.0) / 4.0);
+
+ if (!pass || jb > 9.21) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("p=%f max_err=%f\n"
+ " mean=%f vs. %f\n"
+ " stddev=%f vs. %f\n"
+ " skewness=%f vs. %f\n"
+ " kurtosis=%f vs. %f\n"
+ " z=%f vs. 0\n"
+ " jb=%f vs. 9.21",
+ p, max_err, m.mean, mean(), std::sqrt(m.variance),
+ stddev(), m.skewness, skew(), m.kurtosis,
+ kurtosis(), z, jb));
+ }
+ return pass;
+}
+
+template <typename D>
+double GaussianDistributionTests::SingleChiSquaredTest() {
+ const size_t kSamples = 10000;
+ const int kBuckets = 50;
+
+ // The InverseCDF is the percent point function of the
+ // distribution, and can be used to assign buckets
+ // roughly uniformly.
+ std::vector<double> cutoffs;
+ const double kInc = 1.0 / static_cast<double>(kBuckets);
+ for (double p = kInc; p < 1.0; p += kInc) {
+ cutoffs.push_back(InverseCDF(p));
+ }
+ if (cutoffs.back() != std::numeric_limits<double>::infinity()) {
+ cutoffs.push_back(std::numeric_limits<double>::infinity());
+ }
+
+ D dis(mean(), stddev());
+
+ std::vector<int32_t> counts(cutoffs.size(), 0);
+ for (int j = 0; j < kSamples; j++) {
+ const double x = dis(rng_);
+ auto it = std::upper_bound(cutoffs.begin(), cutoffs.end(), x);
+ counts[std::distance(cutoffs.begin(), it)]++;
+ }
+
+ // Null-hypothesis is that the distribution is a gaussian distribution
+ // with the provided mean and stddev (not estimated from the data).
+ const int dof = static_cast<int>(counts.size()) - 1;
+
+ // Our threshold for logging is 1-in-50.
+ const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
+
+ const double expected =
+ static_cast<double>(kSamples) / static_cast<double>(counts.size());
+
+ double chi_square = absl::random_internal::ChiSquareWithExpected(
+ std::begin(counts), std::end(counts), expected);
+ double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
+
+ // Log if the chi_square value is above the threshold.
+ if (chi_square > threshold) {
+ for (int i = 0; i < cutoffs.size(); i++) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("%d : (%f) = %d", i, cutoffs[i], counts[i]));
+ }
+
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrCat("mean=", mean(), " stddev=", stddev(), "\n", //
+ " expected ", expected, "\n", //
+ kChiSquared, " ", chi_square, " (", p, ")\n", //
+ kChiSquared, " @ 0.98 = ", threshold));
+ }
+ return p;
+}
+
+TEST_P(GaussianDistributionTests, ZTest) {
+ // TODO(absl-team): Run these tests against std::normal_distribution<double>
+ // to validate outcomes are similar.
+ const size_t kSamples = 10000;
+ const auto& param = GetParam();
+ const int expected_failures =
+ std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
+ const double p = absl::random_internal::RequiredSuccessProbability(
+ param.p_fail, param.trials);
+
+ int failures = 0;
+ for (int i = 0; i < param.trials; i++) {
+ failures +=
+ SingleZTest<absl::gaussian_distribution<double>>(p, kSamples) ? 0 : 1;
+ }
+ EXPECT_LE(failures, expected_failures);
+}
+
+TEST_P(GaussianDistributionTests, ChiSquaredTest) {
+ const int kTrials = 20;
+ int failures = 0;
+
+ for (int i = 0; i < kTrials; i++) {
+ double p_value =
+ SingleChiSquaredTest<absl::gaussian_distribution<double>>();
+ if (p_value < 0.0025) { // 1/400
+ failures++;
+ }
+ }
+ // There is a 0.05% chance of producing at least one failure, so raise the
+ // failure threshold high enough to allow for a flake rate of less than one in
+ // 10,000.
+ EXPECT_LE(failures, 4);
+}
+
+std::vector<Param> GenParams() {
+ return {
+ // Mean around 0.
+ Param{0.0, 1.0, 0.01, 100},
+ Param{0.0, 1e2, 0.01, 100},
+ Param{0.0, 1e4, 0.01, 100},
+ Param{0.0, 1e8, 0.01, 100},
+ Param{0.0, 1e16, 0.01, 100},
+ Param{0.0, 1e-3, 0.01, 100},
+ Param{0.0, 1e-5, 0.01, 100},
+ Param{0.0, 1e-9, 0.01, 100},
+ Param{0.0, 1e-17, 0.01, 100},
+
+ // Mean around 1.
+ Param{1.0, 1.0, 0.01, 100},
+ Param{1.0, 1e2, 0.01, 100},
+ Param{1.0, 1e-2, 0.01, 100},
+
+ // Mean around 100 / -100
+ Param{1e2, 1.0, 0.01, 100},
+ Param{-1e2, 1.0, 0.01, 100},
+ Param{1e2, 1e6, 0.01, 100},
+ Param{-1e2, 1e6, 0.01, 100},
+
+ // More extreme
+ Param{1e4, 1e4, 0.01, 100},
+ Param{1e8, 1e4, 0.01, 100},
+ Param{1e12, 1e4, 0.01, 100},
+ };
+}
+
+std::string ParamName(const ::testing::TestParamInfo<Param>& info) {
+ const auto& p = info.param;
+ std::string name = absl::StrCat("mean_", absl::SixDigits(p.mean), "__stddev_",
+ absl::SixDigits(p.stddev));
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_SUITE_P(, GaussianDistributionTests,
+ ::testing::ValuesIn(GenParams()), ParamName);
+
+// NOTE: absl::gaussian_distribution is not guaranteed to be stable.
+TEST(GaussianDistributionTest, StabilityTest) {
+ // absl::gaussian_distribution stability relies on the underlying zignor
+ // data, absl::random_interna::RandU64ToDouble, std::exp, std::log, and
+ // std::abs.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(11);
+
+ {
+ absl::gaussian_distribution<double> dist;
+ std::generate(std::begin(output), std::end(output),
+ [&] { return static_cast<int>(10000000.0 * dist(urbg)); });
+
+ EXPECT_EQ(13, urbg.invocations());
+ EXPECT_THAT(output, //
+ testing::ElementsAre(1494, 25518841, 9991550, 1351856,
+ -20373238, 3456682, 333530, -6804981,
+ -15279580, -16459654, 1494));
+ }
+
+ urbg.reset();
+ {
+ absl::gaussian_distribution<float> dist;
+ std::generate(std::begin(output), std::end(output),
+ [&] { return static_cast<int>(1000000.0f * dist(urbg)); });
+
+ EXPECT_EQ(13, urbg.invocations());
+ EXPECT_THAT(
+ output, //
+ testing::ElementsAre(149, 2551884, 999155, 135185, -2037323, 345668,
+ 33353, -680498, -1527958, -1645965, 149));
+ }
+}
+
+// This is an implementation-specific test. If any part of the implementation
+// changes, then it is likely that this test will change as well.
+// Also, if dependencies of the distribution change, such as RandU64ToDouble,
+// then this is also likely to change.
+TEST(GaussianDistributionTest, AlgorithmBounds) {
+ absl::gaussian_distribution<double> dist;
+
+ // In ~95% of cases, a single value is used to generate the output.
+ // for all inputs where |x| < 0.750461021389 this should be the case.
+ //
+ // The exact constraints are based on the ziggurat tables, and any
+ // changes to the ziggurat tables may require adjusting these bounds.
+ //
+ // for i in range(0, len(X)-1):
+ // print i, X[i+1]/X[i], (X[i+1]/X[i] > 0.984375)
+ //
+ // 0.125 <= |values| <= 0.75
+ const uint64_t kValues[] = {
+ 0x1000000000000100ull, 0x2000000000000100ull, 0x3000000000000100ull,
+ 0x4000000000000100ull, 0x5000000000000100ull, 0x6000000000000100ull,
+ // negative values
+ 0x9000000000000100ull, 0xa000000000000100ull, 0xb000000000000100ull,
+ 0xc000000000000100ull, 0xd000000000000100ull, 0xe000000000000100ull};
+
+ // 0.875 <= |values| <= 0.984375
+ const uint64_t kExtraValues[] = {
+ 0x7000000000000100ull, 0x7800000000000100ull, //
+ 0x7c00000000000100ull, 0x7e00000000000100ull, //
+ // negative values
+ 0xf000000000000100ull, 0xf800000000000100ull, //
+ 0xfc00000000000100ull, 0xfe00000000000100ull};
+
+ auto make_box = [](uint64_t v, uint64_t box) {
+ return (v & 0xffffffffffffff80ull) | box;
+ };
+
+ // The box is the lower 7 bits of the value. When the box == 0, then
+ // the algorithm uses an escape hatch to select the result for large
+ // outputs.
+ for (uint64_t box = 0; box < 0x7f; box++) {
+ for (const uint64_t v : kValues) {
+ // Extra values are added to the sequence to attempt to avoid
+ // infinite loops from rejection sampling on bugs/errors.
+ absl::random_internal::sequence_urbg urbg(
+ {make_box(v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
+
+ auto a = dist(urbg);
+ EXPECT_EQ(1, urbg.invocations()) << box << " " << std::hex << v;
+ if (v & 0x8000000000000000ull) {
+ EXPECT_LT(a, 0.0) << box << " " << std::hex << v;
+ } else {
+ EXPECT_GT(a, 0.0) << box << " " << std::hex << v;
+ }
+ }
+ if (box > 10 && box < 100) {
+ // The center boxes use the fast algorithm for more
+ // than 98.4375% of values.
+ for (const uint64_t v : kExtraValues) {
+ absl::random_internal::sequence_urbg urbg(
+ {make_box(v, box), 0x0003eb76f6f7f755ull, 0x5FCEA50FDB2F953Bull});
+
+ auto a = dist(urbg);
+ EXPECT_EQ(1, urbg.invocations()) << box << " " << std::hex << v;
+ if (v & 0x8000000000000000ull) {
+ EXPECT_LT(a, 0.0) << box << " " << std::hex << v;
+ } else {
+ EXPECT_GT(a, 0.0) << box << " " << std::hex << v;
+ }
+ }
+ }
+ }
+
+ // When the box == 0, the fallback algorithm uses a ratio of uniforms,
+ // which consumes 2 additional values from the urbg.
+ // Fallback also requires that the initial value be > 0.9271586026096681.
+ auto make_fallback = [](uint64_t v) { return (v & 0xffffffffffffff80ull); };
+
+ double tail[2];
+ {
+ // 0.9375
+ absl::random_internal::sequence_urbg urbg(
+ {make_fallback(0x7800000000000000ull), 0x13CCA830EB61BD96ull,
+ 0x00000076f6f7f755ull});
+ tail[0] = dist(urbg);
+ EXPECT_EQ(3, urbg.invocations());
+ EXPECT_GT(tail[0], 0);
+ }
+ {
+ // -0.9375
+ absl::random_internal::sequence_urbg urbg(
+ {make_fallback(0xf800000000000000ull), 0x13CCA830EB61BD96ull,
+ 0x00000076f6f7f755ull});
+ tail[1] = dist(urbg);
+ EXPECT_EQ(3, urbg.invocations());
+ EXPECT_LT(tail[1], 0);
+ }
+ EXPECT_EQ(tail[0], -tail[1]);
+ EXPECT_EQ(418610, static_cast<int64_t>(tail[0] * 100000.0));
+
+ // When the box != 0, the fallback algorithm computes a wedge function.
+ // Depending on the box, the threshold for varies as high as
+ // 0.991522480228.
+ {
+ // 0.9921875, 0.875
+ absl::random_internal::sequence_urbg urbg(
+ {make_box(0x7f00000000000000ull, 120), 0xe000000000000001ull,
+ 0x13CCA830EB61BD96ull});
+ tail[0] = dist(urbg);
+ EXPECT_EQ(2, urbg.invocations());
+ EXPECT_GT(tail[0], 0);
+ }
+ {
+ // -0.9921875, 0.875
+ absl::random_internal::sequence_urbg urbg(
+ {make_box(0xff00000000000000ull, 120), 0xe000000000000001ull,
+ 0x13CCA830EB61BD96ull});
+ tail[1] = dist(urbg);
+ EXPECT_EQ(2, urbg.invocations());
+ EXPECT_LT(tail[1], 0);
+ }
+ EXPECT_EQ(tail[0], -tail[1]);
+ EXPECT_EQ(61948, static_cast<int64_t>(tail[0] * 100000.0));
+
+ // Fallback rejected, try again.
+ {
+ // -0.9921875, 0.0625
+ absl::random_internal::sequence_urbg urbg(
+ {make_box(0xff00000000000000ull, 120), 0x1000000000000001,
+ make_box(0x1000000000000100ull, 50), 0x13CCA830EB61BD96ull});
+ dist(urbg);
+ EXPECT_EQ(3, urbg.invocations());
+ }
+}
+
+} // namespace
diff --git a/absl/random/generators_test.cc b/absl/random/generators_test.cc
new file mode 100644
index 00000000..41725f13
--- /dev/null
+++ b/absl/random/generators_test.cc
@@ -0,0 +1,179 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstddef>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
+
+namespace {
+
+template <typename URBG>
+void TestUniform(URBG* gen) {
+ // [a, b) default-semantics, inferred types.
+ absl::Uniform(*gen, 0, 100); // int
+ absl::Uniform(*gen, 0, 1.0); // Promoted to double
+ absl::Uniform(*gen, 0.0f, 1.0); // Promoted to double
+ absl::Uniform(*gen, 0.0, 1.0); // double
+ absl::Uniform(*gen, -1, 1L); // Promoted to long
+
+ // Roll a die.
+ absl::Uniform(absl::IntervalClosedClosed, *gen, 1, 6);
+
+ // Get a fraction.
+ absl::Uniform(absl::IntervalOpenOpen, *gen, 0.0, 1.0);
+
+ // Assign a value to a random element.
+ std::vector<int> elems = {10, 20, 30, 40, 50};
+ elems[absl::Uniform(*gen, 0u, elems.size())] = 5;
+ elems[absl::Uniform<size_t>(*gen, 0, elems.size())] = 3;
+
+ // Choose some epsilon around zero.
+ absl::Uniform(absl::IntervalOpenOpen, *gen, -1.0, 1.0);
+
+ // (a, b) semantics, inferred types.
+ absl::Uniform(absl::IntervalOpenOpen, *gen, 0, 1.0); // Promoted to double
+
+ // Explict overriding of types.
+ absl::Uniform<int>(*gen, 0, 100);
+ absl::Uniform<int8_t>(*gen, 0, 100);
+ absl::Uniform<int16_t>(*gen, 0, 100);
+ absl::Uniform<uint16_t>(*gen, 0, 100);
+ absl::Uniform<int32_t>(*gen, 0, 1 << 10);
+ absl::Uniform<uint32_t>(*gen, 0, 1 << 10);
+ absl::Uniform<int64_t>(*gen, 0, 1 << 10);
+ absl::Uniform<uint64_t>(*gen, 0, 1 << 10);
+
+ absl::Uniform<float>(*gen, 0.0, 1.0);
+ absl::Uniform<float>(*gen, 0, 1);
+ absl::Uniform<float>(*gen, -1, 1);
+ absl::Uniform<double>(*gen, 0.0, 1.0);
+
+ absl::Uniform<float>(*gen, -1.0, 0);
+ absl::Uniform<double>(*gen, -1.0, 0);
+
+ // Tagged
+ absl::Uniform<double>(absl::IntervalClosedClosed, *gen, 0, 1);
+ absl::Uniform<double>(absl::IntervalClosedOpen, *gen, 0, 1);
+ absl::Uniform<double>(absl::IntervalOpenOpen, *gen, 0, 1);
+ absl::Uniform<double>(absl::IntervalOpenClosed, *gen, 0, 1);
+ absl::Uniform<double>(absl::IntervalClosedClosed, *gen, 0, 1);
+ absl::Uniform<double>(absl::IntervalOpenOpen, *gen, 0, 1);
+
+ absl::Uniform<int>(absl::IntervalClosedClosed, *gen, 0, 100);
+ absl::Uniform<int>(absl::IntervalClosedOpen, *gen, 0, 100);
+ absl::Uniform<int>(absl::IntervalOpenOpen, *gen, 0, 100);
+ absl::Uniform<int>(absl::IntervalOpenClosed, *gen, 0, 100);
+ absl::Uniform<int>(absl::IntervalClosedClosed, *gen, 0, 100);
+ absl::Uniform<int>(absl::IntervalOpenOpen, *gen, 0, 100);
+
+ // With *generator as an R-value reference.
+ absl::Uniform<int>(URBG(), 0, 100);
+ absl::Uniform<double>(URBG(), 0.0, 1.0);
+}
+
+template <typename URBG>
+void TestExponential(URBG* gen) {
+ absl::Exponential<float>(*gen);
+ absl::Exponential<double>(*gen);
+ absl::Exponential<double>(URBG());
+}
+
+template <typename URBG>
+void TestPoisson(URBG* gen) {
+ // [rand.dist.pois] Indicates that the std::poisson_distribution
+ // is parameterized by IntType, however MSVC does not allow 8-bit
+ // types.
+ absl::Poisson<int>(*gen);
+ absl::Poisson<int16_t>(*gen);
+ absl::Poisson<uint16_t>(*gen);
+ absl::Poisson<int32_t>(*gen);
+ absl::Poisson<uint32_t>(*gen);
+ absl::Poisson<int64_t>(*gen);
+ absl::Poisson<uint64_t>(*gen);
+ absl::Poisson<uint64_t>(URBG());
+}
+
+template <typename URBG>
+void TestBernoulli(URBG* gen) {
+ absl::Bernoulli(*gen, 0.5);
+ absl::Bernoulli(*gen, 0.5);
+}
+
+template <typename URBG>
+void TestZipf(URBG* gen) {
+ absl::Zipf<int>(*gen, 100);
+ absl::Zipf<int8_t>(*gen, 100);
+ absl::Zipf<int16_t>(*gen, 100);
+ absl::Zipf<uint16_t>(*gen, 100);
+ absl::Zipf<int32_t>(*gen, 1 << 10);
+ absl::Zipf<uint32_t>(*gen, 1 << 10);
+ absl::Zipf<int64_t>(*gen, 1 << 10);
+ absl::Zipf<uint64_t>(*gen, 1 << 10);
+ absl::Zipf<uint64_t>(URBG(), 1 << 10);
+}
+
+template <typename URBG>
+void TestGaussian(URBG* gen) {
+ absl::Gaussian<float>(*gen, 1.0, 1.0);
+ absl::Gaussian<double>(*gen, 1.0, 1.0);
+ absl::Gaussian<double>(URBG(), 1.0, 1.0);
+}
+
+template <typename URBG>
+void TestLogNormal(URBG* gen) {
+ absl::LogUniform<int>(*gen, 0, 100);
+ absl::LogUniform<int8_t>(*gen, 0, 100);
+ absl::LogUniform<int16_t>(*gen, 0, 100);
+ absl::LogUniform<uint16_t>(*gen, 0, 100);
+ absl::LogUniform<int32_t>(*gen, 0, 1 << 10);
+ absl::LogUniform<uint32_t>(*gen, 0, 1 << 10);
+ absl::LogUniform<int64_t>(*gen, 0, 1 << 10);
+ absl::LogUniform<uint64_t>(*gen, 0, 1 << 10);
+ absl::LogUniform<uint64_t>(URBG(), 0, 1 << 10);
+}
+
+template <typename URBG>
+void CompatibilityTest() {
+ URBG gen;
+
+ TestUniform(&gen);
+ TestExponential(&gen);
+ TestPoisson(&gen);
+ TestBernoulli(&gen);
+ TestZipf(&gen);
+ TestGaussian(&gen);
+ TestLogNormal(&gen);
+}
+
+TEST(std_mt19937_64, Compatibility) {
+ // Validate with std::mt19937_64
+ CompatibilityTest<std::mt19937_64>();
+}
+
+TEST(BitGen, Compatibility) {
+ // Validate with absl::BitGen
+ CompatibilityTest<absl::BitGen>();
+}
+
+TEST(InsecureBitGen, Compatibility) {
+ // Validate with absl::InsecureBitGen
+ CompatibilityTest<absl::InsecureBitGen>();
+}
+
+} // namespace
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
new file mode 100644
index 00000000..fd5471a6
--- /dev/null
+++ b/absl/random/internal/BUILD.bazel
@@ -0,0 +1,658 @@
+# 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",
+)
+
+package(default_visibility = [
+ "//absl/random:__pkg__",
+])
+
+licenses(["notice"]) # Apache 2.0
+
+cc_library(
+ name = "traits",
+ hdrs = ["traits.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/random:__pkg__",
+ ],
+ deps = ["//absl/base:config"],
+)
+
+cc_library(
+ name = "distribution_caller",
+ hdrs = ["distribution_caller.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/random:__pkg__",
+ ],
+)
+
+cc_library(
+ name = "distributions",
+ hdrs = [
+ "distributions.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distribution_caller",
+ ":fast_uniform_bits",
+ ":fastmath",
+ ":traits",
+ ":uniform_helper",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "fast_uniform_bits",
+ hdrs = [
+ "fast_uniform_bits.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ visibility = [
+ "//absl/random:__pkg__",
+ ],
+)
+
+cc_library(
+ name = "seed_material",
+ srcs = [
+ "seed_material.cc",
+ ],
+ hdrs = [
+ "seed_material.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fast_uniform_bits",
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/strings",
+ "//absl/types:optional",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "pool_urbg",
+ srcs = [
+ "pool_urbg.cc",
+ ],
+ hdrs = [
+ "pool_urbg.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":randen",
+ ":seed_material",
+ ":traits",
+ "//absl/base",
+ "//absl/base:config",
+ "//absl/base:core_headers",
+ "//absl/base:endian",
+ "//absl/random:seed_gen_exception",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "explicit_seed_seq",
+ testonly = 1,
+ hdrs = [
+ "explicit_seed_seq.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+)
+
+cc_library(
+ name = "sequence_urbg",
+ testonly = 1,
+ hdrs = [
+ "sequence_urbg.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+)
+
+cc_library(
+ name = "salted_seed_seq",
+ hdrs = [
+ "salted_seed_seq.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":seed_material",
+ "//absl/container:inlined_vector",
+ "//absl/meta:type_traits",
+ "//absl/types:optional",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "iostream_state_saver",
+ hdrs = ["iostream_state_saver.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/meta:type_traits",
+ "//absl/numeric:int128",
+ ],
+)
+
+cc_library(
+ name = "distribution_impl",
+ hdrs = [
+ "distribution_impl.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fastmath",
+ ":traits",
+ "//absl/base:bits",
+ "//absl/base:config",
+ "//absl/numeric:int128",
+ ],
+)
+
+cc_library(
+ name = "fastmath",
+ hdrs = [
+ "fastmath.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = ["//absl/base:bits"],
+)
+
+cc_library(
+ name = "nonsecure_base",
+ hdrs = ["nonsecure_base.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":pool_urbg",
+ ":salted_seed_seq",
+ ":seed_material",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ "//absl/strings",
+ "//absl/types:optional",
+ "//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "pcg_engine",
+ hdrs = ["pcg_engine.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fastmath",
+ ":iostream_state_saver",
+ "//absl/base:config",
+ "//absl/meta:type_traits",
+ "//absl/numeric:int128",
+ ],
+)
+
+cc_library(
+ name = "randen_engine",
+ hdrs = ["randen_engine.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":iostream_state_saver",
+ ":randen",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_library(
+ name = "platform",
+ hdrs = [
+ "randen_traits.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ textual_hdrs = [
+ "randen-keys.inc",
+ "platform.h",
+ ],
+)
+
+cc_library(
+ name = "randen",
+ srcs = [
+ "randen.cc",
+ ],
+ hdrs = [
+ "randen.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":platform",
+ ":randen_hwaes",
+ ":randen_slow",
+ "//absl/base",
+ ],
+)
+
+cc_library(
+ name = "randen_slow",
+ srcs = ["randen_slow.cc"],
+ hdrs = ["randen_slow.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":platform",
+ ],
+)
+
+absl_random_randen_copts_init()
+
+cc_library(
+ name = "randen_hwaes",
+ srcs = [
+ "randen_detect.cc",
+ ],
+ hdrs = [
+ "randen_detect.h",
+ "randen_hwaes.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":platform",
+ ":randen_hwaes_impl",
+ ],
+)
+
+# build with --save_temps to see assembly language output.
+cc_library(
+ name = "randen_hwaes_impl",
+ srcs = [
+ "randen_hwaes.cc",
+ "randen_hwaes.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS + ABSL_RANDOM_RANDEN_COPTS + select({
+ "//absl:windows": [],
+ "//conditions:default": ["-Wno-pass-failed"],
+ }),
+ # copts in RANDEN_HWAES_COPTS can make this target unusable as a module
+ # leading to a Clang diagnostic. Furthermore, it only has a private header
+ # anyway and thus there wouldn't be any gain from using it as a module.
+ features = ["-header_modules"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [":platform"],
+)
+
+cc_binary(
+ name = "gaussian_distribution_gentables",
+ srcs = [
+ "gaussian_distribution_gentables.cc",
+ ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base:core_headers",
+ "//absl/random:distributions",
+ ],
+)
+
+cc_library(
+ name = "distribution_test_util",
+ testonly = 1,
+ srcs = [
+ "chi_square.cc",
+ "distribution_test_util.cc",
+ ],
+ hdrs = [
+ "chi_square.h",
+ "distribution_test_util.h",
+ ],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ "//absl/base",
+ "//absl/base:core_headers",
+ "//absl/strings",
+ "//absl/strings:str_format",
+ "//absl/types:span",
+ ],
+)
+
+# Common tags for tests, etc.
+ABSL_RANDOM_NONPORTABLE_TAGS = [
+ "no_test_android_arm",
+ "no_test_android_arm64",
+ "no_test_android_x86",
+ "no_test_darwin_x86_64",
+ "no_test_ios_x86_64",
+ "no_test_loonix",
+ "no_test_msvc_x64",
+ "no_test_wasm",
+]
+
+cc_test(
+ name = "traits_test",
+ size = "small",
+ srcs = ["traits_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":traits",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "distribution_impl_test",
+ size = "small",
+ srcs = ["distribution_impl_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distribution_impl",
+ "//absl/base:bits",
+ "//absl/flags:flag",
+ "//absl/numeric:int128",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "distribution_test_util_test",
+ size = "small",
+ srcs = ["distribution_test_util_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distribution_test_util",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "fastmath_test",
+ size = "small",
+ srcs = ["fastmath_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fastmath",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "explicit_seed_seq_test",
+ size = "small",
+ srcs = ["explicit_seed_seq_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":explicit_seed_seq",
+ "//absl/random:seed_sequences",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "salted_seed_seq_test",
+ size = "small",
+ srcs = ["salted_seed_seq_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":salted_seed_seq",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "chi_square_test",
+ size = "small",
+ srcs = [
+ "chi_square_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distribution_test_util",
+ "//absl/base:core_headers",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "fast_uniform_bits_test",
+ size = "small",
+ srcs = [
+ "fast_uniform_bits_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":fast_uniform_bits",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "nonsecure_base_test",
+ size = "small",
+ srcs = [
+ "nonsecure_base_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":nonsecure_base",
+ "//absl/random",
+ "//absl/random:distributions",
+ "//absl/random:seed_sequences",
+ "//absl/strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "seed_material_test",
+ size = "small",
+ srcs = ["seed_material_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":seed_material",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "pool_urbg_test",
+ size = "small",
+ srcs = [
+ "pool_urbg_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":pool_urbg",
+ "//absl/meta:type_traits",
+ "//absl/types:span",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "pcg_engine_test",
+ size = "medium", # Trying to measure accuracy.
+ srcs = ["pcg_engine_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ flaky = 1,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":explicit_seed_seq",
+ ":pcg_engine",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "randen_engine_test",
+ size = "medium",
+ srcs = [
+ "randen_engine_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":explicit_seed_seq",
+ ":randen_engine",
+ "//absl/base",
+ "//absl/strings",
+ "//absl/time",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "randen_test",
+ size = "small",
+ srcs = ["randen_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":randen",
+ "//absl/meta:type_traits",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "randen_slow_test",
+ size = "small",
+ srcs = ["randen_slow_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":randen_slow",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
+cc_test(
+ name = "randen_hwaes_test",
+ size = "small",
+ srcs = ["randen_hwaes_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ABSL_RANDOM_NONPORTABLE_TAGS,
+ deps = [
+ ":platform",
+ ":randen_hwaes",
+ ":randen_hwaes_impl", # build_cleaner: keep
+ "//absl/base",
+ "//absl/strings:str_format",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_library(
+ name = "nanobenchmark",
+ srcs = ["nanobenchmark.cc"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ textual_hdrs = ["nanobenchmark.h"],
+ deps = [
+ ":platform",
+ ":randen_engine",
+ "//absl/base",
+ ],
+)
+
+cc_library(
+ name = "uniform_helper",
+ hdrs = ["uniform_helper.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":distribution_impl",
+ ":fast_uniform_bits",
+ ":iostream_state_saver",
+ ":traits",
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "nanobenchmark_test",
+ size = "small",
+ srcs = ["nanobenchmark_test.cc"],
+ flaky = 1,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = [
+ "benchmark",
+ "no_test_ios_x86_64",
+ "no_test_loonix", # Crashing.
+ ],
+ deps = [
+ ":nanobenchmark",
+ "//absl/base",
+ "//absl/strings",
+ ],
+)
+
+cc_test(
+ name = "randen_benchmarks",
+ size = "medium",
+ srcs = ["randen_benchmarks.cc"],
+ copts = ABSL_TEST_COPTS + ABSL_RANDOM_RANDEN_COPTS,
+ flaky = 1,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ tags = ABSL_RANDOM_NONPORTABLE_TAGS + ["benchmark"],
+ deps = [
+ ":nanobenchmark",
+ ":platform",
+ ":randen",
+ ":randen_engine",
+ ":randen_hwaes",
+ ":randen_hwaes_impl",
+ ":randen_slow",
+ "//absl/base",
+ "//absl/strings",
+ ],
+)
+
+cc_test(
+ name = "iostream_state_saver_test",
+ size = "small",
+ srcs = ["iostream_state_saver_test.cc"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":iostream_state_saver",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/random/internal/chi_square.cc b/absl/random/internal/chi_square.cc
new file mode 100644
index 00000000..45671a3e
--- /dev/null
+++ b/absl/random/internal/chi_square.cc
@@ -0,0 +1,232 @@
+// 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/chi_square.h"
+
+#include <cmath>
+
+#include "absl/random/internal/distribution_test_util.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+#if defined(__EMSCRIPTEN__)
+// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found.
+inline double fma(double x, double y, double z) {
+ return (x * y) + z;
+}
+#endif
+
+// Use Horner's method to evaluate a polynomial.
+template <typename T, unsigned N>
+inline T EvaluatePolynomial(T x, const T (&poly)[N]) {
+#if !defined(__EMSCRIPTEN__)
+ using std::fma;
+#endif
+ T p = poly[N - 1];
+ for (unsigned i = 2; i <= N; i++) {
+ p = fma(p, x, poly[N - i]);
+ }
+ return p;
+}
+
+static constexpr int kLargeDOF = 150;
+
+// Returns the probability of a normal z-value.
+//
+// Adapted from the POZ function in:
+// Ibbetson D, Algorithm 209
+// Collected Algorithms of the CACM 1963 p. 616
+//
+double POZ(double z) {
+ static constexpr double kP1[] = {
+ 0.797884560593, -0.531923007300, 0.319152932694,
+ -0.151968751364, 0.059054035642, -0.019198292004,
+ 0.005198775019, -0.001075204047, 0.000124818987,
+ };
+ static constexpr double kP2[] = {
+ 0.999936657524, 0.000535310849, -0.002141268741, 0.005353579108,
+ -0.009279453341, 0.011630447319, -0.010557625006, 0.006549791214,
+ -0.002034254874, -0.000794620820, 0.001390604284, -0.000676904986,
+ -0.000019538132, 0.000152529290, -0.000045255659,
+ };
+
+ const double kZMax = 6.0; // Maximum meaningful z-value.
+ if (z == 0.0) {
+ return 0.5;
+ }
+ double x;
+ double y = 0.5 * std::fabs(z);
+ if (y >= (kZMax * 0.5)) {
+ x = 1.0;
+ } else if (y < 1.0) {
+ double w = y * y;
+ x = EvaluatePolynomial(w, kP1) * y * 2.0;
+ } else {
+ y -= 2.0;
+ x = EvaluatePolynomial(y, kP2);
+ }
+ return z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5);
+}
+
+// Approximates the survival function of the normal distribution.
+//
+// Algorithm 26.2.18, from:
+// [Abramowitz and Stegun, Handbook of Mathematical Functions,p.932]
+// http://people.math.sfu.ca/~cbm/aands/abramowitz_and_stegun.pdf
+//
+double normal_survival(double z) {
+ // Maybe replace with the alternate formulation.
+ // 0.5 * erfc((x - mean)/(sqrt(2) * sigma))
+ static constexpr double kR[] = {
+ 1.0, 0.196854, 0.115194, 0.000344, 0.019527,
+ };
+ double r = EvaluatePolynomial(z, kR);
+ r *= r;
+ return 0.5 / (r * r);
+}
+
+} // namespace
+
+// Calculates the critical chi-square value given degrees-of-freedom and a
+// 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.
+
+ const double p_value = 1.0 - p;
+ if (dof < 1 || p_value > 1.0) {
+ return 0.0;
+ }
+
+ if (dof > kLargeDOF) {
+ // For large degrees of freedom, use the normal approximation by
+ // Wilson, E. B. and Hilferty, M. M. (1931)
+ // chi^2 - mean
+ // Z = --------------
+ // stddev
+ const double z = InverseNormalSurvival(p_value);
+ const double mean = 1 - 2.0 / (9 * dof);
+ const double variance = 2.0 / (9 * dof);
+ // Cannot use this method if the variance is 0.
+ if (variance != 0) {
+ return std::pow(z * std::sqrt(variance) + mean, 3.0) * dof;
+ }
+ }
+
+ if (p_value <= 0.0) return kChiMax;
+
+ // Otherwise search for the p value by bisection
+ double min_chisq = 0.0;
+ double max_chisq = kChiMax;
+ double current = dof / std::sqrt(p_value);
+ while ((max_chisq - min_chisq) > kChiEpsilon) {
+ if (ChiSquarePValue(current, dof) < p_value) {
+ max_chisq = current;
+ } else {
+ min_chisq = current;
+ }
+ current = (max_chisq + min_chisq) * 0.5;
+ }
+ return current;
+}
+
+// Calculates the p-value (probability) of a given chi-square value
+// and degrees of freedom.
+//
+// Adapted from the POCHISQ function from:
+// Hill, I. D. and Pike, M. C. Algorithm 299
+// Collected Algorithms of the CACM 1963 p. 243
+//
+double ChiSquarePValue(double chi_square, int dof) {
+ static constexpr double kLogSqrtPi =
+ 0.5723649429247000870717135; // Log[Sqrt[Pi]]
+ static constexpr double kInverseSqrtPi =
+ 0.5641895835477562869480795; // 1/(Sqrt[Pi])
+
+ // For large degrees of freedom, use the normal approximation by
+ // Wilson, E. B. and Hilferty, M. M. (1931)
+ // Via Wikipedia:
+ // By the Central Limit Theorem, because the chi-square distribution is the
+ // sum of k independent random variables with finite mean and variance, it
+ // converges to a normal distribution for large k.
+ if (dof > kLargeDOF) {
+ // Re-scale everything.
+ const double chi_square_scaled = std::pow(chi_square / dof, 1.0 / 3);
+ const double mean = 1 - 2.0 / (9 * dof);
+ const double variance = 2.0 / (9 * dof);
+ // If variance is 0, this method cannot be used.
+ if (variance != 0) {
+ const double z = (chi_square_scaled - mean) / std::sqrt(variance);
+ if (z > 0) {
+ return normal_survival(z);
+ } else if (z < 0) {
+ return 1.0 - normal_survival(-z);
+ } else {
+ return 0.5;
+ }
+ }
+ }
+
+ // The chi square function is >= 0 for any degrees of freedom.
+ // In other words, probability that the chi square function >= 0 is 1.
+ if (chi_square <= 0.0) return 1.0;
+
+ // If the degrees of freedom is zero, the chi square function is always 0 by
+ // definition. In other words, the probability that the chi square function
+ // is > 0 is zero (chi square values <= 0 have been filtered above).
+ if (dof < 1) return 0;
+
+ auto capped_exp = [](double x) { return x < -20 ? 0.0 : std::exp(x); };
+ static constexpr double kBigX = 20;
+
+ double a = 0.5 * chi_square;
+ const bool even = !(dof & 1); // True if dof is an even number.
+ const double y = capped_exp(-a);
+ double s = even ? y : (2.0 * POZ(-std::sqrt(chi_square)));
+
+ if (dof <= 2) {
+ return s;
+ }
+
+ chi_square = 0.5 * (dof - 1.0);
+ double z = (even ? 1.0 : 0.5);
+ if (a > kBigX) {
+ double e = (even ? 0.0 : kLogSqrtPi);
+ double c = std::log(a);
+ while (z <= chi_square) {
+ e = std::log(z) + e;
+ s += capped_exp(c * z - a - e);
+ z += 1.0;
+ }
+ return s;
+ }
+
+ double e = (even ? 1.0 : (kInverseSqrtPi / std::sqrt(a)));
+ double c = 0.0;
+ while (z <= chi_square) {
+ e = e * (a / z);
+ c = c + e;
+ z += 1.0;
+ }
+ return c * y + s;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/chi_square.h b/absl/random/internal/chi_square.h
new file mode 100644
index 00000000..002b4c95
--- /dev/null
+++ b/absl/random/internal/chi_square.h
@@ -0,0 +1,87 @@
+// 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_CHI_SQUARE_H_
+#define ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_
+
+// The chi-square statistic.
+//
+// Useful for evaluating if `D` independent random variables are behaving as
+// expected, or if two distributions are similar. (`D` is the degrees of
+// freedom).
+//
+// Each bucket should have an expected count of 10 or more for the chi square to
+// be meaningful.
+
+#include <cassert>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+constexpr const char kChiSquared[] = "chi-squared";
+
+// Returns the measured chi square value, using a single expected value. This
+// assumes that the values in [begin, end) are uniformly distributed.
+template <typename Iterator>
+double ChiSquareWithExpected(Iterator begin, Iterator end, double expected) {
+ // Compute the sum and the number of buckets.
+ assert(expected >= 10); // require at least 10 samples per bucket.
+ double chi_square = 0;
+ for (auto it = begin; it != end; it++) {
+ double d = static_cast<double>(*it) - expected;
+ chi_square += d * d;
+ }
+ chi_square = chi_square / expected;
+ return chi_square;
+}
+
+// Returns the measured chi square value, taking the actual value of each bucket
+// from the first set of iterators, and the expected value of each bucket from
+// the second set of iterators.
+template <typename Iterator, typename Expected>
+double ChiSquare(Iterator it, Iterator end, Expected eit, Expected eend) {
+ double chi_square = 0;
+ for (; it != end && eit != eend; ++it, ++eit) {
+ if (*it > 0) {
+ assert(*eit > 0);
+ }
+ double e = static_cast<double>(*eit);
+ double d = static_cast<double>(*it - *eit);
+ if (d != 0) {
+ assert(e > 0);
+ chi_square += (d * d) / e;
+ }
+ }
+ assert(it == end && eit == eend);
+ return chi_square;
+}
+
+// ======================================================================
+// The following methods can be used for an arbitrary significance level.
+//
+
+// Calculates critical chi-square values to produce the given p-value using a
+// bisection search for a value within epsilon, relying on the monotonicity of
+// ChiSquarePValue().
+double ChiSquareValue(int dof, double p);
+
+// Calculates the p-value (probability) of a given chi-square value.
+double ChiSquarePValue(double chi_square, int dof);
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_CHI_SQUARE_H_
diff --git a/absl/random/internal/chi_square_test.cc b/absl/random/internal/chi_square_test.cc
new file mode 100644
index 00000000..5025defa
--- /dev/null
+++ b/absl/random/internal/chi_square_test.cc
@@ -0,0 +1,365 @@
+// 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/chi_square.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <numeric>
+#include <vector>
+
+#include "gtest/gtest.h"
+#include "absl/base/macros.h"
+
+using absl::random_internal::ChiSquare;
+using absl::random_internal::ChiSquarePValue;
+using absl::random_internal::ChiSquareValue;
+using absl::random_internal::ChiSquareWithExpected;
+
+namespace {
+
+TEST(ChiSquare, Value) {
+ struct {
+ int line;
+ double chi_square;
+ int df;
+ double confidence;
+ } const specs[] = {
+ // Testing lookup at 1% confidence
+ {__LINE__, 0, 0, 0.01},
+ {__LINE__, 0.00016, 1, 0.01},
+ {__LINE__, 1.64650, 8, 0.01},
+ {__LINE__, 5.81221, 16, 0.01},
+ {__LINE__, 156.4319, 200, 0.01},
+ {__LINE__, 1121.3784, 1234, 0.01},
+ {__LINE__, 53557.1629, 54321, 0.01},
+ {__LINE__, 651662.6647, 654321, 0.01},
+
+ // Testing lookup at 99% confidence
+ {__LINE__, 0, 0, 0.99},
+ {__LINE__, 6.635, 1, 0.99},
+ {__LINE__, 20.090, 8, 0.99},
+ {__LINE__, 32.000, 16, 0.99},
+ {__LINE__, 249.4456, 200, 0.99},
+ {__LINE__, 1131.1573, 1023, 0.99},
+ {__LINE__, 1352.5038, 1234, 0.99},
+ {__LINE__, 55090.7356, 54321, 0.99},
+ {__LINE__, 656985.1514, 654321, 0.99},
+
+ // Testing lookup at 99.9% confidence
+ {__LINE__, 16.2659, 3, 0.999},
+ {__LINE__, 22.4580, 6, 0.999},
+ {__LINE__, 267.5409, 200, 0.999},
+ {__LINE__, 1168.5033, 1023, 0.999},
+ {__LINE__, 55345.1741, 54321, 0.999},
+ {__LINE__, 657861.7284, 654321, 0.999},
+ {__LINE__, 51.1772, 24, 0.999},
+ {__LINE__, 59.7003, 30, 0.999},
+ {__LINE__, 37.6984, 15, 0.999},
+ {__LINE__, 29.5898, 10, 0.999},
+ {__LINE__, 27.8776, 9, 0.999},
+
+ // Testing lookup at random confidences
+ {__LINE__, 0.000157088, 1, 0.01},
+ {__LINE__, 5.31852, 2, 0.93},
+ {__LINE__, 1.92256, 4, 0.25},
+ {__LINE__, 10.7709, 13, 0.37},
+ {__LINE__, 26.2514, 17, 0.93},
+ {__LINE__, 36.4799, 29, 0.84},
+ {__LINE__, 25.818, 31, 0.27},
+ {__LINE__, 63.3346, 64, 0.50},
+ {__LINE__, 196.211, 128, 0.9999},
+ {__LINE__, 215.21, 243, 0.10},
+ {__LINE__, 285.393, 256, 0.90},
+ {__LINE__, 984.504, 1024, 0.1923},
+ {__LINE__, 2043.85, 2048, 0.4783},
+ {__LINE__, 48004.6, 48273, 0.194},
+ };
+ for (const auto& spec : specs) {
+ SCOPED_TRACE(spec.line);
+ // Verify all values are have at most a 1% relative error.
+ const double val = ChiSquareValue(spec.df, spec.confidence);
+ const double err = std::max(5e-6, spec.chi_square / 5e3); // 1 part in 5000
+ EXPECT_NEAR(spec.chi_square, val, err) << spec.line;
+ }
+
+ // Relaxed test for extreme values, from
+ // http://www.ciphersbyritter.com/JAVASCRP/NORMCHIK.HTM#ChiSquare
+ EXPECT_NEAR(49.2680, ChiSquareValue(100, 1e-6), 5); // 0.000'005 mark
+ EXPECT_NEAR(123.499, ChiSquareValue(200, 1e-6), 5); // 0.000'005 mark
+
+ EXPECT_NEAR(149.449, ChiSquareValue(100, 0.999), 0.01);
+ EXPECT_NEAR(161.318, ChiSquareValue(100, 0.9999), 0.01);
+ EXPECT_NEAR(172.098, ChiSquareValue(100, 0.99999), 0.01);
+
+ EXPECT_NEAR(381.426, ChiSquareValue(300, 0.999), 0.05);
+ EXPECT_NEAR(399.756, ChiSquareValue(300, 0.9999), 0.1);
+ EXPECT_NEAR(416.126, ChiSquareValue(300, 0.99999), 0.2);
+}
+
+TEST(ChiSquareTest, PValue) {
+ struct {
+ int line;
+ double pval;
+ double chi_square;
+ int df;
+ } static const specs[] = {
+ {__LINE__, 1, 0, 0},
+ {__LINE__, 0, 0.001, 0},
+ {__LINE__, 1.000, 0, 453},
+ {__LINE__, 0.134471, 7972.52, 7834},
+ {__LINE__, 0.203922, 28.32, 23},
+ {__LINE__, 0.737171, 48274, 48472},
+ {__LINE__, 0.444146, 583.1234, 579},
+ {__LINE__, 0.294814, 138.2, 130},
+ {__LINE__, 0.0816532, 12.63, 7},
+ {__LINE__, 0, 682.32, 67},
+ {__LINE__, 0.49405, 999, 999},
+ {__LINE__, 1.000, 0, 9999},
+ {__LINE__, 0.997477, 0.00001, 1},
+ {__LINE__, 0, 5823.21, 5040},
+ };
+ for (const auto& spec : specs) {
+ SCOPED_TRACE(spec.line);
+ const double pval = ChiSquarePValue(spec.chi_square, spec.df);
+ EXPECT_NEAR(spec.pval, pval, 1e-3);
+ }
+}
+
+TEST(ChiSquareTest, CalcChiSquare) {
+ struct {
+ int line;
+ std::vector<int> expected;
+ std::vector<int> actual;
+ } const specs[] = {
+ {__LINE__,
+ {56, 234, 76, 1, 546, 1, 87, 345, 1, 234},
+ {2, 132, 4, 43, 234, 8, 345, 8, 236, 56}},
+ {__LINE__,
+ {123, 36, 234, 367, 345, 2, 456, 567, 234, 567},
+ {123, 56, 2345, 8, 345, 8, 2345, 23, 48, 267}},
+ {__LINE__,
+ {123, 234, 345, 456, 567, 678, 789, 890, 98, 76},
+ {123, 234, 345, 456, 567, 678, 789, 890, 98, 76}},
+ {__LINE__, {3, 675, 23, 86, 2, 8, 2}, {456, 675, 23, 86, 23, 65, 2}},
+ {__LINE__, {1}, {23}},
+ };
+ for (const auto& spec : specs) {
+ SCOPED_TRACE(spec.line);
+ double chi_square = 0;
+ for (int i = 0; i < spec.expected.size(); ++i) {
+ const double diff = spec.actual[i] - spec.expected[i];
+ chi_square += (diff * diff) / spec.expected[i];
+ }
+ EXPECT_NEAR(chi_square,
+ ChiSquare(std::begin(spec.actual), std::end(spec.actual),
+ std::begin(spec.expected), std::end(spec.expected)),
+ 1e-5);
+ }
+}
+
+TEST(ChiSquareTest, CalcChiSquareInt64) {
+ const int64_t data[3] = {910293487, 910292491, 910216780};
+ // $ python -c "import scipy.stats
+ // > print scipy.stats.chisquare([910293487, 910292491, 910216780])[0]"
+ // 4.25410123524
+ double sum = std::accumulate(std::begin(data), std::end(data), double{0});
+ size_t n = std::distance(std::begin(data), std::end(data));
+ double a = ChiSquareWithExpected(std::begin(data), std::end(data), sum / n);
+ EXPECT_NEAR(4.254101, a, 1e-6);
+
+ // ... Or with known values.
+ double b =
+ ChiSquareWithExpected(std::begin(data), std::end(data), 910267586.0);
+ EXPECT_NEAR(4.254101, b, 1e-6);
+}
+
+TEST(ChiSquareTest, TableData) {
+ // Test data from
+ // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
+ // 0.90 0.95 0.975 0.99 0.999
+ const double data[100][5] = {
+ /* 1*/ {2.706, 3.841, 5.024, 6.635, 10.828},
+ /* 2*/ {4.605, 5.991, 7.378, 9.210, 13.816},
+ /* 3*/ {6.251, 7.815, 9.348, 11.345, 16.266},
+ /* 4*/ {7.779, 9.488, 11.143, 13.277, 18.467},
+ /* 5*/ {9.236, 11.070, 12.833, 15.086, 20.515},
+ /* 6*/ {10.645, 12.592, 14.449, 16.812, 22.458},
+ /* 7*/ {12.017, 14.067, 16.013, 18.475, 24.322},
+ /* 8*/ {13.362, 15.507, 17.535, 20.090, 26.125},
+ /* 9*/ {14.684, 16.919, 19.023, 21.666, 27.877},
+ /*10*/ {15.987, 18.307, 20.483, 23.209, 29.588},
+ /*11*/ {17.275, 19.675, 21.920, 24.725, 31.264},
+ /*12*/ {18.549, 21.026, 23.337, 26.217, 32.910},
+ /*13*/ {19.812, 22.362, 24.736, 27.688, 34.528},
+ /*14*/ {21.064, 23.685, 26.119, 29.141, 36.123},
+ /*15*/ {22.307, 24.996, 27.488, 30.578, 37.697},
+ /*16*/ {23.542, 26.296, 28.845, 32.000, 39.252},
+ /*17*/ {24.769, 27.587, 30.191, 33.409, 40.790},
+ /*18*/ {25.989, 28.869, 31.526, 34.805, 42.312},
+ /*19*/ {27.204, 30.144, 32.852, 36.191, 43.820},
+ /*20*/ {28.412, 31.410, 34.170, 37.566, 45.315},
+ /*21*/ {29.615, 32.671, 35.479, 38.932, 46.797},
+ /*22*/ {30.813, 33.924, 36.781, 40.289, 48.268},
+ /*23*/ {32.007, 35.172, 38.076, 41.638, 49.728},
+ /*24*/ {33.196, 36.415, 39.364, 42.980, 51.179},
+ /*25*/ {34.382, 37.652, 40.646, 44.314, 52.620},
+ /*26*/ {35.563, 38.885, 41.923, 45.642, 54.052},
+ /*27*/ {36.741, 40.113, 43.195, 46.963, 55.476},
+ /*28*/ {37.916, 41.337, 44.461, 48.278, 56.892},
+ /*29*/ {39.087, 42.557, 45.722, 49.588, 58.301},
+ /*30*/ {40.256, 43.773, 46.979, 50.892, 59.703},
+ /*31*/ {41.422, 44.985, 48.232, 52.191, 61.098},
+ /*32*/ {42.585, 46.194, 49.480, 53.486, 62.487},
+ /*33*/ {43.745, 47.400, 50.725, 54.776, 63.870},
+ /*34*/ {44.903, 48.602, 51.966, 56.061, 65.247},
+ /*35*/ {46.059, 49.802, 53.203, 57.342, 66.619},
+ /*36*/ {47.212, 50.998, 54.437, 58.619, 67.985},
+ /*37*/ {48.363, 52.192, 55.668, 59.893, 69.347},
+ /*38*/ {49.513, 53.384, 56.896, 61.162, 70.703},
+ /*39*/ {50.660, 54.572, 58.120, 62.428, 72.055},
+ /*40*/ {51.805, 55.758, 59.342, 63.691, 73.402},
+ /*41*/ {52.949, 56.942, 60.561, 64.950, 74.745},
+ /*42*/ {54.090, 58.124, 61.777, 66.206, 76.084},
+ /*43*/ {55.230, 59.304, 62.990, 67.459, 77.419},
+ /*44*/ {56.369, 60.481, 64.201, 68.710, 78.750},
+ /*45*/ {57.505, 61.656, 65.410, 69.957, 80.077},
+ /*46*/ {58.641, 62.830, 66.617, 71.201, 81.400},
+ /*47*/ {59.774, 64.001, 67.821, 72.443, 82.720},
+ /*48*/ {60.907, 65.171, 69.023, 73.683, 84.037},
+ /*49*/ {62.038, 66.339, 70.222, 74.919, 85.351},
+ /*50*/ {63.167, 67.505, 71.420, 76.154, 86.661},
+ /*51*/ {64.295, 68.669, 72.616, 77.386, 87.968},
+ /*52*/ {65.422, 69.832, 73.810, 78.616, 89.272},
+ /*53*/ {66.548, 70.993, 75.002, 79.843, 90.573},
+ /*54*/ {67.673, 72.153, 76.192, 81.069, 91.872},
+ /*55*/ {68.796, 73.311, 77.380, 82.292, 93.168},
+ /*56*/ {69.919, 74.468, 78.567, 83.513, 94.461},
+ /*57*/ {71.040, 75.624, 79.752, 84.733, 95.751},
+ /*58*/ {72.160, 76.778, 80.936, 85.950, 97.039},
+ /*59*/ {73.279, 77.931, 82.117, 87.166, 98.324},
+ /*60*/ {74.397, 79.082, 83.298, 88.379, 99.607},
+ /*61*/ {75.514, 80.232, 84.476, 89.591, 100.888},
+ /*62*/ {76.630, 81.381, 85.654, 90.802, 102.166},
+ /*63*/ {77.745, 82.529, 86.830, 92.010, 103.442},
+ /*64*/ {78.860, 83.675, 88.004, 93.217, 104.716},
+ /*65*/ {79.973, 84.821, 89.177, 94.422, 105.988},
+ /*66*/ {81.085, 85.965, 90.349, 95.626, 107.258},
+ /*67*/ {82.197, 87.108, 91.519, 96.828, 108.526},
+ /*68*/ {83.308, 88.250, 92.689, 98.028, 109.791},
+ /*69*/ {84.418, 89.391, 93.856, 99.228, 111.055},
+ /*70*/ {85.527, 90.531, 95.023, 100.425, 112.317},
+ /*71*/ {86.635, 91.670, 96.189, 101.621, 113.577},
+ /*72*/ {87.743, 92.808, 97.353, 102.816, 114.835},
+ /*73*/ {88.850, 93.945, 98.516, 104.010, 116.092},
+ /*74*/ {89.956, 95.081, 99.678, 105.202, 117.346},
+ /*75*/ {91.061, 96.217, 100.839, 106.393, 118.599},
+ /*76*/ {92.166, 97.351, 101.999, 107.583, 119.850},
+ /*77*/ {93.270, 98.484, 103.158, 108.771, 121.100},
+ /*78*/ {94.374, 99.617, 104.316, 109.958, 122.348},
+ /*79*/ {95.476, 100.749, 105.473, 111.144, 123.594},
+ /*80*/ {96.578, 101.879, 106.629, 112.329, 124.839},
+ /*81*/ {97.680, 103.010, 107.783, 113.512, 126.083},
+ /*82*/ {98.780, 104.139, 108.937, 114.695, 127.324},
+ /*83*/ {99.880, 105.267, 110.090, 115.876, 128.565},
+ /*84*/ {100.980, 106.395, 111.242, 117.057, 129.804},
+ /*85*/ {102.079, 107.522, 112.393, 118.236, 131.041},
+ /*86*/ {103.177, 108.648, 113.544, 119.414, 132.277},
+ /*87*/ {104.275, 109.773, 114.693, 120.591, 133.512},
+ /*88*/ {105.372, 110.898, 115.841, 121.767, 134.746},
+ /*89*/ {106.469, 112.022, 116.989, 122.942, 135.978},
+ /*90*/ {107.565, 113.145, 118.136, 124.116, 137.208},
+ /*91*/ {108.661, 114.268, 119.282, 125.289, 138.438},
+ /*92*/ {109.756, 115.390, 120.427, 126.462, 139.666},
+ /*93*/ {110.850, 116.511, 121.571, 127.633, 140.893},
+ /*94*/ {111.944, 117.632, 122.715, 128.803, 142.119},
+ /*95*/ {113.038, 118.752, 123.858, 129.973, 143.344},
+ /*96*/ {114.131, 119.871, 125.000, 131.141, 144.567},
+ /*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}
+ /**/};
+
+ // 0.90 0.95 0.975 0.99 0.999
+ for (int i = 0; i < ABSL_ARRAYSIZE(data); i++) {
+ const double E = 0.0001;
+ EXPECT_NEAR(ChiSquarePValue(data[i][0], i + 1), 0.10, E)
+ << i << " " << data[i][0];
+ EXPECT_NEAR(ChiSquarePValue(data[i][1], i + 1), 0.05, E)
+ << i << " " << data[i][1];
+ EXPECT_NEAR(ChiSquarePValue(data[i][2], i + 1), 0.025, E)
+ << i << " " << data[i][2];
+ EXPECT_NEAR(ChiSquarePValue(data[i][3], i + 1), 0.01, E)
+ << i << " " << data[i][3];
+ EXPECT_NEAR(ChiSquarePValue(data[i][4], i + 1), 0.001, E)
+ << i << " " << data[i][4];
+
+ const double F = 0.1;
+ EXPECT_NEAR(ChiSquareValue(i + 1, 0.90), data[i][0], F) << i;
+ EXPECT_NEAR(ChiSquareValue(i + 1, 0.95), data[i][1], F) << i;
+ EXPECT_NEAR(ChiSquareValue(i + 1, 0.975), data[i][2], F) << i;
+ EXPECT_NEAR(ChiSquareValue(i + 1, 0.99), data[i][3], F) << i;
+ EXPECT_NEAR(ChiSquareValue(i + 1, 0.999), data[i][4], F) << i;
+ }
+}
+
+TEST(ChiSquareTest, ChiSquareTwoIterator) {
+ // Test data from http://www.stat.yale.edu/Courses/1997-98/101/chigf.htm
+ // Null-hypothesis: This data is normally distributed.
+ const int counts[10] = {6, 6, 18, 33, 38, 38, 28, 21, 9, 3};
+ const double expected[10] = {4.6, 8.8, 18.4, 30.0, 38.2,
+ 38.2, 30.0, 18.4, 8.8, 4.6};
+ double chi_square = ChiSquare(std::begin(counts), std::end(counts),
+ std::begin(expected), std::end(expected));
+ EXPECT_NEAR(chi_square, 2.69, 0.001);
+
+ // Degrees of freedom: 10 bins. two estimated parameters. = 10 - 2 - 1.
+ const int dof = 7;
+ // The critical value of 7, 95% => 14.067 (see above test)
+ double p_value_05 = ChiSquarePValue(14.067, dof);
+ EXPECT_NEAR(p_value_05, 0.05, 0.001); // 95%-ile p-value
+
+ double p_actual = ChiSquarePValue(chi_square, dof);
+ EXPECT_GT(p_actual, 0.05); // Accept the null hypothesis.
+}
+
+TEST(ChiSquareTest, DiceRolls) {
+ // Assume we are testing 102 fair dice rolls.
+ // Null-hypothesis: This data is fairly distributed.
+ //
+ // The dof value of 4, @95% = 9.488 (see above test)
+ // The dof value of 5, @95% = 11.070
+ const int rolls[6] = {22, 11, 17, 14, 20, 18};
+ double sum = std::accumulate(std::begin(rolls), std::end(rolls), double{0});
+ size_t n = std::distance(std::begin(rolls), std::end(rolls));
+
+ double a = ChiSquareWithExpected(std::begin(rolls), std::end(rolls), sum / n);
+ EXPECT_NEAR(a, 4.70588, 1e-5);
+ EXPECT_LT(a, ChiSquareValue(4, 0.95));
+
+ double p_a = ChiSquarePValue(a, 4);
+ EXPECT_NEAR(p_a, 0.318828, 1e-5); // Accept the null hypothesis.
+
+ double b = ChiSquareWithExpected(std::begin(rolls), std::end(rolls), 17.0);
+ EXPECT_NEAR(b, 4.70588, 1e-5);
+ EXPECT_LT(b, ChiSquareValue(5, 0.95));
+
+ double p_b = ChiSquarePValue(b, 5);
+ EXPECT_NEAR(p_b, 0.4528180, 1e-5); // Accept the null hypothesis.
+}
+
+} // namespace
diff --git a/absl/random/internal/distribution_caller.h b/absl/random/internal/distribution_caller.h
new file mode 100644
index 00000000..dd06c985
--- /dev/null
+++ b/absl/random/internal/distribution_caller.h
@@ -0,0 +1,58 @@
+//
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
+#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
+
+#include <utility>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// DistributionCaller provides an opportunity to overload the general
+// mechanism for calling a distribution, allowing for mock-RNG classes
+// to intercept such calls.
+template <typename URBG>
+struct DistributionCaller {
+ // Call the provided distribution type. The parameters are expected
+ // to be explicitly specified.
+ // DistrT is the distribution type.
+ // FormatT is the formatter type:
+ //
+ // struct FormatT {
+ // using result_type = distribution_t::result_type;
+ // static std::string FormatCall(
+ // const distribution_t& distr,
+ // absl::Span<const result_type>);
+ //
+ // static std::string FormatExpectation(
+ // absl::string_view match_args,
+ // absl::Span<const result_t> results);
+ // }
+ //
+ template <typename DistrT, typename FormatT, typename... Args>
+ static typename DistrT::result_type Call(URBG* urbg, Args&&... args) {
+ DistrT dist(std::forward<Args>(args)...);
+ return dist(*urbg);
+ }
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_CALLER_H_
diff --git a/absl/random/internal/distribution_impl.h b/absl/random/internal/distribution_impl.h
new file mode 100644
index 00000000..a8e5d61e
--- /dev/null
+++ b/absl/random/internal/distribution_impl.h
@@ -0,0 +1,262 @@
+// 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_DISTRIBUTION_IMPL_H_
+#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_IMPL_H_
+
+// This file contains some implementation details which are used by one or more
+// of the absl random number distributions.
+
+#include <cfloat>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+
+#if (defined(_WIN32) || defined(_WIN64)) && defined(_M_IA64)
+#include <intrin.h> // NOLINT(build/include_order)
+#pragma intrinsic(_umul128)
+#define ABSL_INTERNAL_USE_UMUL128 1
+#endif
+
+#include "absl/base/config.h"
+#include "absl/base/internal/bits.h"
+#include "absl/numeric/int128.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Creates a double from `bits`, with the template fields controlling the
+// output.
+//
+// RandU64To is both more efficient and generates more unique values in the
+// result interval than known implementations of std::generate_canonical().
+//
+// The `Signed` parameter controls whether positive, negative, or both are
+// returned (thus affecting the output interval).
+// When Signed == SignedValueT, range is U(-1, 1)
+// When Signed == NegativeValueT, range is U(-1, 0)
+// When Signed == PositiveValueT, range is U(0, 1)
+//
+// When the `IncludeZero` parameter is true, the function may return 0 for some
+// inputs, otherwise it never returns 0.
+//
+// The `ExponentBias` parameter determines the scale of the output range by
+// adjusting the exponent.
+//
+// When a value in U(0,1) is required, use:
+// RandU64ToDouble<PositiveValueT, true, 0>();
+//
+// When a value in U(-1,1) is required, use:
+// RandU64ToDouble<SignedValueT, false, 0>() => U(-1, 1)
+// This generates more distinct values than the mathematically equivalent
+// expression `U(0, 1) * 2.0 - 1.0`, and is preferable.
+//
+// Scaling the result by powers of 2 (and avoiding a multiply) is also possible:
+// RandU64ToDouble<PositiveValueT, false, 1>(); => U(0, 2)
+// RandU64ToDouble<PositiveValueT, false, -1>(); => U(0, 0.5)
+//
+
+// Tristate types controlling the output.
+struct PositiveValueT {};
+struct NegativeValueT {};
+struct SignedValueT {};
+
+// RandU64ToDouble is the double-result variant of RandU64To, described above.
+template <typename Signed, bool IncludeZero, int ExponentBias = 0>
+inline double RandU64ToDouble(uint64_t bits) {
+ static_assert(std::is_same<Signed, PositiveValueT>::value ||
+ std::is_same<Signed, NegativeValueT>::value ||
+ std::is_same<Signed, SignedValueT>::value,
+ "");
+
+ // Maybe use the left-most bit for a sign bit.
+ uint64_t sign = std::is_same<Signed, NegativeValueT>::value
+ ? 0x8000000000000000ull
+ : 0; // Sign bits.
+
+ if (std::is_same<Signed, SignedValueT>::value) {
+ sign = bits & 0x8000000000000000ull;
+ bits = bits & 0x7FFFFFFFFFFFFFFFull;
+ }
+ if (IncludeZero) {
+ if (bits == 0u) return 0;
+ }
+
+ // Number of leading zeros is mapped to the exponent: 2^-clz
+ int clz = base_internal::CountLeadingZeros64(bits);
+ // Shift number left to erase leading zeros.
+ bits <<= IncludeZero ? clz : (clz & 63);
+
+ // Shift number right to remove bits that overflow double mantissa. The
+ // direction of the shift depends on `clz`.
+ bits >>= (64 - DBL_MANT_DIG);
+
+ // Compute IEEE 754 double exponent.
+ // In the Signed case, bits is a 63-bit number with a 0 msb. Adjust the
+ // exponent to account for that.
+ const uint64_t exp =
+ (std::is_same<Signed, SignedValueT>::value ? 1023U : 1022U) +
+ static_cast<uint64_t>(ExponentBias - clz);
+ constexpr int kExp = DBL_MANT_DIG - 1;
+ // Construct IEEE 754 double from exponent and mantissa.
+ const uint64_t val = sign | (exp << kExp) | (bits & ((1ULL << kExp) - 1U));
+
+ double res;
+ static_assert(sizeof(res) == sizeof(val), "double is not 64 bit");
+ // Memcpy value from "val" to "res" to avoid aliasing problems. Assumes that
+ // endian-ness is same for double and uint64_t.
+ std::memcpy(&res, &val, sizeof(res));
+
+ return res;
+}
+
+// RandU64ToFloat is the float-result variant of RandU64To, described above.
+template <typename Signed, bool IncludeZero, int ExponentBias = 0>
+inline float RandU64ToFloat(uint64_t bits) {
+ static_assert(std::is_same<Signed, PositiveValueT>::value ||
+ std::is_same<Signed, NegativeValueT>::value ||
+ std::is_same<Signed, SignedValueT>::value,
+ "");
+
+ // Maybe use the left-most bit for a sign bit.
+ uint64_t sign = std::is_same<Signed, NegativeValueT>::value
+ ? 0x80000000ul
+ : 0; // Sign bits.
+
+ if (std::is_same<Signed, SignedValueT>::value) {
+ uint64_t a = bits & 0x8000000000000000ull;
+ sign = static_cast<uint32_t>(a >> 32);
+ bits = bits & 0x7FFFFFFFFFFFFFFFull;
+ }
+ if (IncludeZero) {
+ if (bits == 0u) return 0;
+ }
+
+ // Number of leading zeros is mapped to the exponent: 2^-clz
+ int clz = base_internal::CountLeadingZeros64(bits);
+ // Shift number left to erase leading zeros.
+ bits <<= IncludeZero ? clz : (clz & 63);
+ // Shift number right to remove bits that overflow double mantissa. The
+ // direction of the shift depends on `clz`.
+ bits >>= (64 - FLT_MANT_DIG);
+
+ // Construct IEEE 754 float exponent.
+ // In the Signed case, bits is a 63-bit number with a 0 msb. Adjust the
+ // exponent to account for that.
+ const uint32_t exp =
+ (std::is_same<Signed, SignedValueT>::value ? 127U : 126U) +
+ static_cast<uint32_t>(ExponentBias - clz);
+ constexpr int kExp = FLT_MANT_DIG - 1;
+ const uint32_t val = sign | (exp << kExp) | (bits & ((1U << kExp) - 1U));
+
+ float res;
+ static_assert(sizeof(res) == sizeof(val), "float is not 32 bit");
+ // Assumes that endian-ness is same for float and uint32_t.
+ std::memcpy(&res, &val, sizeof(res));
+
+ return res;
+}
+
+template <typename Result>
+struct RandU64ToReal {
+ template <typename Signed, bool IncludeZero, int ExponentBias = 0>
+ static inline Result Value(uint64_t bits) {
+ return RandU64ToDouble<Signed, IncludeZero, ExponentBias>(bits);
+ }
+};
+
+template <>
+struct RandU64ToReal<float> {
+ template <typename Signed, bool IncludeZero, int ExponentBias = 0>
+ static inline float Value(uint64_t bits) {
+ return RandU64ToFloat<Signed, IncludeZero, ExponentBias>(bits);
+ }
+};
+
+inline uint128 MultiplyU64ToU128(uint64_t a, uint64_t b) {
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
+ return uint128(static_cast<__uint128_t>(a) * b);
+#elif defined(ABSL_INTERNAL_USE_UMUL128)
+ // uint64_t * uint64_t => uint128 multiply using imul intrinsic on MSVC.
+ uint64_t high = 0;
+ const uint64_t low = _umul128(a, b, &high);
+ return absl::MakeUint128(high, low);
+#else
+ // uint128(a) * uint128(b) in emulated mode computes a full 128-bit x 128-bit
+ // multiply. However there are many cases where that is not necessary, and it
+ // is only necessary to support a 64-bit x 64-bit = 128-bit multiply. This is
+ // for those cases.
+ const uint64_t a00 = static_cast<uint32_t>(a);
+ const uint64_t a32 = a >> 32;
+ const uint64_t b00 = static_cast<uint32_t>(b);
+ const uint64_t b32 = b >> 32;
+
+ const uint64_t c00 = a00 * b00;
+ const uint64_t c32a = a00 * b32;
+ const uint64_t c32b = a32 * b00;
+ const uint64_t c64 = a32 * b32;
+
+ const uint32_t carry =
+ static_cast<uint32_t>(((c00 >> 32) + static_cast<uint32_t>(c32a) +
+ static_cast<uint32_t>(c32b)) >>
+ 32);
+
+ return absl::MakeUint128(c64 + (c32a >> 32) + (c32b >> 32) + carry,
+ c00 + (c32a << 32) + (c32b << 32));
+#endif
+}
+
+// wide_multiply<T> multiplies two N-bit values to a 2N-bit result.
+template <typename UIntType>
+struct wide_multiply {
+ static constexpr size_t kN = std::numeric_limits<UIntType>::digits;
+ using input_type = UIntType;
+ using result_type = typename random_internal::unsigned_bits<kN * 2>::type;
+
+ static result_type multiply(input_type a, input_type b) {
+ return static_cast<result_type>(a) * b;
+ }
+
+ static input_type hi(result_type r) { return r >> kN; }
+ static input_type lo(result_type r) { return r; }
+
+ static_assert(std::is_unsigned<UIntType>::value,
+ "Class-template wide_multiply<> argument must be unsigned.");
+};
+
+#ifndef ABSL_HAVE_INTRINSIC_INT128
+template <>
+struct wide_multiply<uint64_t> {
+ using input_type = uint64_t;
+ using result_type = uint128;
+
+ static result_type multiply(uint64_t a, uint64_t b) {
+ return MultiplyU64ToU128(a, b);
+ }
+
+ static uint64_t hi(result_type r) { return Uint128High64(r); }
+ static uint64_t lo(result_type r) { return Uint128Low64(r); }
+};
+#endif
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_IMPL_H_
diff --git a/absl/random/internal/distribution_impl_test.cc b/absl/random/internal/distribution_impl_test.cc
new file mode 100644
index 00000000..09e7a318
--- /dev/null
+++ b/absl/random/internal/distribution_impl_test.cc
@@ -0,0 +1,506 @@
+// 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/distribution_impl.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/internal/bits.h"
+#include "absl/flags/flag.h"
+#include "absl/numeric/int128.h"
+
+ABSL_FLAG(int64_t, absl_random_test_trials, 50000,
+ "Number of trials for the probability tests.");
+
+using absl::random_internal::NegativeValueT;
+using absl::random_internal::PositiveValueT;
+using absl::random_internal::RandU64ToDouble;
+using absl::random_internal::RandU64ToFloat;
+using absl::random_internal::SignedValueT;
+
+namespace {
+
+TEST(DistributionImplTest, U64ToFloat_Positive_NoZero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<PositiveValueT, false>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 2.710505431e-20f);
+ EXPECT_EQ(ToFloat(0x0000000000000001), 5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloat_Positive_Zero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<PositiveValueT, true>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 0.0);
+ EXPECT_EQ(ToFloat(0x0000000000000001), 5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloat_Negative_NoZero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<NegativeValueT, false>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), -2.710505431e-20f);
+ EXPECT_EQ(ToFloat(0x0000000000000001), -5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloat_Signed_NoZero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<SignedValueT, false>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x0000000000000001), 1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0x7FFFFFFFFFFFFFFF), 0.9999999404f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), -5.421010862e-20f);
+ EXPECT_EQ(ToFloat(0x8000000000000001), -1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloat_Signed_Zero_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<SignedValueT, true>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 0);
+ EXPECT_EQ(ToFloat(0x0000000000000001), 1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0x7FFFFFFFFFFFFFFF), 0.9999999404f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), 0);
+ EXPECT_EQ(ToFloat(0x8000000000000001), -1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), -0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloat_Signed_Bias_Test) {
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<SignedValueT, true, 1>(a);
+ };
+ EXPECT_EQ(ToFloat(0x0000000000000000), 0);
+ EXPECT_EQ(ToFloat(0x0000000000000001), 2 * 1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0x7FFFFFFFFFFFFFFF), 2 * 0.9999999404f);
+ EXPECT_EQ(ToFloat(0x8000000000000000), 0);
+ EXPECT_EQ(ToFloat(0x8000000000000001), 2 * -1.084202172e-19f);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 2 * -0.9999999404f);
+}
+
+TEST(DistributionImplTest, U64ToFloatTest) {
+ auto ToFloat = [](uint64_t a) -> float {
+ return RandU64ToFloat<PositiveValueT, true>(a);
+ };
+
+ EXPECT_EQ(ToFloat(0x0000000000000000), 0.0f);
+
+ EXPECT_EQ(ToFloat(0x8000000000000000), 0.5f);
+ EXPECT_EQ(ToFloat(0x8000000000000001), 0.5f);
+ EXPECT_EQ(ToFloat(0x800000FFFFFFFFFF), 0.5f);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), 0.9999999404f);
+
+ EXPECT_GT(ToFloat(0x0000000000000001), 0.0f);
+
+ EXPECT_NE(ToFloat(0x7FFFFF0000000000), ToFloat(0x7FFFFEFFFFFFFFFF));
+
+ EXPECT_LT(ToFloat(0xFFFFFFFFFFFFFFFF), 1.0f);
+ int32_t two_to_24 = 1 << 24;
+ EXPECT_EQ(static_cast<int32_t>(ToFloat(0xFFFFFFFFFFFFFFFF) * two_to_24),
+ two_to_24 - 1);
+ EXPECT_NE(static_cast<int32_t>(ToFloat(0xFFFFFFFFFFFFFFFF) * two_to_24 * 2),
+ two_to_24 * 2 - 1);
+ EXPECT_EQ(ToFloat(0xFFFFFFFFFFFFFFFF), ToFloat(0xFFFFFF0000000000));
+ EXPECT_NE(ToFloat(0xFFFFFFFFFFFFFFFF), ToFloat(0xFFFFFEFFFFFFFFFF));
+ EXPECT_EQ(ToFloat(0x7FFFFFFFFFFFFFFF), ToFloat(0x7FFFFF8000000000));
+ EXPECT_NE(ToFloat(0x7FFFFFFFFFFFFFFF), ToFloat(0x7FFFFF7FFFFFFFFF));
+ EXPECT_EQ(ToFloat(0x3FFFFFFFFFFFFFFF), ToFloat(0x3FFFFFC000000000));
+ EXPECT_NE(ToFloat(0x3FFFFFFFFFFFFFFF), ToFloat(0x3FFFFFBFFFFFFFFF));
+
+ // For values where every bit counts, the values scale as multiples of the
+ // input.
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(i * ToFloat(0x0000000000000001), ToFloat(i));
+ }
+
+ // For each i: value generated from (1 << i).
+ float exp_values[64];
+ exp_values[63] = 0.5f;
+ for (int i = 62; i >= 0; --i) exp_values[i] = 0.5f * exp_values[i + 1];
+ constexpr uint64_t one = 1;
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_EQ(ToFloat(one << i), exp_values[i]);
+ for (int j = 1; j < FLT_MANT_DIG && i - j >= 0; ++j) {
+ EXPECT_NE(exp_values[i] + exp_values[i - j], exp_values[i]);
+ EXPECT_EQ(ToFloat((one << i) + (one << (i - j))),
+ exp_values[i] + exp_values[i - j]);
+ }
+ for (int j = FLT_MANT_DIG; i - j >= 0; ++j) {
+ EXPECT_EQ(exp_values[i] + exp_values[i - j], exp_values[i]);
+ EXPECT_EQ(ToFloat((one << i) + (one << (i - j))), exp_values[i]);
+ }
+ }
+}
+
+TEST(DistributionImplTest, U64ToDouble_Positive_NoZero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<PositiveValueT, false>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 2.710505431213761085e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000002), 1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), 0.999999999999999888978);
+}
+
+TEST(DistributionImplTest, U64ToDouble_Positive_Zero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<PositiveValueT, true>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x8000000000000000), 0.5);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), 0.999999999999999888978);
+}
+
+TEST(DistributionImplTest, U64ToDouble_Negative_NoZero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<NegativeValueT, false>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), -2.710505431213761085e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000001), -5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000002), -1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0x8000000000000000), -0.5);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
+}
+
+TEST(DistributionImplTest, U64ToDouble_Signed_NoZero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<SignedValueT, false>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFF), 0.999999999999999888978);
+ EXPECT_EQ(ToDouble(0x8000000000000000), -5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
+}
+
+TEST(DistributionImplTest, U64ToDouble_Signed_Zero_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<SignedValueT, true>(a);
+ };
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFF), 0.999999999999999888978);
+ EXPECT_EQ(ToDouble(0x8000000000000000), 0);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -1.084202172485504434e-19);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978);
+}
+
+TEST(DistributionImplTest, U64ToDouble_Signed_Bias_Test) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<SignedValueT, true, -1>(a);
+ };
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19 / 2);
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFF), 0.999999999999999888978 / 2);
+ EXPECT_EQ(ToDouble(0x8000000000000000), 0);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -1.084202172485504434e-19 / 2);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), -0.999999999999999888978 / 2);
+}
+
+TEST(DistributionImplTest, U64ToDoubleTest) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<PositiveValueT, true>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
+ EXPECT_EQ(ToDouble(0x0000000000000000), 0.0);
+
+ EXPECT_EQ(ToDouble(0x0000000000000001), 5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x7fffffffffffffef), 0.499999999999999944489);
+ EXPECT_EQ(ToDouble(0x8000000000000000), 0.5);
+
+ // For values > 0.5, RandU64ToDouble discards up to 11 bits. (64-53).
+ EXPECT_EQ(ToDouble(0x8000000000000001), 0.5);
+ EXPECT_EQ(ToDouble(0x80000000000007FF), 0.5);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), 0.999999999999999888978);
+ EXPECT_NE(ToDouble(0x7FFFFFFFFFFFF800), ToDouble(0x7FFFFFFFFFFFF7FF));
+
+ EXPECT_LT(ToDouble(0xFFFFFFFFFFFFFFFF), 1.0);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFF), ToDouble(0xFFFFFFFFFFFFF800));
+ EXPECT_NE(ToDouble(0xFFFFFFFFFFFFFFFF), ToDouble(0xFFFFFFFFFFFFF7FF));
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFF), ToDouble(0x7FFFFFFFFFFFFC00));
+ EXPECT_NE(ToDouble(0x7FFFFFFFFFFFFFFF), ToDouble(0x7FFFFFFFFFFFFBFF));
+ EXPECT_EQ(ToDouble(0x3FFFFFFFFFFFFFFF), ToDouble(0x3FFFFFFFFFFFFE00));
+ EXPECT_NE(ToDouble(0x3FFFFFFFFFFFFFFF), ToDouble(0x3FFFFFFFFFFFFDFF));
+
+ EXPECT_EQ(ToDouble(0x1000000000000001), 0.0625);
+ EXPECT_EQ(ToDouble(0x2000000000000001), 0.125);
+ EXPECT_EQ(ToDouble(0x3000000000000001), 0.1875);
+ EXPECT_EQ(ToDouble(0x4000000000000001), 0.25);
+ EXPECT_EQ(ToDouble(0x5000000000000001), 0.3125);
+ EXPECT_EQ(ToDouble(0x6000000000000001), 0.375);
+ EXPECT_EQ(ToDouble(0x7000000000000001), 0.4375);
+ EXPECT_EQ(ToDouble(0x8000000000000001), 0.5);
+ EXPECT_EQ(ToDouble(0x9000000000000001), 0.5625);
+ EXPECT_EQ(ToDouble(0xa000000000000001), 0.625);
+ EXPECT_EQ(ToDouble(0xb000000000000001), 0.6875);
+ EXPECT_EQ(ToDouble(0xc000000000000001), 0.75);
+ EXPECT_EQ(ToDouble(0xd000000000000001), 0.8125);
+ EXPECT_EQ(ToDouble(0xe000000000000001), 0.875);
+ EXPECT_EQ(ToDouble(0xf000000000000001), 0.9375);
+
+ // Large powers of 2.
+ int64_t two_to_53 = int64_t{1} << 53;
+ EXPECT_EQ(static_cast<int64_t>(ToDouble(0xFFFFFFFFFFFFFFFF) * two_to_53),
+ two_to_53 - 1);
+ EXPECT_NE(static_cast<int64_t>(ToDouble(0xFFFFFFFFFFFFFFFF) * two_to_53 * 2),
+ two_to_53 * 2 - 1);
+
+ // For values where every bit counts, the values scale as multiples of the
+ // input.
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_EQ(i * ToDouble(0x0000000000000001), ToDouble(i));
+ }
+
+ // For each i: value generated from (1 << i).
+ double exp_values[64];
+ exp_values[63] = 0.5;
+ for (int i = 62; i >= 0; --i) exp_values[i] = 0.5 * exp_values[i + 1];
+ constexpr uint64_t one = 1;
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_EQ(ToDouble(one << i), exp_values[i]);
+ for (int j = 1; j < DBL_MANT_DIG && i - j >= 0; ++j) {
+ EXPECT_NE(exp_values[i] + exp_values[i - j], exp_values[i]);
+ EXPECT_EQ(ToDouble((one << i) + (one << (i - j))),
+ exp_values[i] + exp_values[i - j]);
+ }
+ for (int j = DBL_MANT_DIG; i - j >= 0; ++j) {
+ EXPECT_EQ(exp_values[i] + exp_values[i - j], exp_values[i]);
+ EXPECT_EQ(ToDouble((one << i) + (one << (i - j))), exp_values[i]);
+ }
+ }
+}
+
+TEST(DistributionImplTest, U64ToDoubleSignedTest) {
+ auto ToDouble = [](uint64_t a) {
+ return RandU64ToDouble<SignedValueT, false>(a);
+ };
+
+ EXPECT_EQ(ToDouble(0x0000000000000000), 5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x0000000000000001), 1.084202172485504434e-19);
+
+ EXPECT_EQ(ToDouble(0x8000000000000000), -5.42101086242752217004e-20);
+ EXPECT_EQ(ToDouble(0x8000000000000001), -1.084202172485504434e-19);
+
+ const double e_plus = ToDouble(0x0000000000000001);
+ const double e_minus = ToDouble(0x8000000000000001);
+ EXPECT_EQ(e_plus, 1.084202172485504434e-19);
+ EXPECT_EQ(e_minus, -1.084202172485504434e-19);
+
+ EXPECT_EQ(ToDouble(0x3fffffffffffffef), 0.499999999999999944489);
+ EXPECT_EQ(ToDouble(0xbfffffffffffffef), -0.499999999999999944489);
+
+ // For values > 0.5, RandU64ToDouble discards up to 10 bits. (63-53).
+ EXPECT_EQ(ToDouble(0x4000000000000000), 0.5);
+ EXPECT_EQ(ToDouble(0x4000000000000001), 0.5);
+ EXPECT_EQ(ToDouble(0x40000000000003FF), 0.5);
+
+ EXPECT_EQ(ToDouble(0xC000000000000000), -0.5);
+ EXPECT_EQ(ToDouble(0xC000000000000001), -0.5);
+ EXPECT_EQ(ToDouble(0xC0000000000003FF), -0.5);
+
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFe), 0.999999999999999888978);
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFe), -0.999999999999999888978);
+
+ EXPECT_NE(ToDouble(0x7FFFFFFFFFFFF800), ToDouble(0x7FFFFFFFFFFFF7FF));
+
+ EXPECT_LT(ToDouble(0x7FFFFFFFFFFFFFFF), 1.0);
+ EXPECT_GT(ToDouble(0x7FFFFFFFFFFFFFFF), 0.9999999999);
+
+ EXPECT_GT(ToDouble(0xFFFFFFFFFFFFFFFe), -1.0);
+ EXPECT_LT(ToDouble(0xFFFFFFFFFFFFFFFe), -0.999999999);
+
+ EXPECT_EQ(ToDouble(0xFFFFFFFFFFFFFFFe), ToDouble(0xFFFFFFFFFFFFFC00));
+ EXPECT_EQ(ToDouble(0x7FFFFFFFFFFFFFFF), ToDouble(0x7FFFFFFFFFFFFC00));
+ EXPECT_NE(ToDouble(0xFFFFFFFFFFFFFFFe), ToDouble(0xFFFFFFFFFFFFF3FF));
+ EXPECT_NE(ToDouble(0x7FFFFFFFFFFFFFFF), ToDouble(0x7FFFFFFFFFFFF3FF));
+
+ EXPECT_EQ(ToDouble(0x1000000000000001), 0.125);
+ EXPECT_EQ(ToDouble(0x2000000000000001), 0.25);
+ EXPECT_EQ(ToDouble(0x3000000000000001), 0.375);
+ EXPECT_EQ(ToDouble(0x4000000000000001), 0.5);
+ EXPECT_EQ(ToDouble(0x5000000000000001), 0.625);
+ EXPECT_EQ(ToDouble(0x6000000000000001), 0.75);
+ EXPECT_EQ(ToDouble(0x7000000000000001), 0.875);
+ EXPECT_EQ(ToDouble(0x7800000000000001), 0.9375);
+ EXPECT_EQ(ToDouble(0x7c00000000000001), 0.96875);
+ EXPECT_EQ(ToDouble(0x7e00000000000001), 0.984375);
+ EXPECT_EQ(ToDouble(0x7f00000000000001), 0.9921875);
+
+ // 0x8000000000000000 ~= 0
+ EXPECT_EQ(ToDouble(0x9000000000000001), -0.125);
+ EXPECT_EQ(ToDouble(0xa000000000000001), -0.25);
+ EXPECT_EQ(ToDouble(0xb000000000000001), -0.375);
+ EXPECT_EQ(ToDouble(0xc000000000000001), -0.5);
+ EXPECT_EQ(ToDouble(0xd000000000000001), -0.625);
+ EXPECT_EQ(ToDouble(0xe000000000000001), -0.75);
+ EXPECT_EQ(ToDouble(0xf000000000000001), -0.875);
+
+ // Large powers of 2.
+ int64_t two_to_53 = int64_t{1} << 53;
+ EXPECT_EQ(static_cast<int64_t>(ToDouble(0x7FFFFFFFFFFFFFFF) * two_to_53),
+ two_to_53 - 1);
+ EXPECT_EQ(static_cast<int64_t>(ToDouble(0xFFFFFFFFFFFFFFFF) * two_to_53),
+ -(two_to_53 - 1));
+
+ EXPECT_NE(static_cast<int64_t>(ToDouble(0x7FFFFFFFFFFFFFFF) * two_to_53 * 2),
+ two_to_53 * 2 - 1);
+
+ // For values where every bit counts, the values scale as multiples of the
+ // input.
+ for (int i = 1; i < 100; ++i) {
+ EXPECT_EQ(i * e_plus, ToDouble(i)) << i;
+ EXPECT_EQ(i * e_minus, ToDouble(0x8000000000000000 | i)) << i;
+ }
+}
+
+TEST(DistributionImplTest, ExhaustiveFloat) {
+ using absl::base_internal::CountLeadingZeros64;
+ auto ToFloat = [](uint64_t a) {
+ return RandU64ToFloat<PositiveValueT, true>(a);
+ };
+
+ // Rely on RandU64ToFloat generating values from greatest to least when
+ // supplied with uint64_t values from greatest (0xfff...) to least (0x0). Thus,
+ // this algorithm stores the previous value, and if the new value is at
+ // greater than or equal to the previous value, then there is a collision in
+ // the generation algorithm.
+ //
+ // Use the computation below to convert the random value into a result:
+ // double res = a() * (1.0f - sample) + b() * sample;
+ float last_f = 1.0, last_g = 2.0;
+ uint64_t f_collisions = 0, g_collisions = 0;
+ uint64_t f_unique = 0, g_unique = 0;
+ uint64_t total = 0;
+ auto count = [&](const float r) {
+ total++;
+ // `f` is mapped to the range [0, 1) (default)
+ const float f = 0.0f * (1.0f - r) + 1.0f * r;
+ if (f >= last_f) {
+ f_collisions++;
+ } else {
+ f_unique++;
+ last_f = f;
+ }
+ // `g` is mapped to the range [1, 2)
+ const float g = 1.0f * (1.0f - r) + 2.0f * r;
+ if (g >= last_g) {
+ g_collisions++;
+ } else {
+ g_unique++;
+ last_g = g;
+ }
+ };
+
+ size_t limit = absl::GetFlag(FLAGS_absl_random_test_trials);
+
+ // Generate all uint64_t which have unique floating point values.
+ // Counting down from 0xFFFFFFFFFFFFFFFFu ... 0x0u
+ uint64_t x = ~uint64_t(0);
+ for (; x != 0 && limit > 0;) {
+ constexpr int kDig = (64 - FLT_MANT_DIG);
+ // Set a decrement value & the next point at which to change
+ // the decrement value. By default these are 1, 0.
+ uint64_t dec = 1;
+ uint64_t chk = 0;
+
+ // Adjust decrement and check value based on how many leading 0
+ // bits are set in the current value.
+ const int clz = CountLeadingZeros64(x);
+ if (clz < kDig) {
+ dec <<= (kDig - clz);
+ chk = (~uint64_t(0)) >> (clz + 1);
+ }
+ for (; x > chk && limit > 0; x -= dec) {
+ count(ToFloat(x));
+ --limit;
+ }
+ }
+
+ static_assert(FLT_MANT_DIG == 24,
+ "The float type is expected to have a 24 bit mantissa.");
+
+ if (limit != 0) {
+ // There are between 2^28 and 2^29 unique values in the range [0, 1). For
+ // the low values of x, there are 2^24 -1 unique values. Once x > 2^24,
+ // there are 40 * 2^24 unique values. Thus:
+ // (2 + 4 + 8 ... + 2^23) + 40 * 2^23
+ EXPECT_LT(1 << 28, f_unique);
+ EXPECT_EQ((1 << 24) + 40 * (1 << 23) - 1, f_unique);
+ EXPECT_EQ(total, f_unique);
+ EXPECT_EQ(0, f_collisions);
+
+ // Expect at least 2^23 unique values for the range [1, 2)
+ EXPECT_LE(1 << 23, g_unique);
+ EXPECT_EQ(total - g_unique, g_collisions);
+ }
+}
+
+TEST(DistributionImplTest, MultiplyU64ToU128Test) {
+ using absl::random_internal::MultiplyU64ToU128;
+ constexpr uint64_t k1 = 1;
+ constexpr uint64_t kMax = ~static_cast<uint64_t>(0);
+
+ EXPECT_EQ(absl::uint128(0), MultiplyU64ToU128(0, 0));
+
+ // Max uint64
+ EXPECT_EQ(MultiplyU64ToU128(kMax, kMax),
+ absl::MakeUint128(0xfffffffffffffffe, 0x0000000000000001));
+ EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(kMax, 1));
+ EXPECT_EQ(absl::MakeUint128(0, kMax), MultiplyU64ToU128(1, kMax));
+ for (int i = 0; i < 64; ++i) {
+ EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
+ MultiplyU64ToU128(kMax, k1 << i));
+ EXPECT_EQ(absl::MakeUint128(0, kMax) << i,
+ MultiplyU64ToU128(k1 << i, kMax));
+ }
+
+ // 1-bit x 1-bit.
+ for (int i = 0; i < 64; ++i) {
+ for (int j = 0; j < 64; ++j) {
+ EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
+ MultiplyU64ToU128(k1 << i, k1 << j));
+ EXPECT_EQ(absl::MakeUint128(0, 1) << (i + j),
+ MultiplyU64ToU128(k1 << i, k1 << j));
+ }
+ }
+
+ // Verified multiplies
+ EXPECT_EQ(MultiplyU64ToU128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888),
+ absl::MakeUint128(0xbbbb9e2692c5dddc, 0xc28f7531048d2c60));
+ EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfedcba9876543210),
+ absl::MakeUint128(0x0121fa00ad77d742, 0x2236d88fe5618cf0));
+ EXPECT_EQ(MultiplyU64ToU128(0x0123456789abcdef, 0xfdb97531eca86420),
+ absl::MakeUint128(0x0120ae99d26725fc, 0xce197f0ecac319e0));
+ EXPECT_EQ(MultiplyU64ToU128(0x97a87f4f261ba3f2, 0xfedcba9876543210),
+ absl::MakeUint128(0x96fbf1a8ae78d0ba, 0x5a6dd4b71f278320));
+ EXPECT_EQ(MultiplyU64ToU128(0xfedcba9876543210, 0xfdb97531eca86420),
+ absl::MakeUint128(0xfc98c6981a413e22, 0x342d0bbf48948200));
+}
+
+} // namespace
diff --git a/absl/random/internal/distribution_test_util.cc b/absl/random/internal/distribution_test_util.cc
new file mode 100644
index 00000000..4fb4149d
--- /dev/null
+++ b/absl/random/internal/distribution_test_util.cc
@@ -0,0 +1,418 @@
+// 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/distribution_test_util.h"
+
+#include <cassert>
+#include <cmath>
+#include <string>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+#if defined(__EMSCRIPTEN__)
+// Workaround __EMSCRIPTEN__ error: llvm_fma_f64 not found.
+inline double fma(double x, double y, double z) { return (x * y) + z; }
+#endif
+
+} // namespace
+
+DistributionMoments ComputeDistributionMoments(
+ absl::Span<const double> data_points) {
+ DistributionMoments result;
+
+ // Compute m1
+ for (double x : data_points) {
+ result.n++;
+ result.mean += x;
+ }
+ result.mean /= static_cast<double>(result.n);
+
+ // Compute m2, m3, m4
+ for (double x : data_points) {
+ double v = x - result.mean;
+ result.variance += v * v;
+ result.skewness += v * v * v;
+ result.kurtosis += v * v * v * v;
+ }
+ result.variance /= static_cast<double>(result.n - 1);
+
+ result.skewness /= static_cast<double>(result.n);
+ result.skewness /= std::pow(result.variance, 1.5);
+
+ result.kurtosis /= static_cast<double>(result.n);
+ result.kurtosis /= std::pow(result.variance, 2.0);
+ return result;
+
+ // When validating the min/max count, the following confidence intervals may
+ // be of use:
+ // 3.291 * stddev = 99.9% CI
+ // 2.576 * stddev = 99% CI
+ // 1.96 * stddev = 95% CI
+ // 1.65 * stddev = 90% CI
+}
+
+std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments) {
+ return os << absl::StrFormat("mean=%f, stddev=%f, skewness=%f, kurtosis=%f",
+ moments.mean, std::sqrt(moments.variance),
+ moments.skewness, moments.kurtosis);
+}
+
+double InverseNormalSurvival(double x) {
+ // inv_sf(u) = -sqrt(2) * erfinv(2u-1)
+ static constexpr double kSqrt2 = 1.4142135623730950488;
+ return -kSqrt2 * absl::random_internal::erfinv(2 * x - 1.0);
+}
+
+bool Near(absl::string_view msg, double actual, double expected, double bound) {
+ assert(bound > 0.0);
+ double delta = fabs(expected - actual);
+ if (delta < bound) {
+ return true;
+ }
+
+ std::string formatted = absl::StrCat(
+ msg, " actual=", actual, " expected=", expected, " err=", delta / bound);
+ ABSL_RAW_LOG(INFO, "%s", formatted.c_str());
+ return false;
+}
+
+// TODO(absl-team): Replace with an "ABSL_HAVE_SPECIAL_MATH" and try
+// to use std::beta(). As of this writing P0226R1 is not implemented
+// in libc++: http://libcxx.llvm.org/cxx1z_status.html
+double beta(double p, double q) {
+ // Beta(x, y) = Gamma(x) * Gamma(y) / Gamma(x+y)
+ double lbeta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q);
+ return std::exp(lbeta);
+}
+
+// Approximation to inverse of the Error Function in double precision.
+// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf)
+double erfinv(double x) {
+#if !defined(__EMSCRIPTEN__)
+ using std::fma;
+#endif
+
+ double w = 0.0;
+ double p = 0.0;
+ w = -std::log((1.0 - x) * (1.0 + x));
+ if (w < 6.250000) {
+ w = w - 3.125000;
+ p = -3.6444120640178196996e-21;
+ p = fma(p, w, -1.685059138182016589e-19);
+ p = fma(p, w, 1.2858480715256400167e-18);
+ p = fma(p, w, 1.115787767802518096e-17);
+ p = fma(p, w, -1.333171662854620906e-16);
+ p = fma(p, w, 2.0972767875968561637e-17);
+ p = fma(p, w, 6.6376381343583238325e-15);
+ p = fma(p, w, -4.0545662729752068639e-14);
+ p = fma(p, w, -8.1519341976054721522e-14);
+ p = fma(p, w, 2.6335093153082322977e-12);
+ p = fma(p, w, -1.2975133253453532498e-11);
+ p = fma(p, w, -5.4154120542946279317e-11);
+ p = fma(p, w, 1.051212273321532285e-09);
+ p = fma(p, w, -4.1126339803469836976e-09);
+ p = fma(p, w, -2.9070369957882005086e-08);
+ p = fma(p, w, 4.2347877827932403518e-07);
+ p = fma(p, w, -1.3654692000834678645e-06);
+ p = fma(p, w, -1.3882523362786468719e-05);
+ p = fma(p, w, 0.0001867342080340571352);
+ p = fma(p, w, -0.00074070253416626697512);
+ p = fma(p, w, -0.0060336708714301490533);
+ p = fma(p, w, 0.24015818242558961693);
+ p = fma(p, w, 1.6536545626831027356);
+ } else if (w < 16.000000) {
+ w = std::sqrt(w) - 3.250000;
+ p = 2.2137376921775787049e-09;
+ p = fma(p, w, 9.0756561938885390979e-08);
+ p = fma(p, w, -2.7517406297064545428e-07);
+ p = fma(p, w, 1.8239629214389227755e-08);
+ p = fma(p, w, 1.5027403968909827627e-06);
+ p = fma(p, w, -4.013867526981545969e-06);
+ p = fma(p, w, 2.9234449089955446044e-06);
+ p = fma(p, w, 1.2475304481671778723e-05);
+ p = fma(p, w, -4.7318229009055733981e-05);
+ p = fma(p, w, 6.8284851459573175448e-05);
+ p = fma(p, w, 2.4031110387097893999e-05);
+ p = fma(p, w, -0.0003550375203628474796);
+ p = fma(p, w, 0.00095328937973738049703);
+ p = fma(p, w, -0.0016882755560235047313);
+ p = fma(p, w, 0.0024914420961078508066);
+ p = fma(p, w, -0.0037512085075692412107);
+ p = fma(p, w, 0.005370914553590063617);
+ p = fma(p, w, 1.0052589676941592334);
+ p = fma(p, w, 3.0838856104922207635);
+ } else {
+ w = std::sqrt(w) - 5.000000;
+ p = -2.7109920616438573243e-11;
+ p = fma(p, w, -2.5556418169965252055e-10);
+ p = fma(p, w, 1.5076572693500548083e-09);
+ p = fma(p, w, -3.7894654401267369937e-09);
+ p = fma(p, w, 7.6157012080783393804e-09);
+ p = fma(p, w, -1.4960026627149240478e-08);
+ p = fma(p, w, 2.9147953450901080826e-08);
+ p = fma(p, w, -6.7711997758452339498e-08);
+ p = fma(p, w, 2.2900482228026654717e-07);
+ p = fma(p, w, -9.9298272942317002539e-07);
+ p = fma(p, w, 4.5260625972231537039e-06);
+ p = fma(p, w, -1.9681778105531670567e-05);
+ p = fma(p, w, 7.5995277030017761139e-05);
+ p = fma(p, w, -0.00021503011930044477347);
+ p = fma(p, w, -0.00013871931833623122026);
+ p = fma(p, w, 1.0103004648645343977);
+ p = fma(p, w, 4.8499064014085844221);
+ }
+ return p * x;
+}
+
+namespace {
+
+// Direct implementation of AS63, BETAIN()
+// https://www.jstor.org/stable/2346797?seq=3#page_scan_tab_contents.
+//
+// BETAIN(x, p, q, beta)
+// x: the value of the upper limit x.
+// p: the value of the parameter p.
+// q: the value of the parameter q.
+// beta: the value of ln B(p, q)
+//
+double BetaIncompleteImpl(const double x, const double p, const double q,
+ const double beta) {
+ if (p < (p + q) * x) {
+ // Incomplete beta function is symmetrical, so return the complement.
+ return 1. - BetaIncompleteImpl(1.0 - x, q, p, beta);
+ }
+
+ double psq = p + q;
+ const double kErr = 1e-14;
+ const double xc = 1. - x;
+ const double pre =
+ std::exp(p * std::log(x) + (q - 1.) * std::log(xc) - beta) / p;
+
+ double term = 1.;
+ double ai = 1.;
+ double result = 1.;
+ int ns = static_cast<int>(q + xc * psq);
+
+ // Use the soper reduction forumla.
+ double rx = (ns == 0) ? x : x / xc;
+ double temp = q - ai;
+ for (;;) {
+ term = term * temp * rx / (p + ai);
+ result = result + term;
+ temp = std::fabs(term);
+ if (temp < kErr && temp < kErr * result) {
+ return result * pre;
+ }
+ ai = ai + 1.;
+ --ns;
+ if (ns >= 0) {
+ temp = q - ai;
+ if (ns == 0) {
+ rx = x;
+ }
+ } else {
+ temp = psq;
+ psq = psq + 1.;
+ }
+ }
+
+ // NOTE: See also TOMS Alogrithm 708.
+ // http://www.netlib.org/toms/index.html
+ //
+ // NOTE: The NWSC library also includes BRATIO / ISUBX (p87)
+ // https://archive.org/details/DTIC_ADA261511/page/n75
+}
+
+// Direct implementation of AS109, XINBTA(p, q, beta, alpha)
+// https://www.jstor.org/stable/2346798?read-now=1&seq=4#page_scan_tab_contents
+// https://www.jstor.org/stable/2346887?seq=1#page_scan_tab_contents
+//
+// XINBTA(p, q, beta, alhpa)
+// p: the value of the parameter p.
+// q: the value of the parameter q.
+// beta: the value of ln B(p, q)
+// alpha: the value of the lower tail area.
+//
+double BetaIncompleteInvImpl(const double p, const double q, const double beta,
+ const double alpha) {
+ if (alpha < 0.5) {
+ // Inverse Incomplete beta function is symmetrical, return the complement.
+ return 1. - BetaIncompleteInvImpl(q, p, beta, 1. - alpha);
+ }
+ const double kErr = 1e-14;
+ double value = kErr;
+
+ // Compute the initial estimate.
+ {
+ double r = std::sqrt(-std::log(alpha * alpha));
+ double y =
+ r - fma(r, 0.27061, 2.30753) / fma(r, fma(r, 0.04481, 0.99229), 1.0);
+ if (p > 1. && q > 1.) {
+ r = (y * y - 3.) / 6.;
+ double s = 1. / (p + p - 1.);
+ double t = 1. / (q + q - 1.);
+ double h = 2. / s + t;
+ double w =
+ y * std::sqrt(h + r) / h - (t - s) * (r + 5. / 6. - t / (3. * h));
+ value = p / (p + q * std::exp(w + w));
+ } else {
+ r = q + q;
+ double t = 1.0 / (9. * q);
+ double u = 1.0 - t + y * std::sqrt(t);
+ t = r * (u * u * u);
+ if (t <= 0) {
+ value = 1.0 - std::exp((std::log((1.0 - alpha) * q) + beta) / q);
+ } else {
+ t = (4.0 * p + r - 2.0) / t;
+ if (t <= 1) {
+ value = std::exp((std::log(alpha * p) + beta) / p);
+ } else {
+ value = 1.0 - 2.0 / (t + 1.0);
+ }
+ }
+ }
+ }
+
+ // Solve for x using a modified newton-raphson method using the function
+ // BetaIncomplete.
+ {
+ value = std::max(value, kErr);
+ value = std::min(value, 1.0 - kErr);
+
+ const double r = 1.0 - p;
+ const double t = 1.0 - q;
+ double y;
+ double yprev = 0;
+ double sq = 1;
+ double prev = 1;
+ for (;;) {
+ if (value < 0 || value > 1.0) {
+ // Error case; value went infinite.
+ return std::numeric_limits<double>::infinity();
+ } else if (value == 0 || value == 1) {
+ y = value;
+ } else {
+ y = BetaIncompleteImpl(value, p, q, beta);
+ if (!std::isfinite(y)) {
+ return y;
+ }
+ }
+ y = (y - alpha) *
+ std::exp(beta + r * std::log(value) + t * std::log(1.0 - value));
+ if (y * yprev <= 0) {
+ prev = std::max(sq, std::numeric_limits<double>::min());
+ }
+ double g = 1.0;
+ for (;;) {
+ const double adj = g * y;
+ const double adj_sq = adj * adj;
+ if (adj_sq >= prev) {
+ g = g / 3.0;
+ continue;
+ }
+ const double tx = value - adj;
+ if (tx < 0 || tx > 1) {
+ g = g / 3.0;
+ continue;
+ }
+ if (prev < kErr) {
+ return value;
+ }
+ if (y * y < kErr) {
+ return value;
+ }
+ if (tx == value) {
+ return value;
+ }
+ if (tx == 0 || tx == 1) {
+ g = g / 3.0;
+ continue;
+ }
+ value = tx;
+ yprev = y;
+ break;
+ }
+ }
+ }
+
+ // NOTES: See also: Asymptotic inversion of the incomplete beta function.
+ // https://core.ac.uk/download/pdf/82140723.pdf
+ //
+ // NOTE: See the Boost library documentation as well:
+ // https://www.boost.org/doc/libs/1_52_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/sf_beta/ibeta_function.html
+}
+
+} // namespace
+
+double BetaIncomplete(const double x, const double p, const double q) {
+ // Error cases.
+ if (p < 0 || q < 0 || x < 0 || x > 1.0) {
+ return std::numeric_limits<double>::infinity();
+ }
+ if (x == 0 || x == 1) {
+ return x;
+ }
+ // ln(Beta(p, q))
+ double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q);
+ return BetaIncompleteImpl(x, p, q, beta);
+}
+
+double BetaIncompleteInv(const double p, const double q, const double alpha) {
+ // Error cases.
+ if (p < 0 || q < 0 || alpha < 0 || alpha > 1.0) {
+ return std::numeric_limits<double>::infinity();
+ }
+ if (alpha == 0 || alpha == 1) {
+ return alpha;
+ }
+ // ln(Beta(p, q))
+ double beta = std::lgamma(p) + std::lgamma(q) - std::lgamma(p + q);
+ return BetaIncompleteInvImpl(p, q, beta, alpha);
+}
+
+// Given `num_trials` trials each with probability `p` of success, the
+// probability of no failures is `p^k`. To ensure the probability of a failure
+// is no more than `p_fail`, it must be that `p^k == 1 - p_fail`. This function
+// computes `p` from that equation.
+double RequiredSuccessProbability(const double p_fail, const int num_trials) {
+ double p = std::exp(std::log(1.0 - p_fail) / static_cast<double>(num_trials));
+ ABSL_ASSERT(p > 0);
+ return p;
+}
+
+double ZScore(double expected_mean, const DistributionMoments& moments) {
+ return (moments.mean - expected_mean) /
+ (std::sqrt(moments.variance) /
+ std::sqrt(static_cast<double>(moments.n)));
+}
+
+double MaxErrorTolerance(double acceptance_probability) {
+ double one_sided_pvalue = 0.5 * (1.0 - acceptance_probability);
+ const double max_err = InverseNormalSurvival(one_sided_pvalue);
+ ABSL_ASSERT(max_err > 0);
+ return max_err;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/distribution_test_util.h b/absl/random/internal/distribution_test_util.h
new file mode 100644
index 00000000..56dc86ac
--- /dev/null
+++ b/absl/random/internal/distribution_test_util.h
@@ -0,0 +1,113 @@
+// 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_DISTRIBUTION_TEST_UTIL_H_
+#define ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_
+
+#include <cstddef>
+#include <iostream>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+
+// NOTE: The functions in this file are test only, and are should not be used in
+// non-test code.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// http://webspace.ship.edu/pgmarr/Geo441/Lectures/Lec%205%20-%20Normality%20Testing.pdf
+
+// Compute the 1st to 4th standard moments:
+// mean, variance, skewness, and kurtosis.
+// http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
+struct DistributionMoments {
+ size_t n = 0;
+ double mean = 0.0;
+ double variance = 0.0;
+ double skewness = 0.0;
+ double kurtosis = 0.0;
+};
+DistributionMoments ComputeDistributionMoments(
+ absl::Span<const double> data_points);
+
+std::ostream& operator<<(std::ostream& os, const DistributionMoments& moments);
+
+// Computes the Z-score for a set of data with the given distribution moments
+// compared against `expected_mean`.
+double ZScore(double expected_mean, const DistributionMoments& moments);
+
+// Returns the probability of success required for a single trial to ensure that
+// after `num_trials` trials, the probability of at least one failure is no more
+// than `p_fail`.
+double RequiredSuccessProbability(double p_fail, int num_trials);
+
+// Computes the maximum distance from the mean tolerable, for Z-Tests that are
+// expected to pass with `acceptance_probability`. Will terminate if the
+// resulting tolerance is zero (due to passing in 0.0 for
+// `acceptance_probability` or rounding errors).
+//
+// For example,
+// MaxErrorTolerance(0.001) = 0.0
+// MaxErrorTolerance(0.5) = ~0.47
+// MaxErrorTolerance(1.0) = inf
+double MaxErrorTolerance(double acceptance_probability);
+
+// Approximation to inverse of the Error Function in double precision.
+// (http://people.maths.ox.ac.uk/gilesm/files/gems_erfinv.pdf)
+double erfinv(double x);
+
+// Beta(p, q) = Gamma(p) * Gamma(q) / Gamma(p+q)
+double beta(double p, double q);
+
+// The inverse of the normal survival function.
+double InverseNormalSurvival(double x);
+
+// Returns whether actual is "near" expected, based on the bound.
+bool Near(absl::string_view msg, double actual, double expected, double bound);
+
+// Implements the incomplete regularized beta function, AS63, BETAIN.
+// https://www.jstor.org/stable/2346797
+//
+// BetaIncomplete(x, p, q), where
+// `x` is the value of the upper limit
+// `p` is beta parameter p, `q` is beta parameter q.
+//
+// NOTE: This is a test-only function which is only accurate to within, at most,
+// 1e-13 of the actual value.
+//
+double BetaIncomplete(double x, double p, double q);
+
+// Implements the inverse of the incomplete regularized beta function, AS109,
+// XINBTA.
+// https://www.jstor.org/stable/2346798
+// https://www.jstor.org/stable/2346887
+//
+// BetaIncompleteInv(p, q, beta, alhpa)
+// `p` is beta parameter p, `q` is beta parameter q.
+// `alpha` is the value of the lower tail area.
+//
+// NOTE: This is a test-only function and, when successful, is only accurate to
+// within ~1e-6 of the actual value; there are some cases where it diverges from
+// the actual value by much more than that. The function uses Newton's method,
+// and thus the runtime is highly variable.
+double BetaIncompleteInv(double p, double q, double alpha);
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTION_TEST_UTIL_H_
diff --git a/absl/random/internal/distribution_test_util_test.cc b/absl/random/internal/distribution_test_util_test.cc
new file mode 100644
index 00000000..c49d44fb
--- /dev/null
+++ b/absl/random/internal/distribution_test_util_test.cc
@@ -0,0 +1,193 @@
+// 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/distribution_test_util.h"
+
+#include "gtest/gtest.h"
+
+namespace {
+
+TEST(TestUtil, InverseErf) {
+ const struct {
+ const double z;
+ const double value;
+ } kErfInvTable[] = {
+ {0.0000001, 8.86227e-8},
+ {0.00001, 8.86227e-6},
+ {0.5, 0.4769362762044},
+ {0.6, 0.5951160814499},
+ {0.99999, 3.1234132743},
+ {0.9999999, 3.7665625816},
+ {0.999999944, 3.8403850690566985}, // = log((1-x) * (1+x)) =~ 16.004
+ {0.999999999, 4.3200053849134452},
+ };
+
+ for (const auto& data : kErfInvTable) {
+ auto value = absl::random_internal::erfinv(data.z);
+
+ // Log using the Wolfram-alpha function name & parameters.
+ EXPECT_NEAR(value, data.value, 1e-8)
+ << " InverseErf[" << data.z << "] (expected=" << data.value << ") -> "
+ << value;
+ }
+}
+
+const struct {
+ const double p;
+ const double q;
+ const double x;
+ const double alpha;
+} kBetaTable[] = {
+ {0.5, 0.5, 0.01, 0.06376856085851985},
+ {0.5, 0.5, 0.1, 0.2048327646991335},
+ {0.5, 0.5, 1, 1},
+ {1, 0.5, 0, 0},
+ {1, 0.5, 0.01, 0.005012562893380045},
+ {1, 0.5, 0.1, 0.0513167019494862},
+ {1, 0.5, 0.5, 0.2928932188134525},
+ {1, 1, 0.5, 0.5},
+ {2, 2, 0.1, 0.028},
+ {2, 2, 0.2, 0.104},
+ {2, 2, 0.3, 0.216},
+ {2, 2, 0.4, 0.352},
+ {2, 2, 0.5, 0.5},
+ {2, 2, 0.6, 0.648},
+ {2, 2, 0.7, 0.784},
+ {2, 2, 0.8, 0.896},
+ {2, 2, 0.9, 0.972},
+ {5.5, 5, 0.5, 0.4361908850559777},
+ {10, 0.5, 0.9, 0.1516409096346979},
+ {10, 5, 0.5, 0.08978271484375},
+ {10, 5, 1, 1},
+ {10, 10, 0.5, 0.5},
+ {20, 5, 0.8, 0.4598773297575791},
+ {20, 10, 0.6, 0.2146816102371739},
+ {20, 10, 0.8, 0.9507364826957875},
+ {20, 20, 0.5, 0.5},
+ {20, 20, 0.6, 0.8979413687105918},
+ {30, 10, 0.7, 0.2241297491808366},
+ {30, 10, 0.8, 0.7586405487192086},
+ {40, 20, 0.7, 0.7001783247477069},
+ {1, 0.5, 0.1, 0.0513167019494862},
+ {1, 0.5, 0.2, 0.1055728090000841},
+ {1, 0.5, 0.3, 0.1633399734659245},
+ {1, 0.5, 0.4, 0.2254033307585166},
+ {1, 2, 0.2, 0.36},
+ {1, 3, 0.2, 0.488},
+ {1, 4, 0.2, 0.5904},
+ {1, 5, 0.2, 0.67232},
+ {2, 2, 0.3, 0.216},
+ {3, 2, 0.3, 0.0837},
+ {4, 2, 0.3, 0.03078},
+ {5, 2, 0.3, 0.010935},
+
+ // These values test small & large points along the range of the Beta
+ // function.
+ //
+ // When selecting test points, remember that if BetaIncomplete(x, p, q)
+ // returns the same value to within the limits of precision over a large
+ // domain of the input, x, then BetaIncompleteInv(alpha, p, q) may return an
+ // essentially arbitrary value where BetaIncomplete(x, p, q) =~ alpha.
+
+ // BetaRegularized[x, 0.00001, 0.00001],
+ // For x in {~0.001 ... ~0.999}, => ~0.5
+ {1e-5, 1e-5, 1e-5, 0.4999424388184638311},
+ {1e-5, 1e-5, (1.0 - 1e-8), 0.5000920948389232964},
+
+ // BetaRegularized[x, 0.00001, 10000].
+ // For x in {~epsilon ... 1.0}, => ~1
+ {1e-5, 1e5, 1e-6, 0.9999817708130066936},
+ {1e-5, 1e5, (1.0 - 1e-7), 1.0},
+
+ // BetaRegularized[x, 10000, 0.00001].
+ // For x in {0 .. 1-epsilon}, => ~0
+ {1e5, 1e-5, 1e-6, 0},
+ {1e5, 1e-5, (1.0 - 1e-6), 1.8229186993306369e-5},
+};
+
+TEST(BetaTest, BetaIncomplete) {
+ for (const auto& data : kBetaTable) {
+ auto value = absl::random_internal::BetaIncomplete(data.x, data.p, data.q);
+
+ // Log using the Wolfram-alpha function name & parameters.
+ EXPECT_NEAR(value, data.alpha, 1e-12)
+ << " BetaRegularized[" << data.x << ", " << data.p << ", " << data.q
+ << "] (expected=" << data.alpha << ") -> " << value;
+ }
+}
+
+TEST(BetaTest, BetaIncompleteInv) {
+ for (const auto& data : kBetaTable) {
+ auto value =
+ absl::random_internal::BetaIncompleteInv(data.p, data.q, data.alpha);
+
+ // Log using the Wolfram-alpha function name & parameters.
+ EXPECT_NEAR(value, data.x, 1e-6)
+ << " InverseBetaRegularized[" << data.alpha << ", " << data.p << ", "
+ << data.q << "] (expected=" << data.x << ") -> " << value;
+ }
+}
+
+TEST(MaxErrorTolerance, MaxErrorTolerance) {
+ std::vector<std::pair<double, double>> cases = {
+ {0.0000001, 8.86227e-8 * 1.41421356237},
+ {0.00001, 8.86227e-6 * 1.41421356237},
+ {0.5, 0.4769362762044 * 1.41421356237},
+ {0.6, 0.5951160814499 * 1.41421356237},
+ {0.99999, 3.1234132743 * 1.41421356237},
+ {0.9999999, 3.7665625816 * 1.41421356237},
+ {0.999999944, 3.8403850690566985 * 1.41421356237},
+ {0.999999999, 4.3200053849134452 * 1.41421356237}};
+ for (auto entry : cases) {
+ EXPECT_NEAR(absl::random_internal::MaxErrorTolerance(entry.first),
+ entry.second, 1e-8);
+ }
+}
+
+TEST(ZScore, WithSameMean) {
+ absl::random_internal::DistributionMoments m;
+ m.n = 100;
+ m.mean = 5;
+ m.variance = 1;
+ EXPECT_NEAR(absl::random_internal::ZScore(5, m), 0, 1e-12);
+
+ m.n = 1;
+ m.mean = 0;
+ m.variance = 1;
+ EXPECT_NEAR(absl::random_internal::ZScore(0, m), 0, 1e-12);
+
+ m.n = 10000;
+ m.mean = -5;
+ m.variance = 100;
+ EXPECT_NEAR(absl::random_internal::ZScore(-5, m), 0, 1e-12);
+}
+
+TEST(ZScore, DifferentMean) {
+ absl::random_internal::DistributionMoments m;
+ m.n = 100;
+ m.mean = 5;
+ m.variance = 1;
+ EXPECT_NEAR(absl::random_internal::ZScore(4, m), 10, 1e-12);
+
+ m.n = 1;
+ m.mean = 0;
+ m.variance = 1;
+ EXPECT_NEAR(absl::random_internal::ZScore(-1, m), 1, 1e-12);
+
+ m.n = 10000;
+ m.mean = -5;
+ m.variance = 100;
+ EXPECT_NEAR(absl::random_internal::ZScore(-4, m), -10, 1e-12);
+}
+} // namespace
diff --git a/absl/random/internal/distributions.h b/absl/random/internal/distributions.h
new file mode 100644
index 00000000..98d4f313
--- /dev/null
+++ b/absl/random/internal/distributions.h
@@ -0,0 +1,84 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
+#define ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
+
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/random/internal/distribution_caller.h"
+#include "absl/random/internal/traits.h"
+#include "absl/random/internal/uniform_helper.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+template <typename D>
+struct DistributionFormatTraits;
+
+// UniformImpl implements the core logic of the Uniform<T> call, which is to
+// select the correct distribution type, compute the bounds based on the
+// interval tag, and then generate a value.
+template <typename NumType, typename TagType, typename URBG>
+NumType UniformImpl(TagType tag,
+ URBG& urbg, // NOLINT(runtime/references)
+ NumType lo, NumType hi) {
+ static_assert(
+ std::is_arithmetic<NumType>::value,
+ "absl::Uniform<T>() must use an integer or real parameter type.");
+
+ using distribution_t =
+ typename std::conditional<std::is_integral<NumType>::value,
+ absl::uniform_int_distribution<NumType>,
+ absl::uniform_real_distribution<NumType>>::type;
+ using format_t = random_internal::DistributionFormatTraits<distribution_t>;
+
+ auto a = random_internal::uniform_lower_bound<NumType>(tag, lo, hi);
+ auto b = random_internal::uniform_upper_bound<NumType>(tag, lo, hi);
+ // TODO(lar): it doesn't make a lot of sense to ask for a random number in an
+ // empty range. Right now we just return a boundary--even though that
+ // boundary is not an acceptable value! Is there something better we can do
+ // here?
+
+ using gen_t = absl::decay_t<URBG>;
+ if (a > b) return a;
+ return DistributionCaller<gen_t>::template Call<distribution_t, format_t>(
+ &urbg, a, b);
+}
+
+// In the absence of an explicitly provided return-type, the template
+// "uniform_inferred_return_t<A, B>" is used to derive a suitable type, based on
+// the data-types of the endpoint-arguments {A lo, B hi}.
+//
+// Given endpoints {A lo, B hi}, one of {A, B} will be chosen as the
+// return-type, if one type can be implicitly converted into the other, in a
+// lossless way. The template "is_widening_convertible" implements the
+// compile-time logic for deciding if such a conversion is possible.
+//
+// If no such conversion between {A, B} exists, then the overload for
+// absl::Uniform() will be discarded, and the call will be ill-formed.
+// Return-type for absl::Uniform() when the return-type is inferred.
+template <typename A, typename B>
+using uniform_inferred_return_t =
+ absl::enable_if_t<absl::disjunction<is_widening_convertible<A, B>,
+ is_widening_convertible<B, A>>::value,
+ typename std::conditional<
+ is_widening_convertible<A, B>::value, B, A>::type>;
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_DISTRIBUTIONS_H_
diff --git a/absl/random/internal/explicit_seed_seq.h b/absl/random/internal/explicit_seed_seq.h
new file mode 100644
index 00000000..66c35f2e
--- /dev/null
+++ b/absl/random/internal/explicit_seed_seq.h
@@ -0,0 +1,89 @@
+// 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_EXPLICIT_SEED_SEQ_H_
+#define ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <iterator>
+#include <vector>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// This class conforms to the C++ Standard "Seed Sequence" concept
+// [rand.req.seedseq].
+//
+// An "ExplicitSeedSeq" is meant to provide a conformant interface for
+// forwarding pre-computed seed material to the constructor of a class
+// conforming to the "Uniform Random Bit Generator" concept. This class makes no
+// attempt to mutate the state provided by its constructor, and returns it
+// directly via ExplicitSeedSeq::generate().
+//
+// If this class is asked to generate more seed material than was provided to
+// the constructor, then the remaining bytes will be filled with deterministic,
+// nonrandom data.
+class ExplicitSeedSeq {
+ public:
+ using result_type = uint32_t;
+
+ ExplicitSeedSeq() : state_() {}
+
+ // Copy and move both allowed.
+ ExplicitSeedSeq(const ExplicitSeedSeq& other) = default;
+ ExplicitSeedSeq& operator=(const ExplicitSeedSeq& other) = default;
+ ExplicitSeedSeq(ExplicitSeedSeq&& other) = default;
+ ExplicitSeedSeq& operator=(ExplicitSeedSeq&& other) = default;
+
+ template <typename Iterator>
+ ExplicitSeedSeq(Iterator begin, Iterator end) {
+ for (auto it = begin; it != end; it++) {
+ state_.push_back(*it & 0xffffffff);
+ }
+ }
+
+ template <typename T>
+ ExplicitSeedSeq(std::initializer_list<T> il)
+ : ExplicitSeedSeq(il.begin(), il.end()) {}
+
+ size_t size() const { return state_.size(); }
+
+ template <typename OutIterator>
+ void param(OutIterator out) const {
+ std::copy(std::begin(state_), std::end(state_), out);
+ }
+
+ template <typename OutIterator>
+ void generate(OutIterator begin, OutIterator end) {
+ for (size_t index = 0; begin != end; begin++) {
+ *begin = state_.empty() ? 0 : state_[index++];
+ if (index >= state_.size()) {
+ index = 0;
+ }
+ }
+ }
+
+ protected:
+ std::vector<uint32_t> state_;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_EXPLICIT_SEED_SEQ_H_
diff --git a/absl/random/internal/explicit_seed_seq_test.cc b/absl/random/internal/explicit_seed_seq_test.cc
new file mode 100644
index 00000000..a55ad739
--- /dev/null
+++ b/absl/random/internal/explicit_seed_seq_test.cc
@@ -0,0 +1,204 @@
+// 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/explicit_seed_seq.h"
+
+#include <iterator>
+#include <random>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/seed_sequences.h"
+
+namespace {
+
+template <typename Sseq>
+bool ConformsToInterface() {
+ // Check that the SeedSequence can be default-constructed.
+ { 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}; }
+ // Check that param() and size() return state provided to constructor.
+ {
+ uint32_t init_array[] = {1, 2, 3, 4, 5};
+ Sseq seq(init_array, &init_array[ABSL_ARRAYSIZE(init_array)]);
+ EXPECT_EQ(seq.size(), ABSL_ARRAYSIZE(init_array));
+
+ uint32_t state_array[ABSL_ARRAYSIZE(init_array)];
+ seq.param(state_array);
+
+ for (int i = 0; i < ABSL_ARRAYSIZE(state_array); i++) {
+ EXPECT_EQ(state_array[i], i + 1);
+ }
+ }
+ // Check for presence of generate() method.
+ {
+ Sseq seq;
+ uint32_t seeds[5];
+
+ seq.generate(seeds, &seeds[ABSL_ARRAYSIZE(seeds)]);
+ }
+ return true;
+}
+} // namespace
+
+TEST(SeedSequences, CheckInterfaces) {
+ // Control case
+ EXPECT_TRUE(ConformsToInterface<std::seed_seq>());
+
+ // Abseil classes
+ EXPECT_TRUE(ConformsToInterface<absl::random_internal::ExplicitSeedSeq>());
+}
+
+TEST(ExplicitSeedSeq, DefaultConstructorGeneratesZeros) {
+ const size_t kNumBlocks = 128;
+
+ uint32_t outputs[kNumBlocks];
+ absl::random_internal::ExplicitSeedSeq seq;
+ seq.generate(outputs, &outputs[kNumBlocks]);
+
+ for (uint32_t& seed : outputs) {
+ EXPECT_EQ(seed, 0);
+ }
+}
+
+TEST(ExplicitSeeqSeq, SeedMaterialIsForwardedIdentically) {
+ const size_t kNumBlocks = 128;
+
+ uint32_t seed_material[kNumBlocks];
+ std::random_device urandom{"/dev/urandom"};
+ for (uint32_t& seed : seed_material) {
+ seed = urandom();
+ }
+ absl::random_internal::ExplicitSeedSeq seq(seed_material,
+ &seed_material[kNumBlocks]);
+
+ // Check that output is same as seed-material provided to constructor.
+ {
+ const size_t kNumGenerated = kNumBlocks / 2;
+ uint32_t outputs[kNumGenerated];
+ seq.generate(outputs, &outputs[kNumGenerated]);
+ for (size_t i = 0; i < kNumGenerated; i++) {
+ EXPECT_EQ(outputs[i], seed_material[i]);
+ }
+ }
+ // Check that SeedSequence is stateless between invocations: Despite the last
+ // invocation of generate() only consuming half of the input-entropy, the same
+ // entropy will be recycled for the next invocation.
+ {
+ const size_t kNumGenerated = kNumBlocks;
+ uint32_t outputs[kNumGenerated];
+ seq.generate(outputs, &outputs[kNumGenerated]);
+ for (size_t i = 0; i < kNumGenerated; i++) {
+ EXPECT_EQ(outputs[i], seed_material[i]);
+ }
+ }
+ // Check that when more seed-material is asked for than is provided, nonzero
+ // values are still written.
+ {
+ const size_t kNumGenerated = kNumBlocks * 2;
+ uint32_t outputs[kNumGenerated];
+ seq.generate(outputs, &outputs[kNumGenerated]);
+ for (size_t i = 0; i < kNumGenerated; i++) {
+ EXPECT_EQ(outputs[i], seed_material[i % kNumBlocks]);
+ }
+ }
+}
+
+TEST(ExplicitSeedSeq, CopyAndMoveConstructors) {
+ using testing::Each;
+ using testing::Eq;
+ using testing::Not;
+ using testing::Pointwise;
+
+ uint32_t entropy[4];
+ std::random_device urandom("/dev/urandom");
+ for (uint32_t& entry : entropy) {
+ entry = urandom();
+ }
+ absl::random_internal::ExplicitSeedSeq seq_from_entropy(std::begin(entropy),
+ std::end(entropy));
+ // Copy constructor.
+ {
+ absl::random_internal::ExplicitSeedSeq seq_copy(seq_from_entropy);
+ EXPECT_EQ(seq_copy.size(), seq_from_entropy.size());
+
+ std::vector<uint32_t> seeds_1;
+ seeds_1.resize(1000, 0);
+ std::vector<uint32_t> seeds_2;
+ seeds_2.resize(1000, 1);
+
+ seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
+ seq_copy.generate(seeds_2.begin(), seeds_2.end());
+
+ EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
+ }
+ // Assignment operator.
+ {
+ for (uint32_t& entry : entropy) {
+ entry = urandom();
+ }
+ absl::random_internal::ExplicitSeedSeq another_seq(std::begin(entropy),
+ std::end(entropy));
+
+ std::vector<uint32_t> seeds_1;
+ seeds_1.resize(1000, 0);
+ std::vector<uint32_t> seeds_2;
+ seeds_2.resize(1000, 0);
+
+ seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
+ another_seq.generate(seeds_2.begin(), seeds_2.end());
+
+ // Assert precondition: Sequences generated by seed-sequences are not equal.
+ EXPECT_THAT(seeds_1, Not(Pointwise(Eq(), seeds_2)));
+
+ // Apply the assignment-operator.
+ another_seq = seq_from_entropy;
+
+ // Re-generate seeds.
+ seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
+ another_seq.generate(seeds_2.begin(), seeds_2.end());
+
+ // Seeds generated by seed-sequences should now be equal.
+ EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
+ }
+ // Move constructor.
+ {
+ // Get seeds from seed-sequence constructed from entropy.
+ std::vector<uint32_t> seeds_1;
+ seeds_1.resize(1000, 0);
+ seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
+
+ // Apply move-constructor move the sequence to another instance.
+ absl::random_internal::ExplicitSeedSeq moved_seq(
+ std::move(seq_from_entropy));
+ std::vector<uint32_t> seeds_2;
+ seeds_2.resize(1000, 1);
+ moved_seq.generate(seeds_2.begin(), seeds_2.end());
+ // Verify that seeds produced by moved-instance are the same as original.
+ EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
+
+ // Verify that the moved-from instance now behaves like a
+ // default-constructed instance.
+ EXPECT_EQ(seq_from_entropy.size(), 0);
+ seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
+ EXPECT_THAT(seeds_1, Each(Eq(0)));
+ }
+}
diff --git a/absl/random/internal/fast_uniform_bits.h b/absl/random/internal/fast_uniform_bits.h
new file mode 100644
index 00000000..5aa9de01
--- /dev/null
+++ b/absl/random/internal/fast_uniform_bits.h
@@ -0,0 +1,262 @@
+// 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_FAST_UNIFORM_BITS_H_
+#define ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+// Returns true if the input value is zero or a power of two. Useful for
+// determining if the range of output values in a URBG
+template <typename UIntType>
+constexpr bool IsPowerOfTwoOrZero(UIntType n) {
+ return (n == 0) || ((n & (n - 1)) == 0);
+}
+
+// Computes the length of the range of values producible by the URBG, or returns
+// zero if that would encompass the entire range of representable values in
+// URBG::result_type.
+template <typename URBG>
+constexpr typename URBG::result_type RangeSize() {
+ using result_type = typename URBG::result_type;
+ return ((URBG::max)() == (std::numeric_limits<result_type>::max)() &&
+ (URBG::min)() == std::numeric_limits<result_type>::lowest())
+ ? result_type{0}
+ : (URBG::max)() - (URBG::min)() + result_type{1};
+}
+
+template <typename UIntType>
+constexpr UIntType LargestPowerOfTwoLessThanOrEqualTo(UIntType n) {
+ return n < 2 ? n : 2 * LargestPowerOfTwoLessThanOrEqualTo(n / 2);
+}
+
+// Given a URBG generating values in the closed interval [Lo, Hi], returns the
+// largest power of two less than or equal to `Hi - Lo + 1`.
+template <typename URBG>
+constexpr typename URBG::result_type PowerOfTwoSubRangeSize() {
+ return LargestPowerOfTwoLessThanOrEqualTo(RangeSize<URBG>());
+}
+
+// Computes the floor of the log. (i.e., std::floor(std::log2(N));
+template <typename UIntType>
+constexpr UIntType IntegerLog2(UIntType n) {
+ return (n <= 1) ? 0 : 1 + IntegerLog2(n / 2);
+}
+
+// Returns the number of bits of randomness returned through
+// `PowerOfTwoVariate(urbg)`.
+template <typename URBG>
+constexpr size_t NumBits() {
+ return RangeSize<URBG>() == 0
+ ? std::numeric_limits<typename URBG::result_type>::digits
+ : IntegerLog2(PowerOfTwoSubRangeSize<URBG>());
+}
+
+// Given a shift value `n`, constructs a mask with exactly the low `n` bits set.
+// If `n == 0`, all bits are set.
+template <typename UIntType>
+constexpr UIntType MaskFromShift(UIntType n) {
+ return ((n % std::numeric_limits<UIntType>::digits) == 0)
+ ? ~UIntType{0}
+ : (UIntType{1} << n) - UIntType{1};
+}
+
+// FastUniformBits implements a fast path to acquire uniform independent bits
+// from a type which conforms to the [rand.req.urbg] concept.
+// Parameterized by:
+// `UIntType`: the result (output) type
+//
+// The std::independent_bits_engine [rand.adapt.ibits] adaptor can be
+// instantiated from an existing generator through a copy or a move. It does
+// not, however, facilitate the production of pseudorandom bits from an un-owned
+// generator that will outlive the std::independent_bits_engine instance.
+template <typename UIntType = uint64_t>
+class FastUniformBits {
+ public:
+ using result_type = UIntType;
+
+ static constexpr result_type(min)() { return 0; }
+ static constexpr result_type(max)() {
+ return (std::numeric_limits<result_type>::max)();
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g); // NOLINT(runtime/references)
+
+ private:
+ static_assert(std::is_unsigned<UIntType>::value,
+ "Class-template FastUniformBits<> must be parameterized using "
+ "an unsigned type.");
+
+ // PowerOfTwoVariate() generates a single random variate, always returning a
+ // value in the half-open interval `[0, PowerOfTwoSubRangeSize<URBG>())`. If
+ // the URBG already generates values in a power-of-two range, the generator
+ // itself is used. Otherwise, we use rejection sampling on the largest
+ // possible power-of-two-sized subrange.
+ struct PowerOfTwoTag {};
+ struct RejectionSamplingTag {};
+ template <typename URBG>
+ static typename URBG::result_type PowerOfTwoVariate(
+ URBG& g) { // NOLINT(runtime/references)
+ using tag =
+ typename std::conditional<IsPowerOfTwoOrZero(RangeSize<URBG>()),
+ PowerOfTwoTag, RejectionSamplingTag>::type;
+ return PowerOfTwoVariate(g, tag{});
+ }
+
+ template <typename URBG>
+ static typename URBG::result_type PowerOfTwoVariate(
+ URBG& g, // NOLINT(runtime/references)
+ PowerOfTwoTag) {
+ return g() - (URBG::min)();
+ }
+
+ template <typename URBG>
+ static typename URBG::result_type PowerOfTwoVariate(
+ URBG& g, // NOLINT(runtime/references)
+ RejectionSamplingTag) {
+ // Use rejection sampling to ensure uniformity across the range.
+ typename URBG::result_type u;
+ do {
+ u = g() - (URBG::min)();
+ } while (u >= PowerOfTwoSubRangeSize<URBG>());
+ return u;
+ }
+
+ // Generate() generates a random value, dispatched on whether
+ // the underlying URBG must loop over multiple calls or not.
+ template <typename URBG>
+ result_type Generate(URBG& g, // NOLINT(runtime/references)
+ std::true_type /* avoid_looping */);
+
+ template <typename URBG>
+ result_type Generate(URBG& g, // NOLINT(runtime/references)
+ std::false_type /* avoid_looping */);
+};
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::operator()(URBG& g) { // NOLINT(runtime/references)
+ // kRangeMask is the mask used when sampling variates from the URBG when the
+ // width of the URBG range is not a power of 2.
+ // Y = (2 ^ kRange) - 1
+ static_assert((URBG::max)() > (URBG::min)(),
+ "URBG::max and URBG::min may not be equal.");
+ using urbg_result_type = typename URBG::result_type;
+ constexpr urbg_result_type kRangeMask =
+ RangeSize<URBG>() == 0
+ ? (std::numeric_limits<urbg_result_type>::max)()
+ : static_cast<urbg_result_type>(PowerOfTwoSubRangeSize<URBG>() - 1);
+ return Generate(g, std::integral_constant<bool, (kRangeMask >= (max)())>{});
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
+ std::true_type /* avoid_looping */) {
+ // The width of the result_type is less than than the width of the random bits
+ // provided by URBG. Thus, generate a single value and then simply mask off
+ // the required bits.
+
+ return PowerOfTwoVariate(g) & (max)();
+}
+
+template <typename UIntType>
+template <typename URBG>
+typename FastUniformBits<UIntType>::result_type
+FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
+ std::false_type /* avoid_looping */) {
+ // See [rand.adapt.ibits] for more details on the constants calculated below.
+ //
+ // It is preferable to use roughly the same number of bits from each generator
+ // call, however this is only possible when the number of bits provided by the
+ // URBG is a divisor of the number of bits in `result_type`. In all other
+ // cases, the number of bits used cannot always be the same, but it can be
+ // guaranteed to be off by at most 1. Thus we run two loops, one with a
+ // smaller bit-width size (`kSmallWidth`) and one with a larger width size
+ // (satisfying `kLargeWidth == kSmallWidth + 1`). The loops are run
+ // `kSmallIters` and `kLargeIters` times respectively such
+ // that
+ //
+ // `kTotalWidth == kSmallIters * kSmallWidth
+ // + kLargeIters * kLargeWidth`
+ //
+ // where `kTotalWidth` is the total number of bits in `result_type`.
+ //
+ constexpr size_t kTotalWidth = std::numeric_limits<result_type>::digits;
+ constexpr size_t kUrbgWidth = NumBits<URBG>();
+ constexpr size_t kTotalIters =
+ kTotalWidth / kUrbgWidth + (kTotalWidth % kUrbgWidth != 0);
+ constexpr size_t kSmallWidth = kTotalWidth / kTotalIters;
+ constexpr size_t kLargeWidth = kSmallWidth + 1;
+ //
+ // Because `kLargeWidth == kSmallWidth + 1`, it follows that
+ //
+ // `kTotalWidth == kTotalIters * kSmallWidth + kLargeIters`
+ //
+ // and therefore
+ //
+ // `kLargeIters == kTotalWidth % kSmallWidth`
+ //
+ // Intuitively, each iteration with the large width accounts for one unit
+ // of the remainder when `kTotalWidth` is divided by `kSmallWidth`. As
+ // mentioned above, if the URBG width is a divisor of `kTotalWidth`, then
+ // there would be no need for any large iterations (i.e., one loop would
+ // suffice), and indeed, in this case, `kLargeIters` would be zero.
+ constexpr size_t kLargeIters = kTotalWidth % kSmallWidth;
+ constexpr size_t kSmallIters =
+ (kTotalWidth - (kLargeWidth * kLargeIters)) / kSmallWidth;
+
+ static_assert(
+ kTotalWidth == kSmallIters * kSmallWidth + kLargeIters * kLargeWidth,
+ "Error in looping constant calculations.");
+
+ result_type s = 0;
+
+ constexpr size_t kSmallShift = kSmallWidth % kTotalWidth;
+ constexpr result_type kSmallMask = MaskFromShift(result_type{kSmallShift});
+ for (size_t n = 0; n < kSmallIters; ++n) {
+ s = (s << kSmallShift) +
+ (static_cast<result_type>(PowerOfTwoVariate(g)) & kSmallMask);
+ }
+
+ constexpr size_t kLargeShift = kLargeWidth % kTotalWidth;
+ constexpr result_type kLargeMask = MaskFromShift(result_type{kLargeShift});
+ for (size_t n = 0; n < kLargeIters; ++n) {
+ s = (s << kLargeShift) +
+ (static_cast<result_type>(PowerOfTwoVariate(g)) & kLargeMask);
+ }
+
+ static_assert(
+ kLargeShift == kSmallShift + 1 ||
+ (kLargeShift == 0 &&
+ kSmallShift == std::numeric_limits<result_type>::digits - 1),
+ "Error in looping constant calculations");
+
+ return s;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
diff --git a/absl/random/internal/fast_uniform_bits_test.cc b/absl/random/internal/fast_uniform_bits_test.cc
new file mode 100644
index 00000000..35c96226
--- /dev/null
+++ b/absl/random/internal/fast_uniform_bits_test.cc
@@ -0,0 +1,274 @@
+// 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/fast_uniform_bits.h"
+
+#include <random>
+
+#include "gtest/gtest.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+template <typename IntType>
+class FastUniformBitsTypedTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t>;
+
+TYPED_TEST_SUITE(FastUniformBitsTypedTest, IntTypes);
+
+TYPED_TEST(FastUniformBitsTypedTest, BasicTest) {
+ using Limits = std::numeric_limits<TypeParam>;
+ using FastBits = FastUniformBits<TypeParam>;
+
+ EXPECT_EQ(0, FastBits::min());
+ EXPECT_EQ(Limits::max(), FastBits::max());
+
+ constexpr int kIters = 10000;
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ FastBits fast;
+ for (int i = 0; i < kIters; i++) {
+ const auto v = fast(gen);
+ EXPECT_LE(v, FastBits::max());
+ EXPECT_GE(v, FastBits::min());
+ }
+}
+
+template <typename UIntType, UIntType Lo, UIntType Hi, UIntType Val = Lo>
+struct FakeUrbg {
+ using result_type = UIntType;
+
+ static constexpr result_type(max)() { return Hi; }
+ static constexpr result_type(min)() { return Lo; }
+ result_type operator()() { return Val; }
+};
+
+using UrngOddbits = FakeUrbg<uint8_t, 1, 0xfe, 0x73>;
+using Urng4bits = FakeUrbg<uint8_t, 1, 0x10, 2>;
+using Urng31bits = FakeUrbg<uint32_t, 1, 0xfffffffe, 0x60070f03>;
+using Urng32bits = FakeUrbg<uint32_t, 0, 0xffffffff, 0x74010f01>;
+
+TEST(FastUniformBitsTest, IsPowerOfTwoOrZero) {
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{0}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{1}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{2}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{16}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{17}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint8_t>::max)()));
+
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{0}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{1}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{2}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{16}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{17}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint16_t>::max)()));
+
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{0}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{1}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{2}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint32_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{32}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint32_t{17}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint32_t>::max)()));
+
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{0}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{1}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{2}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{3}));
+ EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{64}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{17}));
+ EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits<uint64_t>::max)()));
+}
+
+TEST(FastUniformBitsTest, IntegerLog2) {
+ EXPECT_EQ(IntegerLog2(uint16_t{0}), 0);
+ EXPECT_EQ(IntegerLog2(uint16_t{1}), 0);
+ EXPECT_EQ(IntegerLog2(uint16_t{2}), 1);
+ EXPECT_EQ(IntegerLog2(uint16_t{3}), 1);
+ EXPECT_EQ(IntegerLog2(uint16_t{4}), 2);
+ EXPECT_EQ(IntegerLog2(uint16_t{5}), 2);
+ EXPECT_EQ(IntegerLog2(std::numeric_limits<uint64_t>::max()), 63);
+}
+
+TEST(FastUniformBitsTest, RangeSize) {
+ EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 6>>()), 5);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint8_t, 2, 10>>()), 9);
+ EXPECT_EQ(
+ (RangeSize<FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 2, 6>>()), 5);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 18);
+ EXPECT_EQ((RangeSize<
+ FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 6>>()), 5);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 18);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()), 0xffffffff);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()), 0xfffffffe);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint32_t, 2, 0xfffffffe>>()), 0xfffffffd);
+ EXPECT_EQ((RangeSize<
+ FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 6>>()), 5);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 18);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()), 0x100000000ull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()), 0xffffffffull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()), 0xfffffffeull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffe>>()), 0xfffffffdull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()), 0ull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
+ 0xffffffffffffffffull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
+ 0xfffffffffffffffeull);
+ EXPECT_EQ((RangeSize<FakeUrbg<uint64_t, 2, 0xfffffffffffffffeull>>()),
+ 0xfffffffffffffffdull);
+ EXPECT_EQ((RangeSize<
+ FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
+ 0);
+}
+
+TEST(FastUniformBitsTest, PowerOfTwoSubRangeSize) {
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 0, 3>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 2>>()), 1);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 5>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 6>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint8_t, 2, 10>>()), 8);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<
+ FakeUrbg<uint8_t, 0, std::numeric_limits<uint8_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 0, 3>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 2>>()), 1);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 5>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 2, 6>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint16_t, 1000, 1017>>()), 16);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<
+ FakeUrbg<uint16_t, 0, std::numeric_limits<uint16_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 3>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 2>>()), 1);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 5>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 2, 6>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1000, 1017>>()), 16);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 0, 0xffffffff>>()), 0);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xffffffff>>()),
+ 0x80000000);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint32_t, 1, 0xfffffffe>>()),
+ 0x80000000);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<
+ FakeUrbg<uint32_t, 0, std::numeric_limits<uint32_t>::max()>>()),
+ 0);
+
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 3>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 2>>()), 1);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 5>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 2, 6>>()), 4);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1000, 1017>>()), 16);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffff>>()),
+ 0x100000000ull);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffff>>()),
+ 0x80000000ull);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffe>>()),
+ 0x80000000ull);
+ EXPECT_EQ(
+ (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 0, 0xffffffffffffffffull>>()),
+ 0);
+ EXPECT_EQ(
+ (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xffffffffffffffffull>>()),
+ 0x8000000000000000ull);
+ EXPECT_EQ(
+ (PowerOfTwoSubRangeSize<FakeUrbg<uint64_t, 1, 0xfffffffffffffffeull>>()),
+ 0x8000000000000000ull);
+ EXPECT_EQ((PowerOfTwoSubRangeSize<
+ FakeUrbg<uint64_t, 0, std::numeric_limits<uint64_t>::max()>>()),
+ 0);
+}
+
+TEST(FastUniformBitsTest, Urng4_VariousOutputs) {
+ // Tests that how values are composed; the single-bit deltas should be spread
+ // across each invocation.
+ Urng4bits urng4;
+ Urng31bits urng31;
+ Urng32bits urng32;
+
+ // 8-bit types
+ {
+ FastUniformBits<uint8_t> fast8;
+ EXPECT_EQ(0x11, fast8(urng4));
+ EXPECT_EQ(0x2, fast8(urng31));
+ EXPECT_EQ(0x1, fast8(urng32));
+ }
+
+ // 16-bit types
+ {
+ FastUniformBits<uint16_t> fast16;
+ EXPECT_EQ(0x1111, fast16(urng4));
+ EXPECT_EQ(0xf02, fast16(urng31));
+ EXPECT_EQ(0xf01, fast16(urng32));
+ }
+
+ // 32-bit types
+ {
+ FastUniformBits<uint32_t> fast32;
+ EXPECT_EQ(0x11111111, fast32(urng4));
+ EXPECT_EQ(0x0f020f02, fast32(urng31));
+ EXPECT_EQ(0x74010f01, fast32(urng32));
+ }
+
+ // 64-bit types
+ {
+ FastUniformBits<uint64_t> fast64;
+ EXPECT_EQ(0x1111111111111111, fast64(urng4));
+ EXPECT_EQ(0x387811c3c0870f02, fast64(urng31));
+ EXPECT_EQ(0x74010f0174010f01, fast64(urng32));
+ }
+}
+
+TEST(FastUniformBitsTest, URBG32bitRegression) {
+ // Validate with deterministic 32-bit std::minstd_rand
+ // to ensure that operator() performs as expected.
+ std::minstd_rand gen(1);
+ FastUniformBits<uint64_t> fast64;
+
+ EXPECT_EQ(0x05e47095f847c122ull, fast64(gen));
+ EXPECT_EQ(0x8f82c1ba30b64d22ull, fast64(gen));
+ EXPECT_EQ(0x3b971a3558155039ull, fast64(gen));
+}
+
+} // namespace
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/fastmath.h b/absl/random/internal/fastmath.h
new file mode 100644
index 00000000..1dc2cd7b
--- /dev/null
+++ b/absl/random/internal/fastmath.h
@@ -0,0 +1,74 @@
+// 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_FASTMATH_H_
+#define ABSL_RANDOM_INTERNAL_FASTMATH_H_
+
+// This file contains fast math functions (bitwise ops as well as some others)
+// which are implementation details of various absl random number distributions.
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+
+#include "absl/base/internal/bits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Returns the position of the first bit set.
+inline int LeadingSetBit(uint64_t n) {
+ return 64 - base_internal::CountLeadingZeros64(n);
+}
+
+// Compute log2(n) using integer operations.
+// While std::log2 is more accurate than std::log(n) / std::log(2), for
+// very large numbers--those close to std::numeric_limits<uint64_t>::max() - 2,
+// for instance--std::log2 rounds up rather than down, which introduces
+// definite skew in the results.
+inline int IntLog2Floor(uint64_t n) {
+ return (n <= 1) ? 0 : (63 - base_internal::CountLeadingZeros64(n));
+}
+inline int IntLog2Ceil(uint64_t n) {
+ return (n <= 1) ? 0 : (64 - base_internal::CountLeadingZeros64(n - 1));
+}
+
+inline double StirlingLogFactorial(double n) {
+ assert(n >= 1);
+ // Using Stirling's approximation.
+ constexpr double kLog2PI = 1.83787706640934548356;
+ const double logn = std::log(n);
+ const double ninv = 1.0 / static_cast<double>(n);
+ return n * logn - n + 0.5 * (kLog2PI + logn) + (1.0 / 12.0) * ninv -
+ (1.0 / 360.0) * ninv * ninv * ninv;
+}
+
+// Rotate value right.
+//
+// We only implement the uint32_t / uint64_t versions because
+// 1) those are the only ones we use, and
+// 2) those are the only ones where clang detects the rotate idiom correctly.
+inline constexpr uint32_t rotr(uint32_t value, uint8_t bits) {
+ return (value >> (bits & 31)) | (value << ((-bits) & 31));
+}
+inline constexpr uint64_t rotr(uint64_t value, uint8_t bits) {
+ return (value >> (bits & 63)) | (value << ((-bits) & 63));
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_FASTMATH_H_
diff --git a/absl/random/internal/fastmath_test.cc b/absl/random/internal/fastmath_test.cc
new file mode 100644
index 00000000..65859c25
--- /dev/null
+++ b/absl/random/internal/fastmath_test.cc
@@ -0,0 +1,110 @@
+// 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/fastmath.h"
+
+#include "gtest/gtest.h"
+
+#if defined(__native_client__) || defined(__EMSCRIPTEN__)
+// NACL has a less accurate implementation of std::log2 than most of
+// the other platforms. For some values which should have integral results,
+// sometimes NACL returns slightly larger values.
+//
+// The MUSL libc used by emscripten also has a similar bug.
+#define ABSL_RANDOM_INACCURATE_LOG2
+#endif
+
+namespace {
+
+TEST(DistributionImplTest, LeadingSetBit) {
+ using absl::random_internal::LeadingSetBit;
+ constexpr uint64_t kZero = 0;
+ EXPECT_EQ(0, LeadingSetBit(kZero));
+ EXPECT_EQ(64, LeadingSetBit(~kZero));
+
+ for (int index = 0; index < 64; index++) {
+ uint64_t x = static_cast<uint64_t>(1) << index;
+ EXPECT_EQ(index + 1, LeadingSetBit(x)) << index;
+ EXPECT_EQ(index + 1, LeadingSetBit(x + x - 1)) << index;
+ }
+}
+
+TEST(FastMathTest, IntLog2FloorTest) {
+ using absl::random_internal::IntLog2Floor;
+ constexpr uint64_t kZero = 0;
+ EXPECT_EQ(0, IntLog2Floor(0)); // boundary. return 0.
+ EXPECT_EQ(0, IntLog2Floor(1));
+ EXPECT_EQ(1, IntLog2Floor(2));
+ EXPECT_EQ(63, IntLog2Floor(~kZero));
+
+ // A boundary case: Converting 0xffffffffffffffff requires > 53
+ // bits of precision, so the conversion to double rounds up,
+ // and the result of std::log2(x) > IntLog2Floor(x).
+ EXPECT_LT(IntLog2Floor(~kZero), static_cast<int>(std::log2(~kZero)));
+
+ for (int i = 0; i < 64; i++) {
+ const uint64_t i_pow_2 = static_cast<uint64_t>(1) << i;
+ EXPECT_EQ(i, IntLog2Floor(i_pow_2));
+ EXPECT_EQ(i, static_cast<int>(std::log2(i_pow_2)));
+
+ uint64_t y = i_pow_2;
+ for (int j = i - 1; j > 0; --j) {
+ y = y | (i_pow_2 >> j);
+ EXPECT_EQ(i, IntLog2Floor(y));
+ }
+ }
+}
+
+TEST(FastMathTest, IntLog2CeilTest) {
+ using absl::random_internal::IntLog2Ceil;
+ constexpr uint64_t kZero = 0;
+ EXPECT_EQ(0, IntLog2Ceil(0)); // boundary. return 0.
+ EXPECT_EQ(0, IntLog2Ceil(1));
+ EXPECT_EQ(1, IntLog2Ceil(2));
+ EXPECT_EQ(64, IntLog2Ceil(~kZero));
+
+ // A boundary case: Converting 0xffffffffffffffff requires > 53
+ // bits of precision, so the conversion to double rounds up,
+ // and the result of std::log2(x) > IntLog2Floor(x).
+ EXPECT_LE(IntLog2Ceil(~kZero), static_cast<int>(std::log2(~kZero)));
+
+ for (int i = 0; i < 64; i++) {
+ const uint64_t i_pow_2 = static_cast<uint64_t>(1) << i;
+ EXPECT_EQ(i, IntLog2Ceil(i_pow_2));
+#ifndef ABSL_RANDOM_INACCURATE_LOG2
+ EXPECT_EQ(i, static_cast<int>(std::ceil(std::log2(i_pow_2))));
+#endif
+
+ uint64_t y = i_pow_2;
+ for (int j = i - 1; j > 0; --j) {
+ y = y | (i_pow_2 >> j);
+ EXPECT_EQ(i + 1, IntLog2Ceil(y));
+ }
+ }
+}
+
+TEST(FastMathTest, StirlingLogFactorial) {
+ using absl::random_internal::StirlingLogFactorial;
+
+ EXPECT_NEAR(StirlingLogFactorial(1.0), 0, 1e-3);
+ EXPECT_NEAR(StirlingLogFactorial(1.50), 0.284683, 1e-3);
+ EXPECT_NEAR(StirlingLogFactorial(2.0), 0.69314718056, 1e-4);
+
+ for (int i = 2; i < 50; i++) {
+ double d = static_cast<double>(i);
+ EXPECT_NEAR(StirlingLogFactorial(d), std::lgamma(d + 1), 3e-5);
+ }
+}
+
+} // namespace
diff --git a/absl/random/internal/gaussian_distribution_gentables.cc b/absl/random/internal/gaussian_distribution_gentables.cc
new file mode 100644
index 00000000..6f9a28be
--- /dev/null
+++ b/absl/random/internal/gaussian_distribution_gentables.cc
@@ -0,0 +1,147 @@
+// 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.
+
+// Generates gaussian_distribution.cc
+//
+// $ blaze run :gaussian_distribution_gentables > gaussian_distribution.cc
+//
+#include "absl/random/gaussian_distribution.h"
+
+#include <cmath>
+#include <cstddef>
+#include <iostream>
+#include <limits>
+#include <string>
+
+#include "absl/base/macros.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+template <typename T, size_t N>
+void FormatArrayContents(std::ostream* os, T (&data)[N]) {
+ if (!std::numeric_limits<T>::is_exact) {
+ // Note: T is either an integer or a float.
+ // float requires higher precision to ensure that values are
+ // reproduced exactly.
+ // Trivia: C99 has hexadecimal floating point literals, but C++11 does not.
+ // Using them would remove all concern of precision loss.
+ os->precision(std::numeric_limits<T>::max_digits10 + 2);
+ }
+ *os << " {";
+ std::string separator = "";
+ for (size_t i = 0; i < N; ++i) {
+ *os << separator << data[i];
+ if ((i + 1) % 3 != 0) {
+ separator = ", ";
+ } else {
+ separator = ",\n ";
+ }
+ }
+ *os << "}";
+}
+
+} // namespace
+
+class TableGenerator : public gaussian_distribution_base {
+ public:
+ TableGenerator();
+ void Print(std::ostream* os);
+
+ using gaussian_distribution_base::kMask;
+ using gaussian_distribution_base::kR;
+ using gaussian_distribution_base::kV;
+
+ private:
+ Tables tables_;
+};
+
+// Ziggurat gaussian initialization. For an explanation of the algorithm, see
+// the Marsaglia paper, "The Ziggurat Method for Generating Random Variables".
+// http://www.jstatsoft.org/v05/i08/
+//
+// Further details are available in the Doornik paper
+// https://www.doornik.com/research/ziggurat.pdf
+//
+TableGenerator::TableGenerator() {
+ // The constants here should match the values in gaussian_distribution.h
+ static constexpr int kC = kMask + 1;
+
+ static_assert((ABSL_ARRAYSIZE(tables_.x) == kC + 1),
+ "xArray must be length kMask + 2");
+
+ static_assert((ABSL_ARRAYSIZE(tables_.x) == ABSL_ARRAYSIZE(tables_.f)),
+ "fx and x arrays must be identical length");
+
+ auto f = [](double x) { return std::exp(-0.5 * x * x); };
+ auto f_inv = [](double x) { return std::sqrt(-2.0 * std::log(x)); };
+
+ tables_.x[0] = kV / f(kR);
+ tables_.f[0] = f(tables_.x[0]);
+
+ tables_.x[1] = kR;
+ tables_.f[1] = f(tables_.x[1]);
+
+ tables_.x[kC] = 0.0;
+ tables_.f[kC] = f(tables_.x[kC]); // 1.0
+
+ for (int i = 2; i < kC; i++) {
+ double v = (kV / tables_.x[i - 1]) + tables_.f[i - 1];
+ tables_.x[i] = f_inv(v);
+ tables_.f[i] = v;
+ }
+}
+
+void TableGenerator::Print(std::ostream* os) {
+ *os << "// BEGIN GENERATED CODE; DO NOT EDIT\n"
+ "// clang-format off\n"
+ "\n"
+ "#include \"absl/random/gaussian_distribution.h\"\n"
+ "\n"
+ // "namespace " and "absl" are broken apart so as not to conflict with
+ // script that adds the LTS inline namespace.
+ "namespace "
+ "absl {\n"
+ "namespace "
+ "random_internal {\n"
+ "\n"
+ "const gaussian_distribution_base::Tables\n"
+ " gaussian_distribution_base::zg_ = {\n";
+ FormatArrayContents(os, tables_.x);
+ *os << ",\n";
+ FormatArrayContents(os, tables_.f);
+ *os << "};\n"
+ "\n"
+ "} // namespace "
+ "random_internal\n"
+ "} // namespace "
+ "absl\n"
+ "\n"
+ "// clang-format on\n"
+ "// END GENERATED CODE";
+ *os << std::endl;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+int main(int, char**) {
+ std::cerr << "\nCopy the output to gaussian_distribution.cc" << std::endl;
+ absl::random_internal::TableGenerator generator;
+ generator.Print(&std::cout);
+ return 0;
+}
diff --git a/absl/random/internal/iostream_state_saver.h b/absl/random/internal/iostream_state_saver.h
new file mode 100644
index 00000000..b9adca86
--- /dev/null
+++ b/absl/random/internal/iostream_state_saver.h
@@ -0,0 +1,245 @@
+// 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_IOSTREAM_STATE_SAVER_H_
+#define ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// The null_state_saver does nothing.
+template <typename T>
+class null_state_saver {
+ public:
+ using stream_type = T;
+ using flags_type = std::ios_base::fmtflags;
+
+ null_state_saver(T&, flags_type) {}
+ ~null_state_saver() {}
+};
+
+// ostream_state_saver is a RAII object to save and restore the common
+// basic_ostream flags used when implementing `operator <<()` on any of
+// the absl random distributions.
+template <typename OStream>
+class ostream_state_saver {
+ public:
+ using ostream_type = OStream;
+ using flags_type = std::ios_base::fmtflags;
+ using fill_type = typename ostream_type::char_type;
+ using precision_type = std::streamsize;
+
+ ostream_state_saver(ostream_type& os, // NOLINT(runtime/references)
+ flags_type flags, fill_type fill)
+ : os_(os),
+ flags_(os.flags(flags)),
+ fill_(os.fill(fill)),
+ precision_(os.precision()) {
+ // Save state in initialized variables.
+ }
+
+ ~ostream_state_saver() {
+ // Restore saved state.
+ os_.precision(precision_);
+ os_.fill(fill_);
+ os_.flags(flags_);
+ }
+
+ private:
+ ostream_type& os_;
+ const flags_type flags_;
+ const fill_type fill_;
+ const precision_type precision_;
+};
+
+#if defined(__NDK_MAJOR__) && __NDK_MAJOR__ < 16
+#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 1
+#else
+#define ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT 0
+#endif
+
+template <typename CharT, typename Traits>
+ostream_state_saver<std::basic_ostream<CharT, Traits>> make_ostream_state_saver(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ std::ios_base::fmtflags flags = std::ios_base::dec | std::ios_base::left |
+#if ABSL_RANDOM_INTERNAL_IOSTREAM_HEXFLOAT
+ std::ios_base::fixed |
+#endif
+ std::ios_base::scientific) {
+ using result_type = ostream_state_saver<std::basic_ostream<CharT, Traits>>;
+ return result_type(os, flags, os.widen(' '));
+}
+
+template <typename T>
+typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value,
+ 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);
+}
+
+// stream_precision_helper<type>::kPrecision returns the base 10 precision
+// required to stream and reconstruct a real type exact binary value through
+// a binary->decimal->binary transition.
+template <typename T>
+struct stream_precision_helper {
+ // max_digits10 may be 0 on MSVC; if so, use digits10 + 3.
+ static constexpr int kPrecision =
+ (std::numeric_limits<T>::max_digits10 > std::numeric_limits<T>::digits10)
+ ? std::numeric_limits<T>::max_digits10
+ : (std::numeric_limits<T>::digits10 + 3);
+};
+
+template <>
+struct stream_precision_helper<float> {
+ static constexpr int kPrecision = 9;
+};
+template <>
+struct stream_precision_helper<double> {
+ static constexpr int kPrecision = 17;
+};
+template <>
+struct stream_precision_helper<long double> {
+ static constexpr int kPrecision = 36; // assuming fp128
+};
+
+// istream_state_saver is a RAII object to save and restore the common
+// std::basic_istream<> flags used when implementing `operator >>()` on any of
+// the absl random distributions.
+template <typename IStream>
+class istream_state_saver {
+ public:
+ using istream_type = IStream;
+ using flags_type = std::ios_base::fmtflags;
+
+ istream_state_saver(istream_type& is, // NOLINT(runtime/references)
+ flags_type flags)
+ : is_(is), flags_(is.flags(flags)) {}
+
+ ~istream_state_saver() { is_.flags(flags_); }
+
+ private:
+ istream_type& is_;
+ flags_type flags_;
+};
+
+template <typename CharT, typename Traits>
+istream_state_saver<std::basic_istream<CharT, Traits>> make_istream_state_saver(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ std::ios_base::fmtflags flags = std::ios_base::dec |
+ std::ios_base::scientific |
+ std::ios_base::skipws) {
+ using result_type = istream_state_saver<std::basic_istream<CharT, Traits>>;
+ return result_type(is, flags);
+}
+
+template <typename T>
+typename absl::enable_if_t<!std::is_base_of<std::ios_base, T>::value,
+ null_state_saver<T>>
+make_istream_state_saver(T& is, // NOLINT(runtime/references)
+ std::ios_base::fmtflags flags = std::ios_base::dec) {
+ using result_type = null_state_saver<T>;
+ return result_type(is, flags);
+}
+
+// stream_format_type<T> is a helper struct to convert types which
+// basic_iostream cannot output as decimal numbers into types which
+// basic_iostream can output as decimal numbers. Specifically:
+// * signed/unsigned char-width types are converted to int.
+// * TODO(lar): __int128 => uint128, except there is no operator << yet.
+//
+template <typename T>
+struct stream_format_type
+ : public std::conditional<(sizeof(T) == sizeof(char)), int, T> {};
+
+// stream_u128_helper allows us to write out either absl::uint128 or
+// __uint128_t types in the same way, which enables their use as internal
+// state of PRNG engines.
+template <typename T>
+struct stream_u128_helper;
+
+template <>
+struct stream_u128_helper<absl::uint128> {
+ template <typename IStream>
+ inline absl::uint128 read(IStream& in) {
+ uint64_t h = 0;
+ uint64_t l = 0;
+ in >> h >> l;
+ return absl::MakeUint128(h, l);
+ }
+
+ template <typename OStream>
+ inline void write(absl::uint128 val, OStream& out) {
+ uint64_t h = Uint128High64(val);
+ uint64_t l = Uint128Low64(val);
+ out << h << out.fill() << l;
+ }
+};
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+template <>
+struct stream_u128_helper<__uint128_t> {
+ template <typename IStream>
+ inline __uint128_t read(IStream& in) {
+ uint64_t h = 0;
+ uint64_t l = 0;
+ in >> h >> l;
+ return (static_cast<__uint128_t>(h) << 64) | l;
+ }
+
+ template <typename OStream>
+ inline void write(__uint128_t val, OStream& out) {
+ uint64_t h = static_cast<uint64_t>(val >> 64u);
+ uint64_t l = static_cast<uint64_t>(val);
+ out << h << out.fill() << l;
+ }
+};
+#endif
+
+template <typename FloatType, typename IStream>
+inline FloatType read_floating_point(IStream& is) {
+ static_assert(std::is_floating_point<FloatType>::value, "");
+ FloatType dest;
+ is >> dest;
+ // Parsing a double value may report a subnormal value as an error
+ // despite being able to represent it.
+ // See https://stackoverflow.com/q/52410931/3286653
+ // It may also report an underflow when parsing DOUBLE_MIN as an
+ // ERANGE error, as the parsed value may be smaller than DOUBLE_MIN
+ // and rounded up.
+ // See: https://stackoverflow.com/q/42005462
+ if (is.fail() &&
+ (std::fabs(dest) == (std::numeric_limits<FloatType>::min)() ||
+ std::fpclassify(dest) == FP_SUBNORMAL)) {
+ is.clear(is.rdstate() & (~std::ios_base::failbit));
+ }
+ return dest;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_IOSTREAM_STATE_SAVER_H_
diff --git a/absl/random/internal/iostream_state_saver_test.cc b/absl/random/internal/iostream_state_saver_test.cc
new file mode 100644
index 00000000..2ecbaac1
--- /dev/null
+++ b/absl/random/internal/iostream_state_saver_test.cc
@@ -0,0 +1,369 @@
+// 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/iostream_state_saver.h"
+
+#include <sstream>
+#include <string>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::random_internal::make_istream_state_saver;
+using absl::random_internal::make_ostream_state_saver;
+using absl::random_internal::stream_precision_helper;
+
+template <typename T>
+typename absl::enable_if_t<std::is_integral<T>::value, T> //
+StreamRoundTrip(T t) {
+ std::stringstream ss;
+ {
+ auto saver = make_ostream_state_saver(ss);
+ ss.precision(stream_precision_helper<T>::kPrecision);
+ ss << t;
+ }
+ T result = 0;
+ {
+ auto saver = make_istream_state_saver(ss);
+ ss >> result;
+ }
+ EXPECT_FALSE(ss.fail()) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+
+ return result;
+}
+
+template <typename T>
+typename absl::enable_if_t<std::is_floating_point<T>::value, T> //
+StreamRoundTrip(T t) {
+ std::stringstream ss;
+ {
+ auto saver = make_ostream_state_saver(ss);
+ ss.precision(stream_precision_helper<T>::kPrecision);
+ ss << t;
+ }
+ T result = 0;
+ {
+ auto saver = make_istream_state_saver(ss);
+ result = absl::random_internal::read_floating_point<T>(ss);
+ }
+ EXPECT_FALSE(ss.fail()) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+
+ return result;
+}
+
+TEST(IOStreamStateSaver, BasicSaverState) {
+ std::stringstream ss;
+ ss.precision(2);
+ ss.fill('x');
+ ss.flags(std::ios_base::dec | std::ios_base::right);
+
+ {
+ auto saver = make_ostream_state_saver(ss);
+ ss.precision(10);
+ EXPECT_NE('x', ss.fill());
+ EXPECT_EQ(10, ss.precision());
+ EXPECT_NE(std::ios_base::dec | std::ios_base::right, ss.flags());
+
+ ss << 1.23;
+ }
+
+ EXPECT_EQ('x', ss.fill());
+ EXPECT_EQ(2, ss.precision());
+ EXPECT_EQ(std::ios_base::dec | std::ios_base::right, ss.flags());
+}
+
+TEST(IOStreamStateSaver, RoundTripInts) {
+ const uint64_t kUintValues[] = {
+ 0,
+ 1,
+ static_cast<uint64_t>(-1),
+ 2,
+ static_cast<uint64_t>(-2),
+
+ 1 << 7,
+ 1 << 8,
+ 1 << 16,
+ 1ull << 32,
+ 1ull << 50,
+ 1ull << 62,
+ 1ull << 63,
+
+ (1 << 7) - 1,
+ (1 << 8) - 1,
+ (1 << 16) - 1,
+ (1ull << 32) - 1,
+ (1ull << 50) - 1,
+ (1ull << 62) - 1,
+ (1ull << 63) - 1,
+
+ static_cast<uint64_t>(-(1 << 8)),
+ static_cast<uint64_t>(-(1 << 16)),
+ static_cast<uint64_t>(-(1ll << 32)),
+ static_cast<uint64_t>(-(1ll << 50)),
+ static_cast<uint64_t>(-(1ll << 62)),
+
+ static_cast<uint64_t>(-(1 << 8) - 1),
+ static_cast<uint64_t>(-(1 << 16) - 1),
+ static_cast<uint64_t>(-(1ll << 32) - 1),
+ static_cast<uint64_t>(-(1ll << 50) - 1),
+ static_cast<uint64_t>(-(1ll << 62) - 1),
+ };
+
+ for (const uint64_t u : kUintValues) {
+ EXPECT_EQ(u, StreamRoundTrip<uint64_t>(u));
+
+ int64_t x = static_cast<int64_t>(u);
+ EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
+
+ double d = static_cast<double>(x);
+ EXPECT_EQ(d, StreamRoundTrip<double>(d));
+
+ float f = d;
+ EXPECT_EQ(f, StreamRoundTrip<float>(f));
+ }
+}
+
+TEST(IOStreamStateSaver, RoundTripFloats) {
+ static_assert(
+ stream_precision_helper<float>::kPrecision >= 9,
+ "stream_precision_helper<float>::kPrecision should be at least 9");
+
+ const float kValues[] = {
+ 1,
+ std::nextafter(1.0f, 0.0f), // 1 - epsilon
+ std::nextafter(1.0f, 2.0f), // 1 + epsilon
+
+ 1.0e+1f,
+ 1.0e-1f,
+ 1.0e+2f,
+ 1.0e-2f,
+ 1.0e+10f,
+ 1.0e-10f,
+
+ 0.00000051110000111311111111f,
+ -0.00000051110000111211111111f,
+
+ 1.234678912345678912345e+6f,
+ 1.234678912345678912345e-6f,
+ 1.234678912345678912345e+30f,
+ 1.234678912345678912345e-30f,
+ 1.234678912345678912345e+38f,
+ 1.0234678912345678912345e-38f,
+
+ // Boundary cases.
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::lowest(),
+ std::numeric_limits<float>::epsilon(),
+ std::nextafter(std::numeric_limits<float>::min(),
+ 1.0f), // min + epsilon
+ std::numeric_limits<float>::min(), // smallest normal
+ // There are some errors dealing with denorms on apple platforms.
+ std::numeric_limits<float>::denorm_min(), // smallest denorm
+ std::numeric_limits<float>::min() / 2,
+ std::nextafter(std::numeric_limits<float>::min(),
+ 0.0f), // denorm_max
+ std::nextafter(std::numeric_limits<float>::denorm_min(), 1.0f),
+ };
+
+ for (const float f : kValues) {
+ EXPECT_EQ(f, StreamRoundTrip<float>(f));
+ EXPECT_EQ(-f, StreamRoundTrip<float>(-f));
+
+ double d = f;
+ EXPECT_EQ(d, StreamRoundTrip<double>(d));
+ EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
+
+ // Avoid undefined behavior (overflow/underflow).
+ if (d <= std::numeric_limits<int64_t>::max() &&
+ d >= std::numeric_limits<int64_t>::lowest()) {
+ int64_t x = static_cast<int64_t>(f);
+ EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
+ }
+ }
+}
+
+TEST(IOStreamStateSaver, RoundTripDoubles) {
+ static_assert(
+ stream_precision_helper<double>::kPrecision >= 17,
+ "stream_precision_helper<double>::kPrecision should be at least 17");
+
+ const double kValues[] = {
+ 1,
+ std::nextafter(1.0, 0.0), // 1 - epsilon
+ std::nextafter(1.0, 2.0), // 1 + epsilon
+
+ 1.0e+1,
+ 1.0e-1,
+ 1.0e+2,
+ 1.0e-2,
+ 1.0e+10,
+ 1.0e-10,
+
+ 0.00000051110000111311111111,
+ -0.00000051110000111211111111,
+
+ 1.234678912345678912345e+6,
+ 1.234678912345678912345e-6,
+ 1.234678912345678912345e+30,
+ 1.234678912345678912345e-30,
+ 1.234678912345678912345e+38,
+ 1.0234678912345678912345e-38,
+
+ 1.0e+100,
+ 1.0e-100,
+ 1.234678912345678912345e+308,
+ 1.0234678912345678912345e-308,
+ 2.22507385850720138e-308,
+
+ // Boundary cases.
+ std::numeric_limits<double>::max(),
+ std::numeric_limits<double>::lowest(),
+ std::numeric_limits<double>::epsilon(),
+ std::nextafter(std::numeric_limits<double>::min(),
+ 1.0), // min + epsilon
+ std::numeric_limits<double>::min(), // smallest normal
+ // There are some errors dealing with denorms on apple platforms.
+ std::numeric_limits<double>::denorm_min(), // smallest denorm
+ std::numeric_limits<double>::min() / 2,
+ std::nextafter(std::numeric_limits<double>::min(),
+ 0.0), // denorm_max
+ std::nextafter(std::numeric_limits<double>::denorm_min(), 1.0f),
+ };
+
+ for (const double d : kValues) {
+ EXPECT_EQ(d, StreamRoundTrip<double>(d));
+ EXPECT_EQ(-d, StreamRoundTrip<double>(-d));
+
+ // Avoid undefined behavior (overflow/underflow).
+ if (d <= std::numeric_limits<float>::max() &&
+ d >= std::numeric_limits<float>::lowest()) {
+ float f = static_cast<float>(d);
+ EXPECT_EQ(f, StreamRoundTrip<float>(f));
+ }
+
+ // Avoid undefined behavior (overflow/underflow).
+ if (d <= std::numeric_limits<int64_t>::max() &&
+ d >= std::numeric_limits<int64_t>::lowest()) {
+ int64_t x = static_cast<int64_t>(d);
+ EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
+ }
+ }
+}
+
+TEST(IOStreamStateSaver, RoundTripLongDoubles) {
+ // Technically, C++ only guarantees that long double is at least as large as a
+ // double. Practically it varies from 64-bits to 128-bits.
+ //
+ // So it is best to consider long double a best-effort extended precision
+ // type.
+
+ static_assert(
+ stream_precision_helper<long double>::kPrecision >= 36,
+ "stream_precision_helper<long double>::kPrecision should be at least 36");
+
+ using real_type = long double;
+ const real_type kValues[] = {
+ 1,
+ std::nextafter(1.0, 0.0), // 1 - epsilon
+ std::nextafter(1.0, 2.0), // 1 + epsilon
+
+ 1.0e+1,
+ 1.0e-1,
+ 1.0e+2,
+ 1.0e-2,
+ 1.0e+10,
+ 1.0e-10,
+
+ 0.00000051110000111311111111,
+ -0.00000051110000111211111111,
+
+ 1.2346789123456789123456789123456789e+6,
+ 1.2346789123456789123456789123456789e-6,
+ 1.2346789123456789123456789123456789e+30,
+ 1.2346789123456789123456789123456789e-30,
+ 1.2346789123456789123456789123456789e+38,
+ 1.2346789123456789123456789123456789e-38,
+ 1.2346789123456789123456789123456789e+308,
+ 1.2346789123456789123456789123456789e-308,
+
+ 1.0e+100,
+ 1.0e-100,
+ 1.234678912345678912345e+308,
+ 1.0234678912345678912345e-308,
+
+ // Boundary cases.
+ std::numeric_limits<real_type>::max(),
+ std::numeric_limits<real_type>::lowest(),
+ std::numeric_limits<real_type>::epsilon(),
+ std::nextafter(std::numeric_limits<real_type>::min(),
+ real_type(1)), // min + epsilon
+ std::numeric_limits<real_type>::min(), // smallest normal
+ // There are some errors dealing with denorms on apple platforms.
+ std::numeric_limits<real_type>::denorm_min(), // smallest denorm
+ std::numeric_limits<real_type>::min() / 2,
+ std::nextafter(std::numeric_limits<real_type>::min(),
+ 0.0), // denorm_max
+ std::nextafter(std::numeric_limits<real_type>::denorm_min(), 1.0f),
+ };
+
+ int index = -1;
+ for (const long double dd : kValues) {
+ index++;
+ EXPECT_EQ(dd, StreamRoundTrip<real_type>(dd)) << index;
+ EXPECT_EQ(-dd, StreamRoundTrip<real_type>(-dd)) << index;
+
+ // Avoid undefined behavior (overflow/underflow).
+ if (dd <= std::numeric_limits<double>::max() &&
+ dd >= std::numeric_limits<double>::lowest()) {
+ double d = static_cast<double>(dd);
+ EXPECT_EQ(d, StreamRoundTrip<double>(d));
+ }
+
+ // Avoid undefined behavior (overflow/underflow).
+ if (dd <= std::numeric_limits<int64_t>::max() &&
+ dd >= std::numeric_limits<int64_t>::lowest()) {
+ int64_t x = static_cast<int64_t>(dd);
+ EXPECT_EQ(x, StreamRoundTrip<int64_t>(x));
+ }
+ }
+}
+
+TEST(StrToDTest, DoubleMin) {
+ const char kV[] = "2.22507385850720138e-308";
+ char* end;
+ double x = std::strtod(kV, &end);
+ EXPECT_EQ(std::numeric_limits<double>::min(), x);
+ // errno may equal ERANGE.
+}
+
+TEST(StrToDTest, DoubleDenormMin) {
+ const char kV[] = "4.94065645841246544e-324";
+ char* end;
+ double x = std::strtod(kV, &end);
+ EXPECT_EQ(std::numeric_limits<double>::denorm_min(), x);
+ // errno may equal ERANGE.
+}
+
+} // namespace
diff --git a/absl/random/internal/named_generator.cc b/absl/random/internal/named_generator.cc
new file mode 100644
index 00000000..b168a25b
--- /dev/null
+++ b/absl/random/internal/named_generator.cc
@@ -0,0 +1,30 @@
+// 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.
+
+#include <cstddef>
+#include <iostream>
+
+#include "absl/random/random.h"
+
+// This program is used in integration tests.
+
+int main() {
+ auto seed_seq = absl::MakeTaggedSeedSeq("TEST_GENERATOR", std::cerr);
+ absl::BitGen rng(seed_seq);
+ constexpr size_t kSequenceLength = 8;
+ for (size_t i = 0; i < kSequenceLength; i++) {
+ std::cout << rng() << "\n";
+ }
+ return 0;
+}
diff --git a/absl/random/internal/nanobenchmark.cc b/absl/random/internal/nanobenchmark.cc
new file mode 100644
index 00000000..4d26469b
--- /dev/null
+++ b/absl/random/internal/nanobenchmark.cc
@@ -0,0 +1,812 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// 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/nanobenchmark.h"
+
+#include <sys/types.h>
+
+#include <algorithm> // sort
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring> // memcpy
+#include <limits>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_engine.h"
+
+// OS
+#if defined(_WIN32) || defined(_WIN64)
+#define ABSL_OS_WIN
+#include <windows.h> // NOLINT
+
+#elif defined(__ANDROID__)
+#define ABSL_OS_ANDROID
+
+#elif defined(__linux__)
+#define ABSL_OS_LINUX
+#include <sched.h> // NOLINT
+#include <sys/syscall.h> // NOLINT
+#endif
+
+#if defined(ABSL_ARCH_X86_64) && !defined(ABSL_OS_WIN)
+#include <cpuid.h> // NOLINT
+#endif
+
+// __ppc_get_timebase_freq
+#if defined(ABSL_ARCH_PPC)
+#include <sys/platform/ppc.h> // NOLINT
+#endif
+
+// clock_gettime
+#if defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
+#include <time.h> // NOLINT
+#endif
+
+// ABSL_HAVE_ATTRIBUTE
+#if !defined(ABSL_HAVE_ATTRIBUTE)
+#ifdef __has_attribute
+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define ABSL_HAVE_ATTRIBUTE(x) 0
+#endif
+#endif
+
+// ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE prevents inlining of the method.
+#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE __declspec(noinline)
+#else
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE
+#endif
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal_nanobenchmark {
+namespace {
+
+// For code folding.
+namespace platform {
+#if defined(ABSL_ARCH_X86_64)
+
+// TODO(janwas): Merge with the one in randen_hwaes.cc?
+void Cpuid(const uint32_t level, const uint32_t count,
+ uint32_t* ABSL_RANDOM_INTERNAL_RESTRICT abcd) {
+#if defined(ABSL_OS_WIN)
+ int regs[4];
+ __cpuidex(regs, level, count);
+ for (int i = 0; i < 4; ++i) {
+ abcd[i] = regs[i];
+ }
+#else
+ uint32_t a, b, c, d;
+ __cpuid_count(level, count, a, b, c, d);
+ abcd[0] = a;
+ abcd[1] = b;
+ abcd[2] = c;
+ abcd[3] = d;
+#endif
+}
+
+std::string BrandString() {
+ char brand_string[49];
+ uint32_t abcd[4];
+
+ // Check if brand std::string is supported (it is on all reasonable Intel/AMD)
+ Cpuid(0x80000000U, 0, abcd);
+ if (abcd[0] < 0x80000004U) {
+ return std::string();
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ Cpuid(0x80000002U + i, 0, abcd);
+ memcpy(brand_string + i * 16, &abcd, sizeof(abcd));
+ }
+ brand_string[48] = 0;
+ return brand_string;
+}
+
+// Returns the frequency quoted inside the brand string. This does not
+// account for throttling nor Turbo Boost.
+double NominalClockRate() {
+ const std::string& brand_string = BrandString();
+ // Brand strings include the maximum configured frequency. These prefixes are
+ // defined by Intel CPUID documentation.
+ const char* prefixes[3] = {"MHz", "GHz", "THz"};
+ const double multipliers[3] = {1E6, 1E9, 1E12};
+ for (size_t i = 0; i < 3; ++i) {
+ const size_t pos_prefix = brand_string.find(prefixes[i]);
+ if (pos_prefix != std::string::npos) {
+ const size_t pos_space = brand_string.rfind(' ', pos_prefix - 1);
+ if (pos_space != std::string::npos) {
+ const std::string digits =
+ brand_string.substr(pos_space + 1, pos_prefix - pos_space - 1);
+ return std::stod(digits) * multipliers[i];
+ }
+ }
+ }
+
+ return 0.0;
+}
+
+#endif // ABSL_ARCH_X86_64
+} // namespace platform
+
+// Prevents the compiler from eliding the computations that led to "output".
+template <class T>
+inline void PreventElision(T&& output) {
+#ifndef ABSL_OS_WIN
+ // Works by indicating to the compiler that "output" is being read and
+ // modified. The +r constraint avoids unnecessary writes to memory, but only
+ // works for built-in types (typically FuncOutput).
+ asm volatile("" : "+r"(output) : : "memory");
+#else
+ // MSVC does not support inline assembly anymore (and never supported GCC's
+ // RTL constraints). Self-assignment with #pragma optimize("off") might be
+ // expected to prevent elision, but it does not with MSVC 2015. Type-punning
+ // with volatile pointers generates inefficient code on MSVC 2017.
+ static std::atomic<T> dummy(T{});
+ dummy.store(output, std::memory_order_relaxed);
+#endif
+}
+
+namespace timer {
+
+// Start/Stop return absolute timestamps and must be placed immediately before
+// and after the region to measure. We provide separate Start/Stop functions
+// because they use different fences.
+//
+// Background: RDTSC is not 'serializing'; earlier instructions may complete
+// after it, and/or later instructions may complete before it. 'Fences' ensure
+// regions' elapsed times are independent of such reordering. The only
+// documented unprivileged serializing instruction is CPUID, which acts as a
+// full fence (no reordering across it in either direction). Unfortunately
+// the latency of CPUID varies wildly (perhaps made worse by not initializing
+// its EAX input). Because it cannot reliably be deducted from the region's
+// elapsed time, it must not be included in the region to measure (i.e.
+// between the two RDTSC).
+//
+// The newer RDTSCP is sometimes described as serializing, but it actually
+// only serves as a half-fence with release semantics. Although all
+// instructions in the region will complete before the final timestamp is
+// captured, subsequent instructions may leak into the region and increase the
+// elapsed time. Inserting another fence after the final RDTSCP would prevent
+// such reordering without affecting the measured region.
+//
+// Fortunately, such a fence exists. The LFENCE instruction is only documented
+// to delay later loads until earlier loads are visible. However, Intel's
+// reference manual says it acts as a full fence (waiting until all earlier
+// instructions have completed, and delaying later instructions until it
+// completes). AMD assigns the same behavior to MFENCE.
+//
+// We need a fence before the initial RDTSC to prevent earlier instructions
+// from leaking into the region, and arguably another after RDTSC to avoid
+// region instructions from completing before the timestamp is recorded.
+// When surrounded by fences, the additional RDTSCP half-fence provides no
+// benefit, so the initial timestamp can be recorded via RDTSC, which has
+// lower overhead than RDTSCP because it does not read TSC_AUX. In summary,
+// we define Start = LFENCE/RDTSC/LFENCE; Stop = RDTSCP/LFENCE.
+//
+// Using Start+Start leads to higher variance and overhead than Stop+Stop.
+// However, Stop+Stop includes an LFENCE in the region measurements, which
+// adds a delay dependent on earlier loads. The combination of Start+Stop
+// is faster than Start+Start and more consistent than Stop+Stop because
+// the first LFENCE already delayed subsequent loads before the measured
+// region. This combination seems not to have been considered in prior work:
+// http://akaros.cs.berkeley.edu/lxr/akaros/kern/arch/x86/rdtsc_test.c
+//
+// Note: performance counters can measure 'exact' instructions-retired or
+// (unhalted) cycle counts. The RDPMC instruction is not serializing and also
+// requires fences. Unfortunately, it is not accessible on all OSes and we
+// prefer to avoid kernel-mode drivers. Performance counters are also affected
+// by several under/over-count errata, so we use the TSC instead.
+
+// Returns a 64-bit timestamp in unit of 'ticks'; to convert to seconds,
+// divide by InvariantTicksPerSecond.
+inline uint64_t Start64() {
+ uint64_t t;
+#if defined(ABSL_ARCH_PPC)
+ asm volatile("mfspr %0, %1" : "=r"(t) : "i"(268));
+#elif defined(ABSL_ARCH_X86_64)
+#if defined(ABSL_OS_WIN)
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+ t = __rdtsc();
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+#else
+ asm volatile(
+ "lfence\n\t"
+ "rdtsc\n\t"
+ "shl $32, %%rdx\n\t"
+ "or %%rdx, %0\n\t"
+ "lfence"
+ : "=a"(t)
+ :
+ // "memory" avoids reordering. rdx = TSC >> 32.
+ // "cc" = flags modified by SHL.
+ : "rdx", "memory", "cc");
+#endif
+#else
+ // Fall back to OS - unsure how to reliably query cntvct_el0 frequency.
+ timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ t = ts.tv_sec * 1000000000LL + ts.tv_nsec;
+#endif
+ return t;
+}
+
+inline uint64_t Stop64() {
+ uint64_t t;
+#if defined(ABSL_ARCH_X86_64)
+#if defined(ABSL_OS_WIN)
+ _ReadWriteBarrier();
+ unsigned aux;
+ t = __rdtscp(&aux);
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+#else
+ // Use inline asm because __rdtscp generates code to store TSC_AUX (ecx).
+ asm volatile(
+ "rdtscp\n\t"
+ "shl $32, %%rdx\n\t"
+ "or %%rdx, %0\n\t"
+ "lfence"
+ : "=a"(t)
+ :
+ // "memory" avoids reordering. rcx = TSC_AUX. rdx = TSC >> 32.
+ // "cc" = flags modified by SHL.
+ : "rcx", "rdx", "memory", "cc");
+#endif
+#else
+ t = Start64();
+#endif
+ return t;
+}
+
+// Returns a 32-bit timestamp with about 4 cycles less overhead than
+// Start64. Only suitable for measuring very short regions because the
+// timestamp overflows about once a second.
+inline uint32_t Start32() {
+ uint32_t t;
+#if defined(ABSL_ARCH_X86_64)
+#if defined(ABSL_OS_WIN)
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+ t = static_cast<uint32_t>(__rdtsc());
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+#else
+ asm volatile(
+ "lfence\n\t"
+ "rdtsc\n\t"
+ "lfence"
+ : "=a"(t)
+ :
+ // "memory" avoids reordering. rdx = TSC >> 32.
+ : "rdx", "memory");
+#endif
+#else
+ t = static_cast<uint32_t>(Start64());
+#endif
+ return t;
+}
+
+inline uint32_t Stop32() {
+ uint32_t t;
+#if defined(ABSL_ARCH_X86_64)
+#if defined(ABSL_OS_WIN)
+ _ReadWriteBarrier();
+ unsigned aux;
+ t = static_cast<uint32_t>(__rdtscp(&aux));
+ _ReadWriteBarrier();
+ _mm_lfence();
+ _ReadWriteBarrier();
+#else
+ // Use inline asm because __rdtscp generates code to store TSC_AUX (ecx).
+ asm volatile(
+ "rdtscp\n\t"
+ "lfence"
+ : "=a"(t)
+ :
+ // "memory" avoids reordering. rcx = TSC_AUX. rdx = TSC >> 32.
+ : "rcx", "rdx", "memory");
+#endif
+#else
+ t = static_cast<uint32_t>(Stop64());
+#endif
+ return t;
+}
+
+} // namespace timer
+
+namespace robust_statistics {
+
+// Sorts integral values in ascending order (e.g. for Mode). About 3x faster
+// than std::sort for input distributions with very few unique values.
+template <class T>
+void CountingSort(T* values, size_t num_values) {
+ // Unique values and their frequency (similar to flat_map).
+ using Unique = std::pair<T, int>;
+ std::vector<Unique> unique;
+ for (size_t i = 0; i < num_values; ++i) {
+ const T value = values[i];
+ const auto pos =
+ std::find_if(unique.begin(), unique.end(),
+ [value](const Unique u) { return u.first == value; });
+ if (pos == unique.end()) {
+ unique.push_back(std::make_pair(value, 1));
+ } else {
+ ++pos->second;
+ }
+ }
+
+ // Sort in ascending order of value (pair.first).
+ std::sort(unique.begin(), unique.end());
+
+ // Write that many copies of each unique value to the array.
+ T* ABSL_RANDOM_INTERNAL_RESTRICT p = values;
+ for (const auto& value_count : unique) {
+ std::fill(p, p + value_count.second, value_count.first);
+ p += value_count.second;
+ }
+ ABSL_RAW_CHECK(p == values + num_values, "Did not produce enough output");
+}
+
+// @return i in [idx_begin, idx_begin + half_count) that minimizes
+// sorted[i + half_count] - sorted[i].
+template <typename T>
+size_t MinRange(const T* const ABSL_RANDOM_INTERNAL_RESTRICT sorted,
+ const size_t idx_begin, const size_t half_count) {
+ T min_range = (std::numeric_limits<T>::max)();
+ size_t min_idx = 0;
+
+ for (size_t idx = idx_begin; idx < idx_begin + half_count; ++idx) {
+ ABSL_RAW_CHECK(sorted[idx] <= sorted[idx + half_count], "Not sorted");
+ const T range = sorted[idx + half_count] - sorted[idx];
+ if (range < min_range) {
+ min_range = range;
+ min_idx = idx;
+ }
+ }
+
+ return min_idx;
+}
+
+// Returns an estimate of the mode by calling MinRange on successively
+// halved intervals. "sorted" must be in ascending order. This is the
+// Half Sample Mode estimator proposed by Bickel in "On a fast, robust
+// estimator of the mode", with complexity O(N log N). The mode is less
+// affected by outliers in highly-skewed distributions than the median.
+// The averaging operation below assumes "T" is an unsigned integer type.
+template <typename T>
+T ModeOfSorted(const T* const ABSL_RANDOM_INTERNAL_RESTRICT sorted,
+ const size_t num_values) {
+ size_t idx_begin = 0;
+ size_t half_count = num_values / 2;
+ while (half_count > 1) {
+ idx_begin = MinRange(sorted, idx_begin, half_count);
+ half_count >>= 1;
+ }
+
+ const T x = sorted[idx_begin + 0];
+ if (half_count == 0) {
+ return x;
+ }
+ ABSL_RAW_CHECK(half_count == 1, "Should stop at half_count=1");
+ const T average = (x + sorted[idx_begin + 1] + 1) / 2;
+ return average;
+}
+
+// Returns the mode. Side effect: sorts "values".
+template <typename T>
+T Mode(T* values, const size_t num_values) {
+ CountingSort(values, num_values);
+ return ModeOfSorted(values, num_values);
+}
+
+template <typename T, size_t N>
+T Mode(T (&values)[N]) {
+ return Mode(&values[0], N);
+}
+
+// Returns the median value. Side effect: sorts "values".
+template <typename T>
+T Median(T* values, const size_t num_values) {
+ ABSL_RAW_CHECK(num_values != 0, "Empty input");
+ std::sort(values, values + num_values);
+ const size_t half = num_values / 2;
+ // Odd count: return middle
+ if (num_values % 2) {
+ return values[half];
+ }
+ // Even count: return average of middle two.
+ return (values[half] + values[half - 1] + 1) / 2;
+}
+
+// Returns a robust measure of variability.
+template <typename T>
+T MedianAbsoluteDeviation(const T* values, const size_t num_values,
+ const T median) {
+ ABSL_RAW_CHECK(num_values != 0, "Empty input");
+ std::vector<T> abs_deviations;
+ abs_deviations.reserve(num_values);
+ for (size_t i = 0; i < num_values; ++i) {
+ const int64_t abs = std::abs(int64_t(values[i]) - int64_t(median));
+ abs_deviations.push_back(static_cast<T>(abs));
+ }
+ return Median(abs_deviations.data(), num_values);
+}
+
+} // namespace robust_statistics
+
+// Ticks := platform-specific timer values (CPU cycles on x86). Must be
+// unsigned to guarantee wraparound on overflow. 32 bit timers are faster to
+// read than 64 bit.
+using Ticks = uint32_t;
+
+// Returns timer overhead / minimum measurable difference.
+Ticks TimerResolution() {
+ // Nested loop avoids exceeding stack/L1 capacity.
+ Ticks repetitions[Params::kTimerSamples];
+ for (size_t rep = 0; rep < Params::kTimerSamples; ++rep) {
+ Ticks samples[Params::kTimerSamples];
+ for (size_t i = 0; i < Params::kTimerSamples; ++i) {
+ const Ticks t0 = timer::Start32();
+ const Ticks t1 = timer::Stop32();
+ samples[i] = t1 - t0;
+ }
+ repetitions[rep] = robust_statistics::Mode(samples);
+ }
+ return robust_statistics::Mode(repetitions);
+}
+
+static const Ticks timer_resolution = TimerResolution();
+
+// Estimates the expected value of "lambda" values with a variable number of
+// samples until the variability "rel_mad" is less than "max_rel_mad".
+template <class Lambda>
+Ticks SampleUntilStable(const double max_rel_mad, double* rel_mad,
+ const Params& p, const Lambda& lambda) {
+ auto measure_duration = [&lambda]() -> Ticks {
+ const Ticks t0 = timer::Start32();
+ lambda();
+ const Ticks t1 = timer::Stop32();
+ return t1 - t0;
+ };
+
+ // Choose initial samples_per_eval based on a single estimated duration.
+ Ticks est = measure_duration();
+ static const double ticks_per_second = InvariantTicksPerSecond();
+ const size_t ticks_per_eval = ticks_per_second * p.seconds_per_eval;
+ size_t samples_per_eval = ticks_per_eval / est;
+ samples_per_eval = (std::max)(samples_per_eval, p.min_samples_per_eval);
+
+ std::vector<Ticks> samples;
+ samples.reserve(1 + samples_per_eval);
+ samples.push_back(est);
+
+ // Percentage is too strict for tiny differences, so also allow a small
+ // absolute "median absolute deviation".
+ const Ticks max_abs_mad = (timer_resolution + 99) / 100;
+ *rel_mad = 0.0; // ensure initialized
+
+ for (size_t eval = 0; eval < p.max_evals; ++eval, samples_per_eval *= 2) {
+ samples.reserve(samples.size() + samples_per_eval);
+ for (size_t i = 0; i < samples_per_eval; ++i) {
+ const Ticks r = measure_duration();
+ samples.push_back(r);
+ }
+
+ if (samples.size() >= p.min_mode_samples) {
+ est = robust_statistics::Mode(samples.data(), samples.size());
+ } else {
+ // For "few" (depends also on the variance) samples, Median is safer.
+ est = robust_statistics::Median(samples.data(), samples.size());
+ }
+ ABSL_RAW_CHECK(est != 0, "Estimator returned zero duration");
+
+ // Median absolute deviation (mad) is a robust measure of 'variability'.
+ const Ticks abs_mad = robust_statistics::MedianAbsoluteDeviation(
+ samples.data(), samples.size(), est);
+ *rel_mad = static_cast<double>(static_cast<int>(abs_mad)) / est;
+
+ if (*rel_mad <= max_rel_mad || abs_mad <= max_abs_mad) {
+ if (p.verbose) {
+ ABSL_RAW_LOG(INFO,
+ "%6zu samples => %5u (abs_mad=%4u, rel_mad=%4.2f%%)\n",
+ samples.size(), est, abs_mad, *rel_mad * 100.0);
+ }
+ return est;
+ }
+ }
+
+ if (p.verbose) {
+ ABSL_RAW_LOG(WARNING,
+ "rel_mad=%4.2f%% still exceeds %4.2f%% after %6zu samples.\n",
+ *rel_mad * 100.0, max_rel_mad * 100.0, samples.size());
+ }
+ return est;
+}
+
+using InputVec = std::vector<FuncInput>;
+
+// Returns vector of unique input values.
+InputVec UniqueInputs(const FuncInput* inputs, const size_t num_inputs) {
+ InputVec unique(inputs, inputs + num_inputs);
+ std::sort(unique.begin(), unique.end());
+ unique.erase(std::unique(unique.begin(), unique.end()), unique.end());
+ return unique;
+}
+
+// Returns how often we need to call func for sufficient precision, or zero
+// on failure (e.g. the elapsed time is too long for a 32-bit tick count).
+size_t NumSkip(const Func func, const void* arg, const InputVec& unique,
+ const Params& p) {
+ // Min elapsed ticks for any input.
+ Ticks min_duration = ~0u;
+
+ for (const FuncInput input : unique) {
+ // Make sure a 32-bit timer is sufficient.
+ const uint64_t t0 = timer::Start64();
+ PreventElision(func(arg, input));
+ const uint64_t t1 = timer::Stop64();
+ const uint64_t elapsed = t1 - t0;
+ if (elapsed >= (1ULL << 30)) {
+ ABSL_RAW_LOG(WARNING,
+ "Measurement failed: need 64-bit timer for input=%zu\n",
+ static_cast<size_t>(input));
+ return 0;
+ }
+
+ double rel_mad;
+ const Ticks total = SampleUntilStable(
+ p.target_rel_mad, &rel_mad, p,
+ [func, arg, input]() { PreventElision(func(arg, input)); });
+ min_duration = (std::min)(min_duration, total - timer_resolution);
+ }
+
+ // Number of repetitions required to reach the target resolution.
+ const size_t max_skip = p.precision_divisor;
+ // Number of repetitions given the estimated duration.
+ const size_t num_skip =
+ min_duration == 0 ? 0 : (max_skip + min_duration - 1) / min_duration;
+ if (p.verbose) {
+ ABSL_RAW_LOG(INFO, "res=%u max_skip=%zu min_dur=%u num_skip=%zu\n",
+ timer_resolution, max_skip, min_duration, num_skip);
+ }
+ return num_skip;
+}
+
+// Replicates inputs until we can omit "num_skip" occurrences of an input.
+InputVec ReplicateInputs(const FuncInput* inputs, const size_t num_inputs,
+ const size_t num_unique, const size_t num_skip,
+ const Params& p) {
+ InputVec full;
+ if (num_unique == 1) {
+ full.assign(p.subset_ratio * num_skip, inputs[0]);
+ return full;
+ }
+
+ full.reserve(p.subset_ratio * num_skip * num_inputs);
+ for (size_t i = 0; i < p.subset_ratio * num_skip; ++i) {
+ full.insert(full.end(), inputs, inputs + num_inputs);
+ }
+ absl::random_internal::randen_engine<uint32_t> rng;
+ std::shuffle(full.begin(), full.end(), rng);
+ return full;
+}
+
+// Copies the "full" to "subset" in the same order, but with "num_skip"
+// randomly selected occurrences of "input_to_skip" removed.
+void FillSubset(const InputVec& full, const FuncInput input_to_skip,
+ const size_t num_skip, InputVec* subset) {
+ const size_t count = std::count(full.begin(), full.end(), input_to_skip);
+ // Generate num_skip random indices: which occurrence to skip.
+ std::vector<uint32_t> omit;
+ // Replacement for std::iota, not yet available in MSVC builds.
+ omit.reserve(count);
+ for (size_t i = 0; i < count; ++i) {
+ omit.push_back(i);
+ }
+ // omit[] is the same on every call, but that's OK because they identify the
+ // Nth instance of input_to_skip, so the position within full[] differs.
+ absl::random_internal::randen_engine<uint32_t> rng;
+ std::shuffle(omit.begin(), omit.end(), rng);
+ omit.resize(num_skip);
+ std::sort(omit.begin(), omit.end());
+
+ uint32_t occurrence = ~0u; // 0 after preincrement
+ size_t idx_omit = 0; // cursor within omit[]
+ size_t idx_subset = 0; // cursor within *subset
+ for (const FuncInput next : full) {
+ if (next == input_to_skip) {
+ ++occurrence;
+ // Haven't removed enough already
+ if (idx_omit < num_skip) {
+ // This one is up for removal
+ if (occurrence == omit[idx_omit]) {
+ ++idx_omit;
+ continue;
+ }
+ }
+ }
+ if (idx_subset < subset->size()) {
+ (*subset)[idx_subset++] = next;
+ }
+ }
+ ABSL_RAW_CHECK(idx_subset == subset->size(), "idx_subset not at end");
+ ABSL_RAW_CHECK(idx_omit == omit.size(), "idx_omit not at end");
+ ABSL_RAW_CHECK(occurrence == count - 1, "occurrence not at end");
+}
+
+// Returns total ticks elapsed for all inputs.
+Ticks TotalDuration(const Func func, const void* arg, const InputVec* inputs,
+ const Params& p, double* max_rel_mad) {
+ double rel_mad;
+ const Ticks duration =
+ SampleUntilStable(p.target_rel_mad, &rel_mad, p, [func, arg, inputs]() {
+ for (const FuncInput input : *inputs) {
+ PreventElision(func(arg, input));
+ }
+ });
+ *max_rel_mad = (std::max)(*max_rel_mad, rel_mad);
+ return duration;
+}
+
+// (Nearly) empty Func for measuring timer overhead/resolution.
+ABSL_RANDOM_INTERNAL_ATTRIBUTE_NEVER_INLINE FuncOutput
+EmptyFunc(const void* arg, const FuncInput input) {
+ return input;
+}
+
+// Returns overhead of accessing inputs[] and calling a function; this will
+// be deducted from future TotalDuration return values.
+Ticks Overhead(const void* arg, const InputVec* inputs, const Params& p) {
+ double rel_mad;
+ // Zero tolerance because repeatability is crucial and EmptyFunc is fast.
+ return SampleUntilStable(0.0, &rel_mad, p, [arg, inputs]() {
+ for (const FuncInput input : *inputs) {
+ PreventElision(EmptyFunc(arg, input));
+ }
+ });
+}
+
+} // namespace
+
+void PinThreadToCPU(int cpu) {
+ // We might migrate to another CPU before pinning below, but at least cpu
+ // will be one of the CPUs on which this thread ran.
+#if defined(ABSL_OS_WIN)
+ if (cpu < 0) {
+ cpu = static_cast<int>(GetCurrentProcessorNumber());
+ ABSL_RAW_CHECK(cpu >= 0, "PinThreadToCPU detect failed");
+ if (cpu >= 64) {
+ // NOTE: On wine, at least, GetCurrentProcessorNumber() sometimes returns
+ // a value > 64, which is out of range. When this happens, log a message
+ // and don't set a cpu affinity.
+ ABSL_RAW_LOG(ERROR, "Invalid CPU number: %d", cpu);
+ return;
+ }
+ } else if (cpu >= 64) {
+ // User specified an explicit CPU affinity > the valid range.
+ ABSL_RAW_LOG(FATAL, "Invalid CPU number: %d", cpu);
+ }
+ const DWORD_PTR prev = SetThreadAffinityMask(GetCurrentThread(), 1ULL << cpu);
+ ABSL_RAW_CHECK(prev != 0, "SetAffinity failed");
+#elif defined(ABSL_OS_LINUX) && !defined(ABSL_OS_ANDROID)
+ if (cpu < 0) {
+ cpu = sched_getcpu();
+ ABSL_RAW_CHECK(cpu >= 0, "PinThreadToCPU detect failed");
+ }
+ const pid_t pid = 0; // current thread
+ cpu_set_t set;
+ CPU_ZERO(&set);
+ CPU_SET(cpu, &set);
+ const int err = sched_setaffinity(pid, sizeof(set), &set);
+ ABSL_RAW_CHECK(err == 0, "SetAffinity failed");
+#endif
+}
+
+// Returns tick rate. Invariant means the tick counter frequency is independent
+// of CPU throttling or sleep. May be expensive, caller should cache the result.
+double InvariantTicksPerSecond() {
+#if defined(ABSL_ARCH_PPC)
+ return __ppc_get_timebase_freq();
+#elif defined(ABSL_ARCH_X86_64)
+ // We assume the TSC is invariant; it is on all recent Intel/AMD CPUs.
+ return platform::NominalClockRate();
+#else
+ // Fall back to clock_gettime nanoseconds.
+ return 1E9;
+#endif
+}
+
+size_t MeasureImpl(const Func func, const void* arg, const size_t num_skip,
+ const InputVec& unique, const InputVec& full,
+ const Params& p, Result* results) {
+ const float mul = 1.0f / static_cast<int>(num_skip);
+
+ InputVec subset(full.size() - num_skip);
+ const Ticks overhead = Overhead(arg, &full, p);
+ const Ticks overhead_skip = Overhead(arg, &subset, p);
+ if (overhead < overhead_skip) {
+ ABSL_RAW_LOG(WARNING, "Measurement failed: overhead %u < %u\n", overhead,
+ overhead_skip);
+ return 0;
+ }
+
+ if (p.verbose) {
+ ABSL_RAW_LOG(INFO, "#inputs=%5zu,%5zu overhead=%5u,%5u\n", full.size(),
+ subset.size(), overhead, overhead_skip);
+ }
+
+ double max_rel_mad = 0.0;
+ const Ticks total = TotalDuration(func, arg, &full, p, &max_rel_mad);
+
+ for (size_t i = 0; i < unique.size(); ++i) {
+ FillSubset(full, unique[i], num_skip, &subset);
+ const Ticks total_skip = TotalDuration(func, arg, &subset, p, &max_rel_mad);
+
+ if (total < total_skip) {
+ ABSL_RAW_LOG(WARNING, "Measurement failed: total %u < %u\n", total,
+ total_skip);
+ return 0;
+ }
+
+ const Ticks duration = (total - overhead) - (total_skip - overhead_skip);
+ results[i].input = unique[i];
+ results[i].ticks = duration * mul;
+ results[i].variability = max_rel_mad;
+ }
+
+ return unique.size();
+}
+
+size_t Measure(const Func func, const void* arg, const FuncInput* inputs,
+ const size_t num_inputs, Result* results, const Params& p) {
+ ABSL_RAW_CHECK(num_inputs != 0, "No inputs");
+
+ const InputVec unique = UniqueInputs(inputs, num_inputs);
+ const size_t num_skip = NumSkip(func, arg, unique, p); // never 0
+ if (num_skip == 0) return 0; // NumSkip already printed error message
+
+ const InputVec full =
+ ReplicateInputs(inputs, num_inputs, unique.size(), num_skip, p);
+
+ // MeasureImpl may fail up to p.max_measure_retries times.
+ for (size_t i = 0; i < p.max_measure_retries; i++) {
+ auto result = MeasureImpl(func, arg, num_skip, unique, full, p, results);
+ if (result != 0) {
+ return result;
+ }
+ }
+ // All retries failed. (Unusual)
+ return 0;
+}
+
+} // namespace random_internal_nanobenchmark
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/nanobenchmark.h b/absl/random/internal/nanobenchmark.h
new file mode 100644
index 00000000..424d2ba2
--- /dev/null
+++ b/absl/random/internal/nanobenchmark.h
@@ -0,0 +1,170 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// 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_NANOBENCHMARK_H_
+#define ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
+
+// Benchmarks functions of a single integer argument with realistic branch
+// prediction hit rates. Uses a robust estimator to summarize the measurements.
+// The precision is about 0.2%.
+//
+// Examples: see nanobenchmark_test.cc.
+//
+// Background: Microbenchmarks such as http://github.com/google/benchmark
+// can measure elapsed times on the order of a microsecond. Shorter functions
+// are typically measured by repeating them thousands of times and dividing
+// the total elapsed time by this count. Unfortunately, repetition (especially
+// with the same input parameter!) influences the runtime. In time-critical
+// code, it is reasonable to expect warm instruction/data caches and TLBs,
+// but a perfect record of which branches will be taken is unrealistic.
+// Unless the application also repeatedly invokes the measured function with
+// the same parameter, the benchmark is measuring something very different -
+// a best-case result, almost as if the parameter were made a compile-time
+// constant. This may lead to erroneous conclusions about branch-heavy
+// algorithms outperforming branch-free alternatives.
+//
+// Our approach differs in three ways. Adding fences to the timer functions
+// reduces variability due to instruction reordering, improving the timer
+// resolution to about 40 CPU cycles. However, shorter functions must still
+// be invoked repeatedly. For more realistic branch prediction performance,
+// we vary the input parameter according to a user-specified distribution.
+// Thus, instead of VaryInputs(Measure(Repeat(func))), we change the
+// loop nesting to Measure(Repeat(VaryInputs(func))). We also estimate the
+// central tendency of the measurement samples with the "half sample mode",
+// which is more robust to outliers and skewed data than the mean or median.
+
+// NOTE: for compatibility with multiple translation units compiled with
+// distinct flags, avoid #including headers that define functions.
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal_nanobenchmark {
+
+// Input influencing the function being measured (e.g. number of bytes to copy).
+using FuncInput = size_t;
+
+// "Proof of work" returned by Func to ensure the compiler does not elide it.
+using FuncOutput = uint64_t;
+
+// Function to measure: either 1) a captureless lambda or function with two
+// arguments or 2) a lambda with capture, in which case the first argument
+// is reserved for use by MeasureClosure.
+using Func = FuncOutput (*)(const void*, FuncInput);
+
+// Internal parameters that determine precision/resolution/measuring time.
+struct Params {
+ // For measuring timer overhead/resolution. Used in a nested loop =>
+ // quadratic time, acceptable because we know timer overhead is "low".
+ // constexpr because this is used to define array bounds.
+ static constexpr size_t kTimerSamples = 256;
+
+ // Best-case precision, expressed as a divisor of the timer resolution.
+ // Larger => more calls to Func and higher precision.
+ size_t precision_divisor = 1024;
+
+ // Ratio between full and subset input distribution sizes. Cannot be less
+ // than 2; larger values increase measurement time but more faithfully
+ // model the given input distribution.
+ size_t subset_ratio = 2;
+
+ // Together with the estimated Func duration, determines how many times to
+ // call Func before checking the sample variability. Larger values increase
+ // measurement time, memory/cache use and precision.
+ double seconds_per_eval = 4E-3;
+
+ // The minimum number of samples before estimating the central tendency.
+ size_t min_samples_per_eval = 7;
+
+ // The mode is better than median for estimating the central tendency of
+ // skewed/fat-tailed distributions, but it requires sufficient samples
+ // relative to the width of half-ranges.
+ size_t min_mode_samples = 64;
+
+ // Maximum permissible variability (= median absolute deviation / center).
+ double target_rel_mad = 0.002;
+
+ // Abort after this many evals without reaching target_rel_mad. This
+ // prevents infinite loops.
+ size_t max_evals = 9;
+
+ // Retry the measure loop up to this many times.
+ size_t max_measure_retries = 2;
+
+ // Whether to print additional statistics to stdout.
+ bool verbose = true;
+};
+
+// Measurement result for each unique input.
+struct Result {
+ FuncInput input;
+
+ // Robust estimate (mode or median) of duration.
+ float ticks;
+
+ // Measure of variability (median absolute deviation relative to "ticks").
+ float variability;
+};
+
+// Ensures the thread is running on the specified cpu, and no others.
+// Reduces noise due to desynchronized socket RDTSC and context switches.
+// If "cpu" is negative, pin to the currently running core.
+void PinThreadToCPU(const int cpu = -1);
+
+// Returns tick rate, useful for converting measurements to seconds. Invariant
+// means the tick counter frequency is independent of CPU throttling or sleep.
+// This call may be expensive, callers should cache the result.
+double InvariantTicksPerSecond();
+
+// Precisely measures the number of ticks elapsed when calling "func" with the
+// given inputs, shuffled to ensure realistic branch prediction hit rates.
+//
+// "func" returns a 'proof of work' to ensure its computations are not elided.
+// "arg" is passed to Func, or reserved for internal use by MeasureClosure.
+// "inputs" is an array of "num_inputs" (not necessarily unique) arguments to
+// "func". The values should be chosen to maximize coverage of "func". This
+// represents a distribution, so a value's frequency should reflect its
+// probability in the real application. Order does not matter; for example, a
+// uniform distribution over [0, 4) could be represented as {3,0,2,1}.
+// Returns how many Result were written to "results": one per unique input, or
+// zero if the measurement failed (an error message goes to stderr).
+size_t Measure(const Func func, const void* arg, const FuncInput* inputs,
+ const size_t num_inputs, Result* results,
+ const Params& p = Params());
+
+// Calls operator() of the given closure (lambda function).
+template <class Closure>
+static FuncOutput CallClosure(const void* f, const FuncInput input) {
+ return (*reinterpret_cast<const Closure*>(f))(input);
+}
+
+// Same as Measure, except "closure" is typically a lambda function of
+// FuncInput -> FuncOutput with a capture list.
+template <class Closure>
+static inline size_t MeasureClosure(const Closure& closure,
+ const FuncInput* inputs,
+ const size_t num_inputs, Result* results,
+ const Params& p = Params()) {
+ return Measure(reinterpret_cast<Func>(&CallClosure<Closure>),
+ reinterpret_cast<const void*>(&closure), inputs, num_inputs,
+ results, p);
+}
+
+} // namespace random_internal_nanobenchmark
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_NANOBENCHMARK_H_
diff --git a/absl/random/internal/nanobenchmark_test.cc b/absl/random/internal/nanobenchmark_test.cc
new file mode 100644
index 00000000..f96e0f5d
--- /dev/null
+++ b/absl/random/internal/nanobenchmark_test.cc
@@ -0,0 +1,77 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+//
+// 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/nanobenchmark.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/strings/numbers.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal_nanobenchmark {
+namespace {
+
+uint64_t Div(const void*, FuncInput in) {
+ // Here we're measuring the throughput because benchmark invocations are
+ // independent.
+ const int64_t d1 = 0xFFFFFFFFFFll / int64_t(in); // IDIV
+ return d1;
+}
+
+template <size_t N>
+void MeasureDiv(const FuncInput (&inputs)[N]) {
+ Result results[N];
+ Params params;
+ params.max_evals = 6; // avoid test timeout
+ const size_t num_results = Measure(&Div, nullptr, inputs, N, results, params);
+ if (num_results == 0) {
+ ABSL_RAW_LOG(
+ WARNING,
+ "WARNING: Measurement failed, should not happen when using "
+ "PinThreadToCPU unless the region to measure takes > 1 second.\n");
+ return;
+ }
+ for (size_t i = 0; i < num_results; ++i) {
+ ABSL_RAW_LOG(INFO, "%5zu: %6.2f ticks; MAD=%4.2f%%\n", results[i].input,
+ results[i].ticks, results[i].variability * 100.0);
+ ABSL_RAW_CHECK(results[i].ticks != 0.0f, "Zero duration");
+ }
+}
+
+void RunAll(const int argc, char* argv[]) {
+ // Avoid migrating between cores - important on multi-socket systems.
+ int cpu = -1;
+ if (argc == 2) {
+ if (!SimpleAtoi(argv[1], &cpu)) {
+ ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
+ }
+ }
+ PinThreadToCPU(cpu);
+
+ // unpredictable == 1 but the compiler doesn't know that.
+ const FuncInput unpredictable = argc != 999;
+ static const FuncInput inputs[] = {unpredictable * 10, unpredictable * 100};
+
+ MeasureDiv(inputs);
+}
+
+} // namespace
+} // namespace random_internal_nanobenchmark
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+int main(int argc, char* argv[]) {
+ absl::random_internal_nanobenchmark::RunAll(argc, argv);
+ return 0;
+}
diff --git a/absl/random/internal/nonsecure_base.h b/absl/random/internal/nonsecure_base.h
new file mode 100644
index 00000000..c8af51cf
--- /dev/null
+++ b/absl/random/internal/nonsecure_base.h
@@ -0,0 +1,150 @@
+// 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_NONSECURE_BASE_H_
+#define ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
+
+#include <algorithm>
+#include <cstdint>
+#include <iostream>
+#include <iterator>
+#include <random>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "absl/base/macros.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/internal/pool_urbg.h"
+#include "absl/random/internal/salted_seed_seq.h"
+#include "absl/random/internal/seed_material.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced
+// by a thread-unique URBG-instance.
+template <typename URBG>
+class NonsecureURBGBase {
+ public:
+ using result_type = typename URBG::result_type;
+
+ // Default constructor
+ NonsecureURBGBase() : urbg_(ConstructURBG()) {}
+
+ // Copy disallowed, move allowed.
+ NonsecureURBGBase(const NonsecureURBGBase&) = delete;
+ NonsecureURBGBase& operator=(const NonsecureURBGBase&) = delete;
+ NonsecureURBGBase(NonsecureURBGBase&&) = default;
+ NonsecureURBGBase& operator=(NonsecureURBGBase&&) = default;
+
+ // Constructor using a seed
+ template <class SSeq, typename = typename absl::enable_if_t<
+ !std::is_same<SSeq, NonsecureURBGBase>::value>>
+ explicit NonsecureURBGBase(SSeq&& seq)
+ : urbg_(ConstructURBG(std::forward<SSeq>(seq))) {}
+
+ // Note: on MSVC, min() or max() can be interpreted as MIN() or MAX(), so we
+ // enclose min() or max() in parens as (min)() and (max)().
+ // Additionally, clang-format requires no space before this construction.
+
+ // NonsecureURBGBase::min()
+ static constexpr result_type(min)() { return (URBG::min)(); }
+
+ // NonsecureURBGBase::max()
+ static constexpr result_type(max)() { return (URBG::max)(); }
+
+ // NonsecureURBGBase::operator()()
+ result_type operator()() { return urbg_(); }
+
+ // NonsecureURBGBase::discard()
+ void discard(unsigned long long values) { // NOLINT(runtime/int)
+ urbg_.discard(values);
+ }
+
+ bool operator==(const NonsecureURBGBase& other) const {
+ return urbg_ == other.urbg_;
+ }
+
+ bool operator!=(const NonsecureURBGBase& other) const {
+ return !(urbg_ == other.urbg_);
+ }
+
+ private:
+ // Seeder is a custom seed sequence type where generate() fills the provided
+ // buffer via the RandenPool entropy source.
+ struct Seeder {
+ using result_type = uint32_t;
+
+ size_t size() { return 0; }
+
+ template <typename OutIterator>
+ void param(OutIterator) const {}
+
+ template <typename RandomAccessIterator>
+ void generate(RandomAccessIterator begin, RandomAccessIterator end) {
+ if (begin != end) {
+ // begin, end must be random access iterators assignable from uint32_t.
+ generate_impl(
+ std::integral_constant<bool, sizeof(*begin) == sizeof(uint32_t)>{},
+ begin, end);
+ }
+ }
+
+ // Commonly, generate is invoked with a pointer to a buffer which
+ // can be cast to a uint32_t.
+ template <typename RandomAccessIterator>
+ void generate_impl(std::integral_constant<bool, true>,
+ RandomAccessIterator begin, RandomAccessIterator end) {
+ auto buffer = absl::MakeSpan(begin, end);
+ auto target = absl::MakeSpan(reinterpret_cast<uint32_t*>(buffer.data()),
+ buffer.size());
+ RandenPool<uint32_t>::Fill(target);
+ }
+
+ // The non-uint32_t case should be uncommon, and involves an extra copy,
+ // filling the uint32_t buffer and then mixing into the output.
+ template <typename RandomAccessIterator>
+ void generate_impl(std::integral_constant<bool, false>,
+ RandomAccessIterator begin, 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()));
+ std::copy(std::begin(data), std::end(data), begin);
+ }
+ };
+
+ static URBG ConstructURBG() {
+ Seeder seeder;
+ return URBG(seeder);
+ }
+
+ template <typename SSeq>
+ static URBG ConstructURBG(SSeq&& seq) { // NOLINT(runtime/references)
+ auto salted_seq =
+ random_internal::MakeSaltedSeedSeq(std::forward<SSeq>(seq));
+ return URBG(salted_seq);
+ }
+
+ URBG urbg_;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_NONSECURE_BASE_H_
diff --git a/absl/random/internal/nonsecure_base_test.cc b/absl/random/internal/nonsecure_base_test.cc
new file mode 100644
index 00000000..d9de9901
--- /dev/null
+++ b/absl/random/internal/nonsecure_base_test.cc
@@ -0,0 +1,244 @@
+// 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/nonsecure_base.h"
+
+#include <algorithm>
+#include <iostream>
+#include <memory>
+#include <random>
+#include <sstream>
+
+#include "gtest/gtest.h"
+#include "absl/random/distributions.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+using ExampleNonsecureURBG =
+ absl::random_internal::NonsecureURBGBase<std::mt19937>;
+
+template <typename T>
+void Use(const T&) {}
+
+} // namespace
+
+TEST(NonsecureURBGBase, DefaultConstructorIsValid) {
+ ExampleNonsecureURBG urbg;
+}
+
+// Ensure that the recommended template-instantiations are valid.
+TEST(RecommendedTemplates, CanBeConstructed) {
+ absl::BitGen default_generator;
+ absl::InsecureBitGen insecure_generator;
+}
+
+TEST(RecommendedTemplates, CanDiscardValues) {
+ absl::BitGen default_generator;
+ absl::InsecureBitGen insecure_generator;
+
+ default_generator.discard(5);
+ insecure_generator.discard(5);
+}
+
+TEST(NonsecureURBGBase, StandardInterface) {
+ // Names after definition of [rand.req.urbg] in C++ standard.
+ // e us a value of E
+ // v is a lvalue of E
+ // x, y are possibly const values of E
+ // s is a value of T
+ // q is a value satisfying requirements of seed_sequence
+ // z is a value of type unsigned long long
+ // os is a some specialization of basic_ostream
+ // is is a some specialization of basic_istream
+
+ using E = absl::random_internal::NonsecureURBGBase<std::minstd_rand>;
+
+ using T = typename E::result_type;
+
+ static_assert(!std::is_copy_constructible<E>::value,
+ "NonsecureURBGBase should not be copy constructible");
+
+ static_assert(!absl::is_copy_assignable<E>::value,
+ "NonsecureURBGBase should not be copy assignable");
+
+ static_assert(std::is_move_constructible<E>::value,
+ "NonsecureURBGBase should be move constructible");
+
+ static_assert(absl::is_move_assignable<E>::value,
+ "NonsecureURBGBase should be move assignable");
+
+ static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
+ "return type of operator() must be result_type");
+
+ {
+ const E x, y;
+ Use(x);
+ Use(y);
+
+ static_assert(std::is_same<decltype(x == y), bool>::value,
+ "return type of operator== must be bool");
+
+ static_assert(std::is_same<decltype(x != y), bool>::value,
+ "return type of operator== must be bool");
+ }
+
+ E e;
+ std::seed_seq q{1, 2, 3};
+
+ E{};
+ E{q};
+
+ // Copy constructor not supported.
+ // E{x};
+
+ // result_type seed constructor not supported.
+ // E{T{1}};
+
+ // Move constructors are supported.
+ {
+ E tmp(q);
+ E m = std::move(tmp);
+ E n(std::move(m));
+ EXPECT_TRUE(e != n);
+ }
+
+ // Comparisons work.
+ {
+ // MSVC emits error 2718 when using EXPECT_EQ(e, x)
+ // * actual parameter with __declspec(align('#')) won't be aligned
+ E a(q);
+ E b(q);
+
+ EXPECT_TRUE(a != e);
+ EXPECT_TRUE(a == b);
+
+ a();
+ EXPECT_TRUE(a != b);
+ }
+
+ // e.seed(s) not supported.
+
+ // [rand.req.eng] specifies the parameter as 'unsigned long long'
+ // e.discard(unsigned long long) is supported.
+ unsigned long long z = 1; // NOLINT(runtime/int)
+ e.discard(z);
+}
+
+TEST(NonsecureURBGBase, SeedSeqConstructorIsValid) {
+ std::seed_seq seq;
+ ExampleNonsecureURBG rbg(seq);
+}
+
+TEST(NonsecureURBGBase, CompatibleWithDistributionUtils) {
+ ExampleNonsecureURBG rbg;
+
+ absl::Uniform(rbg, 0, 100);
+ absl::Uniform(rbg, 0.5, 0.7);
+ absl::Poisson<uint32_t>(rbg);
+ absl::Exponential<float>(rbg);
+}
+
+TEST(NonsecureURBGBase, CompatibleWithStdDistributions) {
+ ExampleNonsecureURBG rbg;
+
+ std::uniform_int_distribution<uint32_t>(0, 100)(rbg);
+ std::uniform_real_distribution<float>()(rbg);
+ std::bernoulli_distribution(0.2)(rbg);
+}
+
+TEST(NonsecureURBGBase, ConsecutiveDefaultInstancesYieldUniqueVariates) {
+ const size_t kNumSamples = 128;
+
+ ExampleNonsecureURBG rbg1;
+ ExampleNonsecureURBG rbg2;
+
+ for (size_t i = 0; i < kNumSamples; i++) {
+ EXPECT_NE(rbg1(), rbg2());
+ }
+}
+
+TEST(NonsecureURBGBase, EqualSeedSequencesYieldEqualVariates) {
+ std::seed_seq seq;
+
+ ExampleNonsecureURBG rbg1(seq);
+ ExampleNonsecureURBG rbg2(seq);
+
+ // ExampleNonsecureURBG rbg3({1, 2, 3}); // Should not compile.
+
+ for (uint32_t i = 0; i < 1000; i++) {
+ EXPECT_EQ(rbg1(), rbg2());
+ }
+
+ rbg1.discard(100);
+ rbg2.discard(100);
+
+ // The sequences should continue after discarding
+ for (uint32_t i = 0; i < 1000; i++) {
+ EXPECT_EQ(rbg1(), rbg2());
+ }
+}
+
+// This is a PRNG-compatible type specifically designed to test
+// that NonsecureURBGBase::Seeder can correctly handle iterators
+// to arbitrary non-uint32_t size types.
+template <typename T>
+struct SeederTestEngine {
+ using result_type = T;
+
+ static constexpr result_type(min)() {
+ return (std::numeric_limits<result_type>::min)();
+ }
+ static constexpr result_type(max)() {
+ return (std::numeric_limits<result_type>::max)();
+ }
+
+ template <class SeedSequence,
+ typename = typename absl::enable_if_t<
+ !std::is_same<SeedSequence, SeederTestEngine>::value>>
+ explicit SeederTestEngine(SeedSequence&& seq) {
+ seed(seq);
+ }
+
+ SeederTestEngine(const SeederTestEngine&) = default;
+ SeederTestEngine& operator=(const SeederTestEngine&) = default;
+ SeederTestEngine(SeederTestEngine&&) = default;
+ SeederTestEngine& operator=(SeederTestEngine&&) = default;
+
+ result_type operator()() { return state[0]; }
+
+ template <class SeedSequence>
+ void seed(SeedSequence&& seq) {
+ std::fill(std::begin(state), std::end(state), T(0));
+ seq.generate(std::begin(state), std::end(state));
+ }
+
+ T state[2];
+};
+
+TEST(NonsecureURBGBase, SeederWorksForU32) {
+ using U32 =
+ absl::random_internal::NonsecureURBGBase<SeederTestEngine<uint32_t>>;
+ U32 x;
+ EXPECT_NE(0, x());
+}
+
+TEST(NonsecureURBGBase, SeederWorksForU64) {
+ using U64 =
+ absl::random_internal::NonsecureURBGBase<SeederTestEngine<uint64_t>>;
+
+ U64 x;
+ EXPECT_NE(0, x());
+}
diff --git a/absl/random/internal/pcg_engine.h b/absl/random/internal/pcg_engine.h
new file mode 100644
index 00000000..607ac34b
--- /dev/null
+++ b/absl/random/internal/pcg_engine.h
@@ -0,0 +1,307 @@
+// Copyright 2018 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
+#define ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
+
+#include <type_traits>
+
+#include "absl/base/config.h"
+#include "absl/meta/type_traits.h"
+#include "absl/numeric/int128.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// pcg_engine is a simplified implementation of Melissa O'Neil's PCG engine in
+// C++. PCG combines a linear congruential generator (LCG) with output state
+// mixing functions to generate each random variate. pcg_engine supports only a
+// single sequence (oneseq), and does not support streams.
+//
+// pcg_engine is parameterized by two types:
+// Params, which provides the multiplier and increment values;
+// Mix, which mixes the state into the result.
+//
+template <typename Params, typename Mix>
+class pcg_engine {
+ static_assert(std::is_same<typename Params::state_type,
+ typename Mix::state_type>::value,
+ "Class-template absl::pcg_engine must be parameterized by "
+ "Params and Mix with identical state_type");
+
+ static_assert(std::is_unsigned<typename Mix::result_type>::value,
+ "Class-template absl::pcg_engine must be parameterized by "
+ "an unsigned Mix::result_type");
+
+ using params_type = Params;
+ using mix_type = Mix;
+ using state_type = typename Mix::state_type;
+
+ public:
+ // C++11 URBG interface:
+ using result_type = typename Mix::result_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)();
+ }
+
+ explicit pcg_engine(uint64_t seed_value = 0) { seed(seed_value); }
+
+ template <class SeedSequence,
+ typename = typename absl::enable_if_t<
+ !std::is_same<SeedSequence, pcg_engine>::value>>
+ explicit pcg_engine(SeedSequence&& seq) {
+ seed(seq);
+ }
+
+ pcg_engine(const pcg_engine&) = default;
+ pcg_engine& operator=(const pcg_engine&) = default;
+ pcg_engine(pcg_engine&&) = default;
+ pcg_engine& operator=(pcg_engine&&) = default;
+
+ result_type operator()() {
+ // Advance the LCG state, always using the new value to generate the output.
+ state_ = lcg(state_);
+ return Mix{}(state_);
+ }
+
+ void seed(uint64_t seed_value = 0) {
+ state_type tmp = seed_value;
+ state_ = lcg(tmp + Params::increment());
+ }
+
+ template <class SeedSequence>
+ typename absl::enable_if_t<
+ !std::is_convertible<SeedSequence, uint64_t>::value, void>
+ seed(SeedSequence&& seq) {
+ reseed(seq);
+ }
+
+ void discard(uint64_t count) { state_ = advance(state_, count); }
+
+ bool operator==(const pcg_engine& other) const {
+ return state_ == other.state_;
+ }
+
+ bool operator!=(const pcg_engine& other) const { return !(*this == other); }
+
+ template <class CharT, class Traits>
+ friend typename absl::enable_if_t<(sizeof(state_type) == 16),
+ std::basic_ostream<CharT, Traits>&>
+ operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const pcg_engine& engine) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ random_internal::stream_u128_helper<state_type> helper;
+ helper.write(pcg_engine::params_type::multiplier(), os);
+ os << os.fill();
+ helper.write(pcg_engine::params_type::increment(), os);
+ os << os.fill();
+ helper.write(engine.state_, os);
+ return os;
+ }
+
+ template <class CharT, class Traits>
+ friend typename absl::enable_if_t<(sizeof(state_type) <= 8),
+ std::basic_ostream<CharT, Traits>&>
+ operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const pcg_engine& engine) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os << pcg_engine::params_type::multiplier() << os.fill();
+ os << pcg_engine::params_type::increment() << os.fill();
+ os << engine.state_;
+ return os;
+ }
+
+ template <class CharT, class Traits>
+ friend typename absl::enable_if_t<(sizeof(state_type) == 16),
+ std::basic_istream<CharT, Traits>&>
+ operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ pcg_engine& engine) { // NOLINT(runtime/references)
+ random_internal::stream_u128_helper<state_type> helper;
+ auto mult = helper.read(is);
+ auto inc = helper.read(is);
+ auto tmp = helper.read(is);
+ if (mult != pcg_engine::params_type::multiplier() ||
+ inc != pcg_engine::params_type::increment()) {
+ // signal failure by setting the failbit.
+ is.setstate(is.rdstate() | std::ios_base::failbit);
+ }
+ if (!is.fail()) {
+ engine.state_ = tmp;
+ }
+ return is;
+ }
+
+ template <class CharT, class Traits>
+ friend typename absl::enable_if_t<(sizeof(state_type) <= 8),
+ std::basic_istream<CharT, Traits>&>
+ operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ pcg_engine& engine) { // NOLINT(runtime/references)
+ state_type mult{}, inc{}, tmp{};
+ is >> mult >> inc >> tmp;
+ if (mult != pcg_engine::params_type::multiplier() ||
+ inc != pcg_engine::params_type::increment()) {
+ // signal failure by setting the failbit.
+ is.setstate(is.rdstate() | std::ios_base::failbit);
+ }
+ if (!is.fail()) {
+ engine.state_ = tmp;
+ }
+ return is;
+ }
+
+ private:
+ state_type state_;
+
+ // Returns the linear-congruential generator next state.
+ static inline constexpr state_type lcg(state_type s) {
+ return s * Params::multiplier() + Params::increment();
+ }
+
+ // Returns the linear-congruential arbitrary seek state.
+ inline state_type advance(state_type s, uint64_t n) const {
+ state_type mult = Params::multiplier();
+ state_type inc = Params::increment();
+ state_type m = 1;
+ state_type i = 0;
+ while (n > 0) {
+ if (n & 1) {
+ m *= mult;
+ i = i * mult + inc;
+ }
+ inc = (mult + 1) * inc;
+ mult *= mult;
+ n >>= 1;
+ }
+ return m * s + i;
+ }
+
+ template <class SeedSequence>
+ void reseed(SeedSequence& seq) {
+ using sequence_result_type = typename SeedSequence::result_type;
+ constexpr size_t kBufferSize =
+ sizeof(state_type) / sizeof(sequence_result_type);
+ sequence_result_type buffer[kBufferSize];
+ seq.generate(std::begin(buffer), std::end(buffer));
+ // Convert the seed output to a single state value.
+ state_type tmp = buffer[0];
+ for (size_t i = 1; i < kBufferSize; i++) {
+ tmp <<= (sizeof(sequence_result_type) * 8);
+ tmp |= buffer[i];
+ }
+ state_ = lcg(tmp + params_type::increment());
+ }
+};
+
+// Parameterized implementation of the PCG 128-bit oneseq state.
+// This provides state_type, multiplier, and increment for pcg_engine.
+template <uint64_t kMultA, uint64_t kMultB, uint64_t kIncA, uint64_t kIncB>
+class pcg128_params {
+ public:
+#if ABSL_HAVE_INTRINSIC_INT128
+ using state_type = __uint128_t;
+ static inline constexpr state_type make_u128(uint64_t a, uint64_t b) {
+ return (static_cast<__uint128_t>(a) << 64) | b;
+ }
+#else
+ using state_type = absl::uint128;
+ static inline constexpr state_type make_u128(uint64_t a, uint64_t b) {
+ return absl::MakeUint128(a, b);
+ }
+#endif
+
+ static inline constexpr state_type multiplier() {
+ return make_u128(kMultA, kMultB);
+ }
+ static inline constexpr state_type increment() {
+ return make_u128(kIncA, kIncB);
+ }
+};
+
+// Implementation of the PCG xsl_rr_128_64 128-bit mixing function, which
+// accepts an input of state_type and mixes it into an output of result_type.
+struct pcg_xsl_rr_128_64 {
+#if ABSL_HAVE_INTRINSIC_INT128
+ using state_type = __uint128_t;
+#else
+ using state_type = absl::uint128;
+#endif
+ using result_type = uint64_t;
+
+ inline uint64_t operator()(state_type state) {
+ // This is equivalent to the xsl_rr_128_64 mixing function.
+#if ABSL_HAVE_INTRINSIC_INT128
+ uint64_t rotate = static_cast<uint64_t>(state >> 122u);
+ state ^= state >> 64;
+ uint64_t s = static_cast<uint64_t>(state);
+#else
+ uint64_t h = Uint128High64(state);
+ uint64_t rotate = h >> 58u;
+ uint64_t s = Uint128Low64(state) ^ h;
+#endif
+ return random_internal::rotr(s, rotate);
+ }
+};
+
+// Parameterized implementation of the PCG 64-bit oneseq state.
+// This provides state_type, multiplier, and increment for pcg_engine.
+template <uint64_t kMult, uint64_t kInc>
+class pcg64_params {
+ public:
+ using state_type = uint64_t;
+ static inline constexpr state_type multiplier() { return kMult; }
+ static inline constexpr state_type increment() { return kInc; }
+};
+
+// Implementation of the PCG xsh_rr_64_32 64-bit mixing function, which accepts
+// an input of state_type and mixes it into an output of result_type.
+struct pcg_xsh_rr_64_32 {
+ using state_type = uint64_t;
+ using result_type = uint32_t;
+ inline uint32_t operator()(uint64_t state) {
+ return random_internal::rotr(
+ static_cast<uint32_t>(((state >> 18) ^ state) >> 27), state >> 59);
+ }
+};
+
+// Stable pcg_engine implementations:
+// This is a 64-bit generator using 128-bits of state.
+// The output sequence is equivalent to Melissa O'Neil's pcg64_oneseq.
+using pcg64_2018_engine = pcg_engine<
+ random_internal::pcg128_params<0x2360ed051fc65da4ull, 0x4385df649fccf645ull,
+ 0x5851f42d4c957f2d, 0x14057b7ef767814f>,
+ random_internal::pcg_xsl_rr_128_64>;
+
+// This is a 32-bit generator using 64-bits of state.
+// This is equivalent to Melissa O'Neil's pcg32_oneseq.
+using pcg32_2018_engine = pcg_engine<
+ random_internal::pcg64_params<0x5851f42d4c957f2dull, 0x14057b7ef767814full>,
+ random_internal::pcg_xsh_rr_64_32>;
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_PCG_ENGINE_H_
diff --git a/absl/random/internal/pcg_engine_test.cc b/absl/random/internal/pcg_engine_test.cc
new file mode 100644
index 00000000..4d763e89
--- /dev/null
+++ b/absl/random/internal/pcg_engine_test.cc
@@ -0,0 +1,638 @@
+// 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.
+
+#include "absl/random/internal/pcg_engine.h"
+
+#include <algorithm>
+#include <bitset>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/internal/explicit_seed_seq.h"
+#include "absl/time/clock.h"
+
+#define UPDATE_GOLDEN 0
+
+namespace {
+
+using absl::random_internal::ExplicitSeedSeq;
+using absl::random_internal::pcg32_2018_engine;
+using absl::random_internal::pcg64_2018_engine;
+
+template <typename EngineType>
+class PCGEngineTest : public ::testing::Test {};
+
+using EngineTypes = ::testing::Types<pcg64_2018_engine, pcg32_2018_engine>;
+
+TYPED_TEST_SUITE(PCGEngineTest, EngineTypes);
+
+TYPED_TEST(PCGEngineTest, VerifyReseedChangesAllValues) {
+ using engine_type = TypeParam;
+ using result_type = typename engine_type::result_type;
+
+ const size_t kNumOutputs = 16;
+ engine_type engine;
+
+ // MSVC emits error 2719 without the use of std::ref below.
+ // * formal parameter with __declspec(align('#')) won't be aligned
+
+ {
+ std::seed_seq seq1{1, 2, 3, 4, 5, 6, 7};
+ engine.seed(seq1);
+ }
+ result_type a[kNumOutputs];
+ std::generate(std::begin(a), std::end(a), std::ref(engine));
+
+ {
+ std::random_device rd;
+ std::seed_seq seq2{rd(), rd(), rd()};
+ engine.seed(seq2);
+ }
+ result_type b[kNumOutputs];
+ std::generate(std::begin(b), std::end(b), std::ref(engine));
+
+ // Verify that two uncorrelated values have ~50% of there bits in common. Use
+ // a 10% margin-of-error to reduce flakiness.
+ 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);
+}
+
+// Number of values that needs to be consumed to clean two sizes of buffer
+// and trigger third refresh. (slightly overestimates the actual state size).
+constexpr size_t kTwoBufferValues = 16;
+
+TYPED_TEST(PCGEngineTest, VerifyDiscard) {
+ using engine_type = TypeParam;
+
+ for (size_t num_used = 0; num_used < kTwoBufferValues; ++num_used) {
+ engine_type engine_used;
+ for (size_t i = 0; i < num_used; ++i) {
+ engine_used();
+ }
+
+ for (size_t num_discard = 0; num_discard < kTwoBufferValues;
+ ++num_discard) {
+ engine_type engine1 = engine_used;
+ engine_type engine2 = engine_used;
+ for (size_t i = 0; i < num_discard; ++i) {
+ engine1();
+ }
+ engine2.discard(num_discard);
+ for (size_t i = 0; i < kTwoBufferValues; ++i) {
+ const auto r1 = engine1();
+ const auto r2 = engine2();
+ ASSERT_EQ(r1, r2) << "used=" << num_used << " discard=" << num_discard;
+ }
+ }
+ }
+}
+
+TYPED_TEST(PCGEngineTest, StreamOperatorsResult) {
+ using engine_type = TypeParam;
+
+ std::wostringstream os;
+ std::wistringstream is;
+ engine_type engine;
+
+ EXPECT_EQ(&(os << engine), &os);
+ EXPECT_EQ(&(is >> engine), &is);
+}
+
+TYPED_TEST(PCGEngineTest, StreamSerialization) {
+ using engine_type = TypeParam;
+
+ for (size_t discard = 0; discard < kTwoBufferValues; ++discard) {
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ engine_type engine(seed_sequence);
+ engine.discard(discard);
+
+ std::stringstream stream;
+ stream << engine;
+
+ engine_type new_engine;
+ stream >> new_engine;
+ for (size_t i = 0; i < 64; ++i) {
+ EXPECT_EQ(engine(), new_engine()) << " " << i;
+ }
+ }
+}
+
+constexpr size_t kNumGoldenOutputs = 127;
+
+// This test is checking if randen_engine is meets interface requirements
+// defined in [rand.req.urbg].
+TYPED_TEST(PCGEngineTest, RandomNumberEngineInterface) {
+ using engine_type = TypeParam;
+
+ using E = engine_type;
+ using T = typename E::result_type;
+
+ static_assert(std::is_copy_constructible<E>::value,
+ "engine_type must be copy constructible");
+
+ static_assert(absl::is_copy_assignable<E>::value,
+ "engine_type must be copy assignable");
+
+ static_assert(std::is_move_constructible<E>::value,
+ "engine_type must be move constructible");
+
+ static_assert(absl::is_move_assignable<E>::value,
+ "engine_type must be move assignable");
+
+ static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
+ "return type of operator() must be result_type");
+
+ // Names after definition of [rand.req.urbg] in C++ standard.
+ // e us a value of E
+ // v is a lvalue of E
+ // x, y are possibly const values of E
+ // s is a value of T
+ // q is a value satisfying requirements of seed_sequence
+ // z is a value of type unsigned long long
+ // os is a some specialization of basic_ostream
+ // is is a some specialization of basic_istream
+
+ E e, v;
+ const E x, y;
+ T s = 1;
+ std::seed_seq q{1, 2, 3};
+ unsigned long long z = 1; // NOLINT(runtime/int)
+ std::wostringstream os;
+ std::wistringstream is;
+
+ E{};
+ E{x};
+ E{s};
+ E{q};
+
+ e.seed();
+
+ // MSVC emits error 2718 when using EXPECT_EQ(e, x)
+ // * actual parameter with __declspec(align('#')) won't be aligned
+ EXPECT_TRUE(e == x);
+
+ e.seed(q);
+ {
+ E tmp(q);
+ EXPECT_TRUE(e == tmp);
+ }
+
+ e();
+ {
+ E tmp(q);
+ EXPECT_TRUE(e != tmp);
+ }
+
+ e.discard(z);
+
+ static_assert(std::is_same<decltype(x == y), bool>::value,
+ "return type of operator== must be bool");
+
+ static_assert(std::is_same<decltype(x != y), bool>::value,
+ "return type of operator== must be bool");
+}
+
+TYPED_TEST(PCGEngineTest, RandenEngineSFINAETest) {
+ using engine_type = TypeParam;
+ using result_type = typename engine_type::result_type;
+
+ {
+ engine_type engine(result_type(1));
+ engine.seed(result_type(1));
+ }
+
+ {
+ result_type n = 1;
+ engine_type engine(n);
+ engine.seed(n);
+ }
+
+ {
+ engine_type engine(1);
+ engine.seed(1);
+ }
+
+ {
+ int n = 1;
+ engine_type engine(n);
+ engine.seed(n);
+ }
+
+ {
+ std::seed_seq seed_seq;
+ engine_type engine(seed_seq);
+ engine.seed(seed_seq);
+ }
+
+ {
+ engine_type engine{std::seed_seq()};
+ engine.seed(std::seed_seq());
+ }
+}
+
+// ------------------------------------------------------------------
+// Stability tests for pcg64_2018_engine
+// ------------------------------------------------------------------
+TEST(PCG642018EngineTest, VerifyGolden) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0x01070196e695f8f1, 0x703ec840c59f4493, 0xe54954914b3a44fa,
+ 0x96130ff204b9285e, 0x7d9fdef535ceb21a, 0x666feed42e1219a0,
+ 0x981f685721c8326f, 0xad80710d6eab4dda, 0xe202c480b037a029,
+ 0x5d3390eaedd907e2, 0x0756befb39c6b8aa, 0x1fb44ba6634d62a3,
+ 0x8d20423662426642, 0x34ea910167a39fb4, 0x93010b43a80d0ab6,
+ 0x663db08a98fc568a, 0x720b0a1335956fae, 0x2c35483e31e1d3ba,
+ 0x429f39776337409d, 0xb46d99e638687344, 0x105370b96aedcaee,
+ 0x3999e92f811cff71, 0xd230f8bcb591cfc9, 0x0dce3db2ba7bdea5,
+ 0xcf2f52c91eec99af, 0x2bc7c24a8b998a39, 0xbd8af1b0d599a19c,
+ 0x56bc45abc66059f5, 0x170a46dc170f7f1e, 0xc25daf5277b85fad,
+ 0xe629c2e0c948eadb, 0x1720a796915542ed, 0x22fb0caa4f909951,
+ 0x7e0c0f4175acd83d, 0xd9fcab37ff2a860c, 0xab2280fb2054bad1,
+ 0x58e8a06f37fa9e99, 0xc3a52a30b06528c7, 0x0175f773a13fc1bd,
+ 0x731cfc584b00e840, 0x404cc7b2648069cb, 0x5bc29153b0b7f783,
+ 0x771310a38cc999d1, 0x766a572f0a71a916, 0x90f450fb4fc48348,
+ 0xf080ea3e1c7b1a0d, 0x15471a4507d66a44, 0x7d58e55a78f3df69,
+ 0x0130a094576ac99c, 0x46669cb2d04b1d87, 0x17ab5bed20191840,
+ 0x95b177d260adff3e, 0x025fb624b6ee4c07, 0xb35de4330154a95f,
+ 0xe8510fff67e24c79, 0x132c3cbcd76ed2d3, 0x35e7cc145a093904,
+ 0x9f5b5b5f81583b79, 0x3ee749a533966233, 0x4af85886cdeda8cd,
+ 0x0ca5380ecb3ef3aa, 0x4f674eb7661d3192, 0x88a29aad00cd7733,
+ 0x70b627ca045ffac6, 0x5912b43ea887623d, 0x95dc9fc6f62cf221,
+ 0x926081a12a5c905b, 0x9c57d4cd7dfce651, 0x85ab2cbf23e3bb5d,
+ 0xc5cd669f63023152, 0x3067be0fad5d898e, 0x12b56f444cb53d05,
+ 0xbc2e5a640c3434fc, 0x9280bff0e4613fe1, 0x98819094c528743e,
+ 0x999d1c98d829df33, 0x9ff82a012dc89242, 0xf99183ed39c8be94,
+ 0xf0f59161cd421c55, 0x3c705730c2f6c48d, 0x66ad85c6e9278a61,
+ 0x2a3428e4a428d5d0, 0x79207d68fd04940d, 0xea7f2b402edc8430,
+ 0xa06b419ac857f63b, 0xcb1dd0e6fbc47e1c, 0x4f55229200ada6a4,
+ 0x9647b5e6359c927f, 0x30bf8f9197c7efe5, 0xa79519529cc384d0,
+ 0xbb22c4f339ad6497, 0xd7b9782f59d14175, 0x0dff12fff2ec0118,
+ 0xa331ad8305343a7c, 0x48dad7e3f17e0862, 0x324c6fb3fd3c9665,
+ 0xf0e4350e7933dfc4, 0x7ccda2f30b8b03b6, 0xa0afc6179005de40,
+ 0xee65da6d063b3a30, 0xb9506f42f2bfe87a, 0xc9a2e26b0ef5baa0,
+ 0x39fa9d4f495011d6, 0xbecc21a45d023948, 0x6bf484c6593f737f,
+ 0x8065e0070cadc3b7, 0x9ef617ed8d419799, 0xac692cf8c233dd15,
+ 0xd2ed87583c4ebb98, 0xad95ba1bebfedc62, 0x9b60b160a8264e43,
+ 0x0bc8c45f71fcf25b, 0x4a78035cdf1c9931, 0x4602dc106667e029,
+ 0xb335a3c250498ac8, 0x0256ebc4df20cab8, 0x0c61efd153f0c8d9,
+ 0xe5d0150a4f806f88, 0x99d6521d351e7d87, 0x8d4888c9f80f4325,
+ 0x106c5735c1ba868d, 0x73414881b880a878, 0x808a9a58a3064751,
+ 0x339a29f3746de3d5, 0x5410d7fa4f873896, 0xd84623c81d7b8a03,
+ 0x1f7c7e7a7f47f462,
+ };
+
+ pcg64_2018_engine engine(0);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed();
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(PCG642018EngineTest, VerifyGoldenSeeded) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0xb03988f1e39691ee, 0xbd2a1eb5ac31e97a, 0x8f00d6d433634d02,
+ 0x1823c28d483d5776, 0x000c3ee3e1aeb74a, 0xfa82ef27a4f3df9c,
+ 0xc6f382308654e454, 0x414afb1a238996c2, 0x4703a4bc252eb411,
+ 0x99d64f62c8f7f654, 0xbb07ebe11a34fa44, 0x79eb06a363c06131,
+ 0xf66ad3756f1c6b21, 0x130c01d5e869f457, 0x5ca2b9963aecbc81,
+ 0xfef7bebc1de27e6c, 0x1d174faa5ed2cdbf, 0xd75b7a773f2bb889,
+ 0xc35c872327a170a5, 0x46da6d88646a42fe, 0x4622985e0442dae2,
+ 0xbe3cbd67297f1f9b, 0xe7c37b4a4798bfd1, 0x173d5dfad15a25c3,
+ 0x0eb6849ba2961522, 0xb0ff7246e6700d73, 0x88cb9c42d3afa577,
+ 0xb609731dbd94d917, 0xd3941cda04b40081, 0x28d140f7409bea3a,
+ 0x3c96699a920a124a, 0xdb28be521958b2fd, 0x0a3f44db3d4c5124,
+ 0x7ac8e60ba13b70d2, 0x75f03a41ded5195a, 0xaed10ac7c4e4825d,
+ 0xb92a3b18aadb7adc, 0xda45e0081f2bca46, 0x74d39ab3753143fc,
+ 0xb686038018fac9ca, 0x4cc309fe99542dbb, 0xf3e1a4fcb311097c,
+ 0x58763d6fa698d69d, 0xd11c365dbecd8d60, 0x2c15d55725b1dee7,
+ 0x89805f254d85658c, 0x2374c44dfc62158b, 0x9a8350fa7995328d,
+ 0x198f838970cf91da, 0x96aff569562c0e53, 0xd76c8c52b7ec6e3f,
+ 0x23a01cd9ae4baa81, 0x3adb366b6d02a893, 0xb3313e2a4c5b333f,
+ 0x04c11230b96a5425, 0x1f7f7af04787d571, 0xaddb019365275ec7,
+ 0x5c960468ccb09f42, 0x8438db698c69a44a, 0x492be1e46111637e,
+ 0x9c6c01e18100c610, 0xbfe48e75b7d0aceb, 0xb5e0b89ec1ce6a00,
+ 0x9d280ecbc2fe8997, 0x290d9e991ba5fcab, 0xeec5bec7d9d2a4f0,
+ 0x726e81488f19150e, 0x1a6df7955a7e462c, 0x37a12d174ba46bb5,
+ 0x3cdcdffd96b1b5c5, 0x2c5d5ac10661a26e, 0xa742ed18f22e50c4,
+ 0x00e0ed88ff0d8a35, 0x3d3c1718cb1efc0b, 0x1d70c51ffbccbf11,
+ 0xfbbb895132a4092f, 0x619d27f2fb095f24, 0x69af68200985e5c4,
+ 0xbee4885f57373f8d, 0x10b7a6bfe0587e40, 0xa885e6cf2f7e5f0a,
+ 0x59f879464f767550, 0x24e805d69056990d, 0x860970b911095891,
+ 0xca3189954f84170d, 0x6652a5edd4590134, 0x5e1008cef76174bf,
+ 0xcbd417881f2bcfe5, 0xfd49fc9d706ecd17, 0xeebf540221ebd066,
+ 0x46af7679464504cb, 0xd4028486946956f1, 0xd4f41864b86c2103,
+ 0x7af090e751583372, 0x98cdaa09278cb642, 0xffd42b921215602f,
+ 0x1d05bec8466b1740, 0xf036fa78a0132044, 0x787880589d1ecc78,
+ 0x5644552cfef33230, 0x0a97e275fe06884b, 0x96d1b13333d470b5,
+ 0xc8b3cdad52d3b034, 0x091357b9db7376fd, 0xa5fe4232555edf8c,
+ 0x3371bc3b6ada76b5, 0x7deeb2300477c995, 0x6fc6d4244f2849c1,
+ 0x750e8cc797ca340a, 0x81728613cd79899f, 0x3467f4ee6f9aeb93,
+ 0x5ef0a905f58c640f, 0x432db85e5101c98a, 0x6488e96f46ac80c2,
+ 0x22fddb282625048c, 0x15b287a0bc2d4c5d, 0xa7e2343ef1f28bce,
+ 0xc87ee1aa89bed09e, 0x220610107812c5e9, 0xcbdab6fcd640f586,
+ 0x8d41047970928784, 0x1aa431509ec1ade0, 0xac3f0be53f518ddc,
+ 0x16f4428ad81d0cbb, 0x675b13c2736fc4bb, 0x6db073afdd87e32d,
+ 0x572f3ca2f1a078c6,
+ };
+
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ pcg64_2018_engine engine(seed_sequence);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed(seed_sequence);
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(PCG642018EngineTest, VerifyGoldenFromDeserializedEngine) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0xdd425b47b4113dea, 0x1b07176479d444b0, 0x6b391027586f2e42,
+ 0xa166f2b15f4a2143, 0xffb6dbd7a179ee97, 0xb2c00035365bf0b1,
+ 0x8fbb518b45855521, 0xfc789a55ddf87c3b, 0x429531f0f17ff355,
+ 0xbe708560d603d283, 0x5bff415175c5cb6b, 0xe813491f4ad45394,
+ 0xa853f4506d55880d, 0x7e538453e568172e, 0xe101f1e098ddd0ec,
+ 0x6ee31266ee4c766d, 0xa8786d92d66b39d7, 0xfee622a2acf5e5b0,
+ 0x5fe8e82c102fa7b3, 0x01f10be4cdb53c9d, 0xbe0545366f857022,
+ 0x12e74f010a339bca, 0xb10d85ca40d5ce34, 0xe80d6feba5054875,
+ 0x2b7c1ee6d567d4ee, 0x2a9cd043bfd03b66, 0x5cfc531bd239f3f1,
+ 0x1c4734e4647d70f5, 0x85a8f60f006b5760, 0x6a4239ce76dca387,
+ 0x8da0f86d7339335c, 0xf055b0468551374d, 0x486e8567e9bea9a0,
+ 0x4cb531b8405192dd, 0xf813b1ee3157110b, 0x214c2a664a875d8e,
+ 0x74531237b29b35f7, 0xa6f0267bb77a771e, 0x64b552bff54184a4,
+ 0xa2d6f7af2d75b6fc, 0x460a10018e03b5ab, 0x76fd1fdcb81d0800,
+ 0x76f5f81805070d9d, 0x1fb75cb1a70b289a, 0x9dfd25a022c4b27f,
+ 0x9a31a14a80528e9e, 0x910dc565ddc25820, 0xd6aef8e2b0936c10,
+ 0xe1773c507fe70225, 0xe027fd7aadd632bc, 0xc1fecb427089c8b8,
+ 0xb5c74c69fa9dbf26, 0x71bf9b0e4670227d, 0x25f48fad205dcfdd,
+ 0x905248ec4d689c56, 0x5c2b7631b0de5c9d, 0x9f2ee0f8f485036c,
+ 0xfd6ce4ebb90bf7ea, 0xd435d20046085574, 0x6b7eadcb0625f986,
+ 0x679d7d44b48be89e, 0x49683b8e1cdc49de, 0x4366cf76e9a2f4ca,
+ 0x54026ec1cdad7bed, 0xa9a04385207f28d3, 0xc8e66de4eba074b2,
+ 0x40b08c42de0f4cc0, 0x1d4c5e0e93c5bbc0, 0x19b80792e470ae2d,
+ 0x6fcaaeaa4c2a5bd9, 0xa92cb07c4238438e, 0x8bb5c918a007e298,
+ 0x7cd671e944874cf4, 0x88166470b1ba3cac, 0xd013d476eaeeade6,
+ 0xcee416947189b3c3, 0x5d7c16ab0dce6088, 0xd3578a5c32b13d27,
+ 0x3875db5adc9cc973, 0xfbdaba01c5b5dc56, 0xffc4fdd391b231c3,
+ 0x2334520ecb164fec, 0x361c115e7b6de1fa, 0xeee58106cc3563d7,
+ 0x8b7f35a8db25ebb8, 0xb29d00211e2cafa6, 0x22a39fe4614b646b,
+ 0x92ca6de8b998506d, 0x40922fe3d388d1db, 0x9da47f1e540f802a,
+ 0x811dceebf16a25db, 0xf6524ae22e0e53a9, 0x52d9e780a16eb99d,
+ 0x4f504286bb830207, 0xf6654d4786bd5cc3, 0x00bd98316003a7e1,
+ 0xefda054a6ab8f5f3, 0x46cfb0f4c1872827, 0xc22b316965c0f3b2,
+ 0xd1a28087c7e7562a, 0xaa4f6a094b7f5cff, 0xfe2bc853a041f7da,
+ 0xe9d531402a83c3ba, 0xe545d8663d3ce4dd, 0xfa2dcd7d91a13fa8,
+ 0xda1a080e52a127b8, 0x19c98f1f809c3d84, 0x2cef109af4678c88,
+ 0x53462accab3b9132, 0x176b13a80415394e, 0xea70047ef6bc178b,
+ 0x57bca80506d6dcdf, 0xd853ba09ff09f5c4, 0x75f4df3a7ddd4775,
+ 0x209c367ade62f4fe, 0xa9a0bbc74d5f4682, 0x5dfe34bada86c21a,
+ 0xc2c05bbcd38566d1, 0x6de8088e348c916a, 0x6a7001c6000c2196,
+ 0xd9fb51865fc4a367, 0x12f320e444ece8ff, 0x6d56f7f793d65035,
+ 0x138f31b7a865f8aa, 0x58fc68b4026b9adf, 0xcd48954b79fb6436,
+ 0x27dfce4a0232af87,
+ };
+
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ std::seed_seq seed_sequence{1, 2, 3};
+ pcg64_2018_engine engine(seed_sequence);
+ std::ostringstream stream;
+ stream << engine;
+ auto str = stream.str();
+ printf("%s\n\n", str.c_str());
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ pcg64_2018_engine engine;
+ std::istringstream stream(
+ "2549297995355413924 4865540595714422341 6364136223846793005 "
+ "1442695040888963407 18088519957565336995 4845369368158826708");
+ stream >> engine;
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+// ------------------------------------------------------------------
+// Stability tests for pcg32_2018_engine
+// ------------------------------------------------------------------
+TEST(PCG322018EngineTest, VerifyGolden) {
+ constexpr uint32_t kGolden[kNumGoldenOutputs] = {
+ 0x7a7ecbd9, 0x89fd6c06, 0xae646aa8, 0xcd3cf945, 0x6204b303, 0x198c8585,
+ 0x49fce611, 0xd1e9297a, 0x142d9440, 0xee75f56b, 0x473a9117, 0xe3a45903,
+ 0xbce807a1, 0xe54e5f4d, 0x497d6c51, 0x61829166, 0xa740474b, 0x031912a8,
+ 0x9de3defa, 0xd266dbf1, 0x0f38bebb, 0xec3c4f65, 0x07c5057d, 0xbbce03c8,
+ 0xfd2ac7a8, 0xffcf4773, 0x5b10affb, 0xede1c842, 0xe22b01b7, 0xda133c8c,
+ 0xaf89b0f4, 0x25d1b8bc, 0x9f625482, 0x7bfd6882, 0x2e2210c0, 0x2c8fb9a6,
+ 0x42cb3b83, 0x40ce0dab, 0x644a3510, 0x36230ef2, 0xe2cb6d43, 0x1012b343,
+ 0x746c6c9f, 0x36714cf8, 0xed1f5026, 0x8bbbf83e, 0xe98710f4, 0x8a2afa36,
+ 0x09035349, 0x6dc1a487, 0x682b634b, 0xc106794f, 0x7dd78beb, 0x628c262b,
+ 0x852fb232, 0xb153ac4c, 0x4f169d1b, 0xa69ab774, 0x4bd4b6f2, 0xdc351dd3,
+ 0x93ff3c8c, 0xa30819ab, 0xff07758c, 0x5ab13c62, 0xd16d7fb5, 0xc4950ffa,
+ 0xd309ae49, 0xb9677a87, 0x4464e317, 0x90dc44f1, 0xc694c1d4, 0x1d5e1168,
+ 0xadf37a2d, 0xda38990d, 0x1ec4bd33, 0x36ca25ce, 0xfa0dc76a, 0x968a9d43,
+ 0x6950ac39, 0xdd3276bc, 0x06d5a71e, 0x1f6f282d, 0x5c626c62, 0xdde3fc31,
+ 0x152194ce, 0xc35ed14c, 0xb1f7224e, 0x47f76bb8, 0xb34fdd08, 0x7011395e,
+ 0x162d2a49, 0x0d1bf09f, 0x9428a952, 0x03c5c344, 0xd3525616, 0x7816fff3,
+ 0x6bceb8a8, 0x8345a081, 0x366420fd, 0x182abeda, 0x70f82745, 0xaf15ded8,
+ 0xc7f52ca2, 0xa98db9c5, 0x919d99ba, 0x9c376c1c, 0xed8d34c2, 0x716ae9f5,
+ 0xef062fa5, 0xee3b6c56, 0x52325658, 0x61afa9c3, 0xfdaf02f0, 0x961cf3ab,
+ 0x9f291565, 0x4fbf3045, 0x0590c899, 0xde901385, 0x45005ffb, 0x509db162,
+ 0x262fa941, 0x4c421653, 0x4b17c21e, 0xea0d1530, 0xde803845, 0x61bfd515,
+ 0x438523ef,
+ };
+
+ pcg32_2018_engine engine(0);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%08x, ", engine());
+ if (i % 6 == 5) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed();
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(PCG322018EngineTest, VerifyGoldenSeeded) {
+ constexpr uint32_t kGolden[kNumGoldenOutputs] = {
+ 0x60b5a64c, 0x978502f9, 0x80a75f60, 0x241f1158, 0xa4cd1dbb, 0xe7284017,
+ 0x3b678da5, 0x5223ec99, 0xe4bdd5d9, 0x72190e6d, 0xe6e702c9, 0xff80c768,
+ 0xcf126ed3, 0x1fbd20ab, 0x60980489, 0xbc72bf89, 0x407ac6c0, 0x00bf3c51,
+ 0xf9087897, 0x172e4eb6, 0xe9e4f443, 0x1a6098bf, 0xbf44f8c2, 0xdd84a0e5,
+ 0xd9a52364, 0xc0e2e786, 0x061ae2ba, 0x9facb8e3, 0x6109432d, 0xd4e0a013,
+ 0xbd8eb9a6, 0x7e86c3b6, 0x629c0e68, 0x05337430, 0xb495b9f4, 0x11ccd65d,
+ 0xb578db25, 0x66f1246d, 0x6ef20a7f, 0x5e429812, 0x11772130, 0xb944b5c2,
+ 0x01624128, 0xa2385ab7, 0xd3e10d35, 0xbe570ec3, 0xc951656f, 0xbe8944a0,
+ 0x7be41062, 0x5709f919, 0xd745feda, 0x9870b9ae, 0xb44b8168, 0x19e7683b,
+ 0xded8017f, 0xc6e4d544, 0x91ae4225, 0xd6745fba, 0xb992f284, 0x65b12b33,
+ 0xa9d5fdb4, 0xf105ce1a, 0x35ca1a6e, 0x2ff70dd0, 0xd8335e49, 0xfb71ddf2,
+ 0xcaeabb89, 0x5c6f5f84, 0x9a811a7d, 0xbcecbbd1, 0x0f661ba0, 0x9ad93b9d,
+ 0xedd23e0b, 0x42062f48, 0xd38dd7e4, 0x6cd63c9c, 0x640b98ae, 0x4bff5653,
+ 0x12626371, 0x13266017, 0xe7a698d8, 0x39c74667, 0xe8fdf2e3, 0x52803bf8,
+ 0x2af6895b, 0x91335b7b, 0x699e4961, 0x00a40fff, 0x253ff2b6, 0x4a6cf672,
+ 0x9584e85f, 0xf2a5000c, 0x4d58aba8, 0xb8513e6a, 0x767fad65, 0x8e326f9e,
+ 0x182f15a1, 0x163dab52, 0xdf99c780, 0x047282a1, 0xee4f90dd, 0xd50394ae,
+ 0x6c9fd5f0, 0xb06a9194, 0x387e3840, 0x04a9487b, 0xf678a4c2, 0xd0a78810,
+ 0xd502c97e, 0xd6a9b12a, 0x4accc5dc, 0x416ed53e, 0x50411536, 0xeeb89c24,
+ 0x813a7902, 0x034ebca6, 0xffa52e7c, 0x7ecd3d0e, 0xfa37a0d2, 0xb1fbe2c1,
+ 0xb7efc6d1, 0xefa4ccee, 0xf6f80424, 0x2283f3d9, 0x68732284, 0x94f3b5c8,
+ 0xbbdeceb9,
+ };
+
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ pcg32_2018_engine engine(seed_sequence);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%08x, ", engine());
+ if (i % 6 == 5) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed(seed_sequence);
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(PCG322018EngineTest, VerifyGoldenFromDeserializedEngine) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0x780f7042, 0xba137215, 0x43ab6f22, 0x0cb55f46, 0x44b2627d, 0x835597af,
+ 0xea973ea1, 0x0d2abd35, 0x4fdd601c, 0xac4342fe, 0x7db7e93c, 0xe56ebcaf,
+ 0x3596470a, 0x7770a9ad, 0x9b893320, 0x57db3415, 0xb432de54, 0xa02baf71,
+ 0xa256aadb, 0x88921fc7, 0xa35fa6b3, 0xde3eca46, 0x605739a7, 0xa890b82b,
+ 0xe457b7ad, 0x335fb903, 0xeb06790c, 0xb3c54bf6, 0x6141e442, 0xa599a482,
+ 0xb78987cc, 0xc61dfe9d, 0x0f1d6ace, 0x17460594, 0x8f6a5061, 0x083dc354,
+ 0xe9c337fb, 0xcfd105f7, 0x926764b6, 0x638d24dc, 0xeaac650a, 0x67d2cb9c,
+ 0xd807733c, 0x205fc52e, 0xf5399e2e, 0x6c46ddcc, 0xb603e875, 0xce113a25,
+ 0x3c8d4813, 0xfb584db8, 0xf6d255ff, 0xea80954f, 0x42e8be85, 0xb2feee72,
+ 0x62bd8d16, 0x1be4a142, 0x97dca1a4, 0xdd6e7333, 0xb2caa20e, 0xa12b1588,
+ 0xeb3a5a1a, 0x6fa5ba89, 0x077ea931, 0x8ddb1713, 0x0dd03079, 0x2c2ba965,
+ 0xa77fac17, 0xc8325742, 0x8bb893bf, 0xc2315741, 0xeaceee92, 0x81dd2ee2,
+ 0xe5214216, 0x1b9b8fb2, 0x01646d03, 0x24facc25, 0xd8c0e0bb, 0xa33fe106,
+ 0xf34fe976, 0xb3b4b44e, 0x65618fed, 0x032c6192, 0xa9dd72ce, 0xf391887b,
+ 0xf41c6a6e, 0x05c4bd6d, 0x37fa260e, 0x46b05659, 0xb5f6348a, 0x62d26d89,
+ 0x39f6452d, 0xb17b30a2, 0xbdd82743, 0x38ecae3b, 0xfe90f0a2, 0xcb2d226d,
+ 0xcf8a0b1c, 0x0eed3d4d, 0xa1f69cfc, 0xd7ac3ba5, 0xce9d9a6b, 0x121deb4c,
+ 0x4a0d03f3, 0xc1821ed1, 0x59c249ac, 0xc0abb474, 0x28149985, 0xfd9a82ba,
+ 0x5960c3b2, 0xeff00cba, 0x6073aa17, 0x25dc0919, 0x9976626e, 0xdd2ccc33,
+ 0x39ecb6ec, 0xc6e15d13, 0xfac94cfd, 0x28cfd34f, 0xf2d2c32d, 0x51c23d08,
+ 0x4fdb2f48, 0x97baa807, 0xf2c1004c, 0xc4ae8136, 0x71f31c94, 0x8c92d601,
+ 0x36caf5cd,
+ };
+
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ std::seed_seq seed_sequence{1, 2, 3};
+ pcg32_2018_engine engine(seed_sequence);
+ std::ostringstream stream;
+ stream << engine;
+ auto str = stream.str();
+ printf("%s\n\n", str.c_str());
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%08x, ", engine());
+ if (i % 6 == 5) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+
+ EXPECT_FALSE(true);
+#else
+ pcg32_2018_engine engine;
+ std::istringstream stream(
+ "6364136223846793005 1442695040888963407 6537028157270659894");
+ stream >> engine;
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+} // namespace
diff --git a/absl/random/internal/platform.h b/absl/random/internal/platform.h
new file mode 100644
index 00000000..a5a42cbb
--- /dev/null
+++ b/absl/random/internal/platform.h
@@ -0,0 +1,170 @@
+// 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_PLATFORM_H_
+#define ABSL_RANDOM_INTERNAL_PLATFORM_H_
+
+// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
+// symbols from arbitrary system and other headers, since it may be built
+// with different flags from other targets, using different levels of
+// optimization, potentially introducing ODR violations.
+
+// -----------------------------------------------------------------------------
+// Platform Feature Checks
+// -----------------------------------------------------------------------------
+
+// Currently supported operating systems and associated preprocessor
+// symbols:
+//
+// Linux and Linux-derived __linux__
+// Android __ANDROID__ (implies __linux__)
+// Linux (non-Android) __linux__ && !__ANDROID__
+// Darwin (macOS and iOS) __APPLE__
+// Akaros (http://akaros.org) __ros__
+// Windows _WIN32
+// NaCL __native_client__
+// AsmJS __asmjs__
+// WebAssembly __wasm__
+// Fuchsia __Fuchsia__
+//
+// Note that since Android defines both __ANDROID__ and __linux__, one
+// may probe for either Linux or Android by simply testing for __linux__.
+//
+// NOTE: For __APPLE__ platforms, we use #include <TargetConditionals.h>
+// to distinguish os variants.
+//
+// http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
+
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#endif
+
+// -----------------------------------------------------------------------------
+// Architecture Checks
+// -----------------------------------------------------------------------------
+
+// These preprocessor directives are trying to determine CPU architecture,
+// including necessary headers to support hardware AES.
+//
+// ABSL_ARCH_{X86/PPC/ARM} macros determine the platform.
+#if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || \
+ defined(_M_X64)
+#define ABSL_ARCH_X86_64
+#elif defined(__i386) || defined(_M_IX86)
+#define ABSL_ARCH_X86_32
+#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
+#define ABSL_ARCH_AARCH64
+#elif defined(__arm__) || defined(__ARMEL__) || defined(_M_ARM)
+#define ABSL_ARCH_ARM
+#elif defined(__powerpc64__) || defined(__PPC64__) || defined(__powerpc__) || \
+ defined(__ppc__) || defined(__PPC__)
+#define ABSL_ARCH_PPC
+#else
+// Unsupported architecture.
+// * https://sourceforge.net/p/predef/wiki/Architectures/
+// * https://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// * for gcc, clang: "echo | gcc -E -dM -"
+#endif
+
+// -----------------------------------------------------------------------------
+// Attribute Checks
+// -----------------------------------------------------------------------------
+
+// ABSL_RANDOM_INTERNAL_RESTRICT annotates whether pointers may be considered
+// to be unaliased.
+#if defined(__clang__) || defined(__GNUC__)
+#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict__
+#elif defined(_MSC_VER)
+#define ABSL_RANDOM_INTERNAL_RESTRICT __restrict
+#else
+#define ABSL_RANDOM_INTERNAL_RESTRICT
+#endif
+
+// ABSL_HAVE_ACCELERATED_AES indicates whether the currently active compiler
+// flags (e.g. -maes) allow using hardware accelerated AES instructions, which
+// implies us assuming that the target platform supports them.
+#define ABSL_HAVE_ACCELERATED_AES 0
+
+#if defined(ABSL_ARCH_X86_64)
+
+#if defined(__AES__) || defined(__AVX__)
+#undef ABSL_HAVE_ACCELERATED_AES
+#define ABSL_HAVE_ACCELERATED_AES 1
+#endif
+
+#elif defined(ABSL_ARCH_PPC)
+
+// Rely on VSX and CRYPTO extensions for vcipher on PowerPC.
+#if (defined(__VEC__) || defined(__ALTIVEC__)) && defined(__VSX__) && \
+ defined(__CRYPTO__)
+#undef ABSL_HAVE_ACCELERATED_AES
+#define ABSL_HAVE_ACCELERATED_AES 1
+#endif
+
+#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
+
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0053c/IHI0053C_acle_2_0.pdf
+// Rely on NEON+CRYPTO extensions for ARM.
+#if defined(__ARM_NEON) && defined(__ARM_FEATURE_CRYPTO)
+#undef ABSL_HAVE_ACCELERATED_AES
+#define ABSL_HAVE_ACCELERATED_AES 1
+#endif
+
+#endif
+
+// NaCl does not allow AES.
+#if defined(__native_client__)
+#undef ABSL_HAVE_ACCELERATED_AES
+#define ABSL_HAVE_ACCELERATED_AES 0
+#endif
+
+// ABSL_RANDOM_INTERNAL_AES_DISPATCH indicates whether the currently active
+// platform has, or should use run-time dispatch for selecting the
+// acclerated Randen implementation.
+#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 0
+
+#if defined(ABSL_ARCH_X86_64)
+// Dispatch is available on x86_64
+#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
+#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
+#elif defined(__linux__) && defined(ABSL_ARCH_PPC)
+// 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
+#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
+#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
+#elif defined(__linux__) && defined(ABSL_ARCH_ARM) && (__ARM_ARCH >= 8)
+// Or when running linux ARM v8 or higher.
+// (This captures a lot of Android configurations.)
+#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
+#define ABSL_RANDOM_INTERNAL_AES_DISPATCH 1
+#endif
+
+// NaCl does not allow dispatch.
+#if defined(__native_client__)
+#undef ABSL_RANDOM_INTERNAL_AES_DISPATCH
+#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(__APPLE__) && (TARGET_OS_IPHONE || 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.cc b/absl/random/internal/pool_urbg.cc
new file mode 100644
index 00000000..304d9b16
--- /dev/null
+++ b/absl/random/internal/pool_urbg.cc
@@ -0,0 +1,254 @@
+// 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 <atomic>
+#include <cstdint>
+#include <cstring>
+#include <iterator>
+
+#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/random/internal/randen.h"
+#include "absl/random/internal/seed_material.h"
+#include "absl/random/seed_gen_exception.h"
+
+using absl::base_internal::SpinLock;
+using absl::base_internal::SpinLockHolder;
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+// RandenPoolEntry is a thread-safe pseudorandom bit generator, implementing a
+// 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 {
+ public:
+ static constexpr size_t kState = RandenTraits::kStateBytes / sizeof(uint32_t);
+ static constexpr size_t kCapacity =
+ RandenTraits::kCapacityBytes / sizeof(uint32_t);
+
+ void Init(absl::Span<const uint32_t> data) {
+ SpinLockHolder l(&mu_); // Always uncontested.
+ std::copy(data.begin(), data.end(), std::begin(state_));
+ next_ = kState;
+ }
+
+ // Copy bytes into out.
+ void Fill(uint8_t* out, size_t bytes) LOCKS_EXCLUDED(mu_);
+
+ // Returns random bits from the buffer in units of T.
+ template <typename T>
+ inline T Generate() LOCKS_EXCLUDED(mu_);
+
+ inline void MaybeRefill() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
+ if (next_ >= kState) {
+ next_ = kCapacity;
+ impl_.Generate(state_);
+ }
+ }
+
+ private:
+ // Randen URBG state.
+ uint32_t state_[kState] GUARDED_BY(mu_); // First to satisfy alignment.
+ SpinLock mu_;
+ const Randen impl_;
+ size_t next_ 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 to_copy = std::min(bytes, remaining);
+ std::memcpy(out, &state_[next_], to_copy);
+ out += to_copy;
+ bytes -= to_copy;
+ next_ += (to_copy + sizeof(state_[0]) - 1) / sizeof(state_[0]);
+ }
+}
+
+// Number of pooled urbg entries.
+static constexpr int kPoolSize = 8;
+
+// Shared pool entries.
+static absl::once_flag pool_once;
+ABSL_CACHELINE_ALIGNED static RandenPoolEntry* shared_pools[kPoolSize];
+
+// Returns an id in the range [0 ... kPoolSize), which indexes into the
+// pool of random engines.
+//
+// Each thread to access the pool is assigned a sequential ID (without reuse)
+// from the pool-id space; the id is cached in a thread_local variable.
+// This id is assigned based on the arrival-order of the thread to the
+// GetPoolID call; this has no binary, CL, or runtime stability because
+// on subsequent runs the order within the same program may be significantly
+// different. However, as other thread IDs are not assigned sequentially,
+// this is not expected to matter.
+int GetPoolID() {
+ static_assert(kPoolSize >= 1,
+ "At least one urbg instance is required for PoolURBG");
+
+ ABSL_CONST_INIT static std::atomic<int64_t> sequence{0};
+
+#ifdef ABSL_HAVE_THREAD_LOCAL
+ static thread_local int my_pool_id = -1;
+ if (ABSL_PREDICT_FALSE(my_pool_id < 0)) {
+ my_pool_id = (sequence++ % kPoolSize);
+ }
+ return my_pool_id;
+#else
+ static pthread_key_t tid_key = [] {
+ pthread_key_t tmp_key;
+ int err = pthread_key_create(&tmp_key, nullptr);
+ if (err) {
+ ABSL_RAW_LOG(FATAL, "pthread_key_create failed with %d", err);
+ }
+ return tmp_key;
+ }();
+
+ // Store the value in the pthread_{get/set}specific. However an uninitialized
+ // value is 0, so add +1 to distinguish from the null value.
+ intptr_t my_pool_id =
+ reinterpret_cast<intptr_t>(pthread_getspecific(tid_key));
+ if (ABSL_PREDICT_FALSE(my_pool_id == 0)) {
+ // No allocated ID, allocate the next value, cache it, and return.
+ my_pool_id = (sequence++ % kPoolSize) + 1;
+ int err = pthread_setspecific(tid_key, reinterpret_cast<void*>(my_pool_id));
+ if (err) {
+ ABSL_RAW_LOG(FATAL, "pthread_setspecific failed with %d", err);
+ }
+ }
+ return my_pool_id - 1;
+#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.
+ void* memory = std::malloc(sizeof(RandenPoolEntry) + kAlignment);
+ auto x = reinterpret_cast<intptr_t>(memory);
+ auto y = x % kAlignment;
+ void* aligned =
+ (y == 0) ? memory : reinterpret_cast<void*>(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.
+ uint32_t seed_material[kPoolSize * kSeedSize];
+ if (!random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::MakeSpan(seed_material))) {
+ random_internal::ThrowSeedGenException();
+ }
+ for (int i = 0; i < kPoolSize; i++) {
+ shared_pools[i] = PoolAlignedAlloc();
+ shared_pools[i]->Init(
+ absl::MakeSpan(&seed_material[i * kSeedSize], kSeedSize));
+ }
+}
+
+// Returns the pool entry for the current thread.
+RandenPoolEntry* GetPoolForCurrentThread() {
+ absl::call_once(pool_once, InitPoolURBG);
+ return shared_pools[GetPoolID()];
+}
+
+} // namespace
+
+template <typename T>
+typename RandenPool<T>::result_type RandenPool<T>::Generate() {
+ auto* pool = GetPoolForCurrentThread();
+ return pool->Generate<T>();
+}
+
+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
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/pool_urbg.h b/absl/random/internal/pool_urbg.h
new file mode 100644
index 00000000..eac75e2c
--- /dev/null
+++ b/absl/random/internal/pool_urbg.h
@@ -0,0 +1,131 @@
+// 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 {
+inline namespace lts_2019_08_08 {
+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
+} // inline namespace lts_2019_08_08
+} // 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
new file mode 100644
index 00000000..53f4eacf
--- /dev/null
+++ b/absl/random/internal/pool_urbg_test.cc
@@ -0,0 +1,182 @@
+// 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-keys.inc b/absl/random/internal/randen-keys.inc
new file mode 100644
index 00000000..fa4b1668
--- /dev/null
+++ b/absl/random/internal/randen-keys.inc
@@ -0,0 +1,207 @@
+// 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_RANDEN_KEYS_INC_
+#define ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
+
+// Textual header to include the randen_keys where necessary.
+// REQUIRES: struct u64x2{}
+//
+// PROVIDES: kKeys
+// PROVIDES: round_keys[]
+
+// "Nothing up my sleeve" numbers from the first hex digits of Pi, obtained
+// from http://hexpi.sourceforge.net/. The array was generated by following
+// Python script:
+/*
+python << EOF
+"""Generates Randen round keys array from pi-hex.62500.txt file."""
+import binascii
+
+KEYS = 136
+
+def chunks(l, n):
+ """Yield successive n-sized chunks from l."""
+ for i in range(0, len(l), n):
+ yield l[i:i + n]
+
+def pairwise(t):
+ """Transforms sequence into sequence of pairs."""
+ it = iter(t)
+ return zip(it,it)
+
+def digits_from_pi():
+ """Reads digits from hexpi.sourceforge.net file."""
+ with open("pi-hex.62500.txt") as file:
+ return file.read()
+
+def digits_from_urandom():
+ """Reads digits from /dev/urandom."""
+ with open("/dev/urandom") as file:
+ return binascii.hexlify(file.read(KEYS * 16))
+
+digits = digits_from_pi()
+print("static constexpr const size_t kRoundKeys = {0};\n".format(KEYS))
+print("alignas(16) constexpr const u64x2 round_keys[kRoundKeys] = {")
+
+for i, (hi, lo) in zip(range(KEYS), pairwise(chunks(digits, 16))):
+ hi = "0x{0}ull".format(hi)
+ lo = "0x{0}ull".format(lo)
+ print(" u64x2({0}, {1}){2}".format(hi, lo, ',' if i+1 < KEYS else ''))
+
+print("};")
+EOF
+*/
+
+static constexpr const size_t kRoundKeys = 136;
+
+alignas(16) constexpr u64x2 round_keys[kRoundKeys] = {
+ u64x2(0x243F6A8885A308D3ull, 0x13198A2E03707344ull),
+ u64x2(0xA4093822299F31D0ull, 0x082EFA98EC4E6C89ull),
+ u64x2(0x452821E638D01377ull, 0xBE5466CF34E90C6Cull),
+ u64x2(0xC0AC29B7C97C50DDull, 0x3F84D5B5B5470917ull),
+ u64x2(0x9216D5D98979FB1Bull, 0xD1310BA698DFB5ACull),
+ u64x2(0x2FFD72DBD01ADFB7ull, 0xB8E1AFED6A267E96ull),
+ u64x2(0xBA7C9045F12C7F99ull, 0x24A19947B3916CF7ull),
+ u64x2(0x0801F2E2858EFC16ull, 0x636920D871574E69ull),
+ u64x2(0xA458FEA3F4933D7Eull, 0x0D95748F728EB658ull),
+ u64x2(0x718BCD5882154AEEull, 0x7B54A41DC25A59B5ull),
+ u64x2(0x9C30D5392AF26013ull, 0xC5D1B023286085F0ull),
+ u64x2(0xCA417918B8DB38EFull, 0x8E79DCB0603A180Eull),
+ u64x2(0x6C9E0E8BB01E8A3Eull, 0xD71577C1BD314B27ull),
+ u64x2(0x78AF2FDA55605C60ull, 0xE65525F3AA55AB94ull),
+ u64x2(0x5748986263E81440ull, 0x55CA396A2AAB10B6ull),
+ u64x2(0xB4CC5C341141E8CEull, 0xA15486AF7C72E993ull),
+ u64x2(0xB3EE1411636FBC2Aull, 0x2BA9C55D741831F6ull),
+ u64x2(0xCE5C3E169B87931Eull, 0xAFD6BA336C24CF5Cull),
+ u64x2(0x7A32538128958677ull, 0x3B8F48986B4BB9AFull),
+ u64x2(0xC4BFE81B66282193ull, 0x61D809CCFB21A991ull),
+ u64x2(0x487CAC605DEC8032ull, 0xEF845D5DE98575B1ull),
+ u64x2(0xDC262302EB651B88ull, 0x23893E81D396ACC5ull),
+ u64x2(0x0F6D6FF383F44239ull, 0x2E0B4482A4842004ull),
+ u64x2(0x69C8F04A9E1F9B5Eull, 0x21C66842F6E96C9Aull),
+ u64x2(0x670C9C61ABD388F0ull, 0x6A51A0D2D8542F68ull),
+ u64x2(0x960FA728AB5133A3ull, 0x6EEF0B6C137A3BE4ull),
+ u64x2(0xBA3BF0507EFB2A98ull, 0xA1F1651D39AF0176ull),
+ u64x2(0x66CA593E82430E88ull, 0x8CEE8619456F9FB4ull),
+ u64x2(0x7D84A5C33B8B5EBEull, 0xE06F75D885C12073ull),
+ u64x2(0x401A449F56C16AA6ull, 0x4ED3AA62363F7706ull),
+ u64x2(0x1BFEDF72429B023Dull, 0x37D0D724D00A1248ull),
+ u64x2(0xDB0FEAD349F1C09Bull, 0x075372C980991B7Bull),
+ u64x2(0x25D479D8F6E8DEF7ull, 0xE3FE501AB6794C3Bull),
+ u64x2(0x976CE0BD04C006BAull, 0xC1A94FB6409F60C4ull),
+ u64x2(0x5E5C9EC2196A2463ull, 0x68FB6FAF3E6C53B5ull),
+ u64x2(0x1339B2EB3B52EC6Full, 0x6DFC511F9B30952Cull),
+ u64x2(0xCC814544AF5EBD09ull, 0xBEE3D004DE334AFDull),
+ u64x2(0x660F2807192E4BB3ull, 0xC0CBA85745C8740Full),
+ u64x2(0xD20B5F39B9D3FBDBull, 0x5579C0BD1A60320Aull),
+ u64x2(0xD6A100C6402C7279ull, 0x679F25FEFB1FA3CCull),
+ u64x2(0x8EA5E9F8DB3222F8ull, 0x3C7516DFFD616B15ull),
+ u64x2(0x2F501EC8AD0552ABull, 0x323DB5FAFD238760ull),
+ u64x2(0x53317B483E00DF82ull, 0x9E5C57BBCA6F8CA0ull),
+ u64x2(0x1A87562EDF1769DBull, 0xD542A8F6287EFFC3ull),
+ u64x2(0xAC6732C68C4F5573ull, 0x695B27B0BBCA58C8ull),
+ u64x2(0xE1FFA35DB8F011A0ull, 0x10FA3D98FD2183B8ull),
+ u64x2(0x4AFCB56C2DD1D35Bull, 0x9A53E479B6F84565ull),
+ u64x2(0xD28E49BC4BFB9790ull, 0xE1DDF2DAA4CB7E33ull),
+ u64x2(0x62FB1341CEE4C6E8ull, 0xEF20CADA36774C01ull),
+ u64x2(0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull),
+ u64x2(0xEAAD8E716B93D5A0ull, 0xD08ED1D0AFC725E0ull),
+ u64x2(0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull),
+ u64x2(0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull),
+ u64x2(0xD1CFF191B3A8C1ADull, 0x2F2F2218BE0E1777ull),
+ u64x2(0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull),
+ u64x2(0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull),
+ u64x2(0x7CC43B81D2ADA8D9ull, 0x165FA26680957705ull),
+ u64x2(0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull),
+ u64x2(0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull),
+ u64x2(0xD6411BD3AE1E7E49ull, 0x00250E2D2071B35Eull),
+ u64x2(0x226800BB57B8E0AFull, 0x2464369BF009B91Eull),
+ u64x2(0x5563911D59DFA6AAull, 0x78C14389D95A537Full),
+ u64x2(0x207D5BA202E5B9C5ull, 0x832603766295CFA9ull),
+ u64x2(0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull),
+ u64x2(0x1B5100529A532915ull, 0xD60F573FBC9BC6E4ull),
+ u64x2(0x2B60A47681E67400ull, 0x08BA6FB5571BE91Full),
+ u64x2(0xF296EC6B2A0DD915ull, 0xB6636521E7B9F9B6ull),
+ u64x2(0xFF34052EC5855664ull, 0x53B02D5DA99F8FA1ull),
+ u64x2(0x08BA47996E85076Aull, 0x4B7A70E9B5B32944ull),
+ u64x2(0xDB75092EC4192623ull, 0xAD6EA6B049A7DF7Dull),
+ u64x2(0x9CEE60B88FEDB266ull, 0xECAA8C71699A18FFull),
+ u64x2(0x5664526CC2B19EE1ull, 0x193602A575094C29ull),
+ u64x2(0xA0591340E4183A3Eull, 0x3F54989A5B429D65ull),
+ u64x2(0x6B8FE4D699F73FD6ull, 0xA1D29C07EFE830F5ull),
+ u64x2(0x4D2D38E6F0255DC1ull, 0x4CDD20868470EB26ull),
+ u64x2(0x6382E9C6021ECC5Eull, 0x09686B3F3EBAEFC9ull),
+ u64x2(0x3C9718146B6A70A1ull, 0x687F358452A0E286ull),
+ u64x2(0xB79C5305AA500737ull, 0x3E07841C7FDEAE5Cull),
+ u64x2(0x8E7D44EC5716F2B8ull, 0xB03ADA37F0500C0Dull),
+ u64x2(0xF01C1F040200B3FFull, 0xAE0CF51A3CB574B2ull),
+ u64x2(0x25837A58DC0921BDull, 0xD19113F97CA92FF6ull),
+ u64x2(0x9432477322F54701ull, 0x3AE5E58137C2DADCull),
+ u64x2(0xC8B576349AF3DDA7ull, 0xA94461460FD0030Eull),
+ u64x2(0xECC8C73EA4751E41ull, 0xE238CD993BEA0E2Full),
+ u64x2(0x3280BBA1183EB331ull, 0x4E548B384F6DB908ull),
+ u64x2(0x6F420D03F60A04BFull, 0x2CB8129024977C79ull),
+ u64x2(0x5679B072BCAF89AFull, 0xDE9A771FD9930810ull),
+ u64x2(0xB38BAE12DCCF3F2Eull, 0x5512721F2E6B7124ull),
+ u64x2(0x501ADDE69F84CD87ull, 0x7A5847187408DA17ull),
+ u64x2(0xBC9F9ABCE94B7D8Cull, 0xEC7AEC3ADB851DFAull),
+ u64x2(0x63094366C464C3D2ull, 0xEF1C18473215D808ull),
+ u64x2(0xDD433B3724C2BA16ull, 0x12A14D432A65C451ull),
+ u64x2(0x50940002133AE4DDull, 0x71DFF89E10314E55ull),
+ u64x2(0x81AC77D65F11199Bull, 0x043556F1D7A3C76Bull),
+ u64x2(0x3C11183B5924A509ull, 0xF28FE6ED97F1FBFAull),
+ u64x2(0x9EBABF2C1E153C6Eull, 0x86E34570EAE96FB1ull),
+ u64x2(0x860E5E0A5A3E2AB3ull, 0x771FE71C4E3D06FAull),
+ u64x2(0x2965DCB999E71D0Full, 0x803E89D65266C825ull),
+ u64x2(0x2E4CC9789C10B36Aull, 0xC6150EBA94E2EA78ull),
+ u64x2(0xA6FC3C531E0A2DF4ull, 0xF2F74EA7361D2B3Dull),
+ u64x2(0x1939260F19C27960ull, 0x5223A708F71312B6ull),
+ u64x2(0xEBADFE6EEAC31F66ull, 0xE3BC4595A67BC883ull),
+ u64x2(0xB17F37D1018CFF28ull, 0xC332DDEFBE6C5AA5ull),
+ u64x2(0x6558218568AB9702ull, 0xEECEA50FDB2F953Bull),
+ u64x2(0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull),
+ u64x2(0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull),
+ u64x2(0x0334FE1EAA0363CFull, 0xB5735C904C70A239ull),
+ u64x2(0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull),
+ u64x2(0x9CAB5CABB2F3846Eull, 0x648B1EAF19BDF0CAull),
+ u64x2(0xA02369B9655ABB50ull, 0x40685A323C2AB4B3ull),
+ u64x2(0x319EE9D5C021B8F7ull, 0x9B540B19875FA099ull),
+ u64x2(0x95F7997E623D7DA8ull, 0xF837889A97E32D77ull),
+ u64x2(0x11ED935F16681281ull, 0x0E358829C7E61FD6ull),
+ u64x2(0x96DEDFA17858BA99ull, 0x57F584A51B227263ull),
+ u64x2(0x9B83C3FF1AC24696ull, 0xCDB30AEB532E3054ull),
+ u64x2(0x8FD948E46DBC3128ull, 0x58EBF2EF34C6FFEAull),
+ u64x2(0xFE28ED61EE7C3C73ull, 0x5D4A14D9E864B7E3ull),
+ u64x2(0x42105D14203E13E0ull, 0x45EEE2B6A3AAABEAull),
+ u64x2(0xDB6C4F15FACB4FD0ull, 0xC742F442EF6ABBB5ull),
+ u64x2(0x654F3B1D41CD2105ull, 0xD81E799E86854DC7ull),
+ u64x2(0xE44B476A3D816250ull, 0xCF62A1F25B8D2646ull),
+ u64x2(0xFC8883A0C1C7B6A3ull, 0x7F1524C369CB7492ull),
+ u64x2(0x47848A0B5692B285ull, 0x095BBF00AD19489Dull),
+ u64x2(0x1462B17423820D00ull, 0x58428D2A0C55F5EAull),
+ u64x2(0x1DADF43E233F7061ull, 0x3372F0928D937E41ull),
+ u64x2(0xD65FECF16C223BDBull, 0x7CDE3759CBEE7460ull),
+ u64x2(0x4085F2A7CE77326Eull, 0xA607808419F8509Eull),
+ u64x2(0xE8EFD85561D99735ull, 0xA969A7AAC50C06C2ull),
+ u64x2(0x5A04ABFC800BCADCull, 0x9E447A2EC3453484ull),
+ u64x2(0xFDD567050E1E9EC9ull, 0xDB73DBD3105588CDull),
+ u64x2(0x675FDA79E3674340ull, 0xC5C43465713E38D8ull),
+ u64x2(0x3D28F89EF16DFF20ull, 0x153E21E78FB03D4Aull),
+ u64x2(0xE6E39F2BDB83ADF7ull, 0xE93D5A68948140F7ull),
+ u64x2(0xF64C261C94692934ull, 0x411520F77602D4F7ull),
+ u64x2(0xBCF46B2ED4A10068ull, 0xD40824713320F46Aull),
+ u64x2(0x43B7D4B7500061AFull, 0x1E39F62E97244546ull)};
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_KEYS_INC_
diff --git a/absl/random/internal/randen.cc b/absl/random/internal/randen.cc
new file mode 100644
index 00000000..3b087605
--- /dev/null
+++ b/absl/random/internal/randen.cc
@@ -0,0 +1,91 @@
+// 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/randen.h"
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/randen_detect.h"
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// High-level summary:
+// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
+// a sponge-like random generator that requires a cryptographic permutation.
+// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
+// achieving backtracking resistance with only one Permute() per buffer.
+//
+// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
+// Function" constructs up to 1024-bit permutations using an improved
+// Generalized Feistel network with 2-round AES-128 functions. This Feistel
+// block shuffle achieves diffusion faster and is less vulnerable to
+// sliced-biclique attacks than the Type-2 cyclic shuffle.
+//
+// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
+// property" extends the same kind of improved Feistel block shuffle to 16
+// branches, which enables a 2048-bit permutation.
+//
+// We combine these three ideas and also change Simpira's subround keys from
+// structured/low-entropy counters to digits of Pi.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+struct RandenState {
+ const void* keys;
+ bool has_crypto;
+};
+
+RandenState GetRandenState() {
+ static const RandenState state = []() {
+ RandenState tmp;
+#if ABSL_RANDOM_INTERNAL_AES_DISPATCH
+ // HW AES Dispatch.
+ if (HasRandenHwAesImplementation() && CPUSupportsRandenHwAes()) {
+ tmp.has_crypto = true;
+ tmp.keys = RandenHwAes::GetKeys();
+ } else {
+ tmp.has_crypto = false;
+ tmp.keys = RandenSlow::GetKeys();
+ }
+#elif ABSL_HAVE_ACCELERATED_AES
+ // HW AES is enabled.
+ tmp.has_crypto = true;
+ tmp.keys = RandenHwAes::GetKeys();
+#else
+ // HW AES is disabled.
+ tmp.has_crypto = false;
+ tmp.keys = RandenSlow::GetKeys();
+#endif
+ return tmp;
+ }();
+ return state;
+}
+
+} // namespace
+
+Randen::Randen() {
+ auto tmp = GetRandenState();
+ keys_ = tmp.keys;
+#if ABSL_RANDOM_INTERNAL_AES_DISPATCH
+ has_crypto_ = tmp.has_crypto;
+#endif
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/randen.h b/absl/random/internal/randen.h
new file mode 100644
index 00000000..ef375f90
--- /dev/null
+++ b/absl/random/internal/randen.h
@@ -0,0 +1,102 @@
+// 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_RANDEN_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_H_
+
+#include <cstddef>
+
+#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_hwaes.h"
+#include "absl/random/internal/randen_slow.h"
+#include "absl/random/internal/randen_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// Randen implements the basic state manipulation methods.
+class Randen {
+ public:
+ static constexpr size_t kStateBytes = RandenTraits::kStateBytes;
+ static constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes;
+ static constexpr size_t kSeedBytes = RandenTraits::kSeedBytes;
+
+ ~Randen() = default;
+
+ Randen();
+
+ // Generate updates the randen sponge. The outer portion of the sponge
+ // (kCapacityBytes .. kStateBytes) may be consumed as PRNG state.
+ template <typename T, size_t N>
+ void Generate(T (&state)[N]) const {
+ static_assert(N * sizeof(T) == kStateBytes,
+ "Randen::Generate() requires kStateBytes of state");
+#if ABSL_RANDOM_INTERNAL_AES_DISPATCH
+ // HW AES Dispatch.
+ if (has_crypto_) {
+ RandenHwAes::Generate(keys_, state);
+ } else {
+ RandenSlow::Generate(keys_, state);
+ }
+#elif ABSL_HAVE_ACCELERATED_AES
+ // HW AES is enabled.
+ RandenHwAes::Generate(keys_, state);
+#else
+ // HW AES is disabled.
+ RandenSlow::Generate(keys_, state);
+#endif
+ }
+
+ // Absorb incorporates additional seed material into the randen sponge. After
+ // absorb returns, Generate must be called before the state may be consumed.
+ template <typename S, size_t M, typename T, size_t N>
+ void Absorb(const S (&seed)[M], T (&state)[N]) const {
+ static_assert(M * sizeof(S) == RandenTraits::kSeedBytes,
+ "Randen::Absorb() requires kSeedBytes of seed");
+
+ static_assert(N * sizeof(T) == RandenTraits::kStateBytes,
+ "Randen::Absorb() requires kStateBytes of state");
+#if ABSL_RANDOM_INTERNAL_AES_DISPATCH
+ // HW AES Dispatch.
+ if (has_crypto_) {
+ RandenHwAes::Absorb(seed, state);
+ } else {
+ RandenSlow::Absorb(seed, state);
+ }
+#elif ABSL_HAVE_ACCELERATED_AES
+ // HW AES is enabled.
+ RandenHwAes::Absorb(seed, state);
+#else
+ // HW AES is disabled.
+ RandenSlow::Absorb(seed, state);
+#endif
+ }
+
+ private:
+ const void* keys_;
+#if ABSL_RANDOM_INTERNAL_AES_DISPATCH
+ bool has_crypto_;
+#endif
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_H_
diff --git a/absl/random/internal/randen_benchmarks.cc b/absl/random/internal/randen_benchmarks.cc
new file mode 100644
index 00000000..f589172c
--- /dev/null
+++ b/absl/random/internal/randen_benchmarks.cc
@@ -0,0 +1,174 @@
+// 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/randen.h"
+
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/nanobenchmark.h"
+#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_engine.h"
+#include "absl/random/internal/randen_hwaes.h"
+#include "absl/random/internal/randen_slow.h"
+#include "absl/strings/numbers.h"
+
+namespace {
+
+using absl::random_internal::Randen;
+using absl::random_internal::RandenHwAes;
+using absl::random_internal::RandenSlow;
+
+using absl::random_internal_nanobenchmark::FuncInput;
+using absl::random_internal_nanobenchmark::FuncOutput;
+using absl::random_internal_nanobenchmark::InvariantTicksPerSecond;
+using absl::random_internal_nanobenchmark::MeasureClosure;
+using absl::random_internal_nanobenchmark::Params;
+using absl::random_internal_nanobenchmark::PinThreadToCPU;
+using absl::random_internal_nanobenchmark::Result;
+
+// Local state parameters.
+static constexpr size_t kStateSizeT = Randen::kStateBytes / sizeof(uint64_t);
+static constexpr size_t kSeedSizeT = Randen::kSeedBytes / sizeof(uint32_t);
+
+// Randen implementation benchmarks.
+template <typename T>
+struct AbsorbFn : public T {
+ mutable uint64_t state[kStateSizeT] = {};
+ mutable uint32_t seed[kSeedSizeT] = {};
+
+ static constexpr size_t bytes() { return sizeof(seed); }
+
+ FuncOutput operator()(const FuncInput num_iters) const {
+ for (size_t i = 0; i < num_iters; ++i) {
+ this->Absorb(seed, state);
+ }
+ return state[0];
+ }
+};
+
+template <typename T>
+struct GenerateFn : public T {
+ mutable uint64_t state[kStateSizeT];
+ GenerateFn() { std::memset(state, 0, sizeof(state)); }
+
+ static constexpr size_t bytes() { return sizeof(state); }
+
+ FuncOutput operator()(const FuncInput num_iters) const {
+ const auto* keys = this->GetKeys();
+ for (size_t i = 0; i < num_iters; ++i) {
+ this->Generate(keys, state);
+ }
+ return state[0];
+ }
+};
+
+template <typename UInt>
+struct Engine {
+ mutable absl::random_internal::randen_engine<UInt> rng;
+
+ static constexpr size_t bytes() { return sizeof(UInt); }
+
+ FuncOutput operator()(const FuncInput num_iters) const {
+ for (size_t i = 0; i < num_iters - 1; ++i) {
+ rng();
+ }
+ return rng();
+ }
+};
+
+template <size_t N>
+void Print(const char* name, const size_t n, const Result (&results)[N],
+ const size_t bytes) {
+ if (n == 0) {
+ ABSL_RAW_LOG(
+ WARNING,
+ "WARNING: Measurement failed, should not happen when using "
+ "PinThreadToCPU unless the region to measure takes > 1 second.\n");
+ return;
+ }
+
+ static const double ns_per_tick = 1e9 / InvariantTicksPerSecond();
+ static constexpr const double kNsPerS = 1e9; // ns/s
+ static constexpr const double kMBPerByte = 1.0 / 1048576.0; // Mb / b
+ static auto header = [] {
+ return printf("%20s %8s: %12s ticks; %9s (%9s) %8s\n", "Name", "Count",
+ "Total", "Variance", "Time", "bytes/s");
+ }();
+ (void)header;
+
+ for (size_t i = 0; i < n; ++i) {
+ const double ticks_per_call = results[i].ticks / results[i].input;
+ const double ns_per_call = ns_per_tick * ticks_per_call;
+ const double bytes_per_ns = bytes / ns_per_call;
+ const double mb_per_s = bytes_per_ns * kNsPerS * kMBPerByte;
+ // Output
+ printf("%20s %8zu: %12.2f ticks; MAD=%4.2f%% (%6.1f ns) %8.1f Mb/s\n",
+ name, results[i].input, results[i].ticks,
+ results[i].variability * 100.0, ns_per_call, mb_per_s);
+ }
+}
+
+// Fails here
+template <typename Op, size_t N>
+void Measure(const char* name, const FuncInput (&inputs)[N]) {
+ Op op;
+
+ Result results[N];
+ Params params;
+ params.verbose = false;
+ params.max_evals = 6; // avoid test timeout
+ const size_t num_results = MeasureClosure(op, inputs, N, results, params);
+ Print(name, num_results, results, op.bytes());
+}
+
+// unpredictable == 1 but the compiler does not know that.
+void RunAll(const int argc, char* argv[]) {
+ if (argc == 2) {
+ int cpu = -1;
+ if (!absl::SimpleAtoi(argv[1], &cpu)) {
+ ABSL_RAW_LOG(FATAL, "The optional argument must be a CPU number >= 0.\n");
+ }
+ PinThreadToCPU(cpu);
+ }
+
+ // The compiler cannot reduce this to a constant.
+ 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
+ Measure<AbsorbFn<RandenSlow>>("Absorb (Slow)", inputs);
+
+#if !defined(ABSL_INTERNAL_DISABLE_AES) && ABSL_HAVE_ACCELERATED_AES
+ Measure<GenerateFn<RandenHwAes>>("Generate (HwAes)", inputs);
+#endif
+ Measure<GenerateFn<RandenSlow>>("Generate (Slow)", inputs);
+
+ // Measure the production engine.
+ static const FuncInput inputs1[] = {unpredictable * 1000,
+ unpredictable * 10000};
+ Measure<Engine<uint64_t>>("randen_engine<uint64_t>", inputs1);
+ Measure<Engine<uint32_t>>("randen_engine<uint32_t>", inputs1);
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ RunAll(argc, argv);
+ return 0;
+}
diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc
new file mode 100644
index 00000000..610ae319
--- /dev/null
+++ b/absl/random/internal/randen_detect.cc
@@ -0,0 +1,221 @@
+// 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.
+
+// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
+// symbols from arbitrary system and other headers, since it may be built
+// with different flags from other targets, using different levels of
+// optimization, potentially introducing ODR violations.
+
+#include "absl/random/internal/randen_detect.h"
+
+#include <cstdint>
+#include <cstring>
+
+#include "absl/random/internal/platform.h"
+
+#if defined(ABSL_ARCH_X86_64)
+#define ABSL_INTERNAL_USE_X86_CPUID
+#elif defined(ABSL_ARCH_PPC) || defined(ABSL_ARCH_ARM) || \
+ defined(ABSL_ARCH_AARCH64)
+#if defined(__ANDROID__)
+#define ABSL_INTERNAL_USE_ANDROID_GETAUXVAL
+#define ABSL_INTERNAL_USE_GETAUXVAL
+#elif defined(__linux__)
+#define ABSL_INTERNAL_USE_LINUX_GETAUXVAL
+#define ABSL_INTERNAL_USE_GETAUXVAL
+#endif
+#endif
+
+#if defined(ABSL_INTERNAL_USE_X86_CPUID)
+#if defined(_WIN32) || defined(_WIN64)
+#include <intrin.h> // NOLINT(build/include_order)
+#pragma intrinsic(__cpuid)
+#else
+// MSVC-equivalent __cpuid intrinsic function.
+static void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile("cpuid \n\t"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type), "c"(0));
+}
+#endif
+#endif // ABSL_INTERNAL_USE_X86_CPUID
+
+// 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)
+
+static uint32_t GetAuxval(uint32_t hwcap_type) {
+ return static_cast<uint32_t>(getauxval(hwcap_type));
+}
+
+#endif
+
+// On android, probe the system's C library for getauxval().
+// This is the same technique used by the android NDK cpu features library
+// as well as the google open-source cpu_features library.
+//
+// TODO(absl-team): Consider implementing a fallback of directly reading
+// /proc/self/auxval.
+#if defined(ABSL_INTERNAL_USE_ANDROID_GETAUXVAL)
+#include <dlfcn.h>
+
+static uint32_t GetAuxval(uint32_t hwcap_type) {
+ // NOLINTNEXTLINE(runtime/int)
+ typedef unsigned long (*getauxval_func_t)(unsigned long);
+
+ dlerror(); // Cleaning error state before calling dlopen.
+ void* libc_handle = dlopen("libc.so", RTLD_NOW);
+ if (!libc_handle) {
+ return 0;
+ }
+ uint32_t result = 0;
+ void* sym = dlsym(libc_handle, "getauxval");
+ if (sym) {
+ getauxval_func_t func;
+ memcpy(&func, &sym, sizeof(func));
+ result = static_cast<uint32_t>((*func)(hwcap_type));
+ }
+ dlclose(libc_handle);
+ return result;
+}
+
+#endif
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// The default return at the end of the function might be unreachable depending
+// on the configuration. Ignore that warning.
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code-return"
+#endif
+
+// CPUSupportsRandenHwAes returns whether the CPU is a microarchitecture
+// which supports the crpyto/aes instructions or extensions necessary to use the
+// accelerated RandenHwAes implementation.
+//
+// 1. For x86 it is sufficient to use the CPUID instruction to detect whether
+// the cpu supports AES instructions. Done.
+//
+// Fon non-x86 it is much more complicated.
+//
+// 2. When ABSL_INTERNAL_USE_GETAUXVAL is defined, use getauxval() (either
+// the direct c-library version, or the android probing version which loads
+// libc), and read the hardware capability bits.
+// This is based on the technique used by boringssl uses to detect
+// 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.
+//
+
+bool CPUSupportsRandenHwAes() {
+#if defined(ABSL_INTERNAL_USE_X86_CPUID)
+ // 1. For x86: Use CPUID to detect the required AES instruction set.
+ int regs[4];
+ __cpuid(reinterpret_cast<int*>(regs), 1);
+ return regs[2] & (1 << 25); // AES
+
+#elif defined(ABSL_INTERNAL_USE_GETAUXVAL)
+ // 2. Use getauxval() to read the hardware bits and determine
+ // cpu capabilities.
+
+#define AT_HWCAP 16
+#define AT_HWCAP2 26
+#if defined(ABSL_ARCH_PPC)
+ // For Power / PPC: Expect that the cpu supports VCRYPTO
+ // See https://members.openpowerfoundation.org/document/dl/576
+ // VCRYPTO should be present in POWER8 >= 2.07.
+ // Uses Linux kernel constants from arch/powerpc/include/uapi/asm/cputable.h
+ static const uint32_t kVCRYPTO = 0x02000000;
+ const uint32_t hwcap = GetAuxval(AT_HWCAP2);
+ return (hwcap & kVCRYPTO) != 0;
+
+#elif defined(ABSL_ARCH_ARM)
+ // For ARM: Require crypto+neon
+ // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
+ // Uses Linux kernel constants from arch/arm64/include/asm/hwcap.h
+ static const uint32_t kNEON = 1 << 12;
+ uint32_t hwcap = GetAuxval(AT_HWCAP);
+ if ((hwcap & kNEON) == 0) {
+ return false;
+ }
+
+ // And use it again to detect AES.
+ static const uint32_t kAES = 1 << 0;
+ const uint32_t hwcap2 = GetAuxval(AT_HWCAP2);
+ return (hwcap2 & kAES) != 0;
+
+#elif defined(ABSL_ARCH_AARCH64)
+ // For AARCH64: Require crypto+neon
+ // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0500f/CIHBIBBA.html
+ static const uint32_t kNEON = 1 << 1;
+ static const uint32_t kAES = 1 << 3;
+ const uint32_t hwcap = GetAuxval(AT_HWCAP);
+ return ((hwcap & kNEON) != 0) && ((hwcap & kAES) != 0);
+#endif
+
+#else // ABSL_INTERNAL_USE_GETAUXVAL
+ // 3. By default, assume that the compiler default.
+ return ABSL_HAVE_ACCELERATED_AES ? true : false;
+
+#endif
+ // NOTE: There are some other techniques that may be worth trying:
+ //
+ // * Use an environment variable: ABSL_RANDOM_USE_HWAES
+ //
+ // * Rely on compiler-generated target-based dispatch.
+ // Using x86/gcc it might look something like this:
+ //
+ // int __attribute__((target("aes"))) HasAes() { return 1; }
+ // int __attribute__((target("default"))) HasAes() { return 0; }
+ //
+ // This does not work on all architecture/compiler combinations.
+ //
+ // * On Linux consider reading /proc/cpuinfo and/or /proc/self/auxv.
+ // These files have lines which are easy to parse; for ARM/AARCH64 it is quite
+ // easy to find the Features: line and extract aes / neon. Likewise for
+ // PPC.
+ //
+ // * Fork a process and test for SIGILL:
+ //
+ // * Many architectures have instructions to read the ISA. Unfortunately
+ // most of those require that the code is running in ring 0 /
+ // protected-mode.
+ //
+ // There are several examples. e.g. Valgrind detects PPC ISA 2.07:
+ // https://github.com/lu-zero/valgrind/blob/master/none/tests/ppc64/test_isa_2_07_part1.c
+ //
+ // MRS <Xt>, ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt
+ //
+ // uint64_t val;
+ // __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__)
+#pragma clang diagnostic pop
+#endif
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/randen_detect.h b/absl/random/internal/randen_detect.h
new file mode 100644
index 00000000..cb777550
--- /dev/null
+++ b/absl/random/internal/randen_detect.h
@@ -0,0 +1,31 @@
+// 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_RANDEN_DETECT_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Returns whether the current CPU supports RandenHwAes implementation.
+// This typically involves supporting cryptographic extensions on whichever
+// platform is currently running.
+bool CPUSupportsRandenHwAes();
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_DETECT_H_
diff --git a/absl/random/internal/randen_engine.h b/absl/random/internal/randen_engine.h
new file mode 100644
index 00000000..e721559e
--- /dev/null
+++ b/absl/random/internal/randen_engine.h
@@ -0,0 +1,230 @@
+// 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_RANDEN_ENGINE_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_
+
+#include <algorithm>
+#include <cinttypes>
+#include <cstdlib>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+#include "absl/random/internal/randen.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Deterministic pseudorandom byte generator with backtracking resistance
+// (leaking the state does not compromise prior outputs). Based on Reverie
+// (see "A Robust and Sponge-Like PRNG with Improved Efficiency") instantiated
+// with an improved Simpira-like permutation.
+// Returns values of type "T" (must be a built-in unsigned integer type).
+//
+// RANDen = RANDom generator or beetroots in Swiss High German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+template <typename T>
+class alignas(16) randen_engine {
+ public:
+ // C++11 URBG interface:
+ using result_type = T;
+ static_assert(std::is_unsigned<result_type>::value,
+ "randen_engine 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)();
+ }
+
+ explicit randen_engine(result_type seed_value = 0) { seed(seed_value); }
+
+ template <class SeedSequence,
+ typename = typename absl::enable_if_t<
+ !std::is_same<SeedSequence, randen_engine>::value>>
+ explicit randen_engine(SeedSequence&& seq) {
+ seed(seq);
+ }
+
+ randen_engine(const randen_engine&) = default;
+
+ // Returns random bits from the buffer in units of result_type.
+ result_type operator()() {
+ // Refill the buffer if needed (unlikely).
+ if (next_ >= kStateSizeT) {
+ next_ = kCapacityT;
+ impl_.Generate(state_);
+ }
+
+ return state_[next_++];
+ }
+
+ template <class SeedSequence>
+ typename absl::enable_if_t<
+ !std::is_convertible<SeedSequence, result_type>::value>
+ seed(SeedSequence&& seq) {
+ // Zeroes the state.
+ seed();
+ reseed(seq);
+ }
+
+ void seed(result_type seed_value = 0) {
+ next_ = kStateSizeT;
+ // Zeroes the inner state and fills the outer state with seed_value to
+ // mimics behaviour of reseed
+ std::fill(std::begin(state_), std::begin(state_) + kCapacityT, 0);
+ std::fill(std::begin(state_) + kCapacityT, std::end(state_), seed_value);
+ }
+
+ // Inserts entropy into (part of) the state. Calling this periodically with
+ // sufficient entropy ensures prediction resistance (attackers cannot predict
+ // future outputs even if state is compromised).
+ template <class SeedSequence>
+ void reseed(SeedSequence& seq) {
+ using sequence_result_type = typename SeedSequence::result_type;
+ static_assert(sizeof(sequence_result_type) == 4,
+ "SeedSequence::result_type must be 32-bit");
+
+ constexpr size_t kBufferSize =
+ Randen::kSeedBytes / sizeof(sequence_result_type);
+ alignas(16) sequence_result_type buffer[kBufferSize];
+
+ // Randen::Absorb XORs the seed into state, which is then mixed by a call
+ // to Randen::Generate. Seeding with only the provided entropy is preferred
+ // to using an arbitrary generate() call, so use [rand.req.seed_seq]
+ // size as a proxy for the number of entropy units that can be generated
+ // without relying on seed sequence mixing...
+ const size_t entropy_size = seq.size();
+ if (entropy_size < kBufferSize) {
+ // ... and only request that many values, or 256-bits, when unspecified.
+ const size_t requested_entropy = (entropy_size == 0) ? 8u : entropy_size;
+ std::fill(std::begin(buffer) + requested_entropy, std::end(buffer), 0);
+ seq.generate(std::begin(buffer), std::begin(buffer) + requested_entropy);
+ // The Randen paper suggests preferentially initializing even-numbered
+ // 128-bit vectors of the randen state (there are 16 such vectors).
+ // The seed data is merged into the state offset by 128-bits, which
+ // implies prefering seed bytes [16..31, ..., 208..223]. Since the
+ // buffer is 32-bit values, we swap the corresponding buffer positions in
+ // 128-bit chunks.
+ size_t dst = kBufferSize;
+ while (dst > 7) {
+ // leave the odd bucket as-is.
+ dst -= 4;
+ size_t src = dst >> 1;
+ // swap 128-bits into the even bucket
+ std::swap(buffer[--dst], buffer[--src]);
+ std::swap(buffer[--dst], buffer[--src]);
+ std::swap(buffer[--dst], buffer[--src]);
+ std::swap(buffer[--dst], buffer[--src]);
+ }
+ } else {
+ seq.generate(std::begin(buffer), std::end(buffer));
+ }
+ impl_.Absorb(buffer, state_);
+
+ // Generate will be called when operator() is called
+ next_ = kStateSizeT;
+ }
+
+ void discard(uint64_t count) {
+ uint64_t step = std::min<uint64_t>(kStateSizeT - next_, count);
+ count -= step;
+
+ constexpr uint64_t kRateT = kStateSizeT - kCapacityT;
+ while (count > 0) {
+ next_ = kCapacityT;
+ impl_.Generate(state_);
+ step = std::min<uint64_t>(kRateT, count);
+ count -= step;
+ }
+ next_ += step;
+ }
+
+ bool operator==(const randen_engine& other) const {
+ return next_ == other.next_ &&
+ std::equal(std::begin(state_), std::end(state_),
+ std::begin(other.state_));
+ }
+
+ bool operator!=(const randen_engine& other) const {
+ return !(*this == other);
+ }
+
+ template <class CharT, class Traits>
+ friend std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const randen_engine<T>& engine) { // NOLINT(runtime/references)
+ using numeric_type =
+ typename random_internal::stream_format_type<result_type>::type;
+ auto saver = random_internal::make_ostream_state_saver(os);
+ for (const auto& elem : engine.state_) {
+ // In the case that `elem` is `uint8_t`, it must be cast to something
+ // larger so that it prints as an integer rather than a character. For
+ // simplicity, apply the cast all circumstances.
+ os << static_cast<numeric_type>(elem) << os.fill();
+ }
+ os << engine.next_;
+ return os;
+ }
+
+ template <class CharT, class Traits>
+ friend std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ randen_engine<T>& engine) { // NOLINT(runtime/references)
+ using numeric_type =
+ typename random_internal::stream_format_type<result_type>::type;
+ result_type state[kStateSizeT];
+ size_t next;
+ for (auto& elem : state) {
+ // It is not possible to read uint8_t from wide streams, so it is
+ // necessary to read a wider type and then cast it to uint8_t.
+ numeric_type value;
+ is >> value;
+ elem = static_cast<result_type>(value);
+ }
+ is >> next;
+ if (is.fail()) {
+ return is;
+ }
+ std::memcpy(engine.state_, state, sizeof(engine.state_));
+ engine.next_ = next;
+ return is;
+ }
+
+ private:
+ static constexpr size_t kStateSizeT =
+ Randen::kStateBytes / sizeof(result_type);
+ static constexpr size_t kCapacityT =
+ Randen::kCapacityBytes / sizeof(result_type);
+
+ // First kCapacityT are `inner', the others are accessible random bits.
+ alignas(16) result_type state_[kStateSizeT];
+ size_t next_; // index within state_
+ Randen impl_;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_ENGINE_H_
diff --git a/absl/random/internal/randen_engine_test.cc b/absl/random/internal/randen_engine_test.cc
new file mode 100644
index 00000000..c8e7685b
--- /dev/null
+++ b/absl/random/internal/randen_engine_test.cc
@@ -0,0 +1,656 @@
+// 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/randen_engine.h"
+
+#include <algorithm>
+#include <bitset>
+#include <random>
+#include <sstream>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/explicit_seed_seq.h"
+#include "absl/strings/str_cat.h"
+#include "absl/time/clock.h"
+
+#define UPDATE_GOLDEN 0
+
+using randen_u64 = absl::random_internal::randen_engine<uint64_t>;
+using randen_u32 = absl::random_internal::randen_engine<uint32_t>;
+using absl::random_internal::ExplicitSeedSeq;
+
+namespace {
+
+template <typename UIntType>
+class RandenEngineTypedTest : public ::testing::Test {};
+
+using UIntTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t>;
+
+TYPED_TEST_SUITE(RandenEngineTypedTest, UIntTypes);
+
+TYPED_TEST(RandenEngineTypedTest, VerifyReseedChangesAllValues) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+ using result_type = typename randen::result_type;
+
+ const size_t kNumOutputs = (sizeof(randen) * 2 / sizeof(TypeParam)) + 1;
+ randen engine;
+
+ // MSVC emits error 2719 without the use of std::ref below.
+ // * formal parameter with __declspec(align('#')) won't be aligned
+
+ {
+ std::seed_seq seq1{1, 2, 3, 4, 5, 6, 7};
+ engine.seed(seq1);
+ }
+ result_type a[kNumOutputs];
+ std::generate(std::begin(a), std::end(a), std::ref(engine));
+
+ {
+ std::random_device rd;
+ std::seed_seq seq2{rd(), rd(), rd()};
+ engine.seed(seq2);
+ }
+ result_type b[kNumOutputs];
+ std::generate(std::begin(b), std::end(b), std::ref(engine));
+
+ // 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);
+}
+
+// Number of values that needs to be consumed to clean two sizes of buffer
+// and trigger third refresh. (slightly overestimates the actual state size).
+constexpr size_t kTwoBufferValues = sizeof(randen_u64) / sizeof(uint16_t) + 1;
+
+TYPED_TEST(RandenEngineTypedTest, VerifyDiscard) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+
+ for (size_t num_used = 0; num_used < kTwoBufferValues; ++num_used) {
+ randen engine_used;
+ for (size_t i = 0; i < num_used; ++i) {
+ engine_used();
+ }
+
+ for (size_t num_discard = 0; num_discard < kTwoBufferValues;
+ ++num_discard) {
+ randen engine1 = engine_used;
+ randen engine2 = engine_used;
+ for (size_t i = 0; i < num_discard; ++i) {
+ engine1();
+ }
+ engine2.discard(num_discard);
+ for (size_t i = 0; i < kTwoBufferValues; ++i) {
+ const auto r1 = engine1();
+ const auto r2 = engine2();
+ ASSERT_EQ(r1, r2) << "used=" << num_used << " discard=" << num_discard;
+ }
+ }
+ }
+}
+
+TYPED_TEST(RandenEngineTypedTest, StreamOperatorsResult) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+ std::wostringstream os;
+ std::wistringstream is;
+ randen engine;
+
+ EXPECT_EQ(&(os << engine), &os);
+ EXPECT_EQ(&(is >> engine), &is);
+}
+
+TYPED_TEST(RandenEngineTypedTest, StreamSerialization) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+
+ for (size_t discard = 0; discard < kTwoBufferValues; ++discard) {
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ randen engine(seed_sequence);
+ engine.discard(discard);
+
+ std::stringstream stream;
+ stream << engine;
+
+ randen new_engine;
+ stream >> new_engine;
+ for (size_t i = 0; i < 64; ++i) {
+ EXPECT_EQ(engine(), new_engine()) << " " << i;
+ }
+ }
+}
+
+constexpr size_t kNumGoldenOutputs = 127;
+
+// This test is checking if randen_engine is meets interface requirements
+// defined in [rand.req.urbg].
+TYPED_TEST(RandenEngineTypedTest, RandomNumberEngineInterface) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+
+ using E = randen;
+ using T = typename E::result_type;
+
+ static_assert(std::is_copy_constructible<E>::value,
+ "randen_engine must be copy constructible");
+
+ static_assert(absl::is_copy_assignable<E>::value,
+ "randen_engine must be copy assignable");
+
+ static_assert(std::is_move_constructible<E>::value,
+ "randen_engine must be move constructible");
+
+ static_assert(absl::is_move_assignable<E>::value,
+ "randen_engine must be move assignable");
+
+ static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
+ "return type of operator() must be result_type");
+
+ // Names after definition of [rand.req.urbg] in C++ standard.
+ // e us a value of E
+ // v is a lvalue of E
+ // x, y are possibly const values of E
+ // s is a value of T
+ // q is a value satisfying requirements of seed_sequence
+ // z is a value of type unsigned long long
+ // os is a some specialization of basic_ostream
+ // is is a some specialization of basic_istream
+
+ E e, v;
+ const E x, y;
+ T s = 1;
+ std::seed_seq q{1, 2, 3};
+ unsigned long long z = 1; // NOLINT(runtime/int)
+ std::wostringstream os;
+ std::wistringstream is;
+
+ E{};
+ E{x};
+ E{s};
+ E{q};
+
+ e.seed();
+
+ // MSVC emits error 2718 when using EXPECT_EQ(e, x)
+ // * actual parameter with __declspec(align('#')) won't be aligned
+ EXPECT_TRUE(e == x);
+
+ e.seed(q);
+ {
+ E tmp(q);
+ EXPECT_TRUE(e == tmp);
+ }
+
+ e();
+ {
+ E tmp(q);
+ EXPECT_TRUE(e != tmp);
+ }
+
+ e.discard(z);
+
+ static_assert(std::is_same<decltype(x == y), bool>::value,
+ "return type of operator== must be bool");
+
+ static_assert(std::is_same<decltype(x != y), bool>::value,
+ "return type of operator== must be bool");
+}
+
+TYPED_TEST(RandenEngineTypedTest, RandenEngineSFINAETest) {
+ using randen = typename absl::random_internal::randen_engine<TypeParam>;
+ using result_type = typename randen::result_type;
+
+ {
+ randen engine(result_type(1));
+ engine.seed(result_type(1));
+ }
+
+ {
+ result_type n = 1;
+ randen engine(n);
+ engine.seed(n);
+ }
+
+ {
+ randen engine(1);
+ engine.seed(1);
+ }
+
+ {
+ int n = 1;
+ randen engine(n);
+ engine.seed(n);
+ }
+
+ {
+ std::seed_seq seed_seq;
+ randen engine(seed_seq);
+ engine.seed(seed_seq);
+ }
+
+ {
+ randen engine{std::seed_seq()};
+ engine.seed(std::seed_seq());
+ }
+}
+
+TEST(RandenTest, VerifyGoldenRanden64Default) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0xc3c14f134e433977, 0xdda9f47cd90410ee, 0x887bf3087fd8ca10,
+ 0xf0b780f545c72912, 0x15dbb1d37696599f, 0x30ec63baff3c6d59,
+ 0xb29f73606f7f20a6, 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e,
+ 0x9cbf605e3fd9de8a, 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5,
+ 0xf4b327fe0fc73c37, 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d,
+ 0xd5af05dd3eff9556, 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c,
+ 0x58d3575834956d42, 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3,
+ 0x497cabf3431154fc, 0x4e24370570029a8b, 0xd88b5749f090e5ea,
+ 0xc651a582a970692f, 0x78fcec2cbb6342f5, 0x463cb745612f55db,
+ 0x352ee4ad1816afe3, 0x026ff374c101da7e, 0x811ef0821c3de851,
+ 0x6f7e616704c4fa59, 0xa0660379992d58fc, 0x04b0a374a3b795c7,
+ 0x915f3445685da798, 0x26802a8ac76571ce, 0x4663352533ce1882,
+ 0xb9fdefb4a24dc738, 0x5588ba3a4d6e6c51, 0xa2101a42d35f1956,
+ 0x607195a5e200f5fd, 0x7e100308f3290764, 0xe1e5e03c759c0709,
+ 0x082572cc5da6606f, 0xcbcf585399e432f1, 0xe8a2be4f8335d8f1,
+ 0x0904469acbfee8f2, 0xf08bd31b6daecd51, 0x08e8a1f1a69da69a,
+ 0x6542a20aad57bff5, 0x2e9705bb053d6b46, 0xda2fc9db0713c391,
+ 0x78e3a810213b6ffb, 0xdc16a59cdd85f8a6, 0xc0932718cd55781f,
+ 0xb9bfb29c2b20bfe5, 0xb97289c1be0f2f9c, 0xc0a2a0e403a892d4,
+ 0x5524bb834771435b, 0x8265da3d39d1a750, 0xff4af3ab8d1b78c5,
+ 0xf0ec5f424bcad77f, 0x66e455f627495189, 0xc82d3120b57e3270,
+ 0x3424e47dc22596e3, 0xbc0c95129ccedcdd, 0xc191c595afc4dcbf,
+ 0x120392bd2bb70939, 0x7f90650ea6cd6ab4, 0x7287491832695ad3,
+ 0xa7c8fac5a7917eb0, 0xd088cb9418be0361, 0x7c1bf9839c7c1ce5,
+ 0xe2e991fa58e1e79e, 0x78565cdefd28c4ad, 0x7351b9fef98bafad,
+ 0x2a9eac28b08c96bf, 0x6c4f179696cb2225, 0x13a685861bab87e0,
+ 0x64c6de5aa0501971, 0x30537425cac70991, 0x01590d9dc6c532b7,
+ 0x7e05e3aa8ec720dc, 0x74a07d9c54e3e63f, 0x738184388f3bc1d2,
+ 0x26ffdc5067be3acb, 0x6bcdf185561f255f, 0xa0eaf2e1cf99b1c6,
+ 0x171df81934f68604, 0x7ea5a21665683e5a, 0x5d1cb02075ba1cea,
+ 0x957f38cbd2123fdf, 0xba6364eff80de02f, 0x606e0a0e41d452ee,
+ 0x892d8317de82f7a2, 0xe707b1db50f7b43e, 0x4eb28826766fcf5b,
+ 0x5a362d56e80a0951, 0x6ee217df16527d78, 0xf6737962ba6b23dd,
+ 0x443e63857d4076ca, 0x790d9a5f048adfeb, 0xd796b052151ee94d,
+ 0x033ed95c12b04a03, 0x8b833ff84893da5d, 0x3d6724b1bb15eab9,
+ 0x9877c4225061ca76, 0xd68d6810adf74fb3, 0x42e5352fe30ce989,
+ 0x265b565a7431fde7, 0x3cdbf7e358df4b8b, 0x2922a47f6d3e8779,
+ 0x52d2242f65b37f88, 0x5d836d6e2958d6b5, 0x29d40f00566d5e26,
+ 0x288db0e1124b14a0, 0x6c056608b7d9c1b6, 0x0b9471bdb8f19d32,
+ 0x8fb946504faa6c9d, 0x8943a9464540251c, 0xfd1fe27d144a09e0,
+ 0xea6ac458da141bda, 0x8048f217633fce36, 0xfeda1384ade74d31,
+ 0x4334b8b02ff7612f, 0xdbc8441f5227e216, 0x096d119a3605c85b,
+ 0x2b72b31c21b7d7d0};
+
+ randen_u64 engine;
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed();
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(RandenTest, VerifyGoldenRanden64Seeded) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0x83a9e58f94d3dcd5, 0x70bbdff3d97949fb, 0x0438481f7471c1b4,
+ 0x34fdc58ee5fb5930, 0xceee4f2d2a937d17, 0xb5a26a68e432aea9,
+ 0x8b64774a3fb51740, 0xd89ac1fc74249c74, 0x03910d1d23fc3fdf,
+ 0xd38f630878aa897f, 0x0ee8f0f5615f7e44, 0x98f5a53df8279d52,
+ 0xb403f52c25938d0e, 0x240072996ea6e838, 0xd3a791246190fa61,
+ 0xaaedd3df7a7b4f80, 0xc6eacabe05deaf6e, 0xb7967dd8790edf4d,
+ 0x9a0a8e67e049d279, 0x0494f606aebc23e7, 0x598dcd687bc3e0ee,
+ 0x010ac81802d452a1, 0x6407c87160aa2842, 0x5a56e276486f93a0,
+ 0xc887a399d46a8f02, 0x9e1e6100fe93b740, 0x12d02e330f8901f6,
+ 0xc39ca52b47e790b7, 0xb0b0a2fa11e82e61, 0x1542d841a303806a,
+ 0x1fe659fd7d6e9d86, 0xb8c90d80746541ac, 0x239d56a5669ddc94,
+ 0xd40db57c8123d13c, 0x3abc2414153a0db0, 0x9bad665630cb8d61,
+ 0x0bd1fb90ee3f4bbc, 0x8f0b4d7e079b4e42, 0xfa0fb0e0ee59e793,
+ 0x51080b283e071100, 0x2c4b9e715081cc15, 0xbe10ed49de4941df,
+ 0xf8eaac9d4b1b0d37, 0x4bcce4b54605e139, 0xa64722b76765dda6,
+ 0xb9377d738ca28ab5, 0x779fad81a8ccc1af, 0x65cb3ee61ffd3ba7,
+ 0xd74e79087862836f, 0xd05b9c584c3f25bf, 0x2ba93a4693579827,
+ 0xd81530aff05420ce, 0xec06cea215478621, 0x4b1798a6796d65ad,
+ 0xf142f3fb3a6f6fa6, 0x002b7bf7e237b560, 0xf47f2605ef65b4f8,
+ 0x9804ec5517effc18, 0xaed3d7f8b7d481cd, 0x5651c24c1ce338d1,
+ 0x3e7a38208bf0a3c6, 0x6796a7b614534aed, 0x0d0f3b848358460f,
+ 0x0fa5fe7600b19524, 0x2b0cf38253faaedc, 0x10df9188233a9fd6,
+ 0x3a10033880138b59, 0x5fb0b0d23948e80f, 0x9e76f7b02fbf5350,
+ 0x0816052304b1a985, 0x30c9880db41fd218, 0x14aa399b65e20f28,
+ 0xe1454a8cace787b4, 0x325ac971b6c6f0f5, 0x716b1aa2784f3d36,
+ 0x3d5ce14accfd144f, 0x6c0c97710f651792, 0xbc5b0f59fb333532,
+ 0x2a90a7d2140470bc, 0x8da269f55c1e1c8d, 0xcfc37143895792ca,
+ 0xbe21eab1f30b238f, 0x8c47229dee4d65fd, 0x5743614ed1ed7d54,
+ 0x351372a99e9c476e, 0x2bd5ea15e5db085f, 0x6925fde46e0af4ca,
+ 0xed3eda2bdc1f45bd, 0xdef68c68d460fa6e, 0xe42a0de76253e2b5,
+ 0x4e5176dcbc29c305, 0xbfd85fba9f810f6e, 0x76a5a2a9beb815c6,
+ 0x01edc4ddceaf414c, 0xa4e98904b4bb3b4b, 0x00bd63ac7d2f1ddd,
+ 0xb8491fe6e998ddbb, 0xb386a3463dda6800, 0x0081887688871619,
+ 0x33d394b3344e9a38, 0x815dba65a3a8baf9, 0x4232f6ec02c2fd1a,
+ 0xb5cff603edd20834, 0x580189243f687663, 0xa8d5a2cbdc27fe99,
+ 0x725d881693fa0131, 0xa2be2c13db2c7ac5, 0x7b6a9614b509fd78,
+ 0xb6b136d71e717636, 0x660f1a71aff046ea, 0x0ba10ae346c8ec9e,
+ 0xe66dde53e3145b41, 0x3b18288c88c26be6, 0x4d9d9d2ff02db933,
+ 0x4167da8c70f46e8a, 0xf183beef8c6318b4, 0x4d889e1e71eeeef1,
+ 0x7175c71ad6689b6b, 0xfb9e42beacd1b7dd, 0xc33d0e91b29b5e0d,
+ 0xd39b83291ce47922, 0xc4d570fb8493d12e, 0x23d5a5724f424ae6,
+ 0x5245f161876b6616, 0x38d77dbd21ab578d, 0x9c3423311f4ecbfe,
+ 0x76fe31389bacd9d5,
+ };
+
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ randen_u64 engine(seed_sequence);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed(seed_sequence);
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(RandenTest, VerifyGoldenRanden32Default) {
+ constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = {
+ 0x4e433977, 0xc3c14f13, 0xd90410ee, 0xdda9f47c, 0x7fd8ca10, 0x887bf308,
+ 0x45c72912, 0xf0b780f5, 0x7696599f, 0x15dbb1d3, 0xff3c6d59, 0x30ec63ba,
+ 0x6f7f20a6, 0xb29f7360, 0x6f49a54c, 0x02808a31, 0xd5c8e50e, 0x3b8feaf9,
+ 0x3fd9de8a, 0x9cbf605e, 0x78183bbb, 0xc970ae1a, 0x56301ed5, 0xd8b2ffd3,
+ 0x0fc73c37, 0xf4b327fe, 0xeb8f9a19, 0xcdfd8d76, 0x91420c9d, 0xc3a506eb,
+ 0x3eff9556, 0xd5af05dd, 0x8f83c4a1, 0x48db1bb7, 0x0d6bfe8c, 0x7023920e,
+ 0x34956d42, 0x58d35758, 0x6b87b840, 0xed1ef4c2, 0x3e0b2df3, 0x8eef32a2,
+ 0x431154fc, 0x497cabf3, 0x70029a8b, 0x4e243705, 0xf090e5ea, 0xd88b5749,
+ 0xa970692f, 0xc651a582, 0xbb6342f5, 0x78fcec2c, 0x612f55db, 0x463cb745,
+ 0x1816afe3, 0x352ee4ad, 0xc101da7e, 0x026ff374, 0x1c3de851, 0x811ef082,
+ 0x04c4fa59, 0x6f7e6167, 0x992d58fc, 0xa0660379, 0xa3b795c7, 0x04b0a374,
+ 0x685da798, 0x915f3445, 0xc76571ce, 0x26802a8a, 0x33ce1882, 0x46633525,
+ 0xa24dc738, 0xb9fdefb4, 0x4d6e6c51, 0x5588ba3a, 0xd35f1956, 0xa2101a42,
+ 0xe200f5fd, 0x607195a5, 0xf3290764, 0x7e100308, 0x759c0709, 0xe1e5e03c,
+ 0x5da6606f, 0x082572cc, 0x99e432f1, 0xcbcf5853, 0x8335d8f1, 0xe8a2be4f,
+ 0xcbfee8f2, 0x0904469a, 0x6daecd51, 0xf08bd31b, 0xa69da69a, 0x08e8a1f1,
+ 0xad57bff5, 0x6542a20a, 0x053d6b46, 0x2e9705bb, 0x0713c391, 0xda2fc9db,
+ 0x213b6ffb, 0x78e3a810, 0xdd85f8a6, 0xdc16a59c, 0xcd55781f, 0xc0932718,
+ 0x2b20bfe5, 0xb9bfb29c, 0xbe0f2f9c, 0xb97289c1, 0x03a892d4, 0xc0a2a0e4,
+ 0x4771435b, 0x5524bb83, 0x39d1a750, 0x8265da3d, 0x8d1b78c5, 0xff4af3ab,
+ 0x4bcad77f, 0xf0ec5f42, 0x27495189, 0x66e455f6, 0xb57e3270, 0xc82d3120,
+ 0xc22596e3, 0x3424e47d, 0x9ccedcdd, 0xbc0c9512, 0xafc4dcbf, 0xc191c595,
+ 0x2bb70939, 0x120392bd, 0xa6cd6ab4, 0x7f90650e, 0x32695ad3, 0x72874918,
+ 0xa7917eb0, 0xa7c8fac5, 0x18be0361, 0xd088cb94, 0x9c7c1ce5, 0x7c1bf983,
+ 0x58e1e79e, 0xe2e991fa, 0xfd28c4ad, 0x78565cde, 0xf98bafad, 0x7351b9fe,
+ 0xb08c96bf, 0x2a9eac28, 0x96cb2225, 0x6c4f1796, 0x1bab87e0, 0x13a68586,
+ 0xa0501971, 0x64c6de5a, 0xcac70991, 0x30537425, 0xc6c532b7, 0x01590d9d,
+ 0x8ec720dc, 0x7e05e3aa, 0x54e3e63f, 0x74a07d9c, 0x8f3bc1d2, 0x73818438,
+ 0x67be3acb, 0x26ffdc50, 0x561f255f, 0x6bcdf185, 0xcf99b1c6, 0xa0eaf2e1,
+ 0x34f68604, 0x171df819, 0x65683e5a, 0x7ea5a216, 0x75ba1cea, 0x5d1cb020,
+ 0xd2123fdf, 0x957f38cb, 0xf80de02f, 0xba6364ef, 0x41d452ee, 0x606e0a0e,
+ 0xde82f7a2, 0x892d8317, 0x50f7b43e, 0xe707b1db, 0x766fcf5b, 0x4eb28826,
+ 0xe80a0951, 0x5a362d56, 0x16527d78, 0x6ee217df, 0xba6b23dd, 0xf6737962,
+ 0x7d4076ca, 0x443e6385, 0x048adfeb, 0x790d9a5f, 0x151ee94d, 0xd796b052,
+ 0x12b04a03, 0x033ed95c, 0x4893da5d, 0x8b833ff8, 0xbb15eab9, 0x3d6724b1,
+ 0x5061ca76, 0x9877c422, 0xadf74fb3, 0xd68d6810, 0xe30ce989, 0x42e5352f,
+ 0x7431fde7, 0x265b565a, 0x58df4b8b, 0x3cdbf7e3, 0x6d3e8779, 0x2922a47f,
+ 0x65b37f88, 0x52d2242f, 0x2958d6b5, 0x5d836d6e, 0x566d5e26, 0x29d40f00,
+ 0x124b14a0, 0x288db0e1, 0xb7d9c1b6, 0x6c056608, 0xb8f19d32, 0x0b9471bd,
+ 0x4faa6c9d, 0x8fb94650, 0x4540251c, 0x8943a946, 0x144a09e0, 0xfd1fe27d,
+ 0xda141bda, 0xea6ac458, 0x633fce36, 0x8048f217, 0xade74d31, 0xfeda1384,
+ 0x2ff7612f, 0x4334b8b0, 0x5227e216, 0xdbc8441f, 0x3605c85b, 0x096d119a,
+ 0x21b7d7d0, 0x2b72b31c};
+
+ randen_u32 engine;
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) {
+ printf("0x%08x, ", engine());
+ if (i % 6 == 5) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed();
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(RandenTest, VerifyGoldenRanden32Seeded) {
+ constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = {
+ 0x94d3dcd5, 0x83a9e58f, 0xd97949fb, 0x70bbdff3, 0x7471c1b4, 0x0438481f,
+ 0xe5fb5930, 0x34fdc58e, 0x2a937d17, 0xceee4f2d, 0xe432aea9, 0xb5a26a68,
+ 0x3fb51740, 0x8b64774a, 0x74249c74, 0xd89ac1fc, 0x23fc3fdf, 0x03910d1d,
+ 0x78aa897f, 0xd38f6308, 0x615f7e44, 0x0ee8f0f5, 0xf8279d52, 0x98f5a53d,
+ 0x25938d0e, 0xb403f52c, 0x6ea6e838, 0x24007299, 0x6190fa61, 0xd3a79124,
+ 0x7a7b4f80, 0xaaedd3df, 0x05deaf6e, 0xc6eacabe, 0x790edf4d, 0xb7967dd8,
+ 0xe049d279, 0x9a0a8e67, 0xaebc23e7, 0x0494f606, 0x7bc3e0ee, 0x598dcd68,
+ 0x02d452a1, 0x010ac818, 0x60aa2842, 0x6407c871, 0x486f93a0, 0x5a56e276,
+ 0xd46a8f02, 0xc887a399, 0xfe93b740, 0x9e1e6100, 0x0f8901f6, 0x12d02e33,
+ 0x47e790b7, 0xc39ca52b, 0x11e82e61, 0xb0b0a2fa, 0xa303806a, 0x1542d841,
+ 0x7d6e9d86, 0x1fe659fd, 0x746541ac, 0xb8c90d80, 0x669ddc94, 0x239d56a5,
+ 0x8123d13c, 0xd40db57c, 0x153a0db0, 0x3abc2414, 0x30cb8d61, 0x9bad6656,
+ 0xee3f4bbc, 0x0bd1fb90, 0x079b4e42, 0x8f0b4d7e, 0xee59e793, 0xfa0fb0e0,
+ 0x3e071100, 0x51080b28, 0x5081cc15, 0x2c4b9e71, 0xde4941df, 0xbe10ed49,
+ 0x4b1b0d37, 0xf8eaac9d, 0x4605e139, 0x4bcce4b5, 0x6765dda6, 0xa64722b7,
+ 0x8ca28ab5, 0xb9377d73, 0xa8ccc1af, 0x779fad81, 0x1ffd3ba7, 0x65cb3ee6,
+ 0x7862836f, 0xd74e7908, 0x4c3f25bf, 0xd05b9c58, 0x93579827, 0x2ba93a46,
+ 0xf05420ce, 0xd81530af, 0x15478621, 0xec06cea2, 0x796d65ad, 0x4b1798a6,
+ 0x3a6f6fa6, 0xf142f3fb, 0xe237b560, 0x002b7bf7, 0xef65b4f8, 0xf47f2605,
+ 0x17effc18, 0x9804ec55, 0xb7d481cd, 0xaed3d7f8, 0x1ce338d1, 0x5651c24c,
+ 0x8bf0a3c6, 0x3e7a3820, 0x14534aed, 0x6796a7b6, 0x8358460f, 0x0d0f3b84,
+ 0x00b19524, 0x0fa5fe76, 0x53faaedc, 0x2b0cf382, 0x233a9fd6, 0x10df9188,
+ 0x80138b59, 0x3a100338, 0x3948e80f, 0x5fb0b0d2, 0x2fbf5350, 0x9e76f7b0,
+ 0x04b1a985, 0x08160523, 0xb41fd218, 0x30c9880d, 0x65e20f28, 0x14aa399b,
+ 0xace787b4, 0xe1454a8c, 0xb6c6f0f5, 0x325ac971, 0x784f3d36, 0x716b1aa2,
+ 0xccfd144f, 0x3d5ce14a, 0x0f651792, 0x6c0c9771, 0xfb333532, 0xbc5b0f59,
+ 0x140470bc, 0x2a90a7d2, 0x5c1e1c8d, 0x8da269f5, 0x895792ca, 0xcfc37143,
+ 0xf30b238f, 0xbe21eab1, 0xee4d65fd, 0x8c47229d, 0xd1ed7d54, 0x5743614e,
+ 0x9e9c476e, 0x351372a9, 0xe5db085f, 0x2bd5ea15, 0x6e0af4ca, 0x6925fde4,
+ 0xdc1f45bd, 0xed3eda2b, 0xd460fa6e, 0xdef68c68, 0x6253e2b5, 0xe42a0de7,
+ 0xbc29c305, 0x4e5176dc, 0x9f810f6e, 0xbfd85fba, 0xbeb815c6, 0x76a5a2a9,
+ 0xceaf414c, 0x01edc4dd, 0xb4bb3b4b, 0xa4e98904, 0x7d2f1ddd, 0x00bd63ac,
+ 0xe998ddbb, 0xb8491fe6, 0x3dda6800, 0xb386a346, 0x88871619, 0x00818876,
+ 0x344e9a38, 0x33d394b3, 0xa3a8baf9, 0x815dba65, 0x02c2fd1a, 0x4232f6ec,
+ 0xedd20834, 0xb5cff603, 0x3f687663, 0x58018924, 0xdc27fe99, 0xa8d5a2cb,
+ 0x93fa0131, 0x725d8816, 0xdb2c7ac5, 0xa2be2c13, 0xb509fd78, 0x7b6a9614,
+ 0x1e717636, 0xb6b136d7, 0xaff046ea, 0x660f1a71, 0x46c8ec9e, 0x0ba10ae3,
+ 0xe3145b41, 0xe66dde53, 0x88c26be6, 0x3b18288c, 0xf02db933, 0x4d9d9d2f,
+ 0x70f46e8a, 0x4167da8c, 0x8c6318b4, 0xf183beef, 0x71eeeef1, 0x4d889e1e,
+ 0xd6689b6b, 0x7175c71a, 0xacd1b7dd, 0xfb9e42be, 0xb29b5e0d, 0xc33d0e91,
+ 0x1ce47922, 0xd39b8329, 0x8493d12e, 0xc4d570fb, 0x4f424ae6, 0x23d5a572,
+ 0x876b6616, 0x5245f161, 0x21ab578d, 0x38d77dbd, 0x1f4ecbfe, 0x9c342331,
+ 0x9bacd9d5, 0x76fe3138,
+ };
+
+ ExplicitSeedSeq seed_sequence{12, 34, 56};
+ randen_u32 engine(seed_sequence);
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) {
+ printf("0x%08x, ", engine());
+ if (i % 6 == 5) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+ engine.seed(seed_sequence);
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(RandenTest, VerifyGoldenFromDeserializedEngine) {
+ constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+ 0x067f9f9ab919657a, 0x0534605912988583, 0x8a303f72feaa673f,
+ 0x77b7fd747909185c, 0xd9af90403c56d891, 0xd939c6cb204d14b5,
+ 0x7fbe6b954a47b483, 0x8b31a47cc34c768d, 0x3a9e546da2701a9c,
+ 0x5246539046253e71, 0x417191ffb2a848a1, 0x7b1c7bf5a5001d09,
+ 0x9489b15d194f2361, 0xfcebdeea3bcd2461, 0xd643027c854cec97,
+ 0x5885397f91e0d21c, 0x53173b0efae30d58, 0x1c9c71168449fac1,
+ 0xe358202b711ed8aa, 0x94e3918ed1d8227c, 0x5bb4e251450144cf,
+ 0xb5c7a519b489af3b, 0x6f8b560b1f7b3469, 0xfde11dd4a1c74eef,
+ 0x33383d2f76457dcf, 0x3060c0ec6db9fce1, 0x18f451fcddeec766,
+ 0xe73c5d6b9f26da2a, 0x8d4cc566671b32a4, 0xb8189b73776bc9ff,
+ 0x497a70f9caf0bc23, 0x23afcc509791dcea, 0x18af70dc4b27d306,
+ 0xd3853f955a0ce5b9, 0x441db6c01a0afb17, 0xd0136c3fb8e1f13f,
+ 0x5e4fd6fc2f33783c, 0xe0d24548adb5da51, 0x0f4d8362a7d3485a,
+ 0x9f572d68270fa563, 0x6351fbc823024393, 0xa66dbfc61810e9ab,
+ 0x0ff17fc14b651af8, 0xd74c55dafb99e623, 0x36303bc1ad85c6c2,
+ 0x4920cd6a2af7e897, 0x0b8848addc30fecd, 0x9e1562eda6488e93,
+ 0x197553807d607828, 0xbef5eaeda5e21235, 0x18d91d2616aca527,
+ 0xb7821937f5c873cd, 0x2cd4ae5650dbeefc, 0xb35a64376f75ffdf,
+ 0x9226d414d647fe07, 0x663f3db455bbb35e, 0xa829eead6ae93247,
+ 0x7fd69c204dd0d25f, 0xbe1411f891c9acb1, 0xd476f34a506d5f11,
+ 0xf423d2831649c5ca, 0x1e503962951abd75, 0xeccc9e8b1e34b537,
+ 0xb11a147294044854, 0xc4cf27f0abf4929d, 0xe9193abf6fa24c8c,
+ 0xa94a259e3aba8808, 0x21dc414197deffa3, 0xa2ae211d1ff622ae,
+ 0xfe3995c46be5a4f4, 0xe9984c284bf11128, 0xcb1ce9d2f0851a80,
+ 0x42fee17971d87cd8, 0xac76a98d177adc88, 0xa0973b3dedc4af6f,
+ 0xdf56d6bbcb1b8e86, 0xf1e6485f407b11c9, 0x2c63de4deccb15c0,
+ 0x6fe69db32ed4fad7, 0xaa51a65f84bca1f1, 0x242f2ee81d608afc,
+ 0x8eb88b2b69fc153b, 0x22c20098baf73fd1, 0x57759466f576488c,
+ 0x075ca562cea1be9d, 0x9a74814d73d28891, 0x73d1555fc02f4d3d,
+ 0xc17f8f210ee89337, 0x46cca7999eaeafd4, 0x5db8d6a327a0d8ac,
+ 0xb79b4f93c738d7a1, 0x9994512f0036ded1, 0xd3883026f38747f4,
+ 0xf31f7458078d097c, 0x736ce4d480680669, 0x7a496f4c7e1033e3,
+ 0xecf85bf297fbc68c, 0x9e37e1d0f24f3c4e, 0x15b6e067ca0746fc,
+ 0xdd4a39905c5db81c, 0xb5dfafa7bcfdf7da, 0xca6646fb6f92a276,
+ 0x1c6b35f363ef0efd, 0x6a33d06037ad9f76, 0x45544241afd8f80f,
+ 0x83f8d83f859c90c5, 0x22aea9c5365e8c19, 0xfac35b11f20b6a6a,
+ 0xd1acf49d1a27dd2f, 0xf281cd09c4fed405, 0x076000a42cd38e4f,
+ 0x6ace300565070445, 0x463a62781bddc4db, 0x1477126b46b569ac,
+ 0x127f2bb15035fbb8, 0xdfa30946049c04a8, 0x89072a586ba8dd3e,
+ 0x62c809582bb7e74d, 0x22c0c3641406c28b, 0x9b66e36c47ff004d,
+ 0xb9cd2c7519653330, 0x18608d79cd7a598d, 0x92c0bd1323e53e32,
+ 0x887ff00de8524aa5, 0xa074410b787abd10, 0x18ab41b8057a2063,
+ 0x1560abf26bc5f987};
+
+#if UPDATE_GOLDEN
+ (void)kGolden; // Silence warning.
+ std::seed_seq seed_sequence{1, 2, 3, 4, 5};
+ randen_u64 engine(seed_sequence);
+ std::ostringstream stream;
+ stream << engine;
+ auto str = stream.str();
+ printf("%s\n\n", str.c_str());
+ for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
+ printf("0x%016lx, ", engine());
+ if (i % 3 == 2) {
+ printf("\n");
+ }
+ }
+ printf("\n\n\n");
+#else
+ randen_u64 engine;
+ std::istringstream stream(
+ "0 0 9824501439887287479 3242284395352394785 243836530774933777 "
+ "4047941804708365596 17165468127298385802 949276103645889255 "
+ "10659970394998657921 1657570836810929787 11697746266668051452 "
+ "9967209969299905230 14140390331161524430 7383014124183271684 "
+ "13146719127702337852 13983155220295807171 11121125587542359264 "
+ "195757810993252695 17138580243103178492 11326030747260920501 "
+ "8585097322474965590 18342582839328350995 15052982824209724634 "
+ "7321861343874683609 1806786911778767826 10100850842665572955 "
+ "9249328950653985078 13600624835326909759 11137960060943860251 "
+ "10208781341792329629 9282723971471525577 16373271619486811032 32");
+ stream >> engine;
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, engine());
+ }
+#endif
+}
+
+TEST(RandenTest, IsFastOrSlow) {
+ // randen_engine typically costs ~5ns per value for the optimized code paths,
+ // and the ~1000ns per value for slow code paths. However when running under
+ // msan, asan, etc. it can take much longer.
+ //
+ // The estimated operation time is something like:
+ //
+ // linux, optimized ~5ns
+ // ppc, optimized ~7ns
+ // nacl (slow), ~1100ns
+ //
+ // `kCount` is chosen below so that, in debug builds and without hardware
+ // acceleration, the test (assuming ~1us per call) should finish in ~0.1s
+ static constexpr size_t kCount = 100000;
+ randen_u64 engine;
+ randen_u64::result_type sum = 0;
+ auto start = absl::GetCurrentTimeNanos();
+ for (int i = 0; i < kCount; i++) {
+ sum += engine();
+ }
+ auto duration = absl::GetCurrentTimeNanos() - start;
+
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat(static_cast<double>(duration) /
+ static_cast<double>(kCount),
+ "ns"));
+
+ EXPECT_GT(sum, 0);
+ EXPECT_GE(duration, kCount); // Should be slower than 1ns per call.
+}
+
+} // namespace
diff --git a/absl/random/internal/randen_hwaes.cc b/absl/random/internal/randen_hwaes.cc
new file mode 100644
index 00000000..d7eed8b2
--- /dev/null
+++ b/absl/random/internal/randen_hwaes.cc
@@ -0,0 +1,704 @@
+// 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.
+
+// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
+// symbols from arbitrary system and other headers, since it may be built
+// with different flags from other targets, using different levels of
+// optimization, potentially introducing ODR violations.
+
+#include "absl/random/internal/randen_hwaes.h"
+
+#include <cstdint>
+#include <cstring>
+
+#include "absl/random/internal/platform.h"
+
+// ABSL_HAVE_ATTRIBUTE
+#if !defined(ABSL_HAVE_ATTRIBUTE)
+#ifdef __has_attribute
+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define ABSL_HAVE_ATTRIBUTE(x) 0
+#endif
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE \
+ __attribute__((always_inline))
+#elif defined(_MSC_VER)
+// We can achieve something similar to attribute((always_inline)) with MSVC by
+// using the __forceinline keyword, however this is not perfect. MSVC is
+// much less aggressive about inlining, and even with the __forceinline keyword.
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+// ABSL_ATTRIBUTE_FLATTEN enables much more aggressive inlining within
+// the indicated function.
+#undef ABSL_ATTRIBUTE_FLATTEN
+#if ABSL_HAVE_ATTRIBUTE(flatten) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_ATTRIBUTE_FLATTEN __attribute__((flatten))
+#else
+#define ABSL_ATTRIBUTE_FLATTEN
+#endif
+
+// ABSL_RANDEN_HWAES_IMPL indicates whether this file will contain
+// a hardware accelerated implementation of randen, or whether it
+// will contain stubs that exit the process.
+#if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
+// The platform.h directives are sufficient to indicate whether
+// we should build accelerated implementations for x86.
+#if (ABSL_HAVE_ACCELERATED_AES || ABSL_RANDOM_INTERNAL_AES_DISPATCH)
+#define ABSL_RANDEN_HWAES_IMPL 1
+#endif
+#elif defined(ABSL_ARCH_PPC)
+// The platform.h directives are sufficient to indicate whether
+// we should build accelerated implementations for PPC.
+//
+// NOTE: This has mostly been tested on 64-bit Power variants,
+// and not embedded cpus such as powerpc32-8540
+#if ABSL_HAVE_ACCELERATED_AES
+#define ABSL_RANDEN_HWAES_IMPL 1
+#endif
+#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
+// ARM is somewhat more complicated. We might support crypto natively...
+#if ABSL_HAVE_ACCELERATED_AES || \
+ (defined(__ARM_NEON) && defined(__ARM_FEATURE_CRYPTO))
+#define ABSL_RANDEN_HWAES_IMPL 1
+
+#elif ABSL_RANDOM_INTERNAL_AES_DISPATCH && !defined(__APPLE__) && \
+ (defined(__GNUC__) && __GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 9)
+// ...or, on GCC, we can use an ASM directive to
+// instruct the assember to allow crypto instructions.
+#define ABSL_RANDEN_HWAES_IMPL 1
+#define ABSL_RANDEN_HWAES_IMPL_CRYPTO_DIRECTIVE 1
+#endif
+#else
+// HWAES is unsupported by these architectures / platforms:
+// __myriad2__
+// __mips__
+//
+// Other architectures / platforms are unknown.
+//
+// See the Abseil documentation on supported macros at:
+// https://abseil.io/docs/cpp/platforms/macros
+#endif
+
+#if !defined(ABSL_RANDEN_HWAES_IMPL)
+// No accelerated implementation is supported.
+// The RandenHwAes functions are stubs that print an error and exit.
+
+#include <cstdio>
+#include <cstdlib>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// No accelerated implementation.
+bool HasRandenHwAesImplementation() { return false; }
+
+// NOLINTNEXTLINE
+const void* RandenHwAes::GetKeys() {
+ // Attempted to dispatch to an unsupported dispatch target.
+ const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
+ fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
+ exit(1);
+ return nullptr;
+}
+
+// NOLINTNEXTLINE
+void RandenHwAes::Absorb(const void*, void*) {
+ // Attempted to dispatch to an unsupported dispatch target.
+ const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
+ fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
+ exit(1);
+}
+
+// NOLINTNEXTLINE
+void RandenHwAes::Generate(const void*, void*) {
+ // Attempted to dispatch to an unsupported dispatch target.
+ const int d = ABSL_RANDOM_INTERNAL_AES_DISPATCH;
+ fprintf(stderr, "AES Hardware detection failed (%d).\n", d);
+ exit(1);
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#else // defined(ABSL_RANDEN_HWAES_IMPL)
+//
+// Accelerated implementations are supported.
+// We need the per-architecture includes and defines.
+//
+
+#include "absl/random/internal/randen_traits.h"
+
+// ABSL_FUNCTION_ALIGN32 defines a 32-byte alignment attribute
+// for the functions in this file.
+//
+// NOTE: Determine whether we actually have any wins from ALIGN32
+// using microbenchmarks. If not, remove.
+#undef ABSL_FUNCTION_ALIGN32
+#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_FUNCTION_ALIGN32 __attribute__((aligned(32)))
+#else
+#define ABSL_FUNCTION_ALIGN32
+#endif
+
+// TARGET_CRYPTO defines a crypto attribute for each architecture.
+//
+// NOTE: Evaluate whether we should eliminate ABSL_TARGET_CRYPTO.
+#if (defined(__clang__) || defined(__GNUC__))
+#if defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
+#define ABSL_TARGET_CRYPTO __attribute__((target("aes")))
+#elif defined(ABSL_ARCH_PPC)
+#define ABSL_TARGET_CRYPTO __attribute__((target("crypto")))
+#else
+#define ABSL_TARGET_CRYPTO
+#endif
+#else
+#define ABSL_TARGET_CRYPTO
+#endif
+
+#if defined(ABSL_ARCH_PPC)
+// NOTE: Keep in mind that PPC can operate in little-endian or big-endian mode,
+// however the PPC altivec vector registers (and thus the AES instructions)
+// always operate in big-endian mode.
+
+#include <altivec.h>
+// <altivec.h> #defines vector __vector; in C++, this is bad form.
+#undef vector
+
+// Rely on the PowerPC AltiVec vector operations for accelerated AES
+// instructions. GCC support of the PPC vector types is described in:
+// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/PowerPC-AltiVec_002fVSX-Built-in-Functions.html
+//
+// Already provides operator^=.
+using Vector128 = __vector unsigned long long; // NOLINT(runtime/int)
+
+namespace {
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+ReverseBytes(const Vector128& v) {
+ // Reverses the bytes of the vector.
+ const __vector unsigned char perm = {15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0};
+ return vec_perm(v, v, perm);
+}
+
+// WARNING: these load/store in native byte order. It is OK to load and then
+// store an unchanged vector, but interpreting the bits as a number or input
+// to AES will have undefined results.
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+ return vec_vsx_ld(0, reinterpret_cast<const Vector128*>(from));
+}
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+Vector128Store(const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+ vec_vsx_st(v, 0, reinterpret_cast<Vector128*>(to));
+}
+
+// One round of AES. "round_key" is a public constant for breaking the
+// symmetry of AES (ensures previously equal columns differ afterwards).
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+AesRound(const Vector128& state, const Vector128& round_key) {
+ return Vector128(__builtin_crypto_vcipher(state, round_key));
+}
+
+// Enables native loads in the round loop by pre-swapping.
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+SwapEndian(uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+ using absl::random_internal::RandenTraits;
+ constexpr size_t kLanes = 2;
+ constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
+
+ for (uint32_t branch = 0; branch < kFeistelBlocks; ++branch) {
+ const Vector128 v = ReverseBytes(Vector128Load(state + kLanes * branch));
+ Vector128Store(v, state + kLanes * branch);
+ }
+}
+
+} // namespace
+
+#elif defined(ABSL_ARCH_ARM) || defined(ABSL_ARCH_AARCH64)
+
+// This asm directive will cause the file to be compiled with crypto extensions
+// whether or not the cpu-architecture supports it.
+#if ABSL_RANDEN_HWAES_IMPL_CRYPTO_DIRECTIVE
+asm(".arch_extension crypto\n");
+
+// Override missing defines.
+#if !defined(__ARM_NEON)
+#define __ARM_NEON 1
+#endif
+
+#if !defined(__ARM_FEATURE_CRYPTO)
+#define __ARM_FEATURE_CRYPTO 1
+#endif
+
+#endif
+
+// Rely on the ARM NEON+Crypto advanced simd types, defined in <arm_neon.h>.
+// uint8x16_t is the user alias for underlying __simd128_uint8_t type.
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
+//
+// <arm_neon> defines the following
+//
+// typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t;
+// typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t;
+// typedef __attribute__((neon_polyvector_type(16))) int8_t poly8x16_t;
+//
+// vld1q_v
+// vst1q_v
+// vaeseq_v
+// vaesmcq_v
+#include <arm_neon.h>
+
+// Already provides operator^=.
+using Vector128 = uint8x16_t;
+
+namespace {
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+ return vld1q_u8(reinterpret_cast<const uint8_t*>(from));
+}
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+Vector128Store(const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+ vst1q_u8(reinterpret_cast<uint8_t*>(to), v);
+}
+
+// One round of AES. "round_key" is a public constant for breaking the
+// symmetry of AES (ensures previously equal columns differ afterwards).
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+AesRound(const Vector128& state, const Vector128& round_key) {
+ // It is important to always use the full round function - omitting the
+ // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf]
+ // and does not help because we never decrypt.
+ //
+ // Note that ARM divides AES instructions differently than x86 / PPC,
+ // And we need to skip the first AddRoundKey step and add an extra
+ // AddRoundKey step to the end. Lucky for us this is just XOR.
+ return vaesmcq_u8(vaeseq_u8(state, uint8x16_t{})) ^ round_key;
+}
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+SwapEndian(uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+
+} // namespace
+
+#elif defined(ABSL_ARCH_X86_64) || defined(ABSL_ARCH_X86_32)
+// On x86 we rely on the aesni instructions
+#include <wmmintrin.h>
+
+namespace {
+
+// Vector128 class is only wrapper for __m128i, benchmark indicates that it's
+// faster than using __m128i directly.
+class Vector128 {
+ public:
+ // Convert from/to intrinsics.
+ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE explicit Vector128(
+ const __m128i& Vector128)
+ : data_(Vector128) {}
+
+ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __m128i data() const {
+ return data_;
+ }
+
+ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128& operator^=(
+ const Vector128& other) {
+ data_ = _mm_xor_si128(data_, other.data());
+ return *this;
+ }
+
+ private:
+ __m128i data_;
+};
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+ return Vector128(_mm_load_si128(reinterpret_cast<const __m128i*>(from)));
+}
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+Vector128Store(const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+ _mm_store_si128(reinterpret_cast<__m128i * ABSL_RANDOM_INTERNAL_RESTRICT>(to),
+ v.data());
+}
+
+// One round of AES. "round_key" is a public constant for breaking the
+// symmetry of AES (ensures previously equal columns differ afterwards).
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+AesRound(const Vector128& state, const Vector128& round_key) {
+ // It is important to always use the full round function - omitting the
+ // final MixColumns reduces security [https://eprint.iacr.org/2010/041.pdf]
+ // and does not help because we never decrypt.
+ return Vector128(_mm_aesenc_si128(state.data(), round_key.data()));
+}
+
+inline ABSL_TARGET_CRYPTO ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void
+SwapEndian(uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT) {}
+
+} // namespace
+
+#endif
+
+namespace {
+
+// u64x2 is a 128-bit, (2 x uint64_t lanes) struct used to store
+// the randen_keys.
+struct alignas(16) u64x2 {
+ constexpr u64x2(uint64_t hi, uint64_t lo)
+#if defined(ABSL_ARCH_PPC)
+ // This has been tested with PPC running in little-endian mode;
+ // We byte-swap the u64x2 structure from little-endian to big-endian
+ // because altivec always runs in big-endian mode.
+ : v{__builtin_bswap64(hi), __builtin_bswap64(lo)} {
+#else
+ : v{lo, hi} {
+#endif
+ }
+
+ constexpr bool operator==(const u64x2& other) const {
+ return v[0] == other.v[0] && v[1] == other.v[1];
+ }
+
+ constexpr bool operator!=(const u64x2& other) const {
+ return !(*this == other);
+ }
+
+ uint64_t v[2];
+}; // namespace
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#endif
+
+// At this point, all of the platform-specific features have been defined /
+// implemented.
+//
+// REQUIRES: using u64x2 = ...
+// REQUIRES: using Vector128 = ...
+// REQUIRES: Vector128 Vector128Load(void*) {...}
+// REQUIRES: void Vector128Store(Vector128, void*) {...}
+// REQUIRES: Vector128 AesRound(Vector128, Vector128) {...}
+// REQUIRES: void SwapEndian(uint64_t*) {...}
+//
+// PROVIDES: absl::random_internal::RandenHwAes::Absorb
+// PROVIDES: absl::random_internal::RandenHwAes::Generate
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// High-level summary:
+// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
+// a sponge-like random generator that requires a cryptographic permutation.
+// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
+// achieving backtracking resistance with only one Permute() per buffer.
+//
+// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
+// Function" constructs up to 1024-bit permutations using an improved
+// Generalized Feistel network with 2-round AES-128 functions. This Feistel
+// block shuffle achieves diffusion faster and is less vulnerable to
+// sliced-biclique attacks than the Type-2 cyclic shuffle.
+//
+// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
+// property" extends the same kind of improved Feistel block shuffle to 16
+// branches, which enables a 2048-bit permutation.
+//
+// We combine these three ideas and also change Simpira's subround keys from
+// structured/low-entropy counters to digits of Pi.
+
+// Randen constants.
+using absl::random_internal::RandenTraits;
+constexpr size_t kStateBytes = RandenTraits::kStateBytes;
+constexpr size_t kCapacityBytes = RandenTraits::kCapacityBytes;
+constexpr size_t kFeistelBlocks = RandenTraits::kFeistelBlocks;
+constexpr size_t kFeistelRounds = RandenTraits::kFeistelRounds;
+constexpr size_t kFeistelFunctions = RandenTraits::kFeistelFunctions;
+
+// Independent keys (272 = 2.1 KiB) for the first AES subround of each function.
+constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
+
+// INCLUDE keys.
+#include "absl/random/internal/randen-keys.inc"
+
+static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
+static_assert(round_keys[kKeys - 1] != u64x2(0, 0),
+ "Too few round_keys initializers");
+
+// Number of uint64_t lanes per 128-bit vector;
+constexpr size_t kLanes = 2;
+
+// Block shuffles applies a shuffle to the entire state between AES rounds.
+// Improved odd-even shuffle from "New criterion for diffusion property".
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE ABSL_TARGET_CRYPTO void
+BlockShuffle(uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+ static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+
+ constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6,
+ 15, 0, 9, 10, 1, 14, 5, 12};
+
+ // The fully unrolled loop without the memcpy improves the speed by about
+ // 30% over the equivalent loop.
+ const Vector128 v0 = Vector128Load(state + kLanes * shuffle[0]);
+ const Vector128 v1 = Vector128Load(state + kLanes * shuffle[1]);
+ const Vector128 v2 = Vector128Load(state + kLanes * shuffle[2]);
+ const Vector128 v3 = Vector128Load(state + kLanes * shuffle[3]);
+ const Vector128 v4 = Vector128Load(state + kLanes * shuffle[4]);
+ const Vector128 v5 = Vector128Load(state + kLanes * shuffle[5]);
+ const Vector128 v6 = Vector128Load(state + kLanes * shuffle[6]);
+ const Vector128 v7 = Vector128Load(state + kLanes * shuffle[7]);
+ const Vector128 w0 = Vector128Load(state + kLanes * shuffle[8]);
+ const Vector128 w1 = Vector128Load(state + kLanes * shuffle[9]);
+ const Vector128 w2 = Vector128Load(state + kLanes * shuffle[10]);
+ const Vector128 w3 = Vector128Load(state + kLanes * shuffle[11]);
+ const Vector128 w4 = Vector128Load(state + kLanes * shuffle[12]);
+ const Vector128 w5 = Vector128Load(state + kLanes * shuffle[13]);
+ const Vector128 w6 = Vector128Load(state + kLanes * shuffle[14]);
+ const Vector128 w7 = Vector128Load(state + kLanes * shuffle[15]);
+
+ Vector128Store(v0, state + kLanes * 0);
+ Vector128Store(v1, state + kLanes * 1);
+ Vector128Store(v2, state + kLanes * 2);
+ Vector128Store(v3, state + kLanes * 3);
+ Vector128Store(v4, state + kLanes * 4);
+ Vector128Store(v5, state + kLanes * 5);
+ Vector128Store(v6, state + kLanes * 6);
+ Vector128Store(v7, state + kLanes * 7);
+ Vector128Store(w0, state + kLanes * 8);
+ Vector128Store(w1, state + kLanes * 9);
+ Vector128Store(w2, state + kLanes * 10);
+ Vector128Store(w3, state + kLanes * 11);
+ Vector128Store(w4, state + kLanes * 12);
+ Vector128Store(w5, state + kLanes * 13);
+ Vector128Store(w6, state + kLanes * 14);
+ Vector128Store(w7, state + kLanes * 15);
+}
+
+// Feistel round function using two AES subrounds. Very similar to F()
+// from Simpira v2, but with independent subround keys. Uses 17 AES rounds
+// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in
+// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
+// XORs are 'free' (included in the second AES instruction).
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE ABSL_TARGET_CRYPTO const
+ u64x2*
+ FeistelRound(uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
+ const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+ static_assert(kFeistelBlocks == 16, "Expecting 16 FeistelBlocks.");
+
+ // MSVC does a horrible job at unrolling loops.
+ // So we unroll the loop by hand to improve the performance.
+ const Vector128 s0 = Vector128Load(state + kLanes * 0);
+ const Vector128 s1 = Vector128Load(state + kLanes * 1);
+ const Vector128 s2 = Vector128Load(state + kLanes * 2);
+ const Vector128 s3 = Vector128Load(state + kLanes * 3);
+ const Vector128 s4 = Vector128Load(state + kLanes * 4);
+ const Vector128 s5 = Vector128Load(state + kLanes * 5);
+ const Vector128 s6 = Vector128Load(state + kLanes * 6);
+ const Vector128 s7 = Vector128Load(state + kLanes * 7);
+ const Vector128 s8 = Vector128Load(state + kLanes * 8);
+ const Vector128 s9 = Vector128Load(state + kLanes * 9);
+ const Vector128 s10 = Vector128Load(state + kLanes * 10);
+ const Vector128 s11 = Vector128Load(state + kLanes * 11);
+ const Vector128 s12 = Vector128Load(state + kLanes * 12);
+ const Vector128 s13 = Vector128Load(state + kLanes * 13);
+ const Vector128 s14 = Vector128Load(state + kLanes * 14);
+ const Vector128 s15 = Vector128Load(state + kLanes * 15);
+
+ // Encode even blocks with keys.
+ const Vector128 e0 = AesRound(s0, Vector128Load(keys + 0));
+ const Vector128 e2 = AesRound(s2, Vector128Load(keys + 1));
+ const Vector128 e4 = AesRound(s4, Vector128Load(keys + 2));
+ const Vector128 e6 = AesRound(s6, Vector128Load(keys + 3));
+ const Vector128 e8 = AesRound(s8, Vector128Load(keys + 4));
+ const Vector128 e10 = AesRound(s10, Vector128Load(keys + 5));
+ const Vector128 e12 = AesRound(s12, Vector128Load(keys + 6));
+ const Vector128 e14 = AesRound(s14, Vector128Load(keys + 7));
+
+ // Encode odd blocks with even output from above.
+ const Vector128 o1 = AesRound(e0, s1);
+ const Vector128 o3 = AesRound(e2, s3);
+ const Vector128 o5 = AesRound(e4, s5);
+ const Vector128 o7 = AesRound(e6, s7);
+ const Vector128 o9 = AesRound(e8, s9);
+ const Vector128 o11 = AesRound(e10, s11);
+ const Vector128 o13 = AesRound(e12, s13);
+ const Vector128 o15 = AesRound(e14, s15);
+
+ // Store odd blocks. (These will be shuffled later).
+ Vector128Store(o1, state + kLanes * 1);
+ Vector128Store(o3, state + kLanes * 3);
+ Vector128Store(o5, state + kLanes * 5);
+ Vector128Store(o7, state + kLanes * 7);
+ Vector128Store(o9, state + kLanes * 9);
+ Vector128Store(o11, state + kLanes * 11);
+ Vector128Store(o13, state + kLanes * 13);
+ Vector128Store(o15, state + kLanes * 15);
+
+ return keys + 8;
+}
+
+// Cryptographic permutation based via type-2 Generalized Feistel Network.
+// Indistinguishable from ideal by chosen-ciphertext adversaries using less than
+// 2^64 queries if the round function is a PRF. This is similar to the b=8 case
+// of Simpira v2, but more efficient than its generic construction for b=16.
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE ABSL_TARGET_CRYPTO void
+Permute(const void* ABSL_RANDOM_INTERNAL_RESTRICT keys,
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+ const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
+ static_cast<const u64x2*>(keys);
+
+ // (Successfully unrolled; the first iteration jumps into the second half)
+#ifdef __clang__
+#pragma clang loop unroll_count(2)
+#endif
+ for (size_t round = 0; round < kFeistelRounds; ++round) {
+ keys128 = FeistelRound(state, keys128);
+ BlockShuffle(state);
+ }
+}
+
+} // namespace
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+bool HasRandenHwAesImplementation() { return true; }
+
+const void* ABSL_TARGET_CRYPTO ABSL_FUNCTION_ALIGN32 ABSL_ATTRIBUTE_FLATTEN
+RandenHwAes::GetKeys() {
+ // Round keys for one AES per Feistel round and branch.
+ // The canonical implementation uses first digits of Pi.
+ return round_keys;
+}
+
+// NOLINTNEXTLINE
+void ABSL_TARGET_CRYPTO ABSL_FUNCTION_ALIGN32 ABSL_ATTRIBUTE_FLATTEN
+RandenHwAes::Absorb(const void* seed_void, void* state_void) {
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
+ reinterpret_cast<uint64_t*>(state_void);
+ const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
+ reinterpret_cast<const uint64_t*>(seed_void);
+
+ constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(Vector128);
+ constexpr size_t kStateBlocks = kStateBytes / sizeof(Vector128);
+
+ static_assert(kCapacityBlocks * sizeof(Vector128) == kCapacityBytes,
+ "Not i*V");
+ static_assert(kCapacityBlocks == 1, "Unexpected Randen kCapacityBlocks");
+ static_assert(kStateBlocks == 16, "Unexpected Randen kStateBlocks");
+
+ Vector128 b1 = Vector128Load(state + kLanes * 1);
+ b1 ^= Vector128Load(seed + kLanes * 0);
+ Vector128Store(b1, state + kLanes * 1);
+
+ Vector128 b2 = Vector128Load(state + kLanes * 2);
+ b2 ^= Vector128Load(seed + kLanes * 1);
+ Vector128Store(b2, state + kLanes * 2);
+
+ Vector128 b3 = Vector128Load(state + kLanes * 3);
+ b3 ^= Vector128Load(seed + kLanes * 2);
+ Vector128Store(b3, state + kLanes * 3);
+
+ Vector128 b4 = Vector128Load(state + kLanes * 4);
+ b4 ^= Vector128Load(seed + kLanes * 3);
+ Vector128Store(b4, state + kLanes * 4);
+
+ Vector128 b5 = Vector128Load(state + kLanes * 5);
+ b5 ^= Vector128Load(seed + kLanes * 4);
+ Vector128Store(b5, state + kLanes * 5);
+
+ Vector128 b6 = Vector128Load(state + kLanes * 6);
+ b6 ^= Vector128Load(seed + kLanes * 5);
+ Vector128Store(b6, state + kLanes * 6);
+
+ Vector128 b7 = Vector128Load(state + kLanes * 7);
+ b7 ^= Vector128Load(seed + kLanes * 6);
+ Vector128Store(b7, state + kLanes * 7);
+
+ Vector128 b8 = Vector128Load(state + kLanes * 8);
+ b8 ^= Vector128Load(seed + kLanes * 7);
+ Vector128Store(b8, state + kLanes * 8);
+
+ Vector128 b9 = Vector128Load(state + kLanes * 9);
+ b9 ^= Vector128Load(seed + kLanes * 8);
+ Vector128Store(b9, state + kLanes * 9);
+
+ Vector128 b10 = Vector128Load(state + kLanes * 10);
+ b10 ^= Vector128Load(seed + kLanes * 9);
+ Vector128Store(b10, state + kLanes * 10);
+
+ Vector128 b11 = Vector128Load(state + kLanes * 11);
+ b11 ^= Vector128Load(seed + kLanes * 10);
+ Vector128Store(b11, state + kLanes * 11);
+
+ Vector128 b12 = Vector128Load(state + kLanes * 12);
+ b12 ^= Vector128Load(seed + kLanes * 11);
+ Vector128Store(b12, state + kLanes * 12);
+
+ Vector128 b13 = Vector128Load(state + kLanes * 13);
+ b13 ^= Vector128Load(seed + kLanes * 12);
+ Vector128Store(b13, state + kLanes * 13);
+
+ Vector128 b14 = Vector128Load(state + kLanes * 14);
+ b14 ^= Vector128Load(seed + kLanes * 13);
+ Vector128Store(b14, state + kLanes * 14);
+
+ Vector128 b15 = Vector128Load(state + kLanes * 15);
+ b15 ^= Vector128Load(seed + kLanes * 14);
+ Vector128Store(b15, state + kLanes * 15);
+}
+
+// NOLINTNEXTLINE
+void ABSL_TARGET_CRYPTO ABSL_FUNCTION_ALIGN32 ABSL_ATTRIBUTE_FLATTEN
+RandenHwAes::Generate(const void* keys, void* state_void) {
+ static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
+ reinterpret_cast<uint64_t*>(state_void);
+
+ const Vector128 prev_inner = Vector128Load(state);
+
+ SwapEndian(state);
+
+ Permute(keys, state);
+
+ SwapEndian(state);
+
+ // Ensure backtracking resistance.
+ Vector128 inner = Vector128Load(state);
+ inner ^= prev_inner;
+ Vector128Store(inner, state);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // (ABSL_RANDEN_HWAES_IMPL)
diff --git a/absl/random/internal/randen_hwaes.h b/absl/random/internal/randen_hwaes.h
new file mode 100644
index 00000000..848bcead
--- /dev/null
+++ b/absl/random/internal/randen_hwaes.h
@@ -0,0 +1,48 @@
+// 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_RANDEN_HWAES_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_
+
+// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
+// symbols from arbitrary system and other headers, since it may be built
+// with different flags from other targets, using different levels of
+// optimization, potentially introducing ODR violations.
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// RandenHwAes implements the basic state manipulation methods.
+class RandenHwAes {
+ public:
+ static void Generate(const void* keys, void* state_void);
+ static void Absorb(const void* seed_void, void* state_void);
+ static const void* GetKeys();
+};
+
+// HasRandenHwAesImplementation returns true when there is an accelerated
+// implementation, and false otherwise. If there is no implementation,
+// then attempting to use it will abort the program.
+bool HasRandenHwAesImplementation();
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_HWAES_H_
diff --git a/absl/random/internal/randen_hwaes_test.cc b/absl/random/internal/randen_hwaes_test.cc
new file mode 100644
index 00000000..a7cbd46b
--- /dev/null
+++ b/absl/random/internal/randen_hwaes_test.cc
@@ -0,0 +1,102 @@
+// 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/randen_hwaes.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/platform.h"
+#include "absl/random/internal/randen_detect.h"
+#include "absl/random/internal/randen_traits.h"
+#include "absl/strings/str_format.h"
+
+namespace {
+
+using absl::random_internal::RandenHwAes;
+using absl::random_internal::RandenTraits;
+
+struct randen {
+ static constexpr size_t kStateSizeT =
+ RandenTraits::kStateBytes / sizeof(uint64_t);
+ uint64_t state[kStateSizeT];
+ static constexpr size_t kSeedSizeT =
+ RandenTraits::kSeedBytes / sizeof(uint32_t);
+ uint32_t seed[kSeedSizeT];
+};
+
+TEST(RandenHwAesTest, Default) {
+ EXPECT_TRUE(absl::random_internal::CPUSupportsRandenHwAes());
+
+ constexpr uint64_t kGolden[] = {
+ 0x6c6534090ee6d3ee, 0x044e2b9b9d5333c6, 0xc3c14f134e433977,
+ 0xdda9f47cd90410ee, 0x887bf3087fd8ca10, 0xf0b780f545c72912,
+ 0x15dbb1d37696599f, 0x30ec63baff3c6d59, 0xb29f73606f7f20a6,
+ 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e, 0x9cbf605e3fd9de8a,
+ 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5, 0xf4b327fe0fc73c37,
+ 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d, 0xd5af05dd3eff9556,
+ 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c, 0x58d3575834956d42,
+ 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3, 0x497cabf3431154fc,
+ 0x4e24370570029a8b, 0xd88b5749f090e5ea, 0xc651a582a970692f,
+ 0x78fcec2cbb6342f5, 0x463cb745612f55db, 0x352ee4ad1816afe3,
+ 0x026ff374c101da7e, 0x811ef0821c3de851,
+ };
+
+ alignas(16) randen d;
+ memset(d.state, 0, sizeof(d.state));
+ RandenHwAes::Generate(RandenHwAes::GetKeys(), d.state);
+
+ uint64_t* id = d.state;
+ for (const auto& elem : kGolden) {
+ auto a = absl::StrFormat("%#x", elem);
+ auto b = absl::StrFormat("%#x", *id++);
+ EXPECT_EQ(a, b);
+ }
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ testing::InitGoogleTest(&argc, argv);
+
+ ABSL_RAW_LOG(INFO, "ABSL_HAVE_ACCELERATED_AES=%d", ABSL_HAVE_ACCELERATED_AES);
+ ABSL_RAW_LOG(INFO, "ABSL_RANDOM_INTERNAL_AES_DISPATCH=%d",
+ ABSL_RANDOM_INTERNAL_AES_DISPATCH);
+
+#if defined(ABSL_ARCH_X86_64)
+ ABSL_RAW_LOG(INFO, "ABSL_ARCH_X86_64");
+#elif defined(ABSL_ARCH_X86_32)
+ ABSL_RAW_LOG(INFO, "ABSL_ARCH_X86_32");
+#elif defined(ABSL_ARCH_AARCH64)
+ ABSL_RAW_LOG(INFO, "ABSL_ARCH_AARCH64");
+#elif defined(ABSL_ARCH_ARM)
+ ABSL_RAW_LOG(INFO, "ABSL_ARCH_ARM");
+#elif defined(ABSL_ARCH_PPC)
+ ABSL_RAW_LOG(INFO, "ABSL_ARCH_PPC");
+#else
+ ABSL_RAW_LOG(INFO, "ARCH Unknown");
+#endif
+
+ int x = absl::random_internal::HasRandenHwAesImplementation();
+ ABSL_RAW_LOG(INFO, "HasRandenHwAesImplementation = %d", x);
+
+ int y = absl::random_internal::CPUSupportsRandenHwAes();
+ ABSL_RAW_LOG(INFO, "CPUSupportsRandenHwAes = %d", x);
+
+ if (!x || !y) {
+ ABSL_RAW_LOG(INFO, "Skipping Randen HWAES tests.");
+ return 0;
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/absl/random/internal/randen_slow.cc b/absl/random/internal/randen_slow.cc
new file mode 100644
index 00000000..e2d44f88
--- /dev/null
+++ b/absl/random/internal/randen_slow.cc
@@ -0,0 +1,514 @@
+// 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/randen_slow.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+
+#include "absl/random/internal/platform.h"
+
+// ABSL_HAVE_ATTRIBUTE
+#if !defined(ABSL_HAVE_ATTRIBUTE)
+#ifdef __has_attribute
+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
+#else
+#define ABSL_HAVE_ATTRIBUTE(x) 0
+#endif
+#endif
+
+#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
+ (defined(__GNUC__) && !defined(__clang__))
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE \
+ __attribute__((always_inline))
+#elif defined(_MSC_VER)
+// We can achieve something similar to attribute((always_inline)) with MSVC by
+// using the __forceinline keyword, however this is not perfect. MSVC is
+// much less aggressive about inlining, and even with the __forceinline keyword.
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE
+#endif
+
+namespace {
+
+// AES portions based on rijndael-alg-fst.c,
+// https://fastcrypto.org/front/misc/rijndael-alg-fst.c
+//
+// Implementation of
+// http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+constexpr uint32_t te0[256] = {
+ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd,
+ 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
+ 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d,
+ 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+ 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7,
+ 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
+ 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4,
+ 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+ 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1,
+ 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
+ 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e,
+ 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+ 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e,
+ 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
+ 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46,
+ 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+ 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7,
+ 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
+ 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe,
+ 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+ 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a,
+ 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
+ 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2,
+ 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+ 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e,
+ 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
+ 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256,
+ 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+ 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4,
+ 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
+ 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa,
+ 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+ 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1,
+ 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
+ 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42,
+ 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+ 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158,
+ 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
+ 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22,
+ 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+ 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631,
+ 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
+ 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
+};
+
+constexpr uint32_t te1[256] = {
+ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b,
+ 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b,
+ 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282,
+ 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+ 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4,
+ 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626,
+ 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5,
+ 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+ 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696,
+ 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2,
+ 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383,
+ 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+ 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3,
+ 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded,
+ 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb,
+ 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+ 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d,
+ 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f,
+ 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3,
+ 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+ 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff,
+ 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec,
+ 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7,
+ 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+ 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a,
+ 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414,
+ 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232,
+ 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+ 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595,
+ 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d,
+ 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656,
+ 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+ 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6,
+ 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f,
+ 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e,
+ 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+ 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1,
+ 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111,
+ 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e,
+ 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+ 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6,
+ 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f,
+ 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+};
+
+constexpr uint32_t te2[256] = {
+ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b,
+ 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b,
+ 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82,
+ 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+ 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4,
+ 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26,
+ 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5,
+ 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+ 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796,
+ 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2,
+ 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83,
+ 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+ 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3,
+ 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed,
+ 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb,
+ 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+ 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d,
+ 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f,
+ 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3,
+ 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+ 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff,
+ 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec,
+ 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7,
+ 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+ 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a,
+ 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814,
+ 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432,
+ 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+ 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195,
+ 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d,
+ 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56,
+ 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+ 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6,
+ 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f,
+ 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e,
+ 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+ 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1,
+ 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211,
+ 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e,
+ 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+ 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6,
+ 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f,
+ 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+};
+
+constexpr uint32_t te3[256] = {
+ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6,
+ 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56,
+ 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f,
+ 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+ 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753,
+ 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c,
+ 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451,
+ 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+ 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137,
+ 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf,
+ 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d,
+ 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+ 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd,
+ 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1,
+ 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d,
+ 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+ 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a,
+ 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe,
+ 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d,
+ 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+ 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5,
+ 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3,
+ 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255,
+ 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+ 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54,
+ 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28,
+ 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664,
+ 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+ 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431,
+ 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da,
+ 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac,
+ 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+ 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157,
+ 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e,
+ 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c,
+ 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+ 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899,
+ 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322,
+ 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c,
+ 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+ 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7,
+ 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
+ 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
+};
+
+struct alignas(16) u64x2 {
+ constexpr u64x2() : v{0, 0} {};
+ constexpr u64x2(uint64_t hi, uint64_t lo) : v{lo, hi} {}
+
+ uint64_t v[2];
+};
+
+// Software implementation of the Vector128 class, using uint32_t
+// as an underlying vector register.
+//
+struct Vector128 {
+ inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128& operator^=(
+ const Vector128& other) {
+ s[0] ^= other.s[0];
+ s[1] ^= other.s[1];
+ s[2] ^= other.s[2];
+ s[3] ^= other.s[3];
+ return *this;
+ }
+
+ uint32_t s[4];
+};
+
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+Vector128Load(const void* ABSL_RANDOM_INTERNAL_RESTRICT from) {
+ Vector128 result;
+ const uint8_t* ABSL_RANDOM_INTERNAL_RESTRICT src =
+ reinterpret_cast<const uint8_t*>(from);
+
+ result.s[0] = static_cast<uint32_t>(src[0]) << 24 |
+ static_cast<uint32_t>(src[1]) << 16 |
+ static_cast<uint32_t>(src[2]) << 8 |
+ static_cast<uint32_t>(src[3]);
+ result.s[1] = static_cast<uint32_t>(src[4]) << 24 |
+ static_cast<uint32_t>(src[5]) << 16 |
+ static_cast<uint32_t>(src[6]) << 8 |
+ static_cast<uint32_t>(src[7]);
+ result.s[2] = static_cast<uint32_t>(src[8]) << 24 |
+ static_cast<uint32_t>(src[9]) << 16 |
+ static_cast<uint32_t>(src[10]) << 8 |
+ static_cast<uint32_t>(src[11]);
+ result.s[3] = static_cast<uint32_t>(src[12]) << 24 |
+ static_cast<uint32_t>(src[13]) << 16 |
+ static_cast<uint32_t>(src[14]) << 8 |
+ static_cast<uint32_t>(src[15]);
+ return result;
+}
+
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Vector128Store(
+ const Vector128& v, void* ABSL_RANDOM_INTERNAL_RESTRICT to) {
+ uint8_t* dst = reinterpret_cast<uint8_t*>(to);
+ dst[0] = static_cast<uint8_t>(v.s[0] >> 24);
+ dst[1] = static_cast<uint8_t>(v.s[0] >> 16);
+ dst[2] = static_cast<uint8_t>(v.s[0] >> 8);
+ dst[3] = static_cast<uint8_t>(v.s[0]);
+ dst[4] = static_cast<uint8_t>(v.s[1] >> 24);
+ dst[5] = static_cast<uint8_t>(v.s[1] >> 16);
+ dst[6] = static_cast<uint8_t>(v.s[1] >> 8);
+ dst[7] = static_cast<uint8_t>(v.s[1]);
+ dst[8] = static_cast<uint8_t>(v.s[2] >> 24);
+ dst[9] = static_cast<uint8_t>(v.s[2] >> 16);
+ dst[10] = static_cast<uint8_t>(v.s[2] >> 8);
+ dst[11] = static_cast<uint8_t>(v.s[2]);
+ dst[12] = static_cast<uint8_t>(v.s[3] >> 24);
+ dst[13] = static_cast<uint8_t>(v.s[3] >> 16);
+ dst[14] = static_cast<uint8_t>(v.s[3] >> 8);
+ dst[15] = static_cast<uint8_t>(v.s[3]);
+}
+
+// One round of AES. "round_key" is a public constant for breaking the
+// symmetry of AES (ensures previously equal columns differ afterwards).
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE Vector128
+AesRound(const Vector128& state, const Vector128& round_key) {
+ // clang-format off
+ Vector128 result;
+ result.s[0] = round_key.s[0] ^
+ te0[uint8_t(state.s[0] >> 24)] ^
+ te1[uint8_t(state.s[1] >> 16)] ^
+ te2[uint8_t(state.s[2] >> 8)] ^
+ te3[uint8_t(state.s[3])];
+ result.s[1] = round_key.s[1] ^
+ te0[uint8_t(state.s[1] >> 24)] ^
+ te1[uint8_t(state.s[2] >> 16)] ^
+ te2[uint8_t(state.s[3] >> 8)] ^
+ te3[uint8_t(state.s[0])];
+ result.s[2] = round_key.s[2] ^
+ te0[uint8_t(state.s[2] >> 24)] ^
+ te1[uint8_t(state.s[3] >> 16)] ^
+ te2[uint8_t(state.s[0] >> 8)] ^
+ te3[uint8_t(state.s[1])];
+ result.s[3] = round_key.s[3] ^
+ te0[uint8_t(state.s[3] >> 24)] ^
+ te1[uint8_t(state.s[0] >> 16)] ^
+ te2[uint8_t(state.s[1] >> 8)] ^
+ te3[uint8_t(state.s[2])];
+ return result;
+ // clang-format on
+}
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// High-level summary:
+// 1) Reverie (see "A Robust and Sponge-Like PRNG with Improved Efficiency") is
+// a sponge-like random generator that requires a cryptographic permutation.
+// It improves upon "Provably Robust Sponge-Based PRNGs and KDFs" by
+// achieving backtracking resistance with only one Permute() per buffer.
+//
+// 2) "Simpira v2: A Family of Efficient Permutations Using the AES Round
+// Function" constructs up to 1024-bit permutations using an improved
+// Generalized Feistel network with 2-round AES-128 functions. This Feistel
+// block shuffle achieves diffusion faster and is less vulnerable to
+// sliced-biclique attacks than the Type-2 cyclic shuffle.
+//
+// 3) "Improving the Generalized Feistel" and "New criterion for diffusion
+// property" extends the same kind of improved Feistel block shuffle to 16
+// branches, which enables a 2048-bit permutation.
+//
+// Combine these three ideas and also change Simpira's subround keys from
+// structured/low-entropy counters to digits of Pi.
+
+// Randen constants.
+constexpr size_t kFeistelBlocks = 16;
+constexpr size_t kFeistelFunctions = kFeistelBlocks / 2; // = 8
+constexpr size_t kFeistelRounds = 16 + 1; // > 4 * log2(kFeistelBlocks)
+constexpr size_t kKeys = kFeistelRounds * kFeistelFunctions;
+
+// INCLUDE keys.
+#include "absl/random/internal/randen-keys.inc"
+
+static_assert(kKeys == kRoundKeys, "kKeys and kRoundKeys must be equal");
+
+// 2 uint64_t lanes per Vector128
+static constexpr size_t kLanes = 2;
+
+// The improved Feistel block shuffle function for 16 blocks.
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void BlockShuffle(
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state_u64) {
+ static_assert(kFeistelBlocks == 16,
+ "Feistel block shuffle only works for 16 blocks.");
+
+ constexpr size_t shuffle[kFeistelBlocks] = {7, 2, 13, 4, 11, 8, 3, 6,
+ 15, 0, 9, 10, 1, 14, 5, 12};
+
+ u64x2* ABSL_RANDOM_INTERNAL_RESTRICT state =
+ reinterpret_cast<u64x2*>(state_u64);
+
+ // The fully unrolled loop without the memcpy improves the speed by about
+ // 30% over the equivalent (leaving code here as a comment):
+ if (false) {
+ u64x2 source[kFeistelBlocks];
+ std::memcpy(source, state, sizeof(source));
+ for (size_t i = 0; i < kFeistelBlocks; i++) {
+ const u64x2 v0 = source[shuffle[i]];
+ state[i] = v0;
+ }
+ }
+
+ const u64x2 v0 = state[shuffle[0]];
+ const u64x2 v1 = state[shuffle[1]];
+ const u64x2 v2 = state[shuffle[2]];
+ const u64x2 v3 = state[shuffle[3]];
+ const u64x2 v4 = state[shuffle[4]];
+ const u64x2 v5 = state[shuffle[5]];
+ const u64x2 v6 = state[shuffle[6]];
+ const u64x2 v7 = state[shuffle[7]];
+ const u64x2 w0 = state[shuffle[8]];
+ const u64x2 w1 = state[shuffle[9]];
+ const u64x2 w2 = state[shuffle[10]];
+ const u64x2 w3 = state[shuffle[11]];
+ const u64x2 w4 = state[shuffle[12]];
+ const u64x2 w5 = state[shuffle[13]];
+ const u64x2 w6 = state[shuffle[14]];
+ const u64x2 w7 = state[shuffle[15]];
+ state[0] = v0;
+ state[1] = v1;
+ state[2] = v2;
+ state[3] = v3;
+ state[4] = v4;
+ state[5] = v5;
+ state[6] = v6;
+ state[7] = v7;
+ state[8] = w0;
+ state[9] = w1;
+ state[10] = w2;
+ state[11] = w3;
+ state[12] = w4;
+ state[13] = w5;
+ state[14] = w6;
+ state[15] = w7;
+}
+
+// Feistel round function using two AES subrounds. Very similar to F()
+// from Simpira v2, but with independent subround keys. Uses 17 AES rounds
+// per 16 bytes (vs. 10 for AES-CTR). Computing eight round functions in
+// parallel hides the 7-cycle AESNI latency on HSW. Note that the Feistel
+// XORs are 'free' (included in the second AES instruction).
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE const u64x2* FeistelRound(
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state,
+ const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys) {
+ for (size_t branch = 0; branch < kFeistelBlocks; branch += 4) {
+ const Vector128 s0 = Vector128Load(state + kLanes * branch);
+ const Vector128 s1 = Vector128Load(state + kLanes * (branch + 1));
+ const Vector128 f0 = AesRound(s0, Vector128Load(keys));
+ keys++;
+ const Vector128 o1 = AesRound(f0, s1);
+ Vector128Store(o1, state + kLanes * (branch + 1));
+
+ // Manually unroll this loop once. about 10% better than not unrolled.
+ const Vector128 s2 = Vector128Load(state + kLanes * (branch + 2));
+ const Vector128 s3 = Vector128Load(state + kLanes * (branch + 3));
+ const Vector128 f2 = AesRound(s2, Vector128Load(keys));
+ keys++;
+ const Vector128 o3 = AesRound(f2, s3);
+ Vector128Store(o3, state + kLanes * (branch + 3));
+ }
+ return keys;
+}
+
+// Cryptographic permutation based via type-2 Generalized Feistel Network.
+// Indistinguishable from ideal by chosen-ciphertext adversaries using less than
+// 2^64 queries if the round function is a PRF. This is similar to the b=8 case
+// of Simpira v2, but more efficient than its generic construction for b=16.
+inline ABSL_RANDOM_INTERNAL_ATTRIBUTE_ALWAYS_INLINE void Permute(
+ const void* keys, uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state) {
+ const u64x2* ABSL_RANDOM_INTERNAL_RESTRICT keys128 =
+ static_cast<const u64x2*>(keys);
+ for (size_t round = 0; round < kFeistelRounds; ++round) {
+ keys128 = FeistelRound(state, keys128);
+ BlockShuffle(state);
+ }
+}
+
+} // namespace
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+const void* RandenSlow::GetKeys() {
+ // Round keys for one AES per Feistel round and branch.
+ // The canonical implementation uses first digits of Pi.
+ return round_keys;
+}
+
+void RandenSlow::Absorb(const void* seed_void, void* state_void) {
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
+ reinterpret_cast<uint64_t*>(state_void);
+ const uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT seed =
+ reinterpret_cast<const uint64_t*>(seed_void);
+
+ constexpr size_t kCapacityBlocks = kCapacityBytes / sizeof(uint64_t);
+ static_assert(kCapacityBlocks * sizeof(uint64_t) == kCapacityBytes,
+ "Not i*V");
+ for (size_t i = kCapacityBlocks; i < kStateBytes / sizeof(uint64_t); ++i) {
+ state[i] ^= seed[i - kCapacityBlocks];
+ }
+}
+
+void RandenSlow::Generate(const void* keys, void* state_void) {
+ static_assert(kCapacityBytes == sizeof(Vector128), "Capacity mismatch");
+
+ uint64_t* ABSL_RANDOM_INTERNAL_RESTRICT state =
+ reinterpret_cast<uint64_t*>(state_void);
+
+ const Vector128 prev_inner = Vector128Load(state);
+
+ Permute(keys, state);
+
+ // Ensure backtracking resistance.
+ Vector128 inner = Vector128Load(state);
+ inner ^= prev_inner;
+ Vector128Store(inner, state);
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/randen_slow.h b/absl/random/internal/randen_slow.h
new file mode 100644
index 00000000..2133b370
--- /dev/null
+++ b/absl/random/internal/randen_slow.h
@@ -0,0 +1,45 @@
+// 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_RANDEN_SLOW_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_
+
+#include <cstddef>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// RandenSlow implements the basic state manipulation methods for
+// architectures lacking AES hardware acceleration intrinsics.
+class RandenSlow {
+ public:
+ // Size of the entire sponge / state for the randen PRNG.
+ static constexpr size_t kStateBytes = 256; // 2048-bit
+
+ // Size of the 'inner' (inaccessible) part of the sponge. Larger values would
+ // require more frequent calls to RandenGenerate.
+ static constexpr size_t kCapacityBytes = 16; // 128-bit
+
+ static void Generate(const void* keys, void* state_void);
+ static void Absorb(const void* seed_void, void* state_void);
+ static const void* GetKeys();
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_SLOW_H_
diff --git a/absl/random/internal/randen_slow_test.cc b/absl/random/internal/randen_slow_test.cc
new file mode 100644
index 00000000..c07155d8
--- /dev/null
+++ b/absl/random/internal/randen_slow_test.cc
@@ -0,0 +1,61 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/randen_slow.h"
+
+#include <cstring>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::random_internal::RandenSlow;
+
+// Local state parameters.
+constexpr size_t kSeedBytes =
+ RandenSlow::kStateBytes - RandenSlow::kCapacityBytes;
+constexpr size_t kStateSizeT = RandenSlow::kStateBytes / sizeof(uint64_t);
+constexpr size_t kSeedSizeT = kSeedBytes / sizeof(uint32_t);
+
+struct randen {
+ uint64_t state[kStateSizeT];
+ uint32_t seed[kSeedSizeT];
+};
+
+TEST(RandenSlowTest, Default) {
+ constexpr uint64_t kGolden[] = {
+ 0x6c6534090ee6d3ee, 0x044e2b9b9d5333c6, 0xc3c14f134e433977,
+ 0xdda9f47cd90410ee, 0x887bf3087fd8ca10, 0xf0b780f545c72912,
+ 0x15dbb1d37696599f, 0x30ec63baff3c6d59, 0xb29f73606f7f20a6,
+ 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e, 0x9cbf605e3fd9de8a,
+ 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5, 0xf4b327fe0fc73c37,
+ 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d, 0xd5af05dd3eff9556,
+ 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c, 0x58d3575834956d42,
+ 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3, 0x497cabf3431154fc,
+ 0x4e24370570029a8b, 0xd88b5749f090e5ea, 0xc651a582a970692f,
+ 0x78fcec2cbb6342f5, 0x463cb745612f55db, 0x352ee4ad1816afe3,
+ 0x026ff374c101da7e, 0x811ef0821c3de851,
+ };
+
+ alignas(16) randen d;
+ std::memset(d.state, 0, sizeof(d.state));
+ RandenSlow::Generate(RandenSlow::GetKeys(), d.state);
+
+ uint64_t* id = d.state;
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, *id++);
+ }
+}
+
+} // namespace
diff --git a/absl/random/internal/randen_test.cc b/absl/random/internal/randen_test.cc
new file mode 100644
index 00000000..c186fe0d
--- /dev/null
+++ b/absl/random/internal/randen_test.cc
@@ -0,0 +1,70 @@
+// 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/randen.h"
+
+#include <cstring>
+
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+
+namespace {
+
+using absl::random_internal::Randen;
+
+// Local state parameters.
+constexpr size_t kStateSizeT = Randen::kStateBytes / sizeof(uint64_t);
+
+TEST(RandenTest, CopyAndMove) {
+ static_assert(std::is_copy_constructible<Randen>::value,
+ "Randen must be copy constructible");
+
+ static_assert(absl::is_copy_assignable<Randen>::value,
+ "Randen must be copy assignable");
+
+ static_assert(std::is_move_constructible<Randen>::value,
+ "Randen must be move constructible");
+
+ static_assert(absl::is_move_assignable<Randen>::value,
+ "Randen must be move assignable");
+}
+
+TEST(RandenTest, Default) {
+ constexpr uint64_t kGolden[] = {
+ 0x6c6534090ee6d3ee, 0x044e2b9b9d5333c6, 0xc3c14f134e433977,
+ 0xdda9f47cd90410ee, 0x887bf3087fd8ca10, 0xf0b780f545c72912,
+ 0x15dbb1d37696599f, 0x30ec63baff3c6d59, 0xb29f73606f7f20a6,
+ 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e, 0x9cbf605e3fd9de8a,
+ 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5, 0xf4b327fe0fc73c37,
+ 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d, 0xd5af05dd3eff9556,
+ 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c, 0x58d3575834956d42,
+ 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3, 0x497cabf3431154fc,
+ 0x4e24370570029a8b, 0xd88b5749f090e5ea, 0xc651a582a970692f,
+ 0x78fcec2cbb6342f5, 0x463cb745612f55db, 0x352ee4ad1816afe3,
+ 0x026ff374c101da7e, 0x811ef0821c3de851,
+ };
+
+ alignas(16) uint64_t state[kStateSizeT];
+ std::memset(state, 0, sizeof(state));
+
+ Randen r;
+ r.Generate(state);
+
+ auto id = std::begin(state);
+ for (const auto& elem : kGolden) {
+ EXPECT_EQ(elem, *id++);
+ }
+}
+
+} // namespace
diff --git a/absl/random/internal/randen_traits.h b/absl/random/internal/randen_traits.h
new file mode 100644
index 00000000..d2562586
--- /dev/null
+++ b/absl/random/internal/randen_traits.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_
+#define ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_
+
+// HERMETIC NOTE: The randen_hwaes target must not introduce duplicate
+// symbols from arbitrary system and other headers, since it may be built
+// with different flags from other targets, using different levels of
+// optimization, potentially introducing ODR violations.
+
+#include <cstddef>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// RANDen = RANDom generator or beetroots in Swiss German.
+// 'Strong' (well-distributed, unpredictable, backtracking-resistant) random
+// generator, faster in some benchmarks than std::mt19937_64 and pcg64_c32.
+//
+// RandenTraits contains the basic algorithm traits, such as the size of the
+// state, seed, sponge, etc.
+struct RandenTraits {
+ // Size of the entire sponge / state for the randen PRNG.
+ static constexpr size_t kStateBytes = 256; // 2048-bit
+
+ // Size of the 'inner' (inaccessible) part of the sponge. Larger values would
+ // require more frequent calls to RandenGenerate.
+ static constexpr size_t kCapacityBytes = 16; // 128-bit
+
+ // Size of the default seed consumed by the sponge.
+ static constexpr size_t kSeedBytes = kStateBytes - kCapacityBytes;
+
+ // Largest size for which security proofs are known.
+ static constexpr size_t kFeistelBlocks = 16;
+
+ // Type-2 generalized Feistel => one round function for every two blocks.
+ static constexpr size_t kFeistelFunctions = kFeistelBlocks / 2; // = 8
+
+ // Ensures SPRP security and two full subblock diffusions.
+ // Must be > 4 * log2(kFeistelBlocks).
+ static constexpr size_t kFeistelRounds = 16 + 1;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_RANDEN_TRAITS_H_
diff --git a/absl/random/internal/salted_seed_seq.h b/absl/random/internal/salted_seed_seq.h
new file mode 100644
index 00000000..08bf369e
--- /dev/null
+++ b/absl/random/internal/salted_seed_seq.h
@@ -0,0 +1,167 @@
+// 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_SALTED_SEED_SEQ_H_
+#define ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_
+
+#include <cstdint>
+#include <cstdlib>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "absl/container/inlined_vector.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/internal/seed_material.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// This class conforms to the C++ Standard "Seed Sequence" concept
+// [rand.req.seedseq].
+//
+// A `SaltedSeedSeq` is meant to wrap an existing seed sequence and modify
+// generated sequence by mixing with extra entropy. This entropy may be
+// build-dependent or process-dependent. The implementation may change to be
+// have either or both kinds of entropy. If salt is not available sequence is
+// not modified.
+template <typename SSeq>
+class SaltedSeedSeq {
+ public:
+ using inner_sequence_type = SSeq;
+ using result_type = typename SSeq::result_type;
+
+ SaltedSeedSeq() : seq_(absl::make_unique<SSeq>()) {}
+
+ template <typename Iterator>
+ SaltedSeedSeq(Iterator begin, Iterator end)
+ : seq_(absl::make_unique<SSeq>(begin, end)) {}
+
+ template <typename T>
+ SaltedSeedSeq(std::initializer_list<T> il)
+ : SaltedSeedSeq(il.begin(), il.end()) {}
+
+ SaltedSeedSeq(const SaltedSeedSeq&) = delete;
+ SaltedSeedSeq& operator=(const SaltedSeedSeq&) = delete;
+
+ SaltedSeedSeq(SaltedSeedSeq&&) = default;
+ SaltedSeedSeq& operator=(SaltedSeedSeq&&) = default;
+
+ template <typename RandomAccessIterator>
+ void generate(RandomAccessIterator begin, RandomAccessIterator end) {
+ // The common case is that generate is called with ContiguousIterators
+ // to uint arrays. Such contiguous memory regions may be optimized,
+ // which we detect here.
+ using tag = absl::conditional_t<
+ (std::is_pointer<RandomAccessIterator>::value &&
+ std::is_same<absl::decay_t<decltype(*begin)>, uint32_t>::value),
+ ContiguousAndUint32Tag, DefaultTag>;
+ if (begin != end) {
+ generate_impl(begin, end, tag{});
+ }
+ }
+
+ template <typename OutIterator>
+ void param(OutIterator out) const {
+ seq_->param(out);
+ }
+
+ size_t size() const { return seq_->size(); }
+
+ private:
+ struct ContiguousAndUint32Tag {};
+ struct DefaultTag {};
+
+ // Generate which requires the iterators are contiguous pointers to uint32_t.
+ void generate_impl(uint32_t* begin, uint32_t* end, ContiguousAndUint32Tag) {
+ generate_contiguous(absl::MakeSpan(begin, end));
+ }
+
+ // The uncommon case for generate is that it is called with iterators over
+ // some other buffer type which is assignable from a 32-bit value. In this
+ // case we allocate a temporary 32-bit buffer and then copy-assign back
+ // to the initial inputs.
+ template <typename RandomAccessIterator>
+ void generate_impl(RandomAccessIterator begin, RandomAccessIterator end,
+ DefaultTag) {
+ return generate_and_copy(std::distance(begin, end), begin);
+ }
+
+ // Fills the initial seed buffer the underlying SSeq::generate() call,
+ // mixing in the salt material.
+ void generate_contiguous(absl::Span<uint32_t> buffer) {
+ seq_->generate(buffer.begin(), buffer.end());
+ const uint32_t salt = absl::random_internal::GetSaltMaterial().value_or(0);
+ MixIntoSeedMaterial(absl::MakeConstSpan(&salt, 1), buffer);
+ }
+
+ // Allocates a seed buffer of `n` elements, generates the seed, then
+ // copies the result into the `out` iterator.
+ template <typename Iterator>
+ void generate_and_copy(size_t n, Iterator out) {
+ // Allocate a temporary buffer, generate, and then copy.
+ absl::InlinedVector<uint32_t, 8> data(n, 0);
+ generate_contiguous(absl::MakeSpan(data.data(), data.size()));
+ std::copy(data.begin(), data.end(), out);
+ }
+
+ // Because [rand.req.seedseq] is not required to be copy-constructible,
+ // copy-assignable nor movable, we wrap it with unique pointer to be able
+ // to move SaltedSeedSeq.
+ std::unique_ptr<SSeq> seq_;
+};
+
+// is_salted_seed_seq indicates whether the type is a SaltedSeedSeq.
+template <typename T, typename = void>
+struct is_salted_seed_seq : public std::false_type {};
+
+template <typename T>
+struct is_salted_seed_seq<
+ T, typename std::enable_if<std::is_same<
+ T, SaltedSeedSeq<typename T::inner_sequence_type>>::value>::type>
+ : public std::true_type {};
+
+// MakeSaltedSeedSeq returns a salted variant of the seed sequence.
+// When provided with an existing SaltedSeedSeq, returns the input parameter,
+// otherwise constructs a new SaltedSeedSeq which embodies the original
+// non-salted seed parameters.
+template <
+ typename SSeq, //
+ typename EnableIf = absl::enable_if_t<is_salted_seed_seq<SSeq>::value>>
+SSeq MakeSaltedSeedSeq(SSeq&& seq) {
+ return SSeq(std::forward<SSeq>(seq));
+}
+
+template <
+ typename SSeq, //
+ typename EnableIf = absl::enable_if_t<!is_salted_seed_seq<SSeq>::value>>
+SaltedSeedSeq<typename std::decay<SSeq>::type> MakeSaltedSeedSeq(SSeq&& seq) {
+ using sseq_type = typename std::decay<SSeq>::type;
+ using result_type = typename sseq_type::result_type;
+
+ absl::InlinedVector<result_type, 8> data;
+ seq.param(std::back_inserter(data));
+ return SaltedSeedSeq<sseq_type>(data.begin(), data.end());
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_SALTED_SEED_SEQ_H_
diff --git a/absl/random/internal/salted_seed_seq_test.cc b/absl/random/internal/salted_seed_seq_test.cc
new file mode 100644
index 00000000..0bf19a63
--- /dev/null
+++ b/absl/random/internal/salted_seed_seq_test.cc
@@ -0,0 +1,168 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/internal/salted_seed_seq.h"
+
+#include <iterator>
+#include <random>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using absl::random_internal::GetSaltMaterial;
+using absl::random_internal::MakeSaltedSeedSeq;
+using absl::random_internal::SaltedSeedSeq;
+using testing::Eq;
+using testing::Pointwise;
+
+namespace {
+
+template <typename Sseq>
+void ConformsToInterface() {
+ // Check that the SeedSequence can be default-constructed.
+ { 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}; }
+ // Check that param() and size() return state provided to constructor.
+ {
+ uint32_t init_array[] = {1, 2, 3, 4, 5};
+ Sseq seq(std::begin(init_array), std::end(init_array));
+ EXPECT_EQ(seq.size(), ABSL_ARRAYSIZE(init_array));
+
+ std::vector<uint32_t> state_vector;
+ seq.param(std::back_inserter(state_vector));
+
+ EXPECT_EQ(state_vector.size(), ABSL_ARRAYSIZE(init_array));
+ for (int i = 0; i < state_vector.size(); i++) {
+ EXPECT_EQ(state_vector[i], i + 1);
+ }
+ }
+ // Check for presence of generate() method.
+ {
+ Sseq seq;
+ uint32_t seeds[5];
+
+ seq.generate(std::begin(seeds), std::end(seeds));
+ }
+}
+
+TEST(SaltedSeedSeq, CheckInterfaces) {
+ // Control case
+ ConformsToInterface<std::seed_seq>();
+
+ // Abseil classes
+ ConformsToInterface<SaltedSeedSeq<std::seed_seq>>();
+}
+
+TEST(SaltedSeedSeq, CheckConstructingFromOtherSequence) {
+ std::vector<uint32_t> seed_values(10, 1);
+ std::seed_seq seq(seed_values.begin(), seed_values.end());
+ auto salted_seq = MakeSaltedSeedSeq(std::move(seq));
+
+ EXPECT_EQ(seq.size(), salted_seq.size());
+
+ std::vector<uint32_t> param_result;
+ seq.param(std::back_inserter(param_result));
+
+ EXPECT_EQ(seed_values, param_result);
+}
+
+TEST(SaltedSeedSeq, SaltedSaltedSeedSeqIsNotDoubleSalted) {
+ uint32_t init[] = {1, 3, 5, 7, 9};
+
+ std::seed_seq seq(std::begin(init), std::end(init));
+
+ // The first salting.
+ SaltedSeedSeq<std::seed_seq> salted_seq = MakeSaltedSeedSeq(std::move(seq));
+ uint32_t a[16];
+ salted_seq.generate(std::begin(a), std::end(a));
+
+ // The second salting.
+ SaltedSeedSeq<std::seed_seq> salted_salted_seq =
+ MakeSaltedSeedSeq(std::move(salted_seq));
+ uint32_t b[16];
+ salted_salted_seq.generate(std::begin(b), std::end(b));
+
+ // ... both should be equal.
+ EXPECT_THAT(b, Pointwise(Eq(), a)) << "a[0] " << a[0];
+}
+
+TEST(SaltedSeedSeq, SeedMaterialIsSalted) {
+ const size_t kNumBlocks = 16;
+
+ uint32_t seed_material[kNumBlocks];
+ std::random_device urandom{"/dev/urandom"};
+ for (uint32_t& seed : seed_material) {
+ seed = urandom();
+ }
+
+ std::seed_seq seq(std::begin(seed_material), std::end(seed_material));
+ SaltedSeedSeq<std::seed_seq> salted_seq(std::begin(seed_material),
+ std::end(seed_material));
+
+ bool salt_is_available = GetSaltMaterial().has_value();
+
+ // If salt is available generated sequence should be different.
+ if (salt_is_available) {
+ uint32_t outputs[kNumBlocks];
+ uint32_t salted_outputs[kNumBlocks];
+
+ seq.generate(std::begin(outputs), std::end(outputs));
+ salted_seq.generate(std::begin(salted_outputs), std::end(salted_outputs));
+
+ EXPECT_THAT(outputs, Pointwise(testing::Ne(), salted_outputs));
+ }
+}
+
+TEST(SaltedSeedSeq, GenerateAcceptsDifferentTypes) {
+ const size_t kNumBlocks = 4;
+
+ SaltedSeedSeq<std::seed_seq> seq({1, 2, 3});
+
+ uint32_t expected[kNumBlocks];
+ seq.generate(std::begin(expected), std::end(expected));
+
+ // 32-bit outputs
+ {
+ unsigned long seed_material[kNumBlocks]; // NOLINT(runtime/int)
+ seq.generate(std::begin(seed_material), std::end(seed_material));
+ EXPECT_THAT(seed_material, Pointwise(Eq(), expected));
+ }
+ {
+ unsigned int seed_material[kNumBlocks]; // NOLINT(runtime/int)
+ seq.generate(std::begin(seed_material), std::end(seed_material));
+ EXPECT_THAT(seed_material, Pointwise(Eq(), expected));
+ }
+
+ // 64-bit outputs.
+ {
+ uint64_t seed_material[kNumBlocks];
+ seq.generate(std::begin(seed_material), std::end(seed_material));
+ EXPECT_THAT(seed_material, Pointwise(Eq(), expected));
+ }
+ {
+ int64_t seed_material[kNumBlocks];
+ seq.generate(std::begin(seed_material), std::end(seed_material));
+ EXPECT_THAT(seed_material, Pointwise(Eq(), expected));
+ }
+}
+
+} // namespace
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc
new file mode 100644
index 00000000..dae7007f
--- /dev/null
+++ b/absl/random/internal/seed_material.cc
@@ -0,0 +1,207 @@
+// 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/seed_material.h"
+
+#include <fcntl.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include <algorithm>
+#include <cerrno>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+
+#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"
+
+#if defined(__native_client__)
+
+#include <nacl/nacl_random.h>
+#define ABSL_RANDOM_USE_NACL_SECURE_RANDOM 1
+
+#elif defined(_WIN32)
+
+#include <windows.h>
+#define ABSL_RANDOM_USE_BCRYPT 1
+#pragma comment(lib, "bcrypt.lib")
+
+#endif
+
+#if defined(ABSL_RANDOM_USE_BCRYPT)
+#include <bcrypt.h>
+
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
+#endif
+// Also link bcrypt; this can be done via linker options or:
+// #pragma comment(lib, "bcrypt.lib")
+#endif
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+namespace {
+
+// Read OS Entropy for random number seeds.
+// TODO(absl-team): Possibly place a cap on how much entropy may be read at a
+// time.
+
+#if defined(ABSL_RANDOM_USE_BCRYPT)
+
+// On Windows potentially use the BCRYPT CNG API to read available entropy.
+bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+ BCRYPT_ALG_HANDLE hProvider;
+ NTSTATUS ret;
+ ret = BCryptOpenAlgorithmProvider(&hProvider, BCRYPT_RNG_ALGORITHM,
+ MS_PRIMITIVE_PROVIDER, 0);
+ if (!(BCRYPT_SUCCESS(ret))) {
+ ABSL_RAW_LOG(ERROR, "Failed to open crypto provider.");
+ return false;
+ }
+ ret = BCryptGenRandom(
+ hProvider, // provider
+ reinterpret_cast<UCHAR*>(values.data()), // buffer
+ static_cast<ULONG>(sizeof(uint32_t) * values.size()), // bytes
+ 0); // flags
+ BCryptCloseAlgorithmProvider(hProvider, 0);
+ return BCRYPT_SUCCESS(ret);
+}
+
+#elif defined(ABSL_RANDOM_USE_NACL_SECURE_RANDOM)
+
+// On NaCL use nacl_secure_random to acquire bytes.
+bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+ auto buffer = reinterpret_cast<uint8_t*>(values.data());
+ size_t buffer_size = sizeof(uint32_t) * values.size();
+
+ uint8_t* output_ptr = buffer;
+ while (buffer_size > 0) {
+ size_t nread = 0;
+ const int error = nacl_secure_random(output_ptr, buffer_size, &nread);
+ if (error != 0 || nread > buffer_size) {
+ ABSL_RAW_LOG(ERROR, "Failed to read secure_random seed data: %d", error);
+ return false;
+ }
+ output_ptr += nread;
+ buffer_size -= nread;
+ }
+ return true;
+}
+
+#else
+
+// On *nix, read entropy from /dev/urandom.
+bool ReadSeedMaterialFromOSEntropyImpl(absl::Span<uint32_t> values) {
+ const char kEntropyFile[] = "/dev/urandom";
+
+ auto buffer = reinterpret_cast<uint8_t*>(values.data());
+ size_t buffer_size = sizeof(uint32_t) * values.size();
+
+ int dev_urandom = open(kEntropyFile, O_RDONLY);
+ bool success = (-1 != dev_urandom);
+ if (!success) {
+ return false;
+ }
+
+ while (success && buffer_size > 0) {
+ int bytes_read = read(dev_urandom, buffer, buffer_size);
+ int read_error = errno;
+ success = (bytes_read > 0);
+ if (success) {
+ buffer += bytes_read;
+ buffer_size -= bytes_read;
+ } else if (bytes_read == -1 && read_error == EINTR) {
+ success = true; // Need to try again.
+ }
+ }
+ close(dev_urandom);
+ return success;
+}
+
+#endif
+
+} // namespace
+
+bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values) {
+ assert(values.data() != nullptr);
+ if (values.data() == nullptr) {
+ return false;
+ }
+ if (values.empty()) {
+ return true;
+ }
+ return ReadSeedMaterialFromOSEntropyImpl(values);
+}
+
+void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence,
+ absl::Span<uint32_t> seed_material) {
+ // Algorithm is based on code available at
+ // https://gist.github.com/imneme/540829265469e673d045
+ constexpr uint32_t kInitVal = 0x43b0d7e5;
+ constexpr uint32_t kHashMul = 0x931e8875;
+ constexpr uint32_t kMixMulL = 0xca01f9dd;
+ constexpr uint32_t kMixMulR = 0x4973f715;
+ constexpr uint32_t kShiftSize = sizeof(uint32_t) * 8 / 2;
+
+ uint32_t hash_const = kInitVal;
+ auto hash = [&](uint32_t value) {
+ value ^= hash_const;
+ hash_const *= kHashMul;
+ value *= hash_const;
+ value ^= value >> kShiftSize;
+ return value;
+ };
+
+ auto mix = [&](uint32_t x, uint32_t y) {
+ uint32_t result = kMixMulL * x - kMixMulR * y;
+ result ^= result >> kShiftSize;
+ return result;
+ };
+
+ for (const auto& seq_val : sequence) {
+ for (auto& elem : seed_material) {
+ elem = mix(elem, hash(seq_val));
+ }
+ }
+}
+
+absl::optional<uint32_t> GetSaltMaterial() {
+ // Salt must be common for all generators within the same process so read it
+ // only once and store in static variable.
+ static const auto salt_material = []() -> absl::optional<uint32_t> {
+ uint32_t salt_value = 0;
+
+ if (random_internal::ReadSeedMaterialFromOSEntropy(
+ MakeSpan(&salt_value, 1))) {
+ return salt_value;
+ }
+
+ return absl::nullopt;
+ }();
+
+ return salt_material;
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/internal/seed_material.h b/absl/random/internal/seed_material.h
new file mode 100644
index 00000000..41387fe3
--- /dev/null
+++ b/absl/random/internal/seed_material.h
@@ -0,0 +1,104 @@
+// 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_SEED_MATERIAL_H_
+#define ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_
+
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "absl/base/attributes.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/types/optional.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// Returns the number of 32-bit blocks needed to contain the given number of
+// bits.
+constexpr size_t SeedBitsToBlocks(size_t seed_size) {
+ return (seed_size + 31) / 32;
+}
+
+// Amount of entropy (measured in bits) used to instantiate a Seed Sequence,
+// with which to create a URBG.
+constexpr size_t kEntropyBitsNeeded = 256;
+
+// Amount of entropy (measured in 32-bit blocks) used to instantiate a Seed
+// Sequence, with which to create a URBG.
+constexpr size_t kEntropyBlocksNeeded =
+ random_internal::SeedBitsToBlocks(kEntropyBitsNeeded);
+
+static_assert(kEntropyBlocksNeeded > 0,
+ "Entropy used to seed URBGs must be nonzero.");
+
+// Attempts to fill a span of uint32_t-values using an OS-provided source of
+// true entropy (eg. /dev/urandom) into an array of uint32_t blocks of data. The
+// resulting array may be used to initialize an instance of a class conforming
+// to the C++ Standard "Seed Sequence" concept [rand.req.seedseq].
+//
+// If values.data() == nullptr, the behavior is undefined.
+ABSL_MUST_USE_RESULT
+bool ReadSeedMaterialFromOSEntropy(absl::Span<uint32_t> values);
+
+// Attempts to fill a span of uint32_t-values using variates generated by an
+// existing instance of a class conforming to the C++ Standard "Uniform Random
+// Bit Generator" concept [rand.req.urng]. The resulting data may be used to
+// initialize an instance of a class conforming to the C++ Standard
+// "Seed Sequence" concept [rand.req.seedseq].
+//
+// 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) {
+ random_internal::FastUniformBits<uint32_t> distr;
+
+ assert(urbg != nullptr && values.data() != nullptr);
+ if (urbg == nullptr || values.data() == nullptr) {
+ return false;
+ }
+
+ for (uint32_t& seed_value : values) {
+ seed_value = distr(*urbg);
+ }
+ return true;
+}
+
+// Mixes given sequence of values with into given sequence of seed material.
+// Time complexity of this function is O(sequence.size() *
+// seed_material.size()).
+//
+// Algorithm is based on code available at
+// https://gist.github.com/imneme/540829265469e673d045
+// by Melissa O'Neill.
+void MixIntoSeedMaterial(absl::Span<const uint32_t> sequence,
+ absl::Span<uint32_t> seed_material);
+
+// Returns salt value.
+//
+// Salt is obtained only once and stored in static variable.
+//
+// May return empty value if optaining the salt was not possible.
+absl::optional<uint32_t> GetSaltMaterial();
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_SEED_MATERIAL_H_
diff --git a/absl/random/internal/seed_material_test.cc b/absl/random/internal/seed_material_test.cc
new file mode 100644
index 00000000..6db2820e
--- /dev/null
+++ b/absl/random/internal/seed_material_test.cc
@@ -0,0 +1,202 @@
+// 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/seed_material.h"
+
+#include <bitset>
+#include <cstdlib>
+#include <cstring>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#ifdef __ANDROID__
+// Android assert messages only go to system log, so death tests cannot inspect
+// the message for matching.
+#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH_IF_SUPPORTED(statement, ".*")
+#else
+#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH_IF_SUPPORTED(statement, regex)
+#endif
+
+namespace {
+
+using testing::Each;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::Ne;
+using testing::Pointwise;
+
+TEST(SeedBitsToBlocks, VerifyCases) {
+ EXPECT_EQ(0, absl::random_internal::SeedBitsToBlocks(0));
+ EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(1));
+ EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(31));
+ EXPECT_EQ(1, absl::random_internal::SeedBitsToBlocks(32));
+ EXPECT_EQ(2, absl::random_internal::SeedBitsToBlocks(33));
+ EXPECT_EQ(4, absl::random_internal::SeedBitsToBlocks(127));
+ EXPECT_EQ(4, absl::random_internal::SeedBitsToBlocks(128));
+ EXPECT_EQ(5, absl::random_internal::SeedBitsToBlocks(129));
+}
+
+TEST(ReadSeedMaterialFromOSEntropy, SuccessiveReadsAreDistinct) {
+ constexpr size_t kSeedMaterialSize = 64;
+ uint32_t seed_material_1[kSeedMaterialSize] = {};
+ uint32_t seed_material_2[kSeedMaterialSize] = {};
+
+ EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::Span<uint32_t>(seed_material_1, kSeedMaterialSize)));
+ EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::Span<uint32_t>(seed_material_2, kSeedMaterialSize)));
+
+ EXPECT_THAT(seed_material_1, Pointwise(Ne(), seed_material_2));
+}
+
+TEST(ReadSeedMaterialFromOSEntropy, ReadZeroBytesIsNoOp) {
+ uint32_t seed_material[32] = {};
+ std::memset(seed_material, 0xAA, sizeof(seed_material));
+ EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::Span<uint32_t>(seed_material, 0)));
+
+ EXPECT_THAT(seed_material, Each(Eq(0xAAAAAAAA)));
+}
+
+TEST(ReadSeedMaterialFromOSEntropy, NullPtrVectorArgument) {
+#ifdef NDEBUG
+ EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::Span<uint32_t>(nullptr, 32)));
+#else
+ bool result;
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(
+ result = absl::random_internal::ReadSeedMaterialFromOSEntropy(
+ absl::Span<uint32_t>(nullptr, 32)),
+ "!= nullptr");
+ (void)result; // suppress unused-variable warning
+#endif
+}
+
+TEST(ReadSeedMaterialFromURBG, SeedMaterialEqualsVariateSequence) {
+ // Two default-constructed instances of std::mt19937_64 are guaranteed to
+ // produce equal variate-sequences.
+ std::mt19937 urbg_1;
+ std::mt19937 urbg_2;
+ constexpr size_t kSeedMaterialSize = 1024;
+ uint32_t seed_material[kSeedMaterialSize] = {};
+
+ EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromURBG(
+ &urbg_1, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)));
+ for (uint32_t seed : seed_material) {
+ EXPECT_EQ(seed, urbg_2());
+ }
+}
+
+TEST(ReadSeedMaterialFromURBG, ReadZeroBytesIsNoOp) {
+ std::mt19937_64 urbg;
+ uint32_t seed_material[32];
+ std::memset(seed_material, 0xAA, sizeof(seed_material));
+ EXPECT_TRUE(absl::random_internal::ReadSeedMaterialFromURBG(
+ &urbg, absl::Span<uint32_t>(seed_material, 0)));
+
+ EXPECT_THAT(seed_material, Each(Eq(0xAAAAAAAA)));
+}
+
+TEST(ReadSeedMaterialFromURBG, NullUrbgArgument) {
+ constexpr size_t kSeedMaterialSize = 32;
+ uint32_t seed_material[kSeedMaterialSize];
+#ifdef NDEBUG
+ EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromURBG<std::mt19937_64>(
+ nullptr, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)));
+#else
+ bool result;
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(
+ result = absl::random_internal::ReadSeedMaterialFromURBG<std::mt19937_64>(
+ nullptr, absl::Span<uint32_t>(seed_material, kSeedMaterialSize)),
+ "!= nullptr");
+ (void)result; // suppress unused-variable warning
+#endif
+}
+
+TEST(ReadSeedMaterialFromURBG, NullPtrVectorArgument) {
+ std::mt19937_64 urbg;
+#ifdef NDEBUG
+ EXPECT_FALSE(absl::random_internal::ReadSeedMaterialFromURBG(
+ &urbg, absl::Span<uint32_t>(nullptr, 32)));
+#else
+ bool result;
+ ABSL_EXPECT_DEATH_IF_SUPPORTED(
+ result = absl::random_internal::ReadSeedMaterialFromURBG(
+ &urbg, absl::Span<uint32_t>(nullptr, 32)),
+ "!= nullptr");
+ (void)result; // suppress unused-variable warning
+#endif
+}
+
+// The avalanche effect is a desirable cryptographic property of hashes in which
+// changing a single bit in the input causes each bit of the output to be
+// changed with probability near 50%.
+//
+// https://en.wikipedia.org/wiki/Avalanche_effect
+
+TEST(MixSequenceIntoSeedMaterial, AvalancheEffectTestOneBitLong) {
+ std::vector<uint32_t> seed_material = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ // For every 32-bit number with exactly one bit set, verify the avalanche
+ // effect holds. In order to reduce flakiness of tests, accept values
+ // anywhere in the range of 30%-70%.
+ for (uint32_t v = 1; v != 0; v <<= 1) {
+ std::vector<uint32_t> seed_material_copy = seed_material;
+ absl::random_internal::MixIntoSeedMaterial(
+ absl::Span<uint32_t>(&v, 1),
+ absl::Span<uint32_t>(seed_material_copy.data(),
+ seed_material_copy.size()));
+
+ uint32_t changed_bits = 0;
+ for (size_t i = 0; i < seed_material.size(); i++) {
+ std::bitset<sizeof(uint32_t) * 8> bitset(seed_material[i] ^
+ seed_material_copy[i]);
+ changed_bits += bitset.count();
+ }
+
+ EXPECT_LE(changed_bits, 0.7 * sizeof(uint32_t) * 8 * seed_material.size());
+ EXPECT_GE(changed_bits, 0.3 * sizeof(uint32_t) * 8 * seed_material.size());
+ }
+}
+
+TEST(MixSequenceIntoSeedMaterial, AvalancheEffectTestOneBitShort) {
+ std::vector<uint32_t> seed_material = {1};
+
+ // For every 32-bit number with exactly one bit set, verify the avalanche
+ // effect holds. In order to reduce flakiness of tests, accept values
+ // anywhere in the range of 30%-70%.
+ for (uint32_t v = 1; v != 0; v <<= 1) {
+ std::vector<uint32_t> seed_material_copy = seed_material;
+ absl::random_internal::MixIntoSeedMaterial(
+ absl::Span<uint32_t>(&v, 1),
+ absl::Span<uint32_t>(seed_material_copy.data(),
+ seed_material_copy.size()));
+
+ uint32_t changed_bits = 0;
+ for (size_t i = 0; i < seed_material.size(); i++) {
+ std::bitset<sizeof(uint32_t) * 8> bitset(seed_material[i] ^
+ seed_material_copy[i]);
+ changed_bits += bitset.count();
+ }
+
+ EXPECT_LE(changed_bits, 0.7 * sizeof(uint32_t) * 8 * seed_material.size());
+ EXPECT_GE(changed_bits, 0.3 * sizeof(uint32_t) * 8 * seed_material.size());
+ }
+}
+
+} // namespace
diff --git a/absl/random/internal/seed_salting_sequence_generator.cc b/absl/random/internal/seed_salting_sequence_generator.cc
new file mode 100644
index 00000000..31fdcfe1
--- /dev/null
+++ b/absl/random/internal/seed_salting_sequence_generator.cc
@@ -0,0 +1,30 @@
+// 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 <iostream>
+#include <random>
+
+#include "absl/random/random.h"
+
+// This program is used in integration tests.
+
+int main() {
+ std::seed_seq seed_seq{1234};
+ absl::BitGen rng(seed_seq);
+ constexpr size_t kSequenceLength = 8;
+ for (size_t i = 0; i < kSequenceLength; i++) {
+ std::cout << rng() << "\n";
+ }
+ return 0;
+}
diff --git a/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc b/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc
new file mode 100644
index 00000000..8797e2e7
--- /dev/null
+++ b/absl/random/internal/seed_salting_sequence_generator_empty_sequence.cc
@@ -0,0 +1,30 @@
+// 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 <iostream>
+#include <random>
+
+#include "absl/random/random.h"
+
+// This program is used in integration tests.
+
+int main() {
+ std::seed_seq seed_seq{};
+ absl::BitGen rng(seed_seq);
+ constexpr size_t kSequenceLength = 8;
+ for (size_t i = 0; i < kSequenceLength; i++) {
+ std::cout << rng() << "\n";
+ }
+ return 0;
+}
diff --git a/absl/random/internal/sequence_urbg.h b/absl/random/internal/sequence_urbg.h
new file mode 100644
index 00000000..cec0bf9b
--- /dev/null
+++ b/absl/random/internal/sequence_urbg.h
@@ -0,0 +1,58 @@
+// 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_SEQUENCE_URBG_H_
+#define ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_
+
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+#include <vector>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// `sequence_urbg` is a simple random number generator which meets the
+// requirements of [rand.req.urbg], and is solely for testing absl
+// distributions.
+class sequence_urbg {
+ public:
+ using result_type = uint64_t;
+
+ static constexpr result_type(min)() {
+ return (std::numeric_limits<result_type>::min)();
+ }
+ static constexpr result_type(max)() {
+ return (std::numeric_limits<result_type>::max)();
+ }
+
+ sequence_urbg(std::initializer_list<result_type> data) : i_(0), data_(data) {}
+ void reset() { i_ = 0; }
+
+ result_type operator()() { return data_[i_++ % data_.size()]; }
+
+ size_t invocations() const { return i_; }
+
+ private:
+ size_t i_;
+ std::vector<result_type> data_;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_SEQUENCE_URBG_H_
diff --git a/absl/random/internal/traits.h b/absl/random/internal/traits.h
new file mode 100644
index 00000000..9f7d126c
--- /dev/null
+++ b/absl/random/internal/traits.h
@@ -0,0 +1,101 @@
+// 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_TRAITS_H_
+#define ABSL_RANDOM_INTERNAL_TRAITS_H_
+
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#include "absl/base/config.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace random_internal {
+
+// random_internal::is_widening_convertible<A, B>
+//
+// Returns whether a type A is widening-convertible to a type B.
+//
+// A is widening-convertible to B means:
+// A a = <any number>;
+// B b = a;
+// A c = b;
+// EXPECT_EQ(a, c);
+template <typename A, typename B>
+class is_widening_convertible {
+ // As long as there are enough bits in the exact part of a number:
+ // - unsigned can fit in float, signed, unsigned
+ // - signed can fit in float, signed
+ // - float can fit in float
+ // So we define rank to be:
+ // - rank(float) -> 2
+ // - rank(signed) -> 1
+ // - rank(unsigned) -> 0
+ template <class T>
+ static constexpr int rank() {
+ return !std::numeric_limits<T>::is_integer +
+ std::numeric_limits<T>::is_signed;
+ }
+
+ public:
+ // If an arithmetic-type B can represent at least as many digits as a type A,
+ // and B belongs to a rank no lower than A, then A can be safely represented
+ // by B through a widening-conversion.
+ static constexpr bool value =
+ std::numeric_limits<A>::digits <= std::numeric_limits<B>::digits &&
+ rank<A>() <= rank<B>();
+};
+
+// unsigned_bits<N>::type returns the unsigned int type with the indicated
+// number of bits.
+template <size_t N>
+struct unsigned_bits;
+
+template <>
+struct unsigned_bits<8> {
+ using type = uint8_t;
+};
+template <>
+struct unsigned_bits<16> {
+ using type = uint16_t;
+};
+template <>
+struct unsigned_bits<32> {
+ using type = uint32_t;
+};
+template <>
+struct unsigned_bits<64> {
+ using type = uint64_t;
+};
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+template <>
+struct unsigned_bits<128> {
+ using type = __uint128_t;
+};
+#endif
+
+template <typename IntType>
+struct make_unsigned_bits {
+ using type = typename unsigned_bits<std::numeric_limits<
+ typename std::make_unsigned<IntType>::type>::digits>::type;
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_TRAITS_H_
diff --git a/absl/random/internal/traits_test.cc b/absl/random/internal/traits_test.cc
new file mode 100644
index 00000000..a844887d
--- /dev/null
+++ b/absl/random/internal/traits_test.cc
@@ -0,0 +1,126 @@
+// 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/traits.h"
+
+#include <cstdint>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+using absl::random_internal::is_widening_convertible;
+
+// CheckWideningConvertsToSelf<T1, T2, ...>()
+//
+// For each type T, checks:
+// - T IS widening-convertible to itself.
+//
+template <typename T>
+void CheckWideningConvertsToSelf() {
+ static_assert(is_widening_convertible<T, T>::value,
+ "Type is not convertible to self!");
+}
+
+template <typename T, typename Next, typename... Args>
+void CheckWideningConvertsToSelf() {
+ CheckWideningConvertsToSelf<T>();
+ CheckWideningConvertsToSelf<Next, Args...>();
+}
+
+// CheckNotWideningConvertibleWithSigned<T1, T2, ...>()
+//
+// For each unsigned-type T, checks that:
+// - T is NOT widening-convertible to Signed(T)
+// - Signed(T) is NOT widening-convertible to T
+//
+template <typename T>
+void CheckNotWideningConvertibleWithSigned() {
+ using signed_t = typename std::make_signed<T>::type;
+
+ static_assert(!is_widening_convertible<T, signed_t>::value,
+ "Unsigned type is convertible to same-sized signed-type!");
+ static_assert(!is_widening_convertible<signed_t, T>::value,
+ "Signed type is convertible to same-sized unsigned-type!");
+}
+
+template <typename T, typename Next, typename... Args>
+void CheckNotWideningConvertibleWithSigned() {
+ CheckNotWideningConvertibleWithSigned<T>();
+ CheckWideningConvertsToSelf<Next, Args...>();
+}
+
+// CheckWideningConvertsToLargerType<T1, T2, ...>()
+//
+// For each successive unsigned-types {Ti, Ti+1}, checks that:
+// - Ti IS widening-convertible to Ti+1
+// - Ti IS widening-convertible to Signed(Ti+1)
+// - Signed(Ti) is NOT widening-convertible to Ti
+// - Signed(Ti) IS widening-convertible to Ti+1
+template <typename T, typename Higher>
+void CheckWideningConvertsToLargerTypes() {
+ using signed_t = typename std::make_signed<T>::type;
+ using higher_t = Higher;
+ using signed_higher_t = typename std::make_signed<Higher>::type;
+
+ static_assert(is_widening_convertible<T, higher_t>::value,
+ "Type not embeddable into larger type!");
+ static_assert(is_widening_convertible<T, signed_higher_t>::value,
+ "Type not embeddable into larger signed type!");
+ static_assert(!is_widening_convertible<signed_t, higher_t>::value,
+ "Signed type is embeddable into larger unsigned type!");
+ static_assert(is_widening_convertible<signed_t, signed_higher_t>::value,
+ "Signed type not embeddable into larger signed type!");
+}
+
+template <typename T, typename Higher, typename Next, typename... Args>
+void CheckWideningConvertsToLargerTypes() {
+ CheckWideningConvertsToLargerTypes<T, Higher>();
+ CheckWideningConvertsToLargerTypes<Higher, Next, Args...>();
+}
+
+// CheckWideningConvertsTo<T, U, [expect]>
+//
+// Checks that T DOES widening-convert to U.
+// If "expect" is false, then asserts that T does NOT widening-convert to U.
+template <typename T, typename U, bool expect = true>
+void CheckWideningConvertsTo() {
+ static_assert(is_widening_convertible<T, U>::value == expect,
+ "Unexpected result for is_widening_convertible<T, U>!");
+}
+
+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>();
+
+ CheckWideningConvertsTo<float, double>();
+ CheckWideningConvertsTo<uint16_t, float>();
+ CheckWideningConvertsTo<uint32_t, double>();
+ CheckWideningConvertsTo<uint64_t, double, kInvalid>();
+ CheckWideningConvertsTo<double, float, kInvalid>();
+
+ CheckWideningConvertsTo<bool, int>();
+ CheckWideningConvertsTo<bool, float>();
+}
+
+} // namespace
diff --git a/absl/random/internal/uniform_helper.h b/absl/random/internal/uniform_helper.h
new file mode 100644
index 00000000..6af053ef
--- /dev/null
+++ b/absl/random/internal/uniform_helper.h
@@ -0,0 +1,152 @@
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
+#define ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
+
+#include <cmath>
+#include <limits>
+#include <type_traits>
+
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+template <typename IntType>
+class uniform_int_distribution;
+
+template <typename RealType>
+class uniform_real_distribution;
+
+// Interval tag types which specify whether the interval is open or closed
+// on either boundary.
+namespace random_internal {
+struct IntervalClosedClosedT {};
+struct IntervalClosedOpenT {};
+struct IntervalOpenClosedT {};
+struct IntervalOpenOpenT {};
+} // namespace random_internal
+
+namespace random_internal {
+
+// The functions
+// uniform_lower_bound(tag, a, b)
+// and
+// uniform_upper_bound(tag, a, b)
+// are used as implementation-details for absl::Uniform().
+//
+// Conceptually,
+// [a, b] == [uniform_lower_bound(IntervalClosedClosed, a, b),
+// uniform_upper_bound(IntervalClosedClosed, a, b)]
+// (a, b) == [uniform_lower_bound(IntervalOpenOpen, a, b),
+// uniform_upper_bound(IntervalOpenOpen, a, b)]
+// [a, b) == [uniform_lower_bound(IntervalClosedOpen, a, b),
+// uniform_upper_bound(IntervalClosedOpen, a, b)]
+// (a, b] == [uniform_lower_bound(IntervalOpenClosed, a, b),
+// uniform_upper_bound(IntervalOpenClosed, a, b)]
+//
+template <typename IntType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_integral<IntType>,
+ absl::disjunction<std::is_same<Tag, IntervalOpenClosedT>,
+ std::is_same<Tag, IntervalOpenOpenT>>>::value,
+ IntType>
+uniform_lower_bound(Tag, IntType a, IntType) {
+ return a + 1;
+}
+
+template <typename FloatType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_floating_point<FloatType>,
+ absl::disjunction<std::is_same<Tag, IntervalOpenClosedT>,
+ std::is_same<Tag, IntervalOpenOpenT>>>::value,
+ FloatType>
+uniform_lower_bound(Tag, FloatType a, FloatType b) {
+ return std::nextafter(a, b);
+}
+
+template <typename NumType, typename Tag>
+typename absl::enable_if_t<
+ absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
+ std::is_same<Tag, IntervalClosedOpenT>>::value,
+ NumType>
+uniform_lower_bound(Tag, NumType a, NumType) {
+ return a;
+}
+
+template <typename IntType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_integral<IntType>,
+ absl::disjunction<std::is_same<Tag, IntervalClosedOpenT>,
+ std::is_same<Tag, IntervalOpenOpenT>>>::value,
+ IntType>
+uniform_upper_bound(Tag, IntType, IntType b) {
+ return b - 1;
+}
+
+template <typename FloatType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_floating_point<FloatType>,
+ absl::disjunction<std::is_same<Tag, IntervalClosedOpenT>,
+ std::is_same<Tag, IntervalOpenOpenT>>>::value,
+ FloatType>
+uniform_upper_bound(Tag, FloatType, FloatType b) {
+ return b;
+}
+
+template <typename IntType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_integral<IntType>,
+ absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
+ std::is_same<Tag, IntervalOpenClosedT>>>::value,
+ IntType>
+uniform_upper_bound(Tag, IntType, IntType b) {
+ return b;
+}
+
+template <typename FloatType, typename Tag>
+typename absl::enable_if_t<
+ absl::conjunction<
+ std::is_floating_point<FloatType>,
+ absl::disjunction<std::is_same<Tag, IntervalClosedClosedT>,
+ std::is_same<Tag, IntervalOpenClosedT>>>::value,
+ FloatType>
+uniform_upper_bound(Tag, FloatType, FloatType b) {
+ return std::nextafter(b, (std::numeric_limits<FloatType>::max)());
+}
+
+template <typename NumType>
+using UniformDistribution =
+ typename std::conditional<std::is_integral<NumType>::value,
+ absl::uniform_int_distribution<NumType>,
+ absl::uniform_real_distribution<NumType>>::type;
+
+template <typename TagType, typename NumType>
+struct UniformDistributionWrapper : public UniformDistribution<NumType> {
+ explicit UniformDistributionWrapper(NumType lo, NumType hi)
+ : UniformDistribution<NumType>(
+ uniform_lower_bound<NumType>(TagType{}, lo, hi),
+ uniform_upper_bound<NumType>(TagType{}, lo, hi)) {}
+};
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_INTERNAL_UNIFORM_HELPER_H_
diff --git a/absl/random/log_uniform_int_distribution.h b/absl/random/log_uniform_int_distribution.h
new file mode 100644
index 00000000..a12fa4cb
--- /dev/null
+++ b/absl/random/log_uniform_int_distribution.h
@@ -0,0 +1,252 @@
+// 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_LOG_UNIFORM_INT_DISTRIBUTION_H_
+#define ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/iostream_state_saver.h"
+#include "absl/random/internal/traits.h"
+#include "absl/random/uniform_int_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// log_uniform_int_distribution:
+//
+// Returns a random variate R in range [min, max] such that
+// floor(log(R-min, base)) is uniformly distributed.
+// We ensure uniformity by discretization using the
+// boundary sets [0, 1, base, base * base, ... min(base*n, max)]
+//
+template <typename IntType = int>
+class log_uniform_int_distribution {
+ private:
+ using unsigned_type =
+ typename random_internal::make_unsigned_bits<IntType>::type;
+
+ public:
+ using result_type = IntType;
+
+ class param_type {
+ public:
+ using distribution_type = log_uniform_int_distribution;
+
+ explicit param_type(
+ result_type min = 0,
+ result_type max = (std::numeric_limits<result_type>::max)(),
+ result_type base = 2)
+ : min_(min),
+ max_(max),
+ base_(base),
+ range_(static_cast<unsigned_type>(max_) -
+ static_cast<unsigned_type>(min_)),
+ log_range_(0) {
+ assert(max_ >= min_);
+ assert(base_ > 1);
+
+ if (base_ == 2) {
+ // Determine where the first set bit is on range(), giving a log2(range)
+ // value which can be used to construct bounds.
+ log_range_ = (std::min)(random_internal::LeadingSetBit(range()),
+ std::numeric_limits<unsigned_type>::digits);
+ } else {
+ // NOTE: Computing the logN(x) introduces error from 2 sources:
+ // 1. Conversion of int to double loses precision for values >=
+ // 2^53, which may cause some log() computations to operate on
+ // different values.
+ // 2. The error introduced by the division will cause the result
+ // to differ from the expected value.
+ //
+ // Thus a result which should equal K may equal K +/- epsilon,
+ // which can eliminate some values depending on where the bounds fall.
+ const double inv_log_base = 1.0 / std::log(base_);
+ const double log_range = std::log(static_cast<double>(range()) + 0.5);
+ log_range_ = static_cast<int>(std::ceil(inv_log_base * log_range));
+ }
+ }
+
+ result_type(min)() const { return min_; }
+ result_type(max)() const { return max_; }
+ result_type base() const { return base_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.min_ == b.min_ && a.max_ == b.max_ && a.base_ == b.base_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class log_uniform_int_distribution;
+
+ int log_range() const { return log_range_; }
+ unsigned_type range() const { return range_; }
+
+ result_type min_;
+ result_type max_;
+ result_type base_;
+ unsigned_type range_; // max - min
+ int log_range_; // ceil(logN(range_))
+
+ static_assert(std::is_integral<IntType>::value,
+ "Class-template absl::log_uniform_int_distribution<> must be "
+ "parameterized using an integral type.");
+ };
+
+ log_uniform_int_distribution() : log_uniform_int_distribution(0) {}
+
+ explicit log_uniform_int_distribution(
+ result_type min,
+ result_type max = (std::numeric_limits<result_type>::max)(),
+ result_type base = 2)
+ : param_(min, max, base) {}
+
+ explicit log_uniform_int_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ // generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ return (p.min)() + Generate(g, p);
+ }
+
+ result_type(min)() const { return (param_.min)(); }
+ result_type(max)() const { return (param_.max)(); }
+ result_type base() const { return param_.base(); }
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ friend bool operator==(const log_uniform_int_distribution& a,
+ const log_uniform_int_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const log_uniform_int_distribution& a,
+ const log_uniform_int_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ // Returns a log-uniform variate in the range [0, p.range()]. The caller
+ // should add min() to shift the result to the correct range.
+ template <typename URNG>
+ unsigned_type Generate(URNG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ param_type param_;
+};
+
+template <typename IntType>
+template <typename URBG>
+typename log_uniform_int_distribution<IntType>::unsigned_type
+log_uniform_int_distribution<IntType>::Generate(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ // sample e over [0, log_range]. Map the results of e to this:
+ // 0 => 0
+ // 1 => [1, b-1]
+ // 2 => [b, (b^2)-1]
+ // n => [b^(n-1)..(b^n)-1]
+ const int e = absl::uniform_int_distribution<int>(0, p.log_range())(g);
+ if (e == 0) {
+ return 0;
+ }
+ const int d = e - 1;
+
+ unsigned_type base_e, top_e;
+ if (p.base() == 2) {
+ base_e = static_cast<unsigned_type>(1) << d;
+
+ top_e = (e >= std::numeric_limits<unsigned_type>::digits)
+ ? (std::numeric_limits<unsigned_type>::max)()
+ : (static_cast<unsigned_type>(1) << e) - 1;
+ } else {
+ const double r = std::pow(p.base(), d);
+ const double s = (r * p.base()) - 1.0;
+
+ base_e = (r > (std::numeric_limits<unsigned_type>::max)())
+ ? (std::numeric_limits<unsigned_type>::max)()
+ : static_cast<unsigned_type>(r);
+
+ top_e = (s > (std::numeric_limits<unsigned_type>::max)())
+ ? (std::numeric_limits<unsigned_type>::max)()
+ : static_cast<unsigned_type>(s);
+ }
+
+ const unsigned_type lo = (base_e >= p.range()) ? p.range() : base_e;
+ const unsigned_type hi = (top_e >= p.range()) ? p.range() : top_e;
+
+ // choose uniformly over [lo, hi]
+ return absl::uniform_int_distribution<result_type>(lo, hi)(g);
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const log_uniform_int_distribution<IntType>& x) {
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os << static_cast<stream_type>((x.min)()) << os.fill()
+ << static_cast<stream_type>((x.max)()) << os.fill()
+ << static_cast<stream_type>(x.base());
+ return os;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ log_uniform_int_distribution<IntType>& x) { // NOLINT(runtime/references)
+ using param_type = typename log_uniform_int_distribution<IntType>::param_type;
+ using result_type =
+ typename log_uniform_int_distribution<IntType>::result_type;
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+
+ stream_type min;
+ stream_type max;
+ stream_type base;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ is >> min >> max >> base;
+ if (!is.fail()) {
+ x.param(param_type(static_cast<result_type>(min),
+ static_cast<result_type>(max),
+ static_cast<result_type>(base)));
+ }
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_LOG_UNIFORM_INT_DISTRIBUTION_H_
diff --git a/absl/random/log_uniform_int_distribution_test.cc b/absl/random/log_uniform_int_distribution_test.cc
new file mode 100644
index 00000000..0ff4c32d
--- /dev/null
+++ b/absl/random/log_uniform_int_distribution_test.cc
@@ -0,0 +1,277 @@
+// 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/log_uniform_int_distribution.h"
+
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+template <typename IntType>
+class LogUniformIntDistributionTypeTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<int8_t, int16_t, int32_t, int64_t, //
+ uint8_t, uint16_t, uint32_t, uint64_t>;
+TYPED_TEST_CASE(LogUniformIntDistributionTypeTest, IntTypes);
+
+TYPED_TEST(LogUniformIntDistributionTypeTest, SerializeTest) {
+ using param_type =
+ typename absl::log_uniform_int_distribution<TypeParam>::param_type;
+ using Limits = std::numeric_limits<TypeParam>;
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ for (const auto& param : {
+ param_type(0, 1), //
+ param_type(0, 2), //
+ param_type(0, 2, 10), //
+ param_type(9, 32, 4), //
+ param_type(1, 101, 10), //
+ param_type(1, Limits::max() / 2), //
+ param_type(0, Limits::max() - 1), //
+ param_type(0, Limits::max(), 2), //
+ param_type(0, Limits::max(), 10), //
+ param_type(Limits::min(), 0), //
+ param_type(Limits::lowest(), Limits::max()), //
+ param_type(Limits::min(), Limits::max()), //
+ }) {
+ // Validate parameters.
+ const auto min = param.min();
+ const auto max = param.max();
+ const auto base = param.base();
+ absl::log_uniform_int_distribution<TypeParam> before(min, max, base);
+ EXPECT_EQ(before.min(), param.min());
+ EXPECT_EQ(before.max(), param.max());
+ EXPECT_EQ(before.base(), param.base());
+
+ {
+ absl::log_uniform_int_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ }
+
+ // Validate stream serialization.
+ std::stringstream ss;
+ ss << before;
+
+ absl::log_uniform_int_distribution<TypeParam> after(3, 6, 17);
+
+ EXPECT_NE(before.max(), after.max());
+ EXPECT_NE(before.base(), after.base());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.min(), after.min());
+ EXPECT_EQ(before.max(), after.max());
+ EXPECT_EQ(before.base(), after.base());
+ EXPECT_EQ(before.param(), after.param());
+ EXPECT_EQ(before, after);
+
+ // Smoke test.
+ auto sample_min = after.max();
+ auto sample_max = after.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = after(gen);
+ EXPECT_GE(sample, after.min());
+ EXPECT_LE(sample, after.max());
+ if (sample > sample_max) sample_max = sample;
+ if (sample < sample_min) sample_min = sample;
+ }
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("Range: ", +sample_min, ", ", +sample_max));
+ }
+}
+
+using log_uniform_i32 = absl::log_uniform_int_distribution<int32_t>;
+
+class LogUniformIntChiSquaredTest
+ : public testing::TestWithParam<log_uniform_i32::param_type> {
+ public:
+ // The ChiSquaredTestImpl provides a chi-squared goodness of fit test for
+ // data generated by the log-uniform-int distribution.
+ double ChiSquaredTestImpl();
+
+ absl::InsecureBitGen rng_;
+};
+
+double LogUniformIntChiSquaredTest::ChiSquaredTestImpl() {
+ using absl::random_internal::kChiSquared;
+
+ const auto& param = GetParam();
+
+ // Check the distribution of L=log(log_uniform_int_distribution, base),
+ // expecting that L is roughly uniformly distributed, that is:
+ //
+ // P[L=0] ~= P[L=1] ~= ... ~= P[L=log(max)]
+ //
+ // For a total of X entries, each bucket should contain some number of samples
+ // in the interval [X/k - a, X/k + a].
+ //
+ // Where `a` is approximately sqrt(X/k). This is validated by bucketing
+ // according to the log function and using a chi-squared test for uniformity.
+
+ const bool is_2 = (param.base() == 2);
+ const double base_log = 1.0 / std::log(param.base());
+ const auto bucket_index = [base_log, is_2, &param](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);
+ };
+ const int max_bucket = bucket_index(param.max()); // inclusive
+ const size_t trials = 15 + (max_bucket + 1) * 10;
+
+ log_uniform_i32 dist(param);
+
+ std::vector<int64_t> buckets(max_bucket + 1);
+ for (size_t i = 0; i < trials; ++i) {
+ const auto sample = dist(rng_);
+ // Check the bounds.
+ ABSL_ASSERT(sample <= dist.max());
+ ABSL_ASSERT(sample >= dist.min());
+ // Convert the output of the generator to one of num_bucket buckets.
+ int bucket = bucket_index(sample);
+ ABSL_ASSERT(bucket <= max_bucket);
+ ++buckets[bucket];
+ }
+
+ // The null-hypothesis is that the distribution is uniform with respect to
+ // log-uniform-int bucketization.
+ const int dof = buckets.size() - 1;
+ const double expected = trials / static_cast<double>(buckets.size());
+
+ const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
+
+ double chi_square = absl::random_internal::ChiSquareWithExpected(
+ std::begin(buckets), std::end(buckets), expected);
+
+ const double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
+
+ if (chi_square > threshold) {
+ ABSL_INTERNAL_LOG(INFO, "values");
+ for (size_t i = 0; i < buckets.size(); i++) {
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat(i, ": ", buckets[i]));
+ }
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrFormat("trials=%d\n"
+ "%s(data, %d) = %f (%f)\n"
+ "%s @ 0.98 = %f",
+ trials, kChiSquared, dof, chi_square, p,
+ kChiSquared, threshold));
+ }
+ return p;
+}
+
+TEST_P(LogUniformIntChiSquaredTest, MultiTest) {
+ const int kTrials = 5;
+
+ int failures = 0;
+ for (int i = 0; i < kTrials; i++) {
+ double p_value = ChiSquaredTestImpl();
+ if (p_value < 0.005) {
+ failures++;
+ }
+ }
+
+ // There is a 0.10% chance of producing at least one failure, so raise the
+ // failure threshold high enough to allow for a flake rate < 10,000.
+ EXPECT_LE(failures, 4);
+}
+
+// Generate the parameters for the test.
+std::vector<log_uniform_i32::param_type> GenParams() {
+ using Param = log_uniform_i32::param_type;
+ using Limits = std::numeric_limits<int32_t>;
+
+ return std::vector<Param>{
+ Param{0, 1, 2},
+ Param{1, 1, 2},
+ Param{0, 2, 2},
+ Param{0, 3, 2},
+ Param{0, 4, 2},
+ Param{0, 9, 10},
+ Param{0, 10, 10},
+ Param{0, 11, 10},
+ Param{1, 10, 10},
+ Param{0, (1 << 8) - 1, 2},
+ Param{0, (1 << 8), 2},
+ Param{0, (1 << 30) - 1, 2},
+ Param{-1000, 1000, 10},
+ Param{0, Limits::max(), 2},
+ Param{0, Limits::max(), 3},
+ Param{0, Limits::max(), 10},
+ Param{Limits::min(), 0},
+ Param{Limits::min(), Limits::max(), 2},
+ };
+}
+
+std::string ParamName(
+ const ::testing::TestParamInfo<log_uniform_i32::param_type>& info) {
+ const auto& p = info.param;
+ std::string name =
+ absl::StrCat("min_", p.min(), "__max_", p.max(), "__base_", p.base());
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_SUITE_P(, LogUniformIntChiSquaredTest,
+ ::testing::ValuesIn(GenParams()), ParamName);
+
+// NOTE: absl::log_uniform_int_distribution is not guaranteed to be stable.
+TEST(LogUniformIntDistributionTest, StabilityTest) {
+ using testing::ElementsAre;
+ // absl::uniform_int_distribution stability relies on
+ // absl::random_internal::LeadingSetBit, std::log, std::pow.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(6);
+
+ {
+ absl::log_uniform_int_distribution<int32_t> dist(0, 256);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ EXPECT_THAT(output, ElementsAre(256, 66, 4, 6, 57, 103));
+ }
+ urbg.reset();
+ {
+ absl::log_uniform_int_distribution<int32_t> dist(0, 256, 10);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ EXPECT_THAT(output, ElementsAre(8, 4, 0, 0, 0, 69));
+ }
+}
+
+} // namespace
diff --git a/absl/random/poisson_distribution.h b/absl/random/poisson_distribution.h
new file mode 100644
index 00000000..66c75091
--- /dev/null
+++ b/absl/random/poisson_distribution.h
@@ -0,0 +1,256 @@
+// 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_POISSON_DISTRIBUTION_H_
+#define ABSL_RANDOM_POISSON_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/fastmath.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::poisson_distribution:
+// Generates discrete variates conforming to a Poisson distribution.
+// p(n) = (mean^n / n!) exp(-mean)
+//
+// Depending on the parameter, the distribution selects one of the following
+// algorithms:
+// * The standard algorithm, attributed to Knuth, extended using a split method
+// for larger values
+// * The "Ratio of Uniforms as a convenient method for sampling from classical
+// discrete distributions", Stadlober, 1989.
+// http://www.sciencedirect.com/science/article/pii/0377042790903495
+//
+// NOTE: param_type.mean() is a double, which permits values larger than
+// poisson_distribution<IntType>::max(), however this should be avoided and
+// 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>.
+//
+template <typename IntType = int>
+class poisson_distribution {
+ public:
+ using result_type = IntType;
+
+ class param_type {
+ public:
+ using distribution_type = poisson_distribution;
+ explicit param_type(double mean = 1.0);
+
+ double mean() const { return mean_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.mean_ == b.mean_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class poisson_distribution;
+
+ double mean_;
+ double emu_; // e ^ -mean_
+ double lmu_; // ln(mean_)
+ double s_;
+ double log_k_;
+ int split_;
+
+ static_assert(std::is_integral<IntType>::value,
+ "Class-template absl::poisson_distribution<> must be "
+ "parameterized using an integral type.");
+ };
+
+ poisson_distribution() : poisson_distribution(1.0) {}
+
+ explicit poisson_distribution(double mean) : param_(mean) {}
+
+ explicit poisson_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ // generating functions
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const { return 0; }
+ result_type(max)() const { return (std::numeric_limits<result_type>::max)(); }
+
+ double mean() const { return param_.mean(); }
+
+ friend bool operator==(const poisson_distribution& a,
+ const poisson_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const poisson_distribution& a,
+ const poisson_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+ random_internal::FastUniformBits<uint64_t> fast_u64_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation details follow
+// -----------------------------------------------------------------------------
+
+template <typename IntType>
+poisson_distribution<IntType>::param_type::param_type(double mean)
+ : mean_(mean), split_(0) {
+ assert(mean >= 0);
+ assert(mean <= (std::numeric_limits<result_type>::max)());
+ // As a defensive measure, avoid large values of the mean. The rejection
+ // algorithm used does not support very large values well. It my be worth
+ // changing algorithms to better deal with these cases.
+ assert(mean <= 1e10);
+ if (mean_ < 10) {
+ // For small lambda, use the knuth method.
+ split_ = 1;
+ emu_ = std::exp(-mean_);
+ } else if (mean_ <= 50) {
+ // Use split-knuth method.
+ split_ = 1 + static_cast<int>(mean_ / 10.0);
+ emu_ = std::exp(-mean_ / static_cast<double>(split_));
+ } else {
+ // Use ratio of uniforms method.
+ constexpr double k2E = 0.7357588823428846;
+ constexpr double kSA = 0.4494580810294493;
+
+ lmu_ = std::log(mean_);
+ double a = mean_ + 0.5;
+ s_ = kSA + std::sqrt(k2E * a);
+ const double mode = std::ceil(mean_) - 1;
+ log_k_ = lmu_ * mode - absl::random_internal::StirlingLogFactorial(mode);
+ }
+}
+
+template <typename IntType>
+template <typename URBG>
+typename poisson_distribution<IntType>::result_type
+poisson_distribution<IntType>::operator()(
+ URBG& g, // NOLINT(runtime/references)
+ const param_type& p) {
+ using random_internal::PositiveValueT;
+ using random_internal::RandU64ToDouble;
+ using random_internal::SignedValueT;
+
+ if (p.split_ != 0) {
+ // Use Knuth's algorithm with range splitting to avoid floating-point
+ // errors. Knuth's algorithm is: Ui is a sequence of uniform variates on
+ // (0,1); return the number of variates required for product(Ui) <
+ // exp(-lambda).
+ //
+ // The expected number of variates required for Knuth's method can be
+ // computed as follows:
+ // The expected value of U is 0.5, so solving for 0.5^n < exp(-lambda) gives
+ // the expected number of uniform variates
+ // required for a given lambda, which is:
+ // lambda = [2, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17]
+ // n = [3, 8, 13, 15, 16, 18, 19, 21, 22, 24, 25]
+ //
+ result_type n = 0;
+ for (int split = p.split_; split > 0; --split) {
+ double r = 1.0;
+ do {
+ r *= RandU64ToDouble<PositiveValueT, true>(fast_u64_(g));
+ ++n;
+ } while (r > p.emu_);
+ --n;
+ }
+ return n;
+ }
+
+ // Use ratio of uniforms method.
+ //
+ // Let u ~ Uniform(0, 1), v ~ Uniform(-1, 1),
+ // a = lambda + 1/2,
+ // s = 1.5 - sqrt(3/e) + sqrt(2(lambda + 1/2)/e),
+ // x = s * v/u + a.
+ // P(floor(x) = k | u^2 < f(floor(x))/k), where
+ // f(m) = lambda^m exp(-lambda)/ m!, for 0 <= m, and f(m) = 0 otherwise,
+ // and k = max(f).
+ const double a = p.mean_ + 0.5;
+ for (;;) {
+ const double u =
+ RandU64ToDouble<PositiveValueT, false>(fast_u64_(g)); // (0, 1)
+ const double v =
+ RandU64ToDouble<SignedValueT, false>(fast_u64_(g)); // (-1, 1)
+ const double x = std::floor(p.s_ * v / u + a);
+ if (x < 0) continue; // f(negative) = 0
+ const double rhs = x * p.lmu_;
+ // clang-format off
+ double s = (x <= 1.0) ? 0.0
+ : (x == 2.0) ? 0.693147180559945
+ : absl::random_internal::StirlingLogFactorial(x);
+ // clang-format on
+ const double lhs = 2.0 * std::log(u) + p.log_k_ + s;
+ if (lhs < rhs) {
+ return x > (max)() ? (max)()
+ : static_cast<result_type>(x); // f(x)/k >= u^2
+ }
+ }
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const poisson_distribution<IntType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<double>::kPrecision);
+ os << x.mean();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ poisson_distribution<IntType>& x) { // NOLINT(runtime/references)
+ using param_type = typename poisson_distribution<IntType>::param_type;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ double mean = random_internal::read_floating_point<double>(is);
+ if (!is.fail()) {
+ x.param(param_type(mean));
+ }
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_POISSON_DISTRIBUTION_H_
diff --git a/absl/random/poisson_distribution_test.cc b/absl/random/poisson_distribution_test.cc
new file mode 100644
index 00000000..6d68999a
--- /dev/null
+++ b/absl/random/poisson_distribution_test.cc
@@ -0,0 +1,565 @@
+// 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/poisson_distribution.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/base/macros.h"
+#include "absl/container/flat_hash_map.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+// Notes about generating poisson variates:
+//
+// It is unlikely that any implementation of std::poisson_distribution
+// will be stable over time and across library implementations. For instance
+// the three different poisson variate generators listed below all differ:
+//
+// https://github.com/ampl/gsl/tree/master/randist/poisson.c
+// * GSL uses a gamma + binomial + knuth method to compute poisson variates.
+//
+// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/random.tcc
+// * GCC uses the Devroye rejection algorithm, based on
+// Devroye, L. Non-Uniform Random Variates Generation. Springer-Verlag,
+// New York, 1986, Ch. X, Sects. 3.3 & 3.4 (+ Errata!), ~p.511
+// http://www.nrbook.com/devroye/
+//
+// https://github.com/llvm-mirror/libcxx/blob/master/include/random
+// * CLANG uses a different rejection method, which appears to include a
+// normal-distribution approximation and an exponential distribution to
+// compute the threshold, including a similar factorial approximation to this
+// one, but it is unclear where the algorithm comes from, exactly.
+//
+
+namespace {
+
+using absl::random_internal::kChiSquared;
+
+// The PoissonDistributionInterfaceTest provides a basic test that
+// absl::poisson_distribution conforms to the interface and serialization
+// requirements imposed by [rand.req.dist] for the common integer types.
+
+template <typename IntType>
+class PoissonDistributionInterfaceTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<int, int8_t, int16_t, int32_t, int64_t,
+ uint8_t, uint16_t, uint32_t, uint64_t>;
+TYPED_TEST_CASE(PoissonDistributionInterfaceTest, IntTypes);
+
+TYPED_TEST(PoissonDistributionInterfaceTest, SerializeTest) {
+ using param_type = typename absl::poisson_distribution<TypeParam>::param_type;
+ const double kMax =
+ std::min(1e10 /* assertion limit */,
+ static_cast<double>(std::numeric_limits<TypeParam>::max()));
+
+ const double kParams[] = {
+ // Cases around 1.
+ 1, //
+ std::nextafter(1.0, 0.0), // 1 - epsilon
+ std::nextafter(1.0, 2.0), // 1 + epsilon
+ // Arbitrary values.
+ 1e-8, 1e-4,
+ 0.0000005, // ~7.2e-7
+ 0.2, // ~0.2x
+ 0.5, // 0.72
+ 2, // ~2.8
+ 20, // 3x ~9.6
+ 100, 1e4, 1e8, 1.5e9, 1e20,
+ // Boundary cases.
+ std::numeric_limits<double>::max(),
+ std::numeric_limits<double>::epsilon(),
+ std::nextafter(std::numeric_limits<double>::min(),
+ 1.0), // min + epsilon
+ std::numeric_limits<double>::min(), // smallest normal
+ std::numeric_limits<double>::denorm_min(), // smallest denorm
+ std::numeric_limits<double>::min() / 2, // denorm
+ std::nextafter(std::numeric_limits<double>::min(),
+ 0.0), // denorm_max
+ };
+
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ for (const double m : kParams) {
+ const double mean = std::min(kMax, m);
+ const param_type param(mean);
+
+ // Validate parameters.
+ absl::poisson_distribution<TypeParam> before(mean);
+ EXPECT_EQ(before.mean(), param.mean());
+
+ {
+ absl::poisson_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ EXPECT_EQ(via_param.param(), before.param());
+ }
+
+ // Smoke test.
+ auto sample_min = before.max();
+ auto sample_max = before.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = before(gen);
+ EXPECT_GE(sample, before.min());
+ EXPECT_LE(sample, before.max());
+ if (sample > sample_max) sample_max = sample;
+ if (sample < sample_min) sample_min = sample;
+ }
+
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat("Range {", param.mean(), "}: ",
+ +sample_min, ", ", +sample_max));
+
+ // Validate stream serialization.
+ std::stringstream ss;
+ ss << before;
+
+ absl::poisson_distribution<TypeParam> after(3.8);
+
+ EXPECT_NE(before.mean(), after.mean());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.mean(), after.mean()) //
+ << ss.str() << " " //
+ << (ss.good() ? "good " : "") //
+ << (ss.bad() ? "bad " : "") //
+ << (ss.eof() ? "eof " : "") //
+ << (ss.fail() ? "fail " : "");
+ }
+}
+
+// See http://www.itl.nist.gov/div898/handbook/eda/section3/eda366j.htm
+
+class PoissonModel {
+ public:
+ explicit PoissonModel(double mean) : mean_(mean) {}
+
+ double mean() const { return mean_; }
+ double variance() const { return mean_; }
+ double stddev() const { return std::sqrt(variance()); }
+ double skew() const { return 1.0 / mean_; }
+ double kurtosis() const { return 3.0 + 1.0 / mean_; }
+
+ // InitCDF() initializes the CDF for the distribution parameters.
+ void InitCDF();
+
+ // The InverseCDF, or the Percent-point function returns x, P(x) < v.
+ struct CDF {
+ size_t index;
+ double pmf;
+ double cdf;
+ };
+ CDF InverseCDF(double p) {
+ CDF target{0, 0, p};
+ auto it = std::upper_bound(
+ std::begin(cdf_), std::end(cdf_), target,
+ [](const CDF& a, const CDF& b) { return a.cdf < b.cdf; });
+ return *it;
+ }
+
+ void LogCDF() {
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat("CDF (mean = ", mean_, ")"));
+ for (const auto c : cdf_) {
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat(c.index, ": pmf=", c.pmf, " cdf=", c.cdf));
+ }
+ }
+
+ private:
+ const double mean_;
+
+ std::vector<CDF> cdf_;
+};
+
+// The goal is to compute an InverseCDF function, or percent point function for
+// the poisson distribution, and use that to partition our output into equal
+// range buckets. However there is no closed form solution for the inverse cdf
+// for poisson distributions (the closest is the incomplete gamma function).
+// Instead, `InitCDF` iteratively computes the PMF and the CDF. This enables
+// searching for the bucket points.
+void PoissonModel::InitCDF() {
+ if (!cdf_.empty()) {
+ // State already initialized.
+ return;
+ }
+ ABSL_ASSERT(mean_ < 201.0);
+
+ const size_t max_i = 50 * stddev() + mean();
+ const double e_neg_mean = std::exp(-mean());
+ ABSL_ASSERT(e_neg_mean > 0);
+
+ double d = 1;
+ double last_result = e_neg_mean;
+ double cumulative = e_neg_mean;
+ if (e_neg_mean > 1e-10) {
+ cdf_.push_back({0, e_neg_mean, cumulative});
+ }
+ for (size_t i = 1; i < max_i; i++) {
+ d *= (mean() / i);
+ double result = e_neg_mean * d;
+ cumulative += result;
+ if (result < 1e-10 && result < last_result && cumulative > 0.999999) {
+ break;
+ }
+ if (result > 1e-7) {
+ cdf_.push_back({i, result, cumulative});
+ }
+ last_result = result;
+ }
+ ABSL_ASSERT(!cdf_.empty());
+}
+
+// PoissonDistributionZTest implements a z-test for the poisson distribution.
+
+struct ZParam {
+ double mean;
+ double p_fail; // Z-Test probability of failure.
+ int trials; // Z-Test trials.
+ size_t samples; // Z-Test samples.
+};
+
+class PoissonDistributionZTest : public testing::TestWithParam<ZParam>,
+ public PoissonModel {
+ public:
+ PoissonDistributionZTest() : PoissonModel(GetParam().mean) {}
+
+ // ZTestImpl provides a basic z-squared test of the mean vs. expected
+ // mean for data generated by the poisson distribution.
+ template <typename D>
+ bool SingleZTest(const double p, const size_t samples);
+
+ absl::InsecureBitGen rng_;
+};
+
+template <typename D>
+bool PoissonDistributionZTest::SingleZTest(const double p,
+ const size_t samples) {
+ D dis(mean());
+
+ absl::flat_hash_map<int32_t, int> buckets;
+ std::vector<double> data;
+ data.reserve(samples);
+ for (int j = 0; j < samples; j++) {
+ const auto x = dis(rng_);
+ buckets[x]++;
+ data.push_back(x);
+ }
+
+ // The null-hypothesis is that the distribution is a poisson distribution with
+ // the provided mean (not estimated from the data).
+ const auto m = absl::random_internal::ComputeDistributionMoments(data);
+ const double max_err = absl::random_internal::MaxErrorTolerance(p);
+ const double z = absl::random_internal::ZScore(mean(), m);
+ const bool pass = absl::random_internal::Near("z", z, 0.0, max_err);
+
+ if (!pass) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrFormat("p=%f max_err=%f\n"
+ " mean=%f vs. %f\n"
+ " stddev=%f vs. %f\n"
+ " skewness=%f vs. %f\n"
+ " kurtosis=%f vs. %f\n"
+ " z=%f",
+ p, max_err, m.mean, mean(), std::sqrt(m.variance),
+ stddev(), m.skewness, skew(), m.kurtosis,
+ kurtosis(), z));
+ }
+ return pass;
+}
+
+TEST_P(PoissonDistributionZTest, AbslPoissonDistribution) {
+ const auto& param = GetParam();
+ const int expected_failures =
+ std::max(1, static_cast<int>(std::ceil(param.trials * param.p_fail)));
+ const double p = absl::random_internal::RequiredSuccessProbability(
+ param.p_fail, param.trials);
+
+ int failures = 0;
+ for (int i = 0; i < param.trials; i++) {
+ failures +=
+ SingleZTest<absl::poisson_distribution<int32_t>>(p, param.samples) ? 0
+ : 1;
+ }
+ EXPECT_LE(failures, expected_failures);
+}
+
+std::vector<ZParam> GetZParams() {
+ // These values have been adjusted from the "exact" computed values to reduce
+ // failure rates.
+ //
+ // It turns out that the actual values are not as close to the expected values
+ // as would be ideal.
+ return std::vector<ZParam>({
+ // Knuth method.
+ ZParam{0.5, 0.01, 100, 1000},
+ ZParam{1.0, 0.01, 100, 1000},
+ ZParam{10.0, 0.01, 100, 5000},
+ // Split-knuth method.
+ ZParam{20.0, 0.01, 100, 10000},
+ ZParam{50.0, 0.01, 100, 10000},
+ // Ratio of gaussians method.
+ ZParam{51.0, 0.01, 100, 10000},
+ ZParam{200.0, 0.05, 10, 100000},
+ ZParam{100000.0, 0.05, 10, 1000000},
+ });
+}
+
+std::string ZParamName(const ::testing::TestParamInfo<ZParam>& info) {
+ const auto& p = info.param;
+ std::string name = absl::StrCat("mean_", absl::SixDigits(p.mean));
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_SUITE_P(, PoissonDistributionZTest,
+ ::testing::ValuesIn(GetZParams()), ZParamName);
+
+// The PoissonDistributionChiSquaredTest class provides a basic test framework
+// for variates generated by a conforming poisson_distribution.
+class PoissonDistributionChiSquaredTest : public testing::TestWithParam<double>,
+ public PoissonModel {
+ public:
+ PoissonDistributionChiSquaredTest() : PoissonModel(GetParam()) {}
+
+ // The ChiSquaredTestImpl provides a chi-squared goodness of fit test for data
+ // generated by the poisson distribution.
+ template <typename D>
+ double ChiSquaredTestImpl();
+
+ private:
+ void InitChiSquaredTest(const double buckets);
+
+ absl::InsecureBitGen rng_;
+ std::vector<size_t> cutoffs_;
+ std::vector<double> expected_;
+};
+
+void PoissonDistributionChiSquaredTest::InitChiSquaredTest(
+ const double buckets) {
+ if (!cutoffs_.empty() && !expected_.empty()) {
+ return;
+ }
+ InitCDF();
+
+ // The code below finds cuttoffs that yield approximately equally-sized
+ // buckets to the extent that it is possible. However for poisson
+ // distributions this is particularly challenging for small mean parameters.
+ // Track the expected proportion of items in each bucket.
+ double last_cdf = 0;
+ const double inc = 1.0 / buckets;
+ for (double p = inc; p <= 1.0; p += inc) {
+ auto result = InverseCDF(p);
+ if (!cutoffs_.empty() && cutoffs_.back() == result.index) {
+ continue;
+ }
+ double d = result.cdf - last_cdf;
+ cutoffs_.push_back(result.index);
+ expected_.push_back(d);
+ last_cdf = result.cdf;
+ }
+ cutoffs_.push_back(std::numeric_limits<size_t>::max());
+ expected_.push_back(std::max(0.0, 1.0 - last_cdf));
+}
+
+template <typename D>
+double PoissonDistributionChiSquaredTest::ChiSquaredTestImpl() {
+ const int kSamples = 2000;
+ const int kBuckets = 50;
+
+ // The poisson CDF fails for large mean values, since e^-mean exceeds the
+ // machine precision. For these cases, using a normal approximation would be
+ // appropriate.
+ ABSL_ASSERT(mean() <= 200);
+ InitChiSquaredTest(kBuckets);
+
+ D dis(mean());
+
+ std::vector<int32_t> counts(cutoffs_.size(), 0);
+ for (int j = 0; j < kSamples; j++) {
+ const size_t x = dis(rng_);
+ auto it = std::lower_bound(std::begin(cutoffs_), std::end(cutoffs_), x);
+ counts[std::distance(cutoffs_.begin(), it)]++;
+ }
+
+ // Normalize the counts.
+ std::vector<int32_t> e(expected_.size(), 0);
+ for (int i = 0; i < e.size(); i++) {
+ e[i] = kSamples * expected_[i];
+ }
+
+ // The null-hypothesis is that the distribution is a poisson distribution with
+ // the provided mean (not estimated from the data).
+ const int dof = static_cast<int>(counts.size()) - 1;
+
+ // The threshold for logging is 1-in-50.
+ const double threshold = absl::random_internal::ChiSquareValue(dof, 0.98);
+
+ const double chi_square = absl::random_internal::ChiSquare(
+ std::begin(counts), std::end(counts), std::begin(e), std::end(e));
+
+ const double p = absl::random_internal::ChiSquarePValue(chi_square, dof);
+
+ // Log if the chi_squared value is above the threshold.
+ if (chi_square > threshold) {
+ LogCDF();
+
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat("VALUES buckets=", counts.size(),
+ " samples=", kSamples));
+ for (size_t i = 0; i < counts.size(); i++) {
+ ABSL_INTERNAL_LOG(
+ INFO, absl::StrCat(cutoffs_[i], ": ", counts[i], " vs. E=", e[i]));
+ }
+
+ ABSL_INTERNAL_LOG(
+ INFO,
+ absl::StrCat(kChiSquared, "(data, dof=", dof, ") = ", chi_square, " (",
+ p, ")\n", " vs.\n", kChiSquared, " @ 0.98 = ", threshold));
+ }
+ return p;
+}
+
+TEST_P(PoissonDistributionChiSquaredTest, AbslPoissonDistribution) {
+ const int kTrials = 20;
+
+ // Large values are not yet supported -- this requires estimating the cdf
+ // using the normal distribution instead of the poisson in this case.
+ ASSERT_LE(mean(), 200.0);
+ if (mean() > 200.0) {
+ return;
+ }
+
+ int failures = 0;
+ for (int i = 0; i < kTrials; i++) {
+ double p_value = ChiSquaredTestImpl<absl::poisson_distribution<int32_t>>();
+ if (p_value < 0.005) {
+ failures++;
+ }
+ }
+ // There is a 0.10% chance of producing at least one failure, so raise the
+ // failure threshold high enough to allow for a flake rate < 10,000.
+ EXPECT_LE(failures, 4);
+}
+
+INSTANTIATE_TEST_SUITE_P(, PoissonDistributionChiSquaredTest,
+ ::testing::Values(0.5, 1.0, 2.0, 10.0, 50.0, 51.0,
+ 200.0));
+
+// NOTE: absl::poisson_distribution is not guaranteed to be stable.
+TEST(PoissonDistributionTest, StabilityTest) {
+ using testing::ElementsAre;
+ // absl::poisson_distribution stability relies on stability of
+ // std::exp, std::log, std::sqrt, std::ceil, std::floor, and
+ // absl::FastUniformBits, absl::StirlingLogFactorial, absl::RandU64ToDouble.
+ absl::random_internal::sequence_urbg urbg({
+ 0x035b0dc7e0a18acfull, 0x06cebe0d2653682eull, 0x0061e9b23861596bull,
+ 0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull,
+ 0x4864f22c059bf29eull, 0x247856d8b862665cull, 0xe46e86e9a1337e10ull,
+ 0xd8c8541f3519b133ull, 0xe75b5162c567b9e4ull, 0xf732e5ded7009c5bull,
+ 0xb170b98353121eacull, 0x1ec2e8986d2362caull, 0x814c8e35fe9a961aull,
+ 0x0c3cd59c9b638a02ull, 0xcb3bb6478a07715cull, 0x1224e62c978bbc7full,
+ 0x671ef2cb04e81f6eull, 0x3c1cbd811eaf1808ull, 0x1bbc23cfa8fac721ull,
+ 0xa4c2cda65e596a51ull, 0xb77216fad37adf91ull, 0x836d794457c08849ull,
+ 0xe083df03475f49d7ull, 0xbc9feb512e6b0d6cull, 0xb12d74fdd718c8c5ull,
+ 0x12ff09653bfbe4caull, 0x8dd03a105bc4ee7eull, 0x5738341045ba0d85ull,
+ 0xf3fd722dc65ad09eull, 0xfa14fd21ea2a5705ull, 0xffe6ea4d6edb0c73ull,
+ 0xD07E9EFE2BF11FB4ull, 0x95DBDA4DAE909198ull, 0xEAAD8E716B93D5A0ull,
+ 0xD08ED1D0AFC725E0ull, 0x8E3C5B2F8E7594B7ull, 0x8FF6E2FBF2122B64ull,
+ 0x8888B812900DF01Cull, 0x4FAD5EA0688FC31Cull, 0xD1CFF191B3A8C1ADull,
+ 0x2F2F2218BE0E1777ull, 0xEA752DFE8B021FA1ull, 0xE5A0CC0FB56F74E8ull,
+ 0x18ACF3D6CE89E299ull, 0xB4A84FE0FD13E0B7ull, 0x7CC43B81D2ADA8D9ull,
+ 0x165FA26680957705ull, 0x93CC7314211A1477ull, 0xE6AD206577B5FA86ull,
+ 0xC75442F5FB9D35CFull, 0xEBCDAF0C7B3E89A0ull, 0xD6411BD3AE1E7E49ull,
+ 0x00250E2D2071B35Eull, 0x226800BB57B8E0AFull, 0x2464369BF009B91Eull,
+ 0x5563911D59DFA6AAull, 0x78C14389D95A537Full, 0x207D5BA202E5B9C5ull,
+ 0x832603766295CFA9ull, 0x11C819684E734A41ull, 0xB3472DCA7B14A94Aull,
+ });
+
+ std::vector<int> output(10);
+
+ // Method 1.
+ {
+ absl::poisson_distribution<int> dist(5);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ }
+ EXPECT_THAT(output, // mean = 4.2
+ ElementsAre(1, 0, 0, 4, 2, 10, 3, 3, 7, 12));
+
+ // Method 2.
+ {
+ urbg.reset();
+ absl::poisson_distribution<int> dist(25);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ }
+ EXPECT_THAT(output, // mean = 19.8
+ ElementsAre(9, 35, 18, 10, 35, 18, 10, 35, 18, 10));
+
+ // Method 3.
+ {
+ urbg.reset();
+ absl::poisson_distribution<int> dist(121);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ }
+ EXPECT_THAT(output, // mean = 124.1
+ ElementsAre(161, 122, 129, 124, 112, 112, 117, 120, 130, 114));
+}
+
+TEST(PoissonDistributionTest, AlgorithmExpectedValue_1) {
+ // This tests small values of the Knuth method.
+ // The underlying uniform distribution will generate exactly 0.5.
+ absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
+ absl::poisson_distribution<int> dist(5);
+ EXPECT_EQ(7, dist(urbg));
+}
+
+TEST(PoissonDistributionTest, AlgorithmExpectedValue_2) {
+ // This tests larger values of the Knuth method.
+ // The underlying uniform distribution will generate exactly 0.5.
+ absl::random_internal::sequence_urbg urbg({0x8000000000000001ull});
+ absl::poisson_distribution<int> dist(25);
+ EXPECT_EQ(36, dist(urbg));
+}
+
+TEST(PoissonDistributionTest, AlgorithmExpectedValue_3) {
+ // This variant uses the ratio of uniforms method.
+ absl::random_internal::sequence_urbg urbg(
+ {0x7fffffffffffffffull, 0x8000000000000000ull});
+
+ absl::poisson_distribution<int> dist(121);
+ EXPECT_EQ(121, dist(urbg));
+}
+
+} // namespace
diff --git a/absl/random/random.h b/absl/random/random.h
new file mode 100644
index 00000000..72a4cf5b
--- /dev/null
+++ b/absl/random/random.h
@@ -0,0 +1,189 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: random.h
+// -----------------------------------------------------------------------------
+//
+// This header defines the recommended Uniform Random Bit Generator (URBG)
+// types for use within the Abseil Random library. These types are not
+// suitable for security-related use-cases, but should suffice for most other
+// uses of generating random values.
+//
+// The Abseil random library provides the following URBG types:
+//
+// * BitGen, a good general-purpose bit generator, optimized for generating
+// random (but not cryptographically secure) values
+// * InsecureBitGen, a slightly faster, though less random, bit generator, for
+// cases where the existing BitGen is a drag on performance.
+
+#ifndef ABSL_RANDOM_RANDOM_H_
+#define ABSL_RANDOM_RANDOM_H_
+
+#include <random>
+
+#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/randen_engine.h"
+#include "absl/random/seed_sequences.h" // IWYU pragma: export
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// -----------------------------------------------------------------------------
+// absl::BitGen
+// -----------------------------------------------------------------------------
+//
+// `absl::BitGen` is a general-purpose random bit generator for generating
+// random values for use within the Abseil random library. Typically, you use a
+// bit generator in combination with a distribution to provide random values.
+//
+// Example:
+//
+// // Create an absl::BitGen. There is no need to seed this bit generator.
+// absl::BitGen gen;
+//
+// // Generate an integer value in the closed interval [1,6]
+// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen);
+//
+// `absl::BitGen` is seeded by default with non-deterministic data to produce
+// different sequences of random values across different instances, including
+// different binary invocations. This behavior is different than the standard
+// library bit generators, which use golden values as their seeds. Default
+// construction intentionally provides no stability guarantees, to avoid
+// accidental dependence on such a property.
+//
+// `absl::BitGen` may be constructed with an optional seed sequence type,
+// conforming to [rand.req.seed_seq], which will be mixed with additional
+// non-deterministic data.
+//
+// Example:
+//
+// // Create an absl::BitGen using an std::seed_seq seed sequence
+// std::seed_seq seq{1,2,3};
+// absl::BitGen gen_with_seed(seq);
+//
+// // Generate an integer value in the closed interval [1,6]
+// int die_roll2 = absl::uniform_int_distribution<int>(1, 6)(gen_with_seed);
+//
+// `absl::BitGen` meets the requirements of the Uniform Random Bit Generator
+// (URBG) concept as per the C++17 standard [rand.req.urng] though differs
+// slightly with [rand.req.eng]. Like its standard library equivalents (e.g.
+// `std::mersenne_twister_engine`) `absl::BitGen` is not cryptographically
+// secure.
+//
+// Constructing two `absl::BitGen`s with the same seed sequence in the same
+// binary will produce the same sequence of variates within the same binary, but
+// need not do so across multiple binary invocations.
+//
+// This type has been optimized to perform better than Mersenne Twister
+// (https://en.wikipedia.org/wiki/Mersenne_Twister) and many other complex URBG
+// types on modern x86, ARM, and PPC architectures.
+//
+// This type is thread-compatible, but not thread-safe.
+
+// ---------------------------------------------------------------------------
+// absl::BitGen member functions
+// ---------------------------------------------------------------------------
+
+// absl::BitGen::operator()()
+//
+// Calls the BitGen, returning a generated value.
+
+// absl::BitGen::min()
+//
+// Returns the smallest possible value from this bit generator.
+
+// absl::BitGen::max()
+//
+// Returns the largest possible value from this bit generator., and
+
+// absl::BitGen::discard(num)
+//
+// Advances the internal state of this bit generator by `num` times, and
+// discards the intermediate results.
+// ---------------------------------------------------------------------------
+
+using BitGen = random_internal::NonsecureURBGBase<
+ random_internal::randen_engine<uint64_t>>;
+
+// -----------------------------------------------------------------------------
+// absl::InsecureBitGen
+// -----------------------------------------------------------------------------
+//
+// `absl::InsecureBitGen` is an efficient random bit generator for generating
+// random values, recommended only for performance-sensitive use cases where
+// `absl::BitGen` is not satisfactory when compute-bounded by bit generation
+// costs.
+//
+// Example:
+//
+// // Create an absl::InsecureBitGen
+// absl::InsecureBitGen gen;
+// for (size_t i = 0; i < 1000000; i++) {
+//
+// // Generate a bunch of random values from some complex distribution
+// auto my_rnd = some_distribution(gen, 1, 1000);
+// }
+//
+// Like `absl::BitGen`, `absl::InsecureBitGen` is seeded by default with
+// non-deterministic data to produce different sequences of random values across
+// different instances, including different binary invocations. (This behavior
+// is different than the standard library bit generators, which use golden
+// values as their seeds.)
+//
+// `absl::InsecureBitGen` may be constructed with an optional seed sequence
+// type, conforming to [rand.req.seed_seq], which will be mixed with additional
+// non-deterministic data. (See std_seed_seq.h for more information.)
+//
+// `absl::InsecureBitGen` meets the requirements of the Uniform Random Bit
+// Generator (URBG) concept as per the C++17 standard [rand.req.urng] though
+// its implementation differs slightly with [rand.req.eng]. Like its standard
+// library equivalents (e.g. `std::mersenne_twister_engine`)
+// `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()()
+//
+// Calls the InsecureBitGen, returning a generated value.
+
+// absl::InsecureBitGen::min()
+//
+// Returns the smallest possible value from this bit generator.
+
+// absl::InsecureBitGen::max()
+//
+// Returns the largest possible value from this bit generator.
+
+// absl::InsecureBitGen::discard(num)
+//
+// Advances the internal state of this bit generator by `num` times, and
+// discards the intermediate results.
+// ---------------------------------------------------------------------------
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_RANDOM_H_
diff --git a/absl/random/seed_gen_exception.cc b/absl/random/seed_gen_exception.cc
new file mode 100644
index 00000000..5f01a30c
--- /dev/null
+++ b/absl/random/seed_gen_exception.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "absl/random/seed_gen_exception.h"
+
+#include <iostream>
+
+#include "absl/base/config.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+static constexpr const char kExceptionMessage[] =
+ "Failed generating seed-material for URBG.";
+
+SeedGenException::~SeedGenException() = default;
+
+const char* SeedGenException::what() const noexcept {
+ return kExceptionMessage;
+}
+
+namespace random_internal {
+
+void ThrowSeedGenException() {
+#ifdef ABSL_HAVE_EXCEPTIONS
+ throw absl::SeedGenException();
+#else
+ std::cerr << kExceptionMessage << std::endl;
+ std::terminate();
+#endif
+}
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/seed_gen_exception.h b/absl/random/seed_gen_exception.h
new file mode 100644
index 00000000..52afe6cc
--- /dev/null
+++ b/absl/random/seed_gen_exception.h
@@ -0,0 +1,53 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: seed_gen_exception.h
+// -----------------------------------------------------------------------------
+//
+// This header defines an exception class which may be thrown if unpredictable
+// events prevent the derivation of suitable seed-material for constructing a
+// bit generator conforming to [rand.req.urng] (eg. entropy cannot be read from
+// /dev/urandom on a Unix-based system).
+//
+// Note: if exceptions are disabled, `std::terminate()` is called instead.
+
+#ifndef ABSL_RANDOM_SEED_GEN_EXCEPTION_H_
+#define ABSL_RANDOM_SEED_GEN_EXCEPTION_H_
+
+#include <exception>
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+//------------------------------------------------------------------------------
+// SeedGenException
+//------------------------------------------------------------------------------
+class SeedGenException : public std::exception {
+ public:
+ SeedGenException() = default;
+ ~SeedGenException() override;
+ const char* what() const noexcept override;
+};
+
+namespace random_internal {
+
+// throw delegator
+[[noreturn]] void ThrowSeedGenException();
+
+} // namespace random_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_SEED_GEN_EXCEPTION_H_
diff --git a/absl/random/seed_sequences.cc b/absl/random/seed_sequences.cc
new file mode 100644
index 00000000..fb7eb8d1
--- /dev/null
+++ b/absl/random/seed_sequences.cc
@@ -0,0 +1,29 @@
+// 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/seed_sequences.h"
+
+#include "absl/random/internal/pool_urbg.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+SeedSeq MakeSeedSeq() {
+ SeedSeq::result_type seed_material[8];
+ random_internal::RandenPool<uint32_t>::Fill(absl::MakeSpan(seed_material));
+ return SeedSeq(std::begin(seed_material), std::end(seed_material));
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/random/seed_sequences.h b/absl/random/seed_sequences.h
new file mode 100644
index 00000000..73d075c0
--- /dev/null
+++ b/absl/random/seed_sequences.h
@@ -0,0 +1,110 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: seed_sequences.h
+// -----------------------------------------------------------------------------
+//
+// This header contains utilities for creating and working with seed sequences
+// conforming to [rand.req.seedseq]. In general, direct construction of seed
+// sequences is discouraged, but use-cases for construction of identical bit
+// generators (using the same seed sequence) may be helpful (e.g. replaying a
+// simulation whose state is derived from variates of a bit generator).
+
+#ifndef ABSL_RANDOM_SEED_SEQUENCES_H_
+#define ABSL_RANDOM_SEED_SEQUENCES_H_
+
+#include <iterator>
+#include <random>
+
+#include "absl/random/internal/salted_seed_seq.h"
+#include "absl/random/internal/seed_material.h"
+#include "absl/random/seed_gen_exception.h"
+#include "absl/types/span.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// -----------------------------------------------------------------------------
+// absl::SeedSeq
+// -----------------------------------------------------------------------------
+//
+// `absl::SeedSeq` constructs a seed sequence according to [rand.req.seedseq]
+// for use within bit generators. `absl::SeedSeq`, unlike `std::seed_seq`
+// additionally salts the generated seeds with extra implementation-defined
+// entropy. For that reason, you can use `absl::SeedSeq` in combination with
+// standard library bit generators (e.g. `std::mt19937`) to introduce
+// non-determinism in your seeds.
+//
+// Example:
+//
+// absl::SeedSeq my_seed_seq({a, b, c});
+// std::mt19937 my_bitgen(my_seed_seq);
+//
+using SeedSeq = random_internal::SaltedSeedSeq<std::seed_seq>;
+
+// -----------------------------------------------------------------------------
+// absl::CreateSeedSeqFrom(bitgen*)
+// -----------------------------------------------------------------------------
+//
+// Constructs a seed sequence conforming to [rand.req.seedseq] using variates
+// produced by a provided bit generator.
+//
+// You should generally avoid direct construction of seed sequences, but
+// use-cases for reuse of a seed sequence to construct identical bit generators
+// may be helpful (eg. replaying a simulation whose state is derived from bit
+// generator values).
+//
+// If bitgen == nullptr, then behavior is undefined.
+//
+// Example:
+//
+// absl::BitGen my_bitgen;
+// auto seed_seq = absl::CreateSeedSeqFrom(&my_bitgen);
+// absl::BitGen new_engine(seed_seq); // derived from my_bitgen, but not
+// // correlated.
+//
+template <typename URBG>
+SeedSeq CreateSeedSeqFrom(URBG* urbg) {
+ SeedSeq::result_type
+ seed_material[random_internal::kEntropyBlocksNeeded];
+
+ if (!random_internal::ReadSeedMaterialFromURBG(
+ urbg, absl::MakeSpan(seed_material))) {
+ random_internal::ThrowSeedGenException();
+ }
+ return SeedSeq(std::begin(seed_material), std::end(seed_material));
+}
+
+// -----------------------------------------------------------------------------
+// absl::MakeSeedSeq()
+// -----------------------------------------------------------------------------
+//
+// Constructs an `absl::SeedSeq` salting the generated values using
+// implementation-defined entropy. The returned sequence can be used to create
+// equivalent bit generators correlated using this sequence.
+//
+// Example:
+//
+// auto my_seed_seq = absl::MakeSeedSeq();
+// std::mt19937 rng1(my_seed_seq);
+// std::mt19937 rng2(my_seed_seq);
+// EXPECT_EQ(rng1(), rng2());
+//
+SeedSeq MakeSeedSeq();
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_SEED_SEQUENCES_H_
diff --git a/absl/random/seed_sequences_test.cc b/absl/random/seed_sequences_test.cc
new file mode 100644
index 00000000..2cc8b0e6
--- /dev/null
+++ b/absl/random/seed_sequences_test.cc
@@ -0,0 +1,127 @@
+// 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/seed_sequences.h"
+
+#include <iterator>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/random/internal/nonsecure_base.h"
+#include "absl/random/random.h"
+namespace {
+
+TEST(SeedSequences, Examples) {
+ {
+ absl::SeedSeq seed_seq({1, 2, 3});
+ absl::BitGen bitgen(seed_seq);
+
+ EXPECT_NE(0, bitgen());
+ }
+ {
+ absl::BitGen engine;
+ auto seed_seq = absl::CreateSeedSeqFrom(&engine);
+ absl::BitGen bitgen(seed_seq);
+
+ EXPECT_NE(engine(), bitgen());
+ }
+ {
+ auto seed_seq = absl::MakeSeedSeq();
+ std::mt19937 random(seed_seq);
+
+ EXPECT_NE(0, random());
+ }
+}
+
+TEST(CreateSeedSeqFrom, CompatibleWithStdTypes) {
+ using ExampleNonsecureURBG =
+ absl::random_internal::NonsecureURBGBase<std::minstd_rand0>;
+
+ // Construct a URBG instance.
+ ExampleNonsecureURBG rng;
+
+ // Construct a Seed Sequence from its variates.
+ auto seq_from_rng = absl::CreateSeedSeqFrom(&rng);
+
+ // Ensure that another URBG can be validly constructed from the Seed Sequence.
+ std::mt19937_64{seq_from_rng};
+}
+
+TEST(CreateSeedSeqFrom, CompatibleWithBitGenerator) {
+ // Construct a URBG instance.
+ absl::BitGen rng;
+
+ // Construct a Seed Sequence from its variates.
+ auto seq_from_rng = absl::CreateSeedSeqFrom(&rng);
+
+ // Ensure that another URBG can be validly constructed from the Seed Sequence.
+ std::mt19937_64{seq_from_rng};
+}
+
+TEST(CreateSeedSeqFrom, CompatibleWithInsecureBitGen) {
+ // Construct a URBG instance.
+ absl::InsecureBitGen rng;
+
+ // Construct a Seed Sequence from its variates.
+ auto seq_from_rng = absl::CreateSeedSeqFrom(&rng);
+
+ // Ensure that another URBG can be validly constructed from the Seed Sequence.
+ std::mt19937_64{seq_from_rng};
+}
+
+TEST(CreateSeedSeqFrom, CompatibleWithRawURBG) {
+ // Construct a URBG instance.
+ std::random_device urandom;
+
+ // Construct a Seed Sequence from its variates, using 64b of seed-material.
+ auto seq_from_rng = absl::CreateSeedSeqFrom(&urandom);
+
+ // Ensure that another URBG can be validly constructed from the Seed Sequence.
+ std::mt19937_64{seq_from_rng};
+}
+
+template <typename URBG>
+void TestReproducibleVariateSequencesForNonsecureURBG() {
+ const size_t kNumVariates = 1000;
+
+ // Master RNG instance.
+ URBG rng;
+ // Reused for both RNG instances.
+ auto reusable_seed = absl::CreateSeedSeqFrom(&rng);
+
+ typename URBG::result_type variates[kNumVariates];
+ {
+ URBG child(reusable_seed);
+ for (auto& variate : variates) {
+ variate = child();
+ }
+ }
+ // Ensure that variate-sequence can be "replayed" by identical RNG.
+ {
+ URBG child(reusable_seed);
+ for (auto& variate : variates) {
+ ASSERT_EQ(variate, child());
+ }
+ }
+}
+
+TEST(CreateSeedSeqFrom, ReproducesVariateSequencesForInsecureBitGen) {
+ TestReproducibleVariateSequencesForNonsecureURBG<absl::InsecureBitGen>();
+}
+
+TEST(CreateSeedSeqFrom, ReproducesVariateSequencesForBitGenerator) {
+ TestReproducibleVariateSequencesForNonsecureURBG<absl::BitGen>();
+}
+} // namespace
diff --git a/absl/random/uniform_int_distribution.h b/absl/random/uniform_int_distribution.h
new file mode 100644
index 00000000..95eb04a4
--- /dev/null
+++ b/absl/random/uniform_int_distribution.h
@@ -0,0 +1,275 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: uniform_int_distribution.h
+// -----------------------------------------------------------------------------
+//
+// This header defines a class for representing a uniform integer distribution
+// over the closed (inclusive) interval [a,b]. You use this distribution in
+// combination with an Abseil random bit generator to produce random values
+// according to the rules of the distribution.
+//
+// `absl::uniform_int_distribution` is a drop-in replacement for the C++11
+// `std::uniform_int_distribution` [rand.dist.uni.int] but is considerably
+// faster than the libstdc++ implementation.
+
+#ifndef ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
+#define ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
+
+#include <cassert>
+#include <istream>
+#include <limits>
+#include <type_traits>
+
+#include "absl/base/optimization.h"
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+#include "absl/random/internal/traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::uniform_int_distribution<T>
+//
+// This distribution produces random integer values uniformly distributed in the
+// closed (inclusive) interval [a, b].
+//
+// Example:
+//
+// absl::BitGen gen;
+//
+// // Use the distribution to produce a value between 1 and 6, inclusive.
+// int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen);
+//
+template <typename IntType = int>
+class uniform_int_distribution {
+ private:
+ using unsigned_type =
+ typename random_internal::make_unsigned_bits<IntType>::type;
+
+ public:
+ using result_type = IntType;
+
+ class param_type {
+ public:
+ using distribution_type = uniform_int_distribution;
+
+ explicit param_type(
+ result_type lo = 0,
+ result_type hi = (std::numeric_limits<result_type>::max)())
+ : lo_(lo),
+ range_(static_cast<unsigned_type>(hi) -
+ static_cast<unsigned_type>(lo)) {
+ // [rand.dist.uni.int] precondition 2
+ assert(lo <= hi);
+ }
+
+ result_type a() const { return lo_; }
+ result_type b() const {
+ return static_cast<result_type>(static_cast<unsigned_type>(lo_) + range_);
+ }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.lo_ == b.lo_ && a.range_ == b.range_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class uniform_int_distribution;
+ unsigned_type range() const { return range_; }
+
+ result_type lo_;
+ unsigned_type range_;
+
+ static_assert(std::is_integral<result_type>::value,
+ "Class-template absl::uniform_int_distribution<> must be "
+ "parameterized using an integral type.");
+ }; // param_type
+
+ uniform_int_distribution() : uniform_int_distribution(0) {}
+
+ explicit uniform_int_distribution(
+ result_type lo,
+ result_type hi = (std::numeric_limits<result_type>::max)())
+ : param_(lo, hi) {}
+
+ explicit uniform_int_distribution(const param_type& param) : param_(param) {}
+
+ // uniform_int_distribution<T>::reset()
+ //
+ // Resets the uniform int distribution. Note that this function has no effect
+ // because the distribution already produces independent values.
+ void reset() {}
+
+ template <typename URBG>
+ result_type operator()(URBG& gen) { // NOLINT(runtime/references)
+ return (*this)(gen, param());
+ }
+
+ template <typename URBG>
+ result_type operator()(
+ URBG& gen, const param_type& param) { // NOLINT(runtime/references)
+ return param.a() + Generate(gen, param.range());
+ }
+
+ result_type a() const { return param_.a(); }
+ result_type b() const { return param_.b(); }
+
+ param_type param() const { return param_; }
+ void param(const param_type& params) { param_ = params; }
+
+ result_type(min)() const { return a(); }
+ result_type(max)() const { return b(); }
+
+ friend bool operator==(const uniform_int_distribution& a,
+ const uniform_int_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const uniform_int_distribution& a,
+ const uniform_int_distribution& b) {
+ return !(a == b);
+ }
+
+ private:
+ // Generates a value in the *closed* interval [0, R]
+ template <typename URBG>
+ unsigned_type Generate(URBG& g, // NOLINT(runtime/references)
+ unsigned_type R);
+ param_type param_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation details follow
+// -----------------------------------------------------------------------------
+template <typename CharT, typename Traits, typename IntType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os,
+ const uniform_int_distribution<IntType>& x) {
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os << static_cast<stream_type>(x.a()) << os.fill()
+ << static_cast<stream_type>(x.b());
+ return os;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is,
+ uniform_int_distribution<IntType>& x) {
+ using param_type = typename uniform_int_distribution<IntType>::param_type;
+ using result_type = typename uniform_int_distribution<IntType>::result_type;
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+
+ stream_type a;
+ stream_type b;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ is >> a >> b;
+ if (!is.fail()) {
+ x.param(
+ param_type(static_cast<result_type>(a), static_cast<result_type>(b)));
+ }
+ return is;
+}
+
+template <typename IntType>
+template <typename URBG>
+typename random_internal::make_unsigned_bits<IntType>::type
+uniform_int_distribution<IntType>::Generate(
+ URBG& g, // NOLINT(runtime/references)
+ typename random_internal::make_unsigned_bits<IntType>::type R) {
+ random_internal::FastUniformBits<unsigned_type> fast_bits;
+ unsigned_type bits = fast_bits(g);
+ const unsigned_type Lim = R + 1;
+ if ((R & Lim) == 0) {
+ // If the interval's length is a power of two range, just take the low bits.
+ return bits & R;
+ }
+
+ // Generates a uniform variate on [0, Lim) using fixed-point multiplication.
+ // The above fast-path guarantees that Lim is representable in unsigned_type.
+ //
+ // Algorithm adapted from
+ // http://lemire.me/blog/2016/06/30/fast-random-shuffling/, with added
+ // explanation.
+ //
+ // The algorithm creates a uniform variate `bits` in the interval [0, 2^N),
+ // and treats it as the fractional part of a fixed-point real value in [0, 1),
+ // multiplied by 2^N. For example, 0.25 would be represented as 2^(N - 2),
+ // because 2^N * 0.25 == 2^(N - 2).
+ //
+ // Next, `bits` and `Lim` are multiplied with a wide-multiply to bring the
+ // value into the range [0, Lim). The integral part (the high word of the
+ // multiplication result) is then very nearly the desired result. However,
+ // this is not quite accurate; viewing the multiplication result as one
+ // double-width integer, the resulting values for the sample are mapped as
+ // follows:
+ //
+ // If the result lies in this interval: Return this value:
+ // [0, 2^N) 0
+ // [2^N, 2 * 2^N) 1
+ // ... ...
+ // [K * 2^N, (K + 1) * 2^N) K
+ // ... ...
+ // [(Lim - 1) * 2^N, Lim * 2^N) Lim - 1
+ //
+ // While all of these intervals have the same size, the result of `bits * Lim`
+ // must be a multiple of `Lim`, and not all of these intervals contain the
+ // same number of multiples of `Lim`. In particular, some contain
+ // `F = floor(2^N / Lim)` and some contain `F + 1 = ceil(2^N / Lim)`. This
+ // difference produces a small nonuniformity, which is corrected by applying
+ // rejection sampling to one of the values in the "larger intervals" (i.e.,
+ // the intervals containing `F + 1` multiples of `Lim`.
+ //
+ // An interval contains `F + 1` multiples of `Lim` if and only if its smallest
+ // value modulo 2^N is less than `2^N % Lim`. The unique value satisfying
+ // this property is used as the one for rejection. That is, a value of
+ // `bits * Lim` is rejected if `(bit * Lim) % 2^N < (2^N % Lim)`.
+
+ using helper = random_internal::wide_multiply<unsigned_type>;
+ auto product = helper::multiply(bits, Lim);
+
+ // Two optimizations here:
+ // * Rejection occurs with some probability less than 1/2, and for reasonable
+ // ranges considerably less (in particular, less than 1/(F+1)), so
+ // ABSL_PREDICT_FALSE is apt.
+ // * `Lim` is an overestimate of `threshold`, and doesn't require a divide.
+ if (ABSL_PREDICT_FALSE(helper::lo(product) < Lim)) {
+ // This quantity is exactly equal to `2^N % Lim`, but does not require high
+ // precision calculations: `2^N % Lim` is congruent to `(2^N - Lim) % Lim`.
+ // Ideally this could be expressed simply as `-X` rather than `2^N - X`, but
+ // for types smaller than int, this calculation is incorrect due to integer
+ // promotion rules.
+ const unsigned_type threshold =
+ ((std::numeric_limits<unsigned_type>::max)() - Lim + 1) % Lim;
+ while (helper::lo(product) < threshold) {
+ bits = fast_bits(g);
+ product = helper::multiply(bits, Lim);
+ }
+ }
+
+ return helper::hi(product);
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
diff --git a/absl/random/uniform_int_distribution_test.cc b/absl/random/uniform_int_distribution_test.cc
new file mode 100644
index 00000000..aacff88d
--- /dev/null
+++ b/absl/random/uniform_int_distribution_test.cc
@@ -0,0 +1,250 @@
+// 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/uniform_int_distribution.h"
+
+#include <cmath>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <sstream>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+
+namespace {
+
+template <typename IntType>
+class UniformIntDistributionTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<int8_t, uint8_t, int16_t, uint16_t, int32_t,
+ uint32_t, int64_t, uint64_t>;
+TYPED_TEST_SUITE(UniformIntDistributionTest, IntTypes);
+
+TYPED_TEST(UniformIntDistributionTest, ParamSerializeTest) {
+ // This test essentially ensures that the parameters serialize,
+ // not that the values generated cover the full range.
+ using Limits = std::numeric_limits<TypeParam>;
+ using param_type =
+ typename absl::uniform_int_distribution<TypeParam>::param_type;
+ const TypeParam kMin = std::is_unsigned<TypeParam>::value ? 37 : -105;
+ const TypeParam kNegOneOrZero = std::is_unsigned<TypeParam>::value ? 0 : -1;
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ for (const auto& param : {
+ param_type(),
+ param_type(2, 2), // Same
+ param_type(9, 32),
+ param_type(kMin, 115),
+ param_type(kNegOneOrZero, Limits::max()),
+ param_type(Limits::min(), Limits::max()),
+ param_type(Limits::lowest(), Limits::max()),
+ param_type(Limits::min() + 1, Limits::max() - 1),
+ }) {
+ const auto a = param.a();
+ const auto b = param.b();
+ absl::uniform_int_distribution<TypeParam> before(a, b);
+ EXPECT_EQ(before.a(), param.a());
+ EXPECT_EQ(before.b(), param.b());
+
+ {
+ // Initialize via param_type
+ absl::uniform_int_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ }
+
+ // Initialize via iostreams
+ std::stringstream ss;
+ ss << before;
+
+ absl::uniform_int_distribution<TypeParam> after(Limits::min() + 3,
+ Limits::max() - 5);
+
+ EXPECT_NE(before.a(), after.a());
+ EXPECT_NE(before.b(), after.b());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.a(), after.a());
+ EXPECT_EQ(before.b(), after.b());
+ EXPECT_EQ(before.param(), after.param());
+ EXPECT_EQ(before, after);
+
+ // Smoke test.
+ auto sample_min = after.max();
+ auto sample_max = after.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = after(gen);
+ EXPECT_GE(sample, after.min());
+ EXPECT_LE(sample, after.max());
+ if (sample > sample_max) {
+ sample_max = sample;
+ }
+ if (sample < sample_min) {
+ sample_min = sample;
+ }
+ }
+ std::string msg = absl::StrCat("Range: ", +sample_min, ", ", +sample_max);
+ ABSL_RAW_LOG(INFO, "%s", msg.c_str());
+ }
+}
+
+TYPED_TEST(UniformIntDistributionTest, ViolatesPreconditionsDeathTest) {
+#if GTEST_HAS_DEATH_TEST
+ // Hi < Lo
+ 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,
+ // but should not enter an infinite loop.
+ absl::InsecureBitGen gen;
+ absl::uniform_int_distribution<TypeParam> dist(10, 1);
+ auto x = dist(gen);
+
+ // Any value will generate a non-empty std::string.
+ EXPECT_FALSE(absl::StrCat(+x).empty()) << x;
+#endif // NDEBUG
+}
+
+TYPED_TEST(UniformIntDistributionTest, TestMoments) {
+ constexpr int kSize = 100000;
+ using Limits = std::numeric_limits<TypeParam>;
+ using param_type =
+ typename absl::uniform_int_distribution<TypeParam>::param_type;
+
+ absl::InsecureBitGen rng;
+ std::vector<double> values(kSize);
+ for (const auto& param :
+ {param_type(0, Limits::max()), param_type(13, 127)}) {
+ absl::uniform_int_distribution<TypeParam> dist(param);
+ for (int i = 0; i < kSize; i++) {
+ const auto sample = dist(rng);
+ ASSERT_LE(dist.param().a(), sample);
+ ASSERT_GE(dist.param().b(), sample);
+ values[i] = sample;
+ }
+
+ auto moments = absl::random_internal::ComputeDistributionMoments(values);
+ const double a = dist.param().a();
+ const double b = dist.param().b();
+ const double n = (b - a + 1);
+ const double mean = (a + b) / 2;
+ const double var = ((b - a + 1) * (b - a + 1) - 1) / 12;
+ const double kurtosis = 3 - 6 * (n * n + 1) / (5 * (n * n - 1));
+
+ // TODO(ahh): this is not the right bound
+ // empirically validated with --runs_per_test=10000.
+ EXPECT_NEAR(mean, moments.mean, 0.01 * var);
+ EXPECT_NEAR(var, moments.variance, 0.015 * var);
+ EXPECT_NEAR(0.0, moments.skewness, 0.025);
+ EXPECT_NEAR(kurtosis, moments.kurtosis, 0.02 * kurtosis);
+ }
+}
+
+TYPED_TEST(UniformIntDistributionTest, ChiSquaredTest50) {
+ using absl::random_internal::kChiSquared;
+
+ constexpr size_t kTrials = 1000;
+ constexpr int kBuckets = 50; // inclusive, so actally +1
+ constexpr double kExpected =
+ static_cast<double>(kTrials) / static_cast<double>(kBuckets);
+
+ // Empirically validated with --runs_per_test=10000.
+ const int kThreshold =
+ absl::random_internal::ChiSquareValue(kBuckets, 0.999999);
+
+ const TypeParam min = std::is_unsigned<TypeParam>::value ? 37 : -37;
+ const TypeParam max = min + kBuckets;
+
+ absl::InsecureBitGen rng;
+ absl::uniform_int_distribution<TypeParam> dist(min, max);
+
+ std::vector<int32_t> counts(kBuckets + 1, 0);
+ for (size_t i = 0; i < kTrials; i++) {
+ auto x = dist(rng);
+ counts[x - min]++;
+ }
+ double chi_square = absl::random_internal::ChiSquareWithExpected(
+ std::begin(counts), std::end(counts), kExpected);
+ if (chi_square > kThreshold) {
+ double p_value =
+ absl::random_internal::ChiSquarePValue(chi_square, kBuckets);
+
+ // Chi-squared test failed. Output does not appear to be uniform.
+ std::string msg;
+ for (const auto& a : counts) {
+ absl::StrAppend(&msg, a, "\n");
+ }
+ absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n");
+ absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ",
+ kThreshold);
+ ABSL_RAW_LOG(INFO, "%s", msg.c_str());
+ FAIL() << msg;
+ }
+}
+
+TEST(UniformIntDistributionTest, StabilityTest) {
+ // absl::uniform_int_distribution stability relies only on integer operations.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(12);
+
+ {
+ absl::uniform_int_distribution<int32_t> dist(0, 4);
+ for (auto& v : output) {
+ v = dist(urbg);
+ }
+ }
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_THAT(output, testing::ElementsAre(4, 4, 3, 2, 1, 0, 1, 4, 3, 1, 3, 1));
+
+ {
+ urbg.reset();
+ absl::uniform_int_distribution<int32_t> dist(0, 100);
+ for (auto& v : output) {
+ v = dist(urbg);
+ }
+ }
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_THAT(output, testing::ElementsAre(97, 86, 75, 41, 36, 16, 38, 92, 67,
+ 30, 80, 38));
+
+ {
+ urbg.reset();
+ absl::uniform_int_distribution<int32_t> dist(0, 10000);
+ for (auto& v : output) {
+ v = dist(urbg);
+ }
+ }
+ EXPECT_EQ(12, urbg.invocations());
+ EXPECT_THAT(output, testing::ElementsAre(9648, 8562, 7439, 4089, 3571, 1602,
+ 3813, 9195, 6641, 2986, 7956, 3765));
+}
+
+} // namespace
diff --git a/absl/random/uniform_real_distribution.h b/absl/random/uniform_real_distribution.h
new file mode 100644
index 00000000..0ea3163a
--- /dev/null
+++ b/absl/random/uniform_real_distribution.h
@@ -0,0 +1,195 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: uniform_real_distribution.h
+// -----------------------------------------------------------------------------
+//
+// This header defines a class for representing a uniform floating-point
+// distribution over a half-open interval [a,b). You use this distribution in
+// combination with an Abseil random bit generator to produce random values
+// according to the rules of the distribution.
+//
+// `absl::uniform_real_distribution` is a drop-in replacement for the C++11
+// `std::uniform_real_distribution` [rand.dist.uni.real] but is considerably
+// faster than the libstdc++ implementation.
+//
+// Note: the standard-library version may occasionally return `1.0` when
+// default-initialized. See https://bugs.llvm.org//show_bug.cgi?id=18767
+// `absl::uniform_real_distribution` does not exhibit this behavior.
+
+#ifndef ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
+#define ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <cstdint>
+#include <istream>
+#include <limits>
+#include <type_traits>
+
+#include "absl/random/internal/distribution_impl.h"
+#include "absl/random/internal/fast_uniform_bits.h"
+#include "absl/random/internal/iostream_state_saver.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::uniform_real_distribution<T>
+//
+// This distribution produces random floating-point values uniformly distributed
+// over the half-open interval [a, b).
+//
+// Example:
+//
+// absl::BitGen gen;
+//
+// // Use the distribution to produce a value between 0.0 (inclusive)
+// // and 1.0 (exclusive).
+// int value = absl::uniform_real_distribution<double>(0, 1)(gen);
+//
+template <typename RealType = double>
+class uniform_real_distribution {
+ public:
+ using result_type = RealType;
+
+ class param_type {
+ public:
+ using distribution_type = uniform_real_distribution;
+
+ explicit param_type(result_type lo = 0, result_type hi = 1)
+ : lo_(lo), hi_(hi), range_(hi - lo) {
+ // [rand.dist.uni.real] preconditions 2 & 3
+ assert(lo <= hi);
+ // NOTE: For integral types, we can promote the range to an unsigned type,
+ // which gives full width of the range. However for real (fp) types, this
+ // is not possible, so value generation cannot use the full range of the
+ // real type.
+ assert(range_ <= (std::numeric_limits<result_type>::max)());
+ }
+
+ result_type a() const { return lo_; }
+ result_type b() const { return hi_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.lo_ == b.lo_ && a.hi_ == b.hi_;
+ }
+
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class uniform_real_distribution;
+ result_type lo_, hi_, range_;
+
+ static_assert(std::is_floating_point<RealType>::value,
+ "Class-template absl::uniform_real_distribution<> must be "
+ "parameterized using a floating-point type.");
+ };
+
+ uniform_real_distribution() : uniform_real_distribution(0) {}
+
+ explicit uniform_real_distribution(result_type lo, result_type hi = 1)
+ : param_(lo, hi) {}
+
+ explicit uniform_real_distribution(const param_type& param) : param_(param) {}
+
+ // uniform_real_distribution<T>::reset()
+ //
+ // Resets the uniform real distribution. Note that this function has no effect
+ // because the distribution already produces independent values.
+ void reset() {}
+
+ template <typename URBG>
+ result_type operator()(URBG& gen) { // NOLINT(runtime/references)
+ return operator()(gen, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& gen, // NOLINT(runtime/references)
+ const param_type& p);
+
+ result_type a() const { return param_.a(); }
+ result_type b() const { return param_.b(); }
+
+ param_type param() const { return param_; }
+ void param(const param_type& params) { param_ = params; }
+
+ result_type(min)() const { return a(); }
+ result_type(max)() const { return b(); }
+
+ friend bool operator==(const uniform_real_distribution& a,
+ const uniform_real_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const uniform_real_distribution& a,
+ const uniform_real_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+ random_internal::FastUniformBits<uint64_t> fast_u64_;
+};
+
+// -----------------------------------------------------------------------------
+// Implementation details follow
+// -----------------------------------------------------------------------------
+template <typename RealType>
+template <typename URBG>
+typename uniform_real_distribution<RealType>::result_type
+uniform_real_distribution<RealType>::operator()(
+ URBG& gen, const param_type& p) { // NOLINT(runtime/references)
+ using random_internal::PositiveValueT;
+ while (true) {
+ const result_type sample = random_internal::RandU64ToReal<
+ result_type>::template Value<PositiveValueT, true>(fast_u64_(gen));
+ const result_type res = p.a() + (sample * p.range_);
+ if (res < p.b() || p.range_ <= 0 || !std::isfinite(p.range_)) {
+ return res;
+ }
+ // else sample rejected, try again.
+ }
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const uniform_real_distribution<RealType>& x) {
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<RealType>::kPrecision);
+ os << x.a() << os.fill() << x.b();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename RealType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ uniform_real_distribution<RealType>& x) { // NOLINT(runtime/references)
+ using param_type = typename uniform_real_distribution<RealType>::param_type;
+ using result_type = typename uniform_real_distribution<RealType>::result_type;
+ auto saver = random_internal::make_istream_state_saver(is);
+ auto a = random_internal::read_floating_point<result_type>(is);
+ if (is.fail()) return is;
+ auto b = random_internal::read_floating_point<result_type>(is);
+ if (!is.fail()) {
+ x.param(param_type(a, b));
+ }
+ return is;
+}
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_UNIFORM_REAL_DISTRIBUTION_H_
diff --git a/absl/random/uniform_real_distribution_test.cc b/absl/random/uniform_real_distribution_test.cc
new file mode 100644
index 00000000..597f0ee5
--- /dev/null
+++ b/absl/random/uniform_real_distribution_test.cc
@@ -0,0 +1,322 @@
+// 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/uniform_real_distribution.h"
+
+#include <cmath>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/distribution_test_util.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+
+// NOTES:
+// * Some documentation on generating random real values suggests that
+// it is possible to use std::nextafter(b, DBL_MAX) to generate a value on
+// the closed range [a, b]. Unfortunately, that technique is not universally
+// reliable due to floating point quantization.
+//
+// * absl::uniform_real_distribution<float> generates between 2^28 and 2^29
+// distinct floating point values in the range [0, 1).
+//
+// * absl::uniform_real_distribution<float> generates at least 2^23 distinct
+// floating point values in the range [1, 2). This should be the same as
+// any other range covered by a single exponent in IEEE 754.
+//
+// * absl::uniform_real_distribution<double> generates more than 2^52 distinct
+// values in the range [0, 1), and should generate at least 2^52 distinct
+// values in the range of [1, 2).
+//
+
+namespace {
+
+template <typename RealType>
+class UniformRealDistributionTest : public ::testing::Test {};
+
+using RealTypes = ::testing::Types<float, double, long double>;
+TYPED_TEST_SUITE(UniformRealDistributionTest, RealTypes);
+
+TYPED_TEST(UniformRealDistributionTest, ParamSerializeTest) {
+ using param_type =
+ typename absl::uniform_real_distribution<TypeParam>::param_type;
+
+ constexpr const TypeParam a{1152921504606846976};
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ for (const auto& param : {
+ param_type(),
+ param_type(TypeParam(2.0), TypeParam(2.0)), // Same
+ param_type(TypeParam(-0.1), TypeParam(0.1)),
+ param_type(TypeParam(0.05), TypeParam(0.12)),
+ param_type(TypeParam(-0.05), TypeParam(0.13)),
+ param_type(TypeParam(-0.05), TypeParam(-0.02)),
+ // double range = 0
+ // 2^60 , 2^60 + 2^6
+ param_type(a, TypeParam(1152921504606847040)),
+ // 2^60 , 2^60 + 2^7
+ param_type(a, TypeParam(1152921504606847104)),
+ // double range = 2^8
+ // 2^60 , 2^60 + 2^8
+ param_type(a, TypeParam(1152921504606847232)),
+ // float range = 0
+ // 2^60 , 2^60 + 2^36
+ param_type(a, TypeParam(1152921573326323712)),
+ // 2^60 , 2^60 + 2^37
+ param_type(a, TypeParam(1152921642045800448)),
+ // float range = 2^38
+ // 2^60 , 2^60 + 2^38
+ param_type(a, TypeParam(1152921779484753920)),
+ // Limits
+ param_type(0, std::numeric_limits<TypeParam>::max()),
+ param_type(std::numeric_limits<TypeParam>::lowest(), 0),
+ param_type(0, std::numeric_limits<TypeParam>::epsilon()),
+ param_type(-std::numeric_limits<TypeParam>::epsilon(),
+ std::numeric_limits<TypeParam>::epsilon()),
+ param_type(std::numeric_limits<TypeParam>::epsilon(),
+ 2 * std::numeric_limits<TypeParam>::epsilon()),
+ }) {
+ // Validate parameters.
+ const auto a = param.a();
+ const auto b = param.b();
+ absl::uniform_real_distribution<TypeParam> before(a, b);
+ EXPECT_EQ(before.a(), param.a());
+ EXPECT_EQ(before.b(), param.b());
+
+ {
+ absl::uniform_real_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ }
+
+ std::stringstream ss;
+ ss << before;
+ absl::uniform_real_distribution<TypeParam> after(TypeParam(1.0),
+ TypeParam(3.1));
+
+ EXPECT_NE(before.a(), after.a());
+ EXPECT_NE(before.b(), after.b());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.a(), after.a());
+ EXPECT_EQ(before.b(), after.b());
+ EXPECT_EQ(before.param(), after.param());
+ EXPECT_EQ(before, after);
+
+ // Smoke test.
+ auto sample_min = after.max();
+ auto sample_max = after.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = after(gen);
+ // Failure here indicates a bug in uniform_real_distribution::operator(),
+ // or bad parameters--range too large, etc.
+ if (after.min() == after.max()) {
+ EXPECT_EQ(sample, after.min());
+ } else {
+ EXPECT_GE(sample, after.min());
+ EXPECT_LT(sample, after.max());
+ }
+ if (sample > sample_max) {
+ sample_max = sample;
+ }
+ if (sample < sample_min) {
+ sample_min = sample;
+ }
+ }
+
+ if (!std::is_same<TypeParam, long double>::value) {
+ // static_cast<double>(long double) can overflow.
+ std::string msg = absl::StrCat("Range: ", static_cast<double>(sample_min),
+ ", ", static_cast<double>(sample_max));
+ ABSL_RAW_LOG(INFO, "%s", msg.c_str());
+ }
+ }
+}
+
+TYPED_TEST(UniformRealDistributionTest, ViolatesPreconditionsDeathTest) {
+#if GTEST_HAS_DEATH_TEST
+ // Hi < Lo
+ EXPECT_DEBUG_DEATH(
+ { absl::uniform_real_distribution<TypeParam> dist(10.0, 1.0); }, "");
+
+ // Hi - Lo > numeric_limits<>::max()
+ EXPECT_DEBUG_DEATH(
+ {
+ absl::uniform_real_distribution<TypeParam> dist(
+ std::numeric_limits<TypeParam>::lowest(),
+ std::numeric_limits<TypeParam>::max());
+ },
+ "");
+#endif // GTEST_HAS_DEATH_TEST
+#if defined(NDEBUG)
+ // opt-mode, for invalid parameters, will generate a garbage value,
+ // but should not enter an infinite loop.
+ absl::InsecureBitGen gen;
+ {
+ absl::uniform_real_distribution<TypeParam> dist(10.0, 1.0);
+ auto x = dist(gen);
+ EXPECT_FALSE(std::isnan(x)) << x;
+ }
+ {
+ absl::uniform_real_distribution<TypeParam> dist(
+ std::numeric_limits<TypeParam>::lowest(),
+ std::numeric_limits<TypeParam>::max());
+ auto x = dist(gen);
+ // Infinite result.
+ EXPECT_FALSE(std::isfinite(x)) << x;
+ }
+#endif // NDEBUG
+}
+
+TYPED_TEST(UniformRealDistributionTest, TestMoments) {
+ constexpr int kSize = 1000000;
+ std::vector<double> values(kSize);
+
+ absl::InsecureBitGen rng;
+ absl::uniform_real_distribution<TypeParam> dist;
+ for (int i = 0; i < kSize; i++) {
+ values[i] = dist(rng);
+ }
+
+ const auto moments =
+ absl::random_internal::ComputeDistributionMoments(values);
+ EXPECT_NEAR(0.5, moments.mean, 0.01);
+ EXPECT_NEAR(1 / 12.0, moments.variance, 0.015);
+ EXPECT_NEAR(0.0, moments.skewness, 0.02);
+ EXPECT_NEAR(9 / 5.0, moments.kurtosis, 0.015);
+}
+
+TYPED_TEST(UniformRealDistributionTest, ChiSquaredTest50) {
+ using absl::random_internal::kChiSquared;
+ using param_type =
+ typename absl::uniform_real_distribution<TypeParam>::param_type;
+
+ constexpr size_t kTrials = 100000;
+ constexpr int kBuckets = 50;
+ constexpr double kExpected =
+ static_cast<double>(kTrials) / static_cast<double>(kBuckets);
+
+ // 1-in-100000 threshold, but remember, there are about 8 tests
+ // in this file. And the test could fail for other reasons.
+ // Empirically validated with --runs_per_test=10000.
+ const int kThreshold =
+ absl::random_internal::ChiSquareValue(kBuckets - 1, 0.999999);
+
+ absl::InsecureBitGen rng;
+ for (const auto& param : {param_type(0, 1), param_type(5, 12),
+ param_type(-5, 13), param_type(-5, -2)}) {
+ const double min_val = param.a();
+ const double max_val = param.b();
+ const double factor = kBuckets / (max_val - min_val);
+
+ std::vector<int32_t> counts(kBuckets, 0);
+ absl::uniform_real_distribution<TypeParam> dist(param);
+ for (size_t i = 0; i < kTrials; i++) {
+ auto x = dist(rng);
+ auto bucket = static_cast<size_t>((x - min_val) * factor);
+ counts[bucket]++;
+ }
+
+ double chi_square = absl::random_internal::ChiSquareWithExpected(
+ std::begin(counts), std::end(counts), kExpected);
+ if (chi_square > kThreshold) {
+ double p_value =
+ absl::random_internal::ChiSquarePValue(chi_square, kBuckets);
+
+ // Chi-squared test failed. Output does not appear to be uniform.
+ std::string msg;
+ for (const auto& a : counts) {
+ absl::StrAppend(&msg, a, "\n");
+ }
+ absl::StrAppend(&msg, kChiSquared, " p-value ", p_value, "\n");
+ absl::StrAppend(&msg, "High ", kChiSquared, " value: ", chi_square, " > ",
+ kThreshold);
+ ABSL_RAW_LOG(INFO, "%s", msg.c_str());
+ FAIL() << msg;
+ }
+ }
+}
+
+TYPED_TEST(UniformRealDistributionTest, StabilityTest) {
+ // absl::uniform_real_distribution stability relies only on
+ // random_internal::RandU64ToDouble and random_internal::RandU64ToFloat.
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(12);
+
+ absl::uniform_real_distribution<TypeParam> dist;
+ std::generate(std::begin(output), std::end(output), [&] {
+ return static_cast<int>(TypeParam(1000000) * dist(urbg));
+ });
+
+ EXPECT_THAT(
+ output, //
+ testing::ElementsAre(59, 999246, 762494, 395876, 167716, 82545, 925251,
+ 77341, 12527, 708791, 834451, 932808));
+}
+
+TEST(UniformRealDistributionTest, AlgorithmBounds) {
+ absl::uniform_real_distribution<double> dist;
+
+ {
+ // This returns the smallest value >0 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0x0000000000000001ull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 5.42101086242752217004e-20);
+ }
+
+ {
+ // This returns a value very near 0.5 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0x7fffffffffffffefull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 0.499999999999999944489);
+ }
+ {
+ // This returns a value very near 0.5 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0x8000000000000000ull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 0.5);
+ }
+
+ {
+ // This returns the largest value <1 from absl::uniform_real_distribution.
+ absl::random_internal::sequence_urbg urbg({0xFFFFFFFFFFFFFFEFull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 0.999999999999999888978);
+ }
+ {
+ // This *ALSO* returns the largest value <1.
+ absl::random_internal::sequence_urbg urbg({0xFFFFFFFFFFFFFFFFull});
+ double a = dist(urbg);
+ EXPECT_EQ(a, 0.999999999999999888978);
+ }
+}
+
+} // namespace
diff --git a/absl/random/zipf_distribution.h b/absl/random/zipf_distribution.h
new file mode 100644
index 00000000..bba98e88
--- /dev/null
+++ b/absl/random/zipf_distribution.h
@@ -0,0 +1,271 @@
+// 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_ZIPF_DISTRIBUTION_H_
+#define ABSL_RANDOM_ZIPF_DISTRIBUTION_H_
+
+#include <cassert>
+#include <cmath>
+#include <istream>
+#include <limits>
+#include <ostream>
+#include <type_traits>
+
+#include "absl/random/internal/iostream_state_saver.h"
+#include "absl/random/uniform_real_distribution.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// absl::zipf_distribution produces random integer-values in the range [0, k],
+// distributed according to the discrete probability function:
+//
+// P(x) = (v + x) ^ -q
+//
+// The parameter `v` must be greater than 0 and the parameter `q` must be
+// greater than 1. If either of these parameters take invalid values then the
+// behavior is undefined.
+//
+// IntType is the result_type generated by the generator. It must be of integral
+// type; a static_assert ensures this is the case.
+//
+// The implementation is based on W.Hormann, G.Derflinger:
+//
+// "Rejection-Inversion to Generate Variates from Monotone Discrete
+// Distributions"
+//
+// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz
+//
+template <typename IntType = int>
+class zipf_distribution {
+ public:
+ using result_type = IntType;
+
+ class param_type {
+ public:
+ using distribution_type = zipf_distribution;
+
+ // Preconditions: k > 0, v > 0, q > 1
+ // The precondidtions 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.
+ explicit param_type(result_type k = (std::numeric_limits<IntType>::max)(),
+ double q = 2.0, double v = 1.0);
+
+ result_type k() const { return k_; }
+ double q() const { return q_; }
+ double v() const { return v_; }
+
+ friend bool operator==(const param_type& a, const param_type& b) {
+ return a.k_ == b.k_ && a.q_ == b.q_ && a.v_ == b.v_;
+ }
+ friend bool operator!=(const param_type& a, const param_type& b) {
+ return !(a == b);
+ }
+
+ private:
+ friend class zipf_distribution;
+ inline double h(double x) const;
+ inline double hinv(double x) const;
+ inline double compute_s() const;
+ inline double pow_negative_q(double x) const;
+
+ // Parameters here are exactly the same as the parameters of Algorithm ZRI
+ // in the paper.
+ IntType k_;
+ double q_;
+ double v_;
+
+ double one_minus_q_; // 1-q
+ double s_;
+ double one_minus_q_inv_; // 1 / 1-q
+ double hxm_; // h(k + 0.5)
+ double hx0_minus_hxm_; // h(x0) - h(k + 0.5)
+
+ static_assert(std::is_integral<IntType>::value,
+ "Class-template absl::zipf_distribution<> must be "
+ "parameterized using an integral type.");
+ };
+
+ zipf_distribution()
+ : zipf_distribution((std::numeric_limits<IntType>::max)()) {}
+
+ explicit zipf_distribution(result_type k, double q = 2.0, double v = 1.0)
+ : param_(k, q, v) {}
+
+ explicit zipf_distribution(const param_type& p) : param_(p) {}
+
+ void reset() {}
+
+ template <typename URBG>
+ result_type operator()(URBG& g) { // NOLINT(runtime/references)
+ return (*this)(g, param_);
+ }
+
+ template <typename URBG>
+ result_type operator()(URBG& g, // NOLINT(runtime/references)
+ const param_type& p);
+
+ result_type k() const { return param_.k(); }
+ double q() const { return param_.q(); }
+ double v() const { return param_.v(); }
+
+ param_type param() const { return param_; }
+ void param(const param_type& p) { param_ = p; }
+
+ result_type(min)() const { return 0; }
+ result_type(max)() const { return k(); }
+
+ friend bool operator==(const zipf_distribution& a,
+ const zipf_distribution& b) {
+ return a.param_ == b.param_;
+ }
+ friend bool operator!=(const zipf_distribution& a,
+ const zipf_distribution& b) {
+ return a.param_ != b.param_;
+ }
+
+ private:
+ param_type param_;
+};
+
+// --------------------------------------------------------------------------
+// Implementation details follow
+// --------------------------------------------------------------------------
+
+template <typename IntType>
+zipf_distribution<IntType>::param_type::param_type(
+ typename zipf_distribution<IntType>::result_type k, double q, double v)
+ : k_(k), q_(q), v_(v), one_minus_q_(1 - q) {
+ assert(q > 1);
+ assert(v > 0);
+ assert(k > 0);
+ one_minus_q_inv_ = 1 / one_minus_q_;
+
+ // Setup for the ZRI algorithm (pg 17 of the paper).
+ // Compute: h(i max) => h(k + 0.5)
+ constexpr double kMax = 18446744073709549568.0;
+ double kd = static_cast<double>(k);
+ // TODO(absl-team): Determine if this check is needed, and if so, add a test
+ // that fails for k > kMax
+ if (kd > kMax) {
+ // Ensure that our maximum value is capped to a value which will
+ // round-trip back through double.
+ kd = kMax;
+ }
+ hxm_ = h(kd + 0.5);
+
+ // Compute: h(0)
+ const bool use_precomputed = (v == 1.0 && q == 2.0);
+ const double h0x5 = use_precomputed ? (-1.0 / 1.5) // exp(-log(1.5))
+ : h(0.5);
+ const double elogv_q = (v_ == 1.0) ? 1 : pow_negative_q(v_);
+
+ // h(0) = h(0.5) - exp(log(v) * -q)
+ hx0_minus_hxm_ = (h0x5 - elogv_q) - hxm_;
+
+ // And s
+ s_ = use_precomputed ? 0.46153846153846123 : compute_s();
+}
+
+template <typename IntType>
+double zipf_distribution<IntType>::param_type::h(double x) const {
+ // std::exp(one_minus_q_ * std::log(v_ + x)) * one_minus_q_inv_;
+ x += v_;
+ return (one_minus_q_ == -1.0)
+ ? (-1.0 / x) // -exp(-log(x))
+ : (std::exp(std::log(x) * one_minus_q_) * one_minus_q_inv_);
+}
+
+template <typename IntType>
+double zipf_distribution<IntType>::param_type::hinv(double x) const {
+ // std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x)) - v_;
+ return -v_ + ((one_minus_q_ == -1.0)
+ ? (-1.0 / x) // exp(-log(-x))
+ : std::exp(one_minus_q_inv_ * std::log(one_minus_q_ * x)));
+}
+
+template <typename IntType>
+double zipf_distribution<IntType>::param_type::compute_s() const {
+ // 1 - hinv(h(1.5) - std::exp(std::log(v_ + 1) * -q_));
+ return 1.0 - hinv(h(1.5) - pow_negative_q(v_ + 1.0));
+}
+
+template <typename IntType>
+double zipf_distribution<IntType>::param_type::pow_negative_q(double x) const {
+ // std::exp(std::log(x) * -q_);
+ return q_ == 2.0 ? (1.0 / (x * x)) : std::exp(std::log(x) * -q_);
+}
+
+template <typename IntType>
+template <typename URBG>
+typename zipf_distribution<IntType>::result_type
+zipf_distribution<IntType>::operator()(
+ URBG& g, const param_type& p) { // NOLINT(runtime/references)
+ absl::uniform_real_distribution<double> uniform_double;
+ double k;
+ for (;;) {
+ 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);
+ if (k > p.k()) continue; // reject k > max_k
+ if (k - x <= p.s_) break;
+ const double h = p.h(k + 0.5);
+ const double r = p.pow_negative_q(p.v_ + k);
+ if (u >= h - r) break;
+ }
+ IntType ki = static_cast<IntType>(k);
+ assert(ki <= p.k_);
+ return ki;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_ostream<CharT, Traits>& operator<<(
+ std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
+ const zipf_distribution<IntType>& x) {
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+ auto saver = random_internal::make_ostream_state_saver(os);
+ os.precision(random_internal::stream_precision_helper<double>::kPrecision);
+ os << static_cast<stream_type>(x.k()) << os.fill() << x.q() << os.fill()
+ << x.v();
+ return os;
+}
+
+template <typename CharT, typename Traits, typename IntType>
+std::basic_istream<CharT, Traits>& operator>>(
+ std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
+ zipf_distribution<IntType>& x) { // NOLINT(runtime/references)
+ using result_type = typename zipf_distribution<IntType>::result_type;
+ using param_type = typename zipf_distribution<IntType>::param_type;
+ using stream_type =
+ typename random_internal::stream_format_type<IntType>::type;
+ stream_type k;
+ double q;
+ double v;
+
+ auto saver = random_internal::make_istream_state_saver(is);
+ is >> k >> q >> v;
+ if (!is.fail()) {
+ x.param(param_type(static_cast<result_type>(k), q, v));
+ }
+ return is;
+}
+
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_RANDOM_ZIPF_DISTRIBUTION_H_
diff --git a/absl/random/zipf_distribution_test.cc b/absl/random/zipf_distribution_test.cc
new file mode 100644
index 00000000..4d4a0fcf
--- /dev/null
+++ b/absl/random/zipf_distribution_test.cc
@@ -0,0 +1,423 @@
+// 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/zipf_distribution.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <random>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/internal/raw_logging.h"
+#include "absl/random/internal/chi_square.h"
+#include "absl/random/internal/sequence_urbg.h"
+#include "absl/random/random.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/strip.h"
+
+namespace {
+
+using ::absl::random_internal::kChiSquared;
+using ::testing::ElementsAre;
+
+template <typename IntType>
+class ZipfDistributionTypedTest : public ::testing::Test {};
+
+using IntTypes = ::testing::Types<int, int8_t, int16_t, int32_t, int64_t,
+ uint8_t, uint16_t, uint32_t, uint64_t>;
+TYPED_TEST_CASE(ZipfDistributionTypedTest, IntTypes);
+
+TYPED_TEST(ZipfDistributionTypedTest, SerializeTest) {
+ using param_type = typename absl::zipf_distribution<TypeParam>::param_type;
+
+ constexpr int kCount = 1000;
+ absl::InsecureBitGen gen;
+ for (const auto& param : {
+ param_type(),
+ param_type(32),
+ param_type(100, 3, 2),
+ param_type(std::numeric_limits<TypeParam>::max(), 4, 3),
+ param_type(std::numeric_limits<TypeParam>::max() / 2),
+ }) {
+ // Validate parameters.
+ const auto k = param.k();
+ const auto q = param.q();
+ const auto v = param.v();
+
+ absl::zipf_distribution<TypeParam> before(k, q, v);
+ EXPECT_EQ(before.k(), param.k());
+ EXPECT_EQ(before.q(), param.q());
+ EXPECT_EQ(before.v(), param.v());
+
+ {
+ absl::zipf_distribution<TypeParam> via_param(param);
+ EXPECT_EQ(via_param, before);
+ }
+
+ // Validate stream serialization.
+ std::stringstream ss;
+ ss << before;
+ absl::zipf_distribution<TypeParam> after(4, 5.5, 4.4);
+
+ EXPECT_NE(before.k(), after.k());
+ EXPECT_NE(before.q(), after.q());
+ EXPECT_NE(before.v(), after.v());
+ EXPECT_NE(before.param(), after.param());
+ EXPECT_NE(before, after);
+
+ ss >> after;
+
+ EXPECT_EQ(before.k(), after.k());
+ EXPECT_EQ(before.q(), after.q());
+ EXPECT_EQ(before.v(), after.v());
+ EXPECT_EQ(before.param(), after.param());
+ EXPECT_EQ(before, after);
+
+ // Smoke test.
+ auto sample_min = after.max();
+ auto sample_max = after.min();
+ for (int i = 0; i < kCount; i++) {
+ auto sample = after(gen);
+ EXPECT_GE(sample, after.min());
+ EXPECT_LE(sample, after.max());
+ if (sample > sample_max) sample_max = sample;
+ if (sample < sample_min) sample_min = sample;
+ }
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("Range: ", +sample_min, ", ", +sample_max));
+ }
+}
+
+class ZipfModel {
+ public:
+ ZipfModel(size_t k, double q, double v) : k_(k), q_(q), v_(v) {}
+
+ double mean() const { return mean_; }
+
+ // For the other moments of the Zipf distribution, see, for example,
+ // http://mathworld.wolfram.com/ZipfDistribution.html
+
+ // PMF(k) = (1 / k^s) / H(N,s)
+ // Returns the probability that any single invocation returns k.
+ double PMF(size_t i) { return i >= hnq_.size() ? 0.0 : hnq_[i] / sum_hnq_; }
+
+ // CDF = H(k, s) / H(N,s)
+ double CDF(size_t i) {
+ if (i >= hnq_.size()) {
+ return 1.0;
+ }
+ auto it = std::begin(hnq_);
+ double h = 0.0;
+ for (const auto end = it; it != end; it++) {
+ h += *it;
+ }
+ return h / sum_hnq_;
+ }
+
+ // The InverseCDF returns the k values which bound p on the upper and lower
+ // bound. Since there is no closed-form solution, this is implemented as a
+ // bisction of the cdf.
+ std::pair<size_t, size_t> InverseCDF(double p) {
+ size_t min = 0;
+ size_t max = hnq_.size();
+ while (max > min + 1) {
+ size_t target = (max + min) >> 1;
+ double x = CDF(target);
+ if (x > p) {
+ max = target;
+ } else {
+ min = target;
+ }
+ }
+ return {min, max};
+ }
+
+ // Compute the probability totals, which are based on the generalized harmonic
+ // number, H(N,s).
+ // H(N,s) == SUM(k=1..N, 1 / k^s)
+ //
+ // In the limit, H(N,s) == zetac(s) + 1.
+ //
+ // NOTE: The mean of a zipf distribution could be computed here as well.
+ // Mean := H(N, s-1) / H(N,s).
+ // Given the parameter v = 1, this gives the following function:
+ // (Hn(100, 1) - Hn(1,1)) / (Hn(100,2) - Hn(1,2)) = 6.5944
+ //
+ void Init() {
+ if (!hnq_.empty()) {
+ return;
+ }
+ hnq_.clear();
+ hnq_.reserve(std::min(k_, size_t{1000}));
+
+ sum_hnq_ = 0;
+ double qm1 = q_ - 1.0;
+ double sum_hnq_m1 = 0;
+ for (size_t i = 0; i < k_; i++) {
+ // Partial n-th generalized harmonic number
+ 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);
+ 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_);
+ sum_hnq_ += hnq;
+ hnq_.push_back(hnq);
+ if (i > 1000 && hnq <= 1e-10) {
+ // The harmonic number is too small.
+ break;
+ }
+ }
+ assert(sum_hnq_ > 0);
+ mean_ = sum_hnq_m1 / sum_hnq_;
+ }
+
+ private:
+ const size_t k_;
+ const double q_;
+ const double v_;
+
+ double mean_;
+ std::vector<double> hnq_;
+ double sum_hnq_;
+};
+
+using zipf_u64 = absl::zipf_distribution<uint64_t>;
+
+class ZipfTest : public testing::TestWithParam<zipf_u64::param_type>,
+ public ZipfModel {
+ public:
+ ZipfTest() : ZipfModel(GetParam().k(), GetParam().q(), GetParam().v()) {}
+
+ absl::InsecureBitGen rng_;
+};
+
+TEST_P(ZipfTest, ChiSquaredTest) {
+ const auto& param = GetParam();
+ Init();
+
+ size_t trials = 10000;
+
+ // Find the split-points for the buckets.
+ std::vector<size_t> points;
+ std::vector<double> expected;
+ {
+ double last_cdf = 0.0;
+ double min_p = 1.0;
+ for (double p = 0.01; p < 1.0; p += 0.01) {
+ auto x = InverseCDF(p);
+ if (points.empty() || points.back() < x.second) {
+ const double p = CDF(x.second);
+ points.push_back(x.second);
+ double q = p - last_cdf;
+ expected.push_back(q);
+ last_cdf = p;
+ if (q < min_p) {
+ min_p = q;
+ }
+ }
+ }
+ if (last_cdf < 0.999) {
+ points.push_back(std::numeric_limits<size_t>::max());
+ double q = 1.0 - last_cdf;
+ expected.push_back(q);
+ if (q < min_p) {
+ min_p = q;
+ }
+ } else {
+ points.back() = std::numeric_limits<size_t>::max();
+ expected.back() += (1.0 - last_cdf);
+ }
+ // The Chi-Squared score is not completely scale-invariant; it works best
+ // when the small values are in the small digits.
+ trials = static_cast<size_t>(8.0 / min_p);
+ }
+ ASSERT_GT(points.size(), 0);
+
+ // Generate n variates and fill the counts vector with the count of their
+ // occurrences.
+ std::vector<int64_t> buckets(points.size(), 0);
+ double avg = 0;
+ {
+ zipf_u64 dis(param);
+ for (size_t i = 0; i < trials; i++) {
+ uint64_t x = dis(rng_);
+ ASSERT_LE(x, dis.max());
+ ASSERT_GE(x, dis.min());
+ avg += static_cast<double>(x);
+ auto it = std::upper_bound(std::begin(points), std::end(points),
+ static_cast<size_t>(x));
+ buckets[std::distance(std::begin(points), it)]++;
+ }
+ avg = avg / static_cast<double>(trials);
+ }
+
+ // Validate the output using the Chi-Squared test.
+ for (auto& e : expected) {
+ e *= trials;
+ }
+
+ // The null-hypothesis is that the distribution is a poisson distribution with
+ // the provided mean (not estimated from the data).
+ const int dof = static_cast<int>(expected.size()) - 1;
+
+ // NOTE: This test runs about 15x per invocation, so a value of 0.9995 is
+ // approximately correct for a test suite failure rate of 1 in 100. In
+ // practice we see failures slightly higher than that.
+ const double threshold = absl::random_internal::ChiSquareValue(dof, 0.9999);
+
+ const double chi_square = absl::random_internal::ChiSquare(
+ std::begin(buckets), std::end(buckets), std::begin(expected),
+ std::end(expected));
+
+ const double p_actual =
+ absl::random_internal::ChiSquarePValue(chi_square, dof);
+
+ // Log if the chi_squared value is above the threshold.
+ if (chi_square > threshold) {
+ ABSL_INTERNAL_LOG(INFO, "values");
+ for (size_t i = 0; i < expected.size(); i++) {
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat(points[i], ": ", buckets[i],
+ " vs. E=", expected[i]));
+ }
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat("trials ", trials));
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat("mean ", avg, " vs. expected ", mean()));
+ ABSL_INTERNAL_LOG(INFO, absl::StrCat(kChiSquared, "(data, ", dof, ") = ",
+ chi_square, " (", p_actual, ")"));
+ ABSL_INTERNAL_LOG(INFO,
+ absl::StrCat(kChiSquared, " @ 0.9995 = ", threshold));
+ FAIL() << kChiSquared << " value of " << chi_square
+ << " is above the threshold.";
+ }
+}
+
+std::vector<zipf_u64::param_type> GenParams() {
+ using param = zipf_u64::param_type;
+ const auto k = param().k();
+ const auto q = param().q();
+ const auto v = param().v();
+ const uint64_t k2 = 1 << 10;
+ return std::vector<zipf_u64::param_type>{
+ // Default
+ param(k, q, v),
+ // vary K
+ param(4, q, v), param(1 << 4, q, v), param(k2, q, v),
+ // vary V
+ param(k2, q, 0.5), param(k2, q, 1.5), param(k2, q, 2.5), param(k2, q, 10),
+ // vary Q
+ param(k2, 1.5, v), param(k2, 3, v), param(k2, 5, v), param(k2, 10, v),
+ // Vary V & Q
+ param(k2, 1.5, 0.5), param(k2, 3, 1.5), param(k, 10, 10)};
+}
+
+std::string ParamName(
+ const ::testing::TestParamInfo<zipf_u64::param_type>& info) {
+ const auto& p = info.param;
+ std::string name = absl::StrCat("k_", p.k(), "__q_", absl::SixDigits(p.q()),
+ "__v_", absl::SixDigits(p.v()));
+ return absl::StrReplaceAll(name, {{"+", "_"}, {"-", "_"}, {".", "_"}});
+}
+
+INSTANTIATE_TEST_SUITE_P(All, ZipfTest, ::testing::ValuesIn(GenParams()),
+ ParamName);
+
+// NOTE: absl::zipf_distribution is not guaranteed to be stable.
+TEST(ZipfDistributionTest, StabilityTest) {
+ // absl::zipf_distribution stability relies on
+ // absl::uniform_real_distribution, std::log, std::exp, std::log1p
+ absl::random_internal::sequence_urbg urbg(
+ {0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
+ 0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
+ 0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
+ 0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
+
+ std::vector<int> output(10);
+
+ {
+ absl::zipf_distribution<int32_t> dist;
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ EXPECT_THAT(output, ElementsAre(10031, 0, 0, 3, 6, 0, 7, 47, 0, 0));
+ }
+ urbg.reset();
+ {
+ absl::zipf_distribution<int32_t> dist(std::numeric_limits<int32_t>::max(),
+ 3.3);
+ std::generate(std::begin(output), std::end(output),
+ [&] { return dist(urbg); });
+ EXPECT_THAT(output, ElementsAre(44, 0, 0, 0, 0, 1, 0, 1, 3, 0));
+ }
+}
+
+TEST(ZipfDistributionTest, AlgorithmBounds) {
+ absl::zipf_distribution<int32_t> dist;
+
+ // Small values from absl::uniform_real_distribution map to larger Zipf
+ // distribution values.
+ const std::pair<uint64_t, int32_t> kInputs[] = {
+ {0xffffffffffffffff, 0x0}, {0x7fffffffffffffff, 0x0},
+ {0x3ffffffffffffffb, 0x1}, {0x1ffffffffffffffd, 0x4},
+ {0xffffffffffffffe, 0x9}, {0x7ffffffffffffff, 0x12},
+ {0x3ffffffffffffff, 0x25}, {0x1ffffffffffffff, 0x4c},
+ {0xffffffffffffff, 0x99}, {0x7fffffffffffff, 0x132},
+ {0x3fffffffffffff, 0x265}, {0x1fffffffffffff, 0x4cc},
+ {0xfffffffffffff, 0x999}, {0x7ffffffffffff, 0x1332},
+ {0x3ffffffffffff, 0x2665}, {0x1ffffffffffff, 0x4ccc},
+ {0xffffffffffff, 0x9998}, {0x7fffffffffff, 0x1332f},
+ {0x3fffffffffff, 0x2665a}, {0x1fffffffffff, 0x4cc9e},
+ {0xfffffffffff, 0x998e0}, {0x7ffffffffff, 0x133051},
+ {0x3ffffffffff, 0x265ae4}, {0x1ffffffffff, 0x4c9ed3},
+ {0xffffffffff, 0x98e223}, {0x7fffffffff, 0x13058c4},
+ {0x3fffffffff, 0x25b178e}, {0x1fffffffff, 0x4a062b2},
+ {0xfffffffff, 0x8ee23b8}, {0x7ffffffff, 0x10b21642},
+ {0x3ffffffff, 0x1d89d89d}, {0x1ffffffff, 0x2fffffff},
+ {0xffffffff, 0x45d1745d}, {0x7fffffff, 0x5a5a5a5a},
+ {0x3fffffff, 0x69ee5846}, {0x1fffffff, 0x73ecade3},
+ {0xfffffff, 0x79a9d260}, {0x7ffffff, 0x7cc0532b},
+ {0x3ffffff, 0x7e5ad146}, {0x1ffffff, 0x7f2c0bec},
+ {0xffffff, 0x7f95adef}, {0x7fffff, 0x7fcac0da},
+ {0x3fffff, 0x7fe55ae2}, {0x1fffff, 0x7ff2ac0e},
+ {0xfffff, 0x7ff955ae}, {0x7ffff, 0x7ffcaac1},
+ {0x3ffff, 0x7ffe555b}, {0x1ffff, 0x7fff2aac},
+ {0xffff, 0x7fff9556}, {0x7fff, 0x7fffcaab},
+ {0x3fff, 0x7fffe555}, {0x1fff, 0x7ffff2ab},
+ {0xfff, 0x7ffff955}, {0x7ff, 0x7ffffcab},
+ {0x3ff, 0x7ffffe55}, {0x1ff, 0x7fffff2b},
+ {0xff, 0x7fffff95}, {0x7f, 0x7fffffcb},
+ {0x3f, 0x7fffffe5}, {0x1f, 0x7ffffff3},
+ {0xf, 0x7ffffff9}, {0x7, 0x7ffffffd},
+ {0x3, 0x7ffffffe}, {0x1, 0x7fffffff},
+ };
+
+ for (const auto& instance : kInputs) {
+ absl::random_internal::sequence_urbg urbg({instance.first});
+ EXPECT_EQ(instance.second, dist(urbg));
+ }
+}
+
+} // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index 3b85f1b4..20511a35 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -5,21 +5,20 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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.
-#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
- "ABSL_TEST_COPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(
@@ -405,7 +404,7 @@ cc_test(
cc_test(
name = "numbers_test",
- size = "small",
+ size = "medium",
srcs = [
"internal/numbers_test_common.h",
"numbers_test.cc",
@@ -558,8 +557,8 @@ cc_library(
visibility = ["//visibility:private"],
deps = [
":strings",
+ "//absl/base:config",
"//absl/base:core_headers",
- "//absl/container:inlined_vector",
"//absl/meta:type_traits",
"//absl/numeric:int128",
"//absl/types:span",
@@ -629,7 +628,7 @@ cc_test(
cc_test(
name = "str_format_convert_test",
- size = "small",
+ size = "medium",
srcs = ["internal/str_format/convert_test.cc"],
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 5b877ad1..e63eec19 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,468 +14,507 @@
# limitations under the License.
#
-
-list(APPEND STRINGS_PUBLIC_HEADERS
- "ascii.h"
- "charconv.h"
- "escaping.h"
- "match.h"
- "numbers.h"
- "str_cat.h"
- "string_view.h"
- "strip.h"
- "str_join.h"
- "str_replace.h"
- "str_split.h"
- "substitute.h"
-)
-
-
-list(APPEND STRINGS_INTERNAL_HEADERS
- "internal/char_map.h"
- "internal/charconv_bigint.h"
- "internal/charconv_parse.h"
- "internal/memutil.h"
- "internal/ostringstream.h"
- "internal/resize_uninitialized.h"
- "internal/stl_type_traits.h"
- "internal/str_join_internal.h"
- "internal/str_split_internal.h"
- "internal/utf8.h"
-)
-
-
-
-# add string library
-list(APPEND STRINGS_SRC
- "ascii.cc"
- "charconv.cc"
- "escaping.cc"
- "internal/charconv_bigint.cc"
- "internal/charconv_parse.cc"
- "internal/memutil.cc"
- "internal/memutil.h"
- "internal/utf8.cc"
- "internal/ostringstream.cc"
- "match.cc"
- "numbers.cc"
- "str_cat.cc"
- "str_replace.cc"
- "str_split.cc"
- "string_view.cc"
- "substitute.cc"
- ${STRINGS_PUBLIC_HEADERS}
- ${STRINGS_INTERNAL_HEADERS}
-)
-set(STRINGS_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate)
-
-absl_library(
- TARGET
- absl_strings
- SOURCES
- ${STRINGS_SRC}
- PUBLIC_LIBRARIES
- ${STRINGS_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
strings
-)
-
-# add str_format library
-absl_header_library(
- TARGET
- absl_str_format
- PUBLIC_LIBRARIES
- str_format_internal
- EXPORT_NAME
- str_format
-)
-
-# str_format_internal
-absl_library(
- TARGET
- str_format_internal
- SOURCES
- "internal/str_format/arg.cc"
- "internal/str_format/bind.cc"
- "internal/str_format/extension.cc"
- "internal/str_format/float_conversion.cc"
- "internal/str_format/output.cc"
- "internal/str_format/parser.cc"
- "internal/str_format/arg.h"
- "internal/str_format/bind.h"
- "internal/str_format/checker.h"
- "internal/str_format/extension.h"
- "internal/str_format/float_conversion.h"
- "internal/str_format/output.h"
- "internal/str_format/parser.h"
- PUBLIC_LIBRARIES
- str_format_extension_internal
- absl::strings
+ HDRS
+ "ascii.h"
+ "charconv.h"
+ "escaping.h"
+ "match.h"
+ "numbers.h"
+ "str_cat.h"
+ "str_join.h"
+ "str_replace.h"
+ "str_split.h"
+ "string_view.h"
+ "strip.h"
+ "substitute.h"
+ SRCS
+ "ascii.cc"
+ "charconv.cc"
+ "escaping.cc"
+ "internal/charconv_bigint.cc"
+ "internal/charconv_bigint.h"
+ "internal/charconv_parse.cc"
+ "internal/charconv_parse.h"
+ "internal/memutil.cc"
+ "internal/memutil.h"
+ "internal/stl_type_traits.h"
+ "internal/str_join_internal.h"
+ "internal/str_split_internal.h"
+ "match.cc"
+ "numbers.cc"
+ "str_cat.cc"
+ "str_replace.cc"
+ "str_split.cc"
+ "string_view.cc"
+ "substitute.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::strings_internal
absl::base
- absl::numeric
- absl::inlined_vector
- absl::span
-)
-
-# str_format_extension_internal
-absl_library(
- TARGET
- str_format_extension_internal
- SOURCES
- "internal/str_format/extension.cc"
- "internal/str_format/extension.h"
- "internal/str_format/output.cc"
- "internal/str_format/output.h"
- PUBLIC_LIBRARIES
- absl::base
- absl::strings
-)
-
-# pow10_helper
-absl_library(
- TARGET
- pow10_helper
- SOURCES
- "internal/pow10_helper.cc"
- "internal/pow10_helper.h"
-)
-
-#
-## TESTS
-#
-
-# test match_test
-set(MATCH_TEST_SRC "match_test.cc")
-set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+ absl::bits
+ absl::config
+ absl::core_headers
+ absl::endian
+ absl::throw_delegate
+ absl::memory
+ absl::type_traits
+ absl::int128
+ PUBLIC
+)
+
+absl_cc_library(
+ NAME
+ strings_internal
+ HDRS
+ "internal/char_map.h"
+ "internal/ostringstream.h"
+ "internal/resize_uninitialized.h"
+ "internal/utf8.h"
+ SRCS
+ "internal/ostringstream.cc"
+ "internal/utf8.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::endian
+ absl::type_traits
+)
+
+absl_cc_test(
+ NAME
match_test
- SOURCES
- ${MATCH_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MATCH_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "match_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
)
-
-# test escaping_test
-set(ESCAPING_TEST_SRC "escaping_test.cc")
-set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
escaping_test
- SOURCES
- ${ESCAPING_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ESCAPING_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "escaping_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ absl::fixed_array
+ gmock_main
)
-
-# test ascii_test
-set(ASCII_TEST_SRC "ascii_test.cc")
-set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
ascii_test
- SOURCES
- ${ASCII_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ASCII_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "ascii_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
)
-
-# test memutil_test
-set(MEMUTIL_TEST_SRC "internal/memutil_test.cc")
-set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
memutil_test
- SOURCES
- ${MEMUTIL_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MEMUTIL_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/memutil.h"
+ "internal/memutil_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
)
-
-# test utf8_test
-set(UTF8_TEST_SRC "internal/utf8_test.cc")
-set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
utf8_test
- SOURCES
- ${UTF8_TEST_SRC}
- PUBLIC_LIBRARIES
- ${UTF8_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/utf8_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ absl::base
+ absl::core_headers
+ gmock_main
)
-
-# test string_view_test
-set(STRING_VIEW_TEST_SRC "string_view_test.cc")
-set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_internal_throw_delegate absl::base)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
string_view_test
- SOURCES
- ${STRING_VIEW_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STRING_VIEW_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "string_view_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::strings
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ gmock_main
)
-
-# test substitute_test
-set(SUBSTITUTE_TEST_SRC "substitute_test.cc")
-set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
substitute_test
- SOURCES
- ${SUBSTITUTE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "substitute_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
)
-
-# test str_replace_test
-set(STR_REPLACE_TEST_SRC "str_replace_test.cc")
-set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_internal_throw_delegate)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_replace_test
- SOURCES
- ${STR_REPLACE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_REPLACE_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "str_replace_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ gmock_main
)
-
-# test str_split_test
-set(STR_SPLIT_TEST_SRC "str_split_test.cc")
-set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_internal_throw_delegate)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_split_test
- SOURCES
- ${STR_SPLIT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_SPLIT_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "str_split_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::dynamic_annotations
+ gmock_main
)
-
-# test ostringstream_test
-set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc")
-set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
ostringstream_test
- SOURCES
- ${OSTRINGSTREAM_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/ostringstream_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ gmock_main
)
-
-# test resize_uninitialized_test
-set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc")
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
resize_uninitialized_test
- SOURCES
- ${RESIZE_UNINITIALIZED_TEST_SRC}
+ SRCS
+ "internal/resize_uninitialized.h"
+ "internal/resize_uninitialized_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::type_traits
+ gmock_main
)
-
-# test str_join_test
-set(STR_JOIN_TEST_SRC "str_join_test.cc")
-set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_join_test
- SOURCES
- ${STR_JOIN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_JOIN_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "str_join_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::memory
+ gmock_main
)
-
-# test str_cat_test
-set(STR_CAT_TEST_SRC "str_cat_test.cc")
-set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_cat_test
- SOURCES
- ${STR_CAT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STR_CAT_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "str_cat_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::core_headers
+ gmock_main
)
-
-# test numbers_test
-set(NUMBERS_TEST_SRC "numbers_test.cc")
-set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings pow10_helper)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
numbers_test
- SOURCES
- ${NUMBERS_TEST_SRC}
- PUBLIC_LIBRARIES
- ${NUMBERS_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/numbers_test_common.h"
+ "numbers_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ absl::core_headers
+ absl::pow10_helper
+ gmock_main
)
-
-# test strip_test
-set(STRIP_TEST_SRC "strip_test.cc")
-set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
strip_test
- SOURCES
- ${STRIP_TEST_SRC}
- PUBLIC_LIBRARIES
- ${STRIP_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "strip_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
)
-
-# test char_map_test
-set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc")
-set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
char_map_test
- SOURCES
- ${CHAR_MAP_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHAR_MAP_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/char_map_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings_internal
+ gmock_main
)
-
-# test charconv_test
-set(CHARCONV_TEST_SRC "charconv_test.cc")
-set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings absl::str_format pow10_helper)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
charconv_test
- SOURCES
- ${CHARCONV_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "charconv_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::str_format
+ absl::base
+ absl::pow10_helper
+ gmock_main
)
-
-# test charconv_parse_test
-set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc")
-set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
charconv_parse_test
- SOURCES
- ${CHARCONV_PARSE_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/charconv_parse.h"
+ "internal/charconv_parse_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
)
+absl_cc_test(
+ NAME
+ charconv_bigint_test
+ SRCS
+ "internal/charconv_bigint.h"
+ "internal/charconv_bigint_test.cc"
+ "internal/charconv_parse.h"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::strings
+ absl::base
+ gmock_main
+)
-# test charconv_bigint_test
-set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc")
-set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings)
+absl_cc_library(
+ NAME
+ str_format
+ HDRS
+ "str_format.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::str_format_internal
+ PUBLIC
+)
-absl_test(
- TARGET
- charconv_bigint_test
- SOURCES
- ${CHARCONV_BIGINT_TEST_SRC}
- PUBLIC_LIBRARIES
- ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES}
-)
-# test str_format_test
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
+ str_format_internal
+ HDRS
+ "internal/str_format/arg.h"
+ "internal/str_format/bind.h"
+ "internal/str_format/checker.h"
+ "internal/str_format/extension.h"
+ "internal/str_format/float_conversion.h"
+ "internal/str_format/output.h"
+ "internal/str_format/parser.h"
+ SRCS
+ "internal/str_format/arg.cc"
+ "internal/str_format/bind.cc"
+ "internal/str_format/extension.cc"
+ "internal/str_format/float_conversion.cc"
+ "internal/str_format/output.cc"
+ "internal/str_format/parser.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::strings
+ absl::config
+ absl::core_headers
+ absl::type_traits
+ absl::int128
+ absl::span
+)
+
+absl_cc_test(
+ NAME
str_format_test
- SOURCES
+ SRCS
"str_format_test.cc"
- PUBLIC_LIBRARIES
- absl::base
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
absl::str_format
absl::strings
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_format_extension_test
+ SRCS
+ "internal/str_format/extension_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format
+ absl::str_format_internal
+ gmock_main
+)
+
+absl_cc_test(
+ NAME
+ str_format_arg_test
+ SRCS
+ "internal/str_format/arg_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format
+ absl::str_format_internal
+ gmock_main
)
-# test str_format_bind_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_bind_test
- SOURCES
+ SRCS
"internal/str_format/bind_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ gmock_main
)
-# test str_format_checker_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_checker_test
- SOURCES
+ SRCS
"internal/str_format/checker_test.cc"
- PUBLIC_LIBRARIES
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
absl::str_format
+ gmock_main
)
-# test str_format_convert_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_convert_test
- SOURCES
+ SRCS
"internal/str_format/convert_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
- absl::numeric
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ absl::int128
+ gmock_main
)
-# test str_format_output_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_output_test
- SOURCES
+ SRCS
"internal/str_format/output_test.cc"
- PUBLIC_LIBRARIES
- str_format_extension_internal
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ gmock_main
)
-# test str_format_parser_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
str_format_parser_test
- SOURCES
+ SRCS
"internal/str_format/parser_test.cc"
- PUBLIC_LIBRARIES
- str_format_internal
- absl::base
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::str_format_internal
+ absl::core_headers
+ gmock_main
+)
+
+absl_cc_library(
+ NAME
+ pow10_helper
+ HDRS
+ "internal/pow10_helper.h"
+ SRCS
+ "internal/pow10_helper.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ TESTONLY
)
-# test pow10_helper_test
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
pow10_helper_test
- SOURCES
+ SRCS
"internal/pow10_helper_test.cc"
- PUBLIC_LIBRARIES
- pow10_helper
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::pow10_helper
absl::str_format
+ gmock_main
)
diff --git a/absl/strings/ascii.cc b/absl/strings/ascii.cc
index 5d08e816..045a5e21 100644
--- a/absl/strings/ascii.cc
+++ b/absl/strings/ascii.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/strings/ascii.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace ascii_internal {
// # Table generated by this Python code (bit 0x02 is currently unused):
@@ -196,5 +196,5 @@ void RemoveExtraAsciiWhitespace(std::string* str) {
str->erase(output_it - &(*str)[0]);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/ascii.h b/absl/strings/ascii.h
index 98418fd2..ebcbb11a 100644
--- a/absl/strings/ascii.h
+++ b/absl/strings/ascii.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -59,7 +59,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace ascii_internal {
// Declaration for an array of bitfields holding character information.
@@ -235,7 +235,7 @@ inline void StripAsciiWhitespace(std::string* str) {
// Removes leading, trailing, and consecutive internal whitespace.
void RemoveExtraAsciiWhitespace(std::string*);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_ASCII_H_
diff --git a/absl/strings/ascii_benchmark.cc b/absl/strings/ascii_benchmark.cc
index 8dea4b8c..aca458c8 100644
--- a/absl/strings/ascii_benchmark.cc
+++ b/absl/strings/ascii_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/ascii_test.cc b/absl/strings/ascii_test.cc
index 9903b049..5ecd23f8 100644
--- a/absl/strings/ascii_test.cc
+++ b/absl/strings/ascii_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/charconv.cc b/absl/strings/charconv.cc
index 21ea17b1..866a163e 100644
--- a/absl/strings/charconv.cc
+++ b/absl/strings/charconv.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -57,7 +57,7 @@
// narrower mantissas.
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
template <typename FloatType>
@@ -552,9 +552,10 @@ CalculatedFloat CalculateFromParsedDecimal(
int binary_exponent = Power10Exponent(parsed_decimal.exponent);
// Discard bits that are inaccurate due to truncation error. The magic
- // `mantissa_width` constants below are justified in charconv_algorithm.md.
- // They represent the number of bits in `wide_binary_mantissa` that are
- // guaranteed to be unaffected by error propagation.
+ // `mantissa_width` constants below are justified in
+ // https://abseil.io/about/design/charconv. They represent the number of bits
+ // in `wide_binary_mantissa` that are guaranteed to be unaffected by error
+ // propagation.
bool mantissa_exact;
int mantissa_width;
if (parsed_decimal.subrange_begin) {
@@ -980,5 +981,5 @@ const int16_t kPower10ExponentTable[] = {
};
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/charconv.h b/absl/strings/charconv.h
index 160306e6..0b84ccac 100644
--- a/absl/strings/charconv.h
+++ b/absl/strings/charconv.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include <system_error> // NOLINT(build/c++11)
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Workalike compatibilty version of std::chars_format from C++17.
//
@@ -50,9 +50,9 @@ struct from_chars_result {
// this only supports the `double` and `float` types.
//
// This interface incorporates the proposed resolutions for library issues
-// DR 3800 and DR 3801. If these are adopted with different wording,
+// DR 3080 and DR 3081. If these are adopted with different wording,
// Abseil's behavior will change to match the standard. (The behavior most
-// likely to change is for DR 3801, which says what `value` will be set to in
+// likely to change is for DR 3081, which says what `value` will be set to in
// the case of overflow and underflow. Code that wants to avoid possible
// breaking changes in this area should not depend on `value` when the returned
// from_chars_result indicates a range error.)
@@ -111,7 +111,7 @@ inline chars_format& operator^=(chars_format& lhs, chars_format rhs) {
return lhs;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_CHARCONV_H_
diff --git a/absl/strings/charconv_benchmark.cc b/absl/strings/charconv_benchmark.cc
index fd83f44e..644b2abd 100644
--- a/absl/strings/charconv_benchmark.cc
+++ b/absl/strings/charconv_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/charconv_test.cc b/absl/strings/charconv_test.cc
index d07537eb..b58fad26 100644
--- a/absl/strings/charconv_test.cc
+++ b/absl/strings/charconv_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -279,7 +279,8 @@ void TestHalfwayValue(const std::string& mantissa, int exponent,
absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low);
EXPECT_EQ(expected_low, actual_low);
- std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent);
+ std::string high_rep =
+ absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent);
FloatType actual_high = 0;
absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(),
actual_high);
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index 69053c19..eb0974dc 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,7 +33,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
// Digit conversion.
@@ -180,7 +180,8 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
ch = (ch << 4) + hex_digit_to_int(*++p);
if (ch > 0xFF) {
if (error) {
- *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) +
+ *error = "Value of \\" +
+ std::string(hex_start, p + 1 - hex_start) +
" exceeds 0xff";
}
return false;
@@ -295,7 +296,7 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
// ----------------------------------------------------------------------
// CUnescapeInternal()
//
-// Same as above but uses a C++ string for output. 'source' and 'dest'
+// 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,
@@ -325,7 +326,8 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
//
// Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint().
// ----------------------------------------------------------------------
-std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) {
+std::string CEscapeInternal(absl::string_view src, bool use_hex,
+ bool utf8_safe) {
std::string dest;
bool last_hex_escape = false; // true if last output char was \xNN.
@@ -787,7 +789,7 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
// Base64 encodes three bytes of input at a time. If the input is not
// divisible by three, we pad as appropriate.
//
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// Special processing is performed if fewer than 24 bits are available
// at the end of the data being encoded. A full encoding quantum is
// always completed at the end of a quantity. When fewer than 24 input
@@ -801,12 +803,12 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
size_t len = (input_len / 3) * 4;
if (input_len % 3 == 0) {
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (1) the final quantum of encoding input is an integral multiple of 24
// bits; here, the final unit of encoded output will be an integral
// multiple of 4 characters with no "=" padding,
} else if (input_len % 3 == 1) {
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (2) the final quantum of encoding input is exactly 8 bits; here, the
// final unit of encoded output will be two characters followed by two
// "=" padding characters, or
@@ -815,7 +817,7 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
len += 2;
}
} else { // (input_len % 3 == 2)
- // (from http://tools.ietf.org/html/rfc3548)
+ // (from https://tools.ietf.org/html/rfc3548)
// (3) the final quantum of encoding input is exactly 16 bits; here, the
// final unit of encoded output will be three characters followed by one
// "=" padding character.
@@ -844,8 +846,8 @@ size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest,
// Three bytes of data encodes to four characters of cyphertext.
// So we can pump through three-byte chunks atomically.
- if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3
- while (cur_src < limit_src - 3) { // as long as we have >= 32 bits
+ if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3.
+ while (cur_src < limit_src - 3) { // While we have >= 32 bits.
uint32_t in = absl::big_endian::Load32(cur_src) >> 8;
cur_dest[0] = base64[in >> 18];
@@ -1012,7 +1014,8 @@ void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) {
}
}
-// This is a templated function so that T can be either a char* or a string.
+// This is a templated function so that T can be either a char* or a
+// std::string.
template <typename T>
void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
auto dest_ptr = &dest[0];
@@ -1029,7 +1032,8 @@ void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) {
//
// See CUnescapeInternal() for implementation details.
// ----------------------------------------------------------------------
-bool CUnescape(absl::string_view source, std::string* dest, std::string* error) {
+bool CUnescape(absl::string_view source, std::string* dest,
+ std::string* error) {
return CUnescapeInternal(source, kUnescapeNulls, dest, error);
}
@@ -1052,10 +1056,10 @@ std::string Utf8SafeCHexEscape(absl::string_view src) {
}
// ----------------------------------------------------------------------
-// ptrdiff_t Base64Unescape() - base64 decoder
-// ptrdiff_t Base64Escape() - base64 encoder
-// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder
-// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder
+// Base64Unescape() - base64 decoder
+// Base64Escape() - base64 encoder
+// WebSafeBase64Unescape() - Google's variation of base64 decoder
+// WebSafeBase64Escape() - Google's variation of base64 encoder
//
// Check out
// http://tools.ietf.org/html/rfc2045 for formal description, but what we
@@ -1093,6 +1097,20 @@ void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
src.size(), dest, false, kWebSafeBase64Chars);
}
+std::string Base64Escape(absl::string_view src) {
+ std::string dest;
+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+ src.size(), &dest, true, kBase64Chars);
+ return dest;
+}
+
+std::string WebSafeBase64Escape(absl::string_view src) {
+ std::string dest;
+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()),
+ src.size(), &dest, false, kWebSafeBase64Chars);
+ return dest;
+}
+
std::string HexStringToBytes(absl::string_view from) {
std::string result;
const auto num = from.size() / 2;
@@ -1109,5 +1127,5 @@ std::string BytesToHexString(absl::string_view from) {
return result;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/escaping.h b/absl/strings/escaping.h
index a31fb374..7f1c5d46 100644
--- a/absl/strings/escaping.h
+++ b/absl/strings/escaping.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,6 @@
//
// This header file contains string utilities involved in escaping and
// unescaping strings in various ways.
-//
#ifndef ABSL_STRINGS_ESCAPING_H_
#define ABSL_STRINGS_ESCAPING_H_
@@ -34,12 +33,12 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// CUnescape()
//
// Unescapes a `source` string and copies it into `dest`, rewriting C-style
-// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into
+// escape sequences (https://en.cppreference.com/w/cpp/language/escape) into
// their proper code point equivalents, returning `true` if successful.
//
// The following unescape sequences can be handled:
@@ -57,7 +56,6 @@ inline namespace lts_2018_12_18 {
// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and
// 0x99).
//
-//
// If any errors are encountered, this function returns `false`, leaving the
// `dest` output parameter in an unspecified state, and stores the first
// encountered error in `error`. To disable error reporting, set `error` to
@@ -81,7 +79,7 @@ inline bool CUnescape(absl::string_view source, std::string* dest) {
// CEscape()
//
// Escapes a 'src' string using C-style escapes sequences
-// (http://en.cppreference.com/w/cpp/language/escape), escaping other
+// (https://en.cppreference.com/w/cpp/language/escape), escaping other
// non-printable/non-whitespace bytes as octal sequences (e.g. "\377").
//
// Example:
@@ -135,16 +133,18 @@ bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
// Base64Escape()
//
-// Encodes a `src` string into a `dest` buffer using base64 encoding, with
-// padding characters. This function conforms with RFC 4648 section 4 (base64).
+// Encodes a `src` string into a base64-encoded string, with padding characters.
+// This function conforms with RFC 4648 section 4 (base64).
void Base64Escape(absl::string_view src, std::string* dest);
+std::string Base64Escape(absl::string_view src);
// WebSafeBase64Escape()
//
-// Encodes a `src` string into a `dest` buffer using '-' instead of '+' and
-// '_' instead of '/', and without padding. This function conforms with RFC 4648
-// section 5 (base64url).
+// Encodes a `src` string into a base64-like string, using '-' instead of '+'
+// and '_' instead of '/', and without padding. This function conforms with RFC
+// 4648 section 5 (base64url).
void WebSafeBase64Escape(absl::string_view src, std::string* dest);
+std::string WebSafeBase64Escape(absl::string_view src);
// HexStringToBytes()
//
@@ -158,7 +158,7 @@ std::string HexStringToBytes(absl::string_view from);
// `2*from.size()`.
std::string BytesToHexString(absl::string_view from);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_ESCAPING_H_
diff --git a/absl/strings/escaping_benchmark.cc b/absl/strings/escaping_benchmark.cc
index 0f791f4e..10d5b033 100644
--- a/absl/strings/escaping_benchmark.cc
+++ b/absl/strings/escaping_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/escaping_test.cc b/absl/strings/escaping_test.cc
index 9dc27f3f..1967975b 100644
--- a/absl/strings/escaping_test.cc
+++ b/absl/strings/escaping_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -36,18 +36,19 @@ struct epair {
TEST(CEscape, EscapeAndUnescape) {
const std::string inputs[] = {
- std::string("foo\nxx\r\b\0023"),
- std::string(""),
- std::string("abc"),
- std::string("\1chad_rules"),
- std::string("\1arnar_drools"),
- std::string("xxxx\r\t'\"\\"),
- std::string("\0xx\0", 4),
- std::string("\x01\x31"),
- std::string("abc\xb\x42\141bc"),
- std::string("123\1\x31\x32\x33"),
- std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
- std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
+ std::string("foo\nxx\r\b\0023"),
+ std::string(""),
+ std::string("abc"),
+ std::string("\1chad_rules"),
+ std::string("\1arnar_drools"),
+ std::string("xxxx\r\t'\"\\"),
+ std::string("\0xx\0", 4),
+ std::string("\x01\x31"),
+ std::string("abc\xb\x42\141bc"),
+ std::string("123\1\x31\x32\x33"),
+ std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"),
+ std::string(
+ "\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"),
};
// Do this twice, once for octal escapes and once for hex escapes.
for (int kind = 0; kind < 4; kind++) {
@@ -71,6 +72,11 @@ TEST(CEscape, EscapeAndUnescape) {
EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str));
EXPECT_EQ(unescaped_str, original);
+ unescaped_str.erase();
+ std::string error;
+ EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str, &error));
+ EXPECT_EQ(error, "");
+
// Check in-place unescaping
std::string s = escaped;
EXPECT_TRUE(absl::CUnescape(s, &s));
@@ -149,7 +155,8 @@ TEST(CEscape, BasicEscaping) {
TEST(Unescape, BasicFunction) {
epair tests[] =
- {{"\\u0030", "0"},
+ {{"", ""},
+ {"\\u0030", "0"},
{"\\u00A3", "\xC2\xA3"},
{"\\u22FD", "\xE2\x8B\xBD"},
{"\\U00010000", "\xF0\x90\x80\x80"},
@@ -159,20 +166,22 @@ TEST(Unescape, BasicFunction) {
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
+ 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) {
std::string error;
std::string out;
EXPECT_FALSE(absl::CUnescape(e, &out, &error));
EXPECT_FALSE(error.empty());
+
+ out.erase();
+ EXPECT_FALSE(absl::CUnescape(e, &out));
}
}
@@ -258,9 +267,11 @@ TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) {
// All escapes, including newlines and null escapes, should have been
// converted to the equivalent characters.
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0\n"
- "\0", 7), result_string_);
+ "0\n"
+ "\0\n"
+ "\0",
+ 7),
+ result_string_);
}
@@ -268,17 +279,21 @@ TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) {
std::string original_string(kStringWithMultipleHexNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0\n"
- "\0", 7), result_string_);
+ "0\n"
+ "\0\n"
+ "\0",
+ 7),
+ result_string_);
}
TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) {
std::string original_string(kStringWithMultipleUnicodeNulls);
EXPECT_TRUE(absl::CUnescape(original_string, &result_string_));
EXPECT_EQ(std::string("\0\n"
- "0\n"
- "\0", 5), result_string_);
+ "0\n"
+ "\0",
+ 5),
+ result_string_);
}
static struct {
@@ -550,6 +565,7 @@ void TestEscapeAndUnescape() {
StringType encoded("this junk should be ignored");
absl::Base64Escape(tc.plaintext, &encoded);
EXPECT_EQ(encoded, tc.cyphertext);
+ EXPECT_EQ(absl::Base64Escape(tc.plaintext), tc.cyphertext);
StringType decoded("this junk should be ignored");
EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded));
@@ -568,6 +584,7 @@ void TestEscapeAndUnescape() {
encoded = "this junk should be ignored";
absl::WebSafeBase64Escape(tc.plaintext, &encoded);
EXPECT_EQ(encoded, websafe);
+ EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), websafe);
// Let's try the std::string version of the decoder
decoded = "this junk should be ignored";
@@ -580,6 +597,7 @@ void TestEscapeAndUnescape() {
StringType buffer;
absl::WebSafeBase64Escape(tc.plaintext, &buffer);
EXPECT_EQ(tc.cyphertext, buffer);
+ EXPECT_EQ(absl::WebSafeBase64Escape(tc.plaintext), tc.cyphertext);
}
// Verify the behavior when decoding bad data
diff --git a/absl/strings/internal/char_map.h b/absl/strings/internal/char_map.h
index 10b7d007..772ae869 100644
--- a/absl/strings/internal/char_map.h
+++ b/absl/strings/internal/char_map.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
class Charmap {
@@ -150,7 +150,7 @@ constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); }
constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); }
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_
diff --git a/absl/strings/internal/char_map_benchmark.cc b/absl/strings/internal/char_map_benchmark.cc
index c45f3157..5cef967b 100644
--- a/absl/strings/internal/char_map_benchmark.cc
+++ b/absl/strings/internal/char_map_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/char_map_test.cc b/absl/strings/internal/char_map_test.cc
index c3601e10..d3306241 100644
--- a/absl/strings/internal/char_map_test.cc
+++ b/absl/strings/internal/char_map_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/charconv_bigint.cc b/absl/strings/internal/charconv_bigint.cc
index dac907e2..58c909f4 100644
--- a/absl/strings/internal/charconv_bigint.cc
+++ b/absl/strings/internal/charconv_bigint.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
namespace {
@@ -355,5 +355,5 @@ template class BigUnsigned<4>;
template class BigUnsigned<84>;
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/charconv_bigint.h b/absl/strings/internal/charconv_bigint.h
index ffafc11c..5aef416b 100644
--- a/absl/strings/internal/charconv_bigint.h
+++ b/absl/strings/internal/charconv_bigint.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// The largest power that 5 that can be raised to, and still fit in a uint32_t.
@@ -104,12 +104,12 @@ class BigUnsigned {
SetToZero();
return;
}
- size_ = std::min(size_ + word_shift, max_words);
+ size_ = (std::min)(size_ + word_shift, max_words);
count %= 32;
if (count == 0) {
std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
} else {
- for (int i = std::min(size_, max_words - 1); i > word_shift; --i) {
+ for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) {
words_[i] = (words_[i - word_shift] << count) |
(words_[i - word_shift - 1] >> (32 - count));
}
@@ -268,7 +268,7 @@ class BigUnsigned {
void MultiplyBy(int other_size, const uint32_t* other_words) {
const int original_size = size_;
const int first_step =
- std::min(original_size + other_size - 2, max_words - 1);
+ (std::min)(original_size + other_size - 2, max_words - 1);
for (int step = first_step; step >= 0; --step) {
MultiplyStep(original_size, other_words, other_size, step);
}
@@ -287,7 +287,7 @@ class BigUnsigned {
value = 0;
}
}
- size_ = std::min(max_words, std::max(index + 1, size_));
+ size_ = (std::min)(max_words, (std::max)(index + 1, size_));
}
}
@@ -310,7 +310,7 @@ class BigUnsigned {
} else {
// Normally 32-bit AddWithCarry() sets size_, but since we don't call
// it when `high` is 0, do it ourselves here.
- size_ = std::min(max_words, std::max(index + 1, size_));
+ size_ = (std::min)(max_words, (std::max)(index + 1, size_));
}
}
}
@@ -349,7 +349,7 @@ class BigUnsigned {
// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs.
template <int N, int M>
int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
- int limit = std::max(lhs.size(), rhs.size());
+ int limit = (std::max)(lhs.size(), rhs.size());
for (int i = limit - 1; i >= 0; --i) {
const uint32_t lhs_word = lhs.GetWord(i);
const uint32_t rhs_word = rhs.GetWord(i);
@@ -364,7 +364,7 @@ int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
template <int N, int M>
bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) {
- int limit = std::max(lhs.size(), rhs.size());
+ int limit = (std::max)(lhs.size(), rhs.size());
for (int i = 0; i < limit; ++i) {
if (lhs.GetWord(i) != rhs.GetWord(i)) {
return false;
@@ -415,7 +415,7 @@ extern template class BigUnsigned<4>;
extern template class BigUnsigned<84>;
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_
diff --git a/absl/strings/internal/charconv_bigint_test.cc b/absl/strings/internal/charconv_bigint_test.cc
index dbab3208..590511d0 100644
--- a/absl/strings/internal/charconv_bigint_test.cc
+++ b/absl/strings/internal/charconv_bigint_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
TEST(BigUnsigned, ShiftLeft) {
@@ -201,5 +201,5 @@ TEST(BigUnsigned, TenToTheNth) {
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/charconv_parse.cc b/absl/strings/internal/charconv_parse.cc
index 68d65a8a..4dd4ecb3 100644
--- a/absl/strings/internal/charconv_parse.cc
+++ b/absl/strings/internal/charconv_parse.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
// ParseFloat<10> will read the first 19 significant digits of the mantissa.
@@ -494,5 +494,5 @@ template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
chars_format format_flags);
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/charconv_parse.h b/absl/strings/internal/charconv_parse.h
index 17d5a8f8..ddfc87f8 100644
--- a/absl/strings/internal/charconv_parse.h
+++ b/absl/strings/internal/charconv_parse.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "absl/strings/charconv.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// Enum indicating whether a parsed float is a number or special value.
@@ -93,6 +93,6 @@ extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end,
absl::chars_format format_flags);
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_
diff --git a/absl/strings/internal/charconv_parse_test.cc b/absl/strings/internal/charconv_parse_test.cc
index f48b9aee..9511c987 100644
--- a/absl/strings/internal/charconv_parse_test.cc
+++ b/absl/strings/internal/charconv_parse_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/escaping_test_common.h b/absl/strings/internal/escaping_test_common.h
index 50ef595f..ecd3aa35 100644
--- a/absl/strings/internal/escaping_test_common.h
+++ b/absl/strings/internal/escaping_test_common.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
struct base64_testcase {
@@ -127,7 +127,7 @@ inline const std::array<base64_testcase, 5>& base64_strings() {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_
diff --git a/absl/strings/internal/memutil.cc b/absl/strings/internal/memutil.cc
index 1d6cfa36..05251377 100644
--- a/absl/strings/internal/memutil.cc
+++ b/absl/strings/internal/memutil.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include <cstdlib>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
int memcasecmp(const char* s1, const char* s2, size_t len) {
@@ -108,5 +108,5 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/memutil.h b/absl/strings/internal/memutil.h
index dcc5c9a3..4efac989 100644
--- a/absl/strings/internal/memutil.h
+++ b/absl/strings/internal/memutil.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -69,7 +69,7 @@
#include "absl/strings/ascii.h" // for absl::ascii_tolower
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
inline char* memcat(char* dest, size_t destlen, const char* src,
@@ -142,7 +142,7 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle,
size_t neelen);
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc
index 77915adb..dc95c3e5 100644
--- a/absl/strings/internal/memutil_benchmark.cc
+++ b/absl/strings/internal/memutil_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/memutil_test.cc b/absl/strings/internal/memutil_test.cc
index 09424de9..d8681ddf 100644
--- a/absl/strings/internal/memutil_test.cc
+++ b/absl/strings/internal/memutil_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/numbers_test_common.h b/absl/strings/internal/numbers_test_common.h
index 32aa0bfa..3f6965f2 100644
--- a/absl/strings/internal/numbers_test_common.h
+++ b/absl/strings/internal/numbers_test_common.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
template <typename IntType>
@@ -175,7 +175,7 @@ inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_
diff --git a/absl/strings/internal/ostringstream.cc b/absl/strings/internal/ostringstream.cc
index 77f4b0b3..ce2dd6c7 100644
--- a/absl/strings/internal/ostringstream.cc
+++ b/absl/strings/internal/ostringstream.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/strings/internal/ostringstream.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
OStringStream::Buf::int_type OStringStream::overflow(int c) {
@@ -32,5 +32,5 @@ std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/ostringstream.h b/absl/strings/internal/ostringstream.h
index 908e170c..2cf65133 100644
--- a/absl/strings/internal/ostringstream.h
+++ b/absl/strings/internal/ostringstream.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,21 +23,21 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
-// The same as std::ostringstream but appends to a user-specified string,
+// The same as std::ostringstream but appends to a user-specified std::string,
// and is faster. It is ~70% faster to create, ~50% faster to write to, and
-// completely free to extract the result string.
+// completely free to extract the result std::string.
//
-// string s;
+// std::string s;
// OStringStream strm(&s);
// strm << 42 << ' ' << 3.14; // appends to `s`
//
// The stream object doesn't have to be named. Starting from C++11 operator<<
// works with rvalues of std::ostream.
//
-// string s;
+// std::string s;
// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s`
//
// OStringStream is faster to create than std::ostringstream but it's still
@@ -46,14 +46,14 @@ namespace strings_internal {
//
// Creates unnecessary instances of OStringStream: slow.
//
-// string s;
+// std::string s;
// OStringStream(&s) << 42;
// OStringStream(&s) << ' ';
// OStringStream(&s) << 3.14;
//
// Creates a single instance of OStringStream and reuses it: fast.
//
-// string s;
+// std::string s;
// OStringStream strm(&s);
// strm << 42;
// strm << ' ';
@@ -65,8 +65,8 @@ class OStringStream : private std::basic_streambuf<char>, public std::ostream {
// The argument can be null, in which case you'll need to call str(p) with a
// non-null argument before you can write to the stream.
//
- // The destructor of OStringStream doesn't use the std::string. It's OK to destroy
- // the std::string before the stream.
+ // The destructor of OStringStream doesn't use the std::string. It's OK to
+ // destroy the std::string before the stream.
explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {}
std::string* str() { return s_; }
@@ -83,7 +83,7 @@ class OStringStream : private std::basic_streambuf<char>, public std::ostream {
};
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_
diff --git a/absl/strings/internal/ostringstream_benchmark.cc b/absl/strings/internal/ostringstream_benchmark.cc
index c93f9690..5979f182 100644
--- a/absl/strings/internal/ostringstream_benchmark.cc
+++ b/absl/strings/internal/ostringstream_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/ostringstream_test.cc b/absl/strings/internal/ostringstream_test.cc
index 069a0e1f..2879e50e 100644
--- a/absl/strings/internal/ostringstream_test.cc
+++ b/absl/strings/internal/ostringstream_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/internal/pow10_helper.cc b/absl/strings/internal/pow10_helper.cc
index c7f4875a..5c02ab8f 100644
--- a/absl/strings/internal/pow10_helper.cc
+++ b/absl/strings/internal/pow10_helper.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include <cmath>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
namespace {
@@ -118,5 +118,5 @@ double Pow10(int exp) {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h
index 750051bd..c9a1b27f 100644
--- a/absl/strings/internal/pow10_helper.h
+++ b/absl/strings/internal/pow10_helper.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,13 +17,13 @@
// precise values are computed across the full range of doubles. We can't rely
// on the pow() function, because not all standard libraries ship a version
// that is precise.
-#ifndef ABSL_STRINGS_POW10_HELPER_H_
-#define ABSL_STRINGS_POW10_HELPER_H_
+#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
#include <vector>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// Computes the precise value of 10^exp. (I.e. the nearest representable
@@ -32,7 +32,7 @@ namespace strings_internal {
double Pow10(int exp);
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
-#endif // ABSL_STRINGS_POW10_HELPER_H_
+#endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
diff --git a/absl/strings/internal/pow10_helper_test.cc b/absl/strings/internal/pow10_helper_test.cc
index 371fe122..4a62a70d 100644
--- a/absl/strings/internal/pow10_helper_test.cc
+++ b/absl/strings/internal/pow10_helper_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "absl/strings/str_format.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
namespace {
@@ -118,5 +118,5 @@ TEST(Pow10HelperTest, Works) {
} // namespace
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/resize_uninitialized.h b/absl/strings/internal/resize_uninitialized.h
index 2951bf84..ab1d8684 100644
--- a/absl/strings/internal/resize_uninitialized.h
+++ b/absl/strings/internal/resize_uninitialized.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,54 +18,57 @@
#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
#include <string>
+#include <type_traits>
#include <utility>
#include "absl/base/port.h"
#include "absl/meta/type_traits.h" // for void_t
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// Is a subclass of true_type or false_type, depending on whether or not
-// T has a resize_uninitialized member.
-template <typename T, typename = void>
-struct HasResizeUninitialized : std::false_type {};
-template <typename T>
-struct HasResizeUninitialized<
- T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>>
- : std::true_type {};
+// T has a __resize_default_init member.
+template <typename string_type, typename = void>
+struct ResizeUninitializedTraits {
+ using HasMember = std::false_type;
+ static void Resize(string_type* s, size_t new_size) { s->resize(new_size); }
+};
+// __resize_default_init is provided by libc++ >= 8.0 and by Google's internal
+// ::string implementation.
template <typename string_type>
-void ResizeUninit(string_type* s, size_t new_size, std::true_type) {
- s->resize_uninitialized(new_size);
-}
-template <typename string_type>
-void ResizeUninit(string_type* s, size_t new_size, std::false_type) {
- s->resize(new_size);
-}
+struct ResizeUninitializedTraits<
+ string_type, absl::void_t<decltype(std::declval<string_type&>()
+ .__resize_default_init(237))> > {
+ using HasMember = std::true_type;
+ static void Resize(string_type* s, size_t new_size) {
+ s->__resize_default_init(new_size);
+ }
+};
-// Returns true if the string implementation supports a resize where
-// the new characters added to the string are left untouched.
+// Returns true if the std::string implementation supports a resize where
+// the new characters added to the std::string are left untouched.
//
// (A better name might be "STLStringSupportsUninitializedResize", alluding to
// the previous function.)
template <typename string_type>
inline constexpr bool STLStringSupportsNontrashingResize(string_type*) {
- return HasResizeUninitialized<string_type>();
+ return ResizeUninitializedTraits<string_type>::HasMember::value;
}
// Like str->resize(new_size), except any new characters added to "*str" as a
// result of resizing may be left uninitialized, rather than being filled with
// '0' bytes. Typically used when code is then going to overwrite the backing
-// store of the string with known data. Uses a Google extension to ::string.
+// store of the std::string with known data.
template <typename string_type, typename = void>
inline void STLStringResizeUninitialized(string_type* s, size_t new_size) {
- ResizeUninit(s, new_size, HasResizeUninitialized<string_type>());
+ ResizeUninitializedTraits<string_type>::Resize(s, new_size);
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_
diff --git a/absl/strings/internal/resize_uninitialized_test.cc b/absl/strings/internal/resize_uninitialized_test.cc
index ad282efc..c5be0b12 100644
--- a/absl/strings/internal/resize_uninitialized_test.cc
+++ b/absl/strings/internal/resize_uninitialized_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,44 +24,44 @@ struct resizable_string {
void resize(size_t) { resize_call_count += 1; }
};
-int resize_uninitialized_call_count = 0;
+int resize_default_init_call_count = 0;
-struct resize_uninitializable_string {
+struct resize_default_init_string {
void resize(size_t) { resize_call_count += 1; }
- void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; }
+ void __resize_default_init(size_t) { resize_default_init_call_count += 1; }
};
TEST(ResizeUninit, WithAndWithout) {
resize_call_count = 0;
- resize_uninitialized_call_count = 0;
+ resize_default_init_call_count = 0;
{
resizable_string rs;
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_FALSE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rs));
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rs, 237);
EXPECT_EQ(resize_call_count, 1);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
}
resize_call_count = 0;
- resize_uninitialized_call_count = 0;
+ resize_default_init_call_count = 0;
{
- resize_uninitializable_string rus;
+ resize_default_init_string rus;
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
EXPECT_TRUE(
absl::strings_internal::STLStringSupportsNontrashingResize(&rus));
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 0);
+ EXPECT_EQ(resize_default_init_call_count, 0);
absl::strings_internal::STLStringResizeUninitialized(&rus, 237);
EXPECT_EQ(resize_call_count, 0);
- EXPECT_EQ(resize_uninitialized_call_count, 1);
+ EXPECT_EQ(resize_default_init_call_count, 1);
}
}
diff --git a/absl/strings/internal/stl_type_traits.h b/absl/strings/internal/stl_type_traits.h
index fed7bf7c..af50be7c 100644
--- a/absl/strings/internal/stl_type_traits.h
+++ b/absl/strings/internal/stl_type_traits.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -40,7 +40,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
template <typename C, template <typename...> class T>
@@ -243,6 +243,6 @@ struct IsStrictlyBaseOfAndConvertibleToSTLContainer
IsConvertibleToSTLContainer<C>> {};
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_
diff --git a/absl/strings/internal/str_format/arg.cc b/absl/strings/internal/str_format/arg.cc
index e5e1eee5..667cc133 100644
--- a/absl/strings/internal/str_format/arg.cc
+++ b/absl/strings/internal/str_format/arg.cc
@@ -14,7 +14,7 @@
#include "absl/strings/internal/str_format/float_conversion.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -375,5 +375,5 @@ ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/arg.h b/absl/strings/internal/str_format/arg.h
index 0af4c839..b6f708c6 100644
--- a/absl/strings/internal/str_format/arg.h
+++ b/absl/strings/internal/str_format/arg.h
@@ -7,6 +7,7 @@
#include <cstdio>
#include <iomanip>
#include <limits>
+#include <memory>
#include <sstream>
#include <string>
#include <type_traits>
@@ -21,7 +22,7 @@ class Cord;
class CordReader;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class FormatCountCapture;
class FormatSink;
@@ -36,12 +37,14 @@ struct HasUserDefinedConvert<
T, void_t<decltype(AbslFormatConvert(
std::declval<const T&>(), std::declval<ConversionSpec>(),
std::declval<FormatSink*>()))>> : std::true_type {};
+
template <typename T>
class StreamedWrapper;
// If 'v' can be converted (in the printf sense) according to 'conv',
// then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`.
+
// Raw pointers.
struct VoidPtr {
VoidPtr() = default;
@@ -55,7 +58,8 @@ ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, ConversionSpec conv,
FormatSinkImpl* sink);
// Strings.
-ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, ConversionSpec conv,
+ConvertResult<Conv::s> FormatConvertImpl(const std::string& v,
+ ConversionSpec conv,
FormatSinkImpl* sink);
ConvertResult<Conv::s> FormatConvertImpl(string_view v, ConversionSpec conv,
FormatSinkImpl* sink);
@@ -81,7 +85,7 @@ ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value,
int precision = conv.precision();
if (precision >= 0)
- to_write = std::min(to_write, static_cast<size_t>(precision));
+ to_write = (std::min)(to_write, static_cast<size_t>(precision));
space_remaining = Excess(to_write, space_remaining);
@@ -290,7 +294,7 @@ class FormatArgImpl {
struct Manager<T, ByPointer> {
static Data SetValue(const T& value) {
Data data;
- data.ptr = &value;
+ data.ptr = std::addressof(value);
return data;
}
@@ -410,13 +414,13 @@ class FormatArgImpl {
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(double, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(long double, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(const char*, __VA_ARGS__); \
- ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \
+ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(std::string, __VA_ARGS__); \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(string_view, __VA_ARGS__)
ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern);
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
diff --git a/absl/strings/internal/str_format/arg_test.cc b/absl/strings/internal/str_format/arg_test.cc
index 9cb9559c..c9c51951 100644
--- a/absl/strings/internal/str_format/arg_test.cc
+++ b/absl/strings/internal/str_format/arg_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
#include "absl/strings/internal/str_format/arg.h"
@@ -14,7 +14,7 @@
#include "absl/strings/str_format.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -109,5 +109,5 @@ const char kMyArray[] = "ABCDE";
} // namespace
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/bind.cc b/absl/strings/internal/str_format/bind.cc
index 5cf026b6..48a306d4 100644
--- a/absl/strings/internal/str_format/bind.cc
+++ b/absl/strings/internal/str_format/bind.cc
@@ -6,7 +6,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -26,12 +26,12 @@ class ArgContext {
explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
// Fill 'bound' with the results of applying the context's argument pack
- // to the specified 'props'. We synthesize a BoundConversion by
+ // to the specified 'unbound'. We synthesize a BoundConversion by
// lining up a UnboundConversion with a user argument. We also
// resolve any '*' specifiers for width and precision, so after
// this call, 'bound' has all the information it needs to be formatted.
// Returns false on failure.
- bool Bind(const UnboundConversion *props, BoundConversion *bound);
+ bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
private:
absl::Span<const FormatArgImpl> pack_;
@@ -54,7 +54,8 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound,
// "A negative field width is taken as a '-' flag followed by a
// positive field width."
force_left = true;
- width = -width;
+ // Make sure we don't overflow the width when negating it.
+ width = -std::max(width, -std::numeric_limits<int>::max());
}
}
@@ -160,7 +161,7 @@ bool BindWithPack(const UnboundConversion* props,
}
std::string Summarize(const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
typedef SummarizingConverter Converter;
std::string out;
{
@@ -188,7 +189,7 @@ std::ostream& Streamable::Print(std::ostream& os) const {
}
std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
size_t orig = out->size();
if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
out->erase(orig);
@@ -227,5 +228,5 @@ int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/bind.h b/absl/strings/internal/str_format/bind.h
index df5562f6..db79eb6c 100644
--- a/absl/strings/internal/str_format/bind.h
+++ b/absl/strings/internal/str_format/bind.h
@@ -7,14 +7,13 @@
#include <string>
#include "absl/base/port.h"
-#include "absl/container/inlined_vector.h"
#include "absl/strings/internal/str_format/arg.h"
#include "absl/strings/internal/str_format/checker.h"
#include "absl/strings/internal/str_format/parser.h"
#include "absl/types/span.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class UntypedFormatSpec;
@@ -139,7 +138,17 @@ class Streamable {
public:
Streamable(const UntypedFormatSpecImpl& format,
absl::Span<const FormatArgImpl> args)
- : format_(format), args_(args.begin(), args.end()) {}
+ : format_(format) {
+ if (args.size() <= ABSL_ARRAYSIZE(few_args_)) {
+ for (size_t i = 0; i < args.size(); ++i) {
+ few_args_[i] = args[i];
+ }
+ args_ = absl::MakeSpan(few_args_, args.size());
+ } else {
+ many_args_.assign(args.begin(), args.end());
+ args_ = many_args_;
+ }
+ }
std::ostream& Print(std::ostream& os) const;
@@ -149,12 +158,17 @@ class Streamable {
private:
const UntypedFormatSpecImpl& format_;
- absl::InlinedVector<FormatArgImpl, 4> args_;
+ absl::Span<const FormatArgImpl> args_;
+ // if args_.size() is 4 or less:
+ FormatArgImpl few_args_[4] = {FormatArgImpl(0), FormatArgImpl(0),
+ FormatArgImpl(0), FormatArgImpl(0)};
+ // if args_.size() is more than 4:
+ std::vector<FormatArgImpl> many_args_;
};
// for testing
std::string Summarize(UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args);
+ absl::Span<const FormatArgImpl> args);
bool BindWithPack(const UnboundConversion* props,
absl::Span<const FormatArgImpl> pack, BoundConversion* bound);
@@ -163,10 +177,10 @@ bool FormatUntyped(FormatRawSinkImpl raw_sink,
absl::Span<const FormatArgImpl> args);
std::string& AppendPack(std::string* out, UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args);
+ absl::Span<const FormatArgImpl> args);
inline std::string FormatPack(const UntypedFormatSpecImpl format,
- absl::Span<const FormatArgImpl> args) {
+ absl::Span<const FormatArgImpl> args) {
std::string out;
AppendPack(&out, format, args);
return out;
@@ -177,7 +191,7 @@ int FprintF(std::FILE* output, UntypedFormatSpecImpl format,
int SnprintF(char* output, size_t size, UntypedFormatSpecImpl format,
absl::Span<const FormatArgImpl> args);
-// Returned by Streamed(v). Converts via '%s' to the string created
+// Returned by Streamed(v). Converts via '%s' to the std::string created
// by std::ostream << v.
template <typename T>
class StreamedWrapper {
@@ -193,7 +207,7 @@ class StreamedWrapper {
};
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
diff --git a/absl/strings/internal/str_format/bind_test.cc b/absl/strings/internal/str_format/bind_test.cc
index 58d9e072..8bccc92a 100644
--- a/absl/strings/internal/str_format/bind_test.cc
+++ b/absl/strings/internal/str_format/bind_test.cc
@@ -1,24 +1,20 @@
#include "absl/strings/internal/str_format/bind.h"
#include <string.h>
+#include <limits>
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
-template <typename T, size_t N>
-size_t ArraySize(T (&)[N]) {
- return N;
-}
-
class FormatBindTest : public ::testing::Test {
public:
bool Extract(const char *s, UnboundConversion *props, int *next) const {
- absl::string_view src = s;
- return ConsumeUnboundConversion(&src, props, next) && src.empty();
+ return ConsumeUnboundConversion(s, s + strlen(s), props, next) ==
+ s + strlen(s);
}
};
@@ -92,6 +88,20 @@ TEST_F(FormatBindTest, BindSingle) {
}
}
+TEST_F(FormatBindTest, WidthUnderflowRegression) {
+ UnboundConversion props;
+ BoundConversion bound;
+ int next = 0;
+ const int args_i[] = {std::numeric_limits<int>::min(), 17};
+ const FormatArgImpl args[] = {FormatArgImpl(args_i[0]),
+ FormatArgImpl(args_i[1])};
+ ASSERT_TRUE(Extract("*d", &props, &next));
+ ASSERT_TRUE(BindWithPack(&props, args, &bound));
+
+ EXPECT_EQ(bound.width(), std::numeric_limits<int>::max());
+ EXPECT_EQ(bound.arg(), args + 1);
+}
+
TEST_F(FormatBindTest, FormatPack) {
struct Expectation {
int line;
@@ -129,5 +139,5 @@ TEST_F(FormatBindTest, FormatPack) {
} // namespace
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/checker.h b/absl/strings/internal/str_format/checker.h
index d0191968..262887cd 100644
--- a/absl/strings/internal/str_format/checker.h
+++ b/absl/strings/internal/str_format/checker.h
@@ -15,7 +15,7 @@
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
constexpr bool AllOf() { return true; }
@@ -321,7 +321,7 @@ constexpr bool ValidFormatImpl(string_view format) {
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
diff --git a/absl/strings/internal/str_format/checker_test.cc b/absl/strings/internal/str_format/checker_test.cc
index b4f38979..2aa3b128 100644
--- a/absl/strings/internal/str_format/checker_test.cc
+++ b/absl/strings/internal/str_format/checker_test.cc
@@ -5,7 +5,7 @@
#include "absl/strings/str_format.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -63,32 +63,32 @@ TEST(StrFormatChecker, ValidFormat) {
ValidFormat<int>("%% %d"), //
ValidFormat<int>("%ld"), //
ValidFormat<int>("%lld"), //
- ValidFormat<std::string>("%s"), //
- ValidFormat<std::string>("%10s"), //
+ ValidFormat<std::string>("%s"), //
+ ValidFormat<std::string>("%10s"), //
ValidFormat<int>("%.10x"), //
ValidFormat<int, int>("%*.3x"), //
ValidFormat<int>("%1.d"), //
ValidFormat<int>("%.d"), //
ValidFormat<int, double>("%d %g"), //
- ValidFormat<int, std::string>("%*s"), //
+ ValidFormat<int, std::string>("%*s"), //
ValidFormat<int, double>("%.*f"), //
ValidFormat<void (*)(), volatile int*>("%p %p"), //
ValidFormat<string_view, const char*, double, void*>(
"string_view=%s const char*=%s double=%f void*=%p)"),
- ValidFormat<int>("%% %1$d"), //
- ValidFormat<int>("%1$ld"), //
- ValidFormat<int>("%1$lld"), //
- ValidFormat<std::string>("%1$s"), //
- ValidFormat<std::string>("%1$10s"), //
- ValidFormat<int>("%1$.10x"), //
- ValidFormat<int>("%1$*1$.*1$d"), //
- ValidFormat<int, int>("%1$*2$.3x"), //
- ValidFormat<int>("%1$1.d"), //
- ValidFormat<int>("%1$.d"), //
- ValidFormat<double, int>("%2$d %1$g"), //
- ValidFormat<int, std::string>("%2$*1$s"), //
- ValidFormat<int, double>("%2$.*1$f"), //
+ ValidFormat<int>("%% %1$d"), //
+ ValidFormat<int>("%1$ld"), //
+ ValidFormat<int>("%1$lld"), //
+ ValidFormat<std::string>("%1$s"), //
+ ValidFormat<std::string>("%1$10s"), //
+ ValidFormat<int>("%1$.10x"), //
+ ValidFormat<int>("%1$*1$.*1$d"), //
+ ValidFormat<int, int>("%1$*2$.3x"), //
+ ValidFormat<int>("%1$1.d"), //
+ ValidFormat<int>("%1$.d"), //
+ ValidFormat<double, int>("%2$d %1$g"), //
+ ValidFormat<int, std::string>("%2$*1$s"), //
+ ValidFormat<int, double>("%2$.*1$f"), //
ValidFormat<void*, string_view, const char*, double>(
"string_view=%2$s const char*=%3$s double=%4$f void*=%1$p "
"repeat=%3$s)")};
@@ -100,25 +100,25 @@ TEST(StrFormatChecker, ValidFormat) {
constexpr Case falses[] = {
ValidFormat<int>(""), //
- ValidFormat<e>("%s"), //
- ValidFormat<e2>("%s"), //
- ValidFormat<>("%s"), //
- ValidFormat<>("%r"), //
- ValidFormat<int>("%s"), //
- ValidFormat<int>("%.1.d"), //
- ValidFormat<int>("%*1d"), //
- ValidFormat<int>("%1-d"), //
+ ValidFormat<e>("%s"), //
+ ValidFormat<e2>("%s"), //
+ ValidFormat<>("%s"), //
+ ValidFormat<>("%r"), //
+ ValidFormat<int>("%s"), //
+ ValidFormat<int>("%.1.d"), //
+ ValidFormat<int>("%*1d"), //
+ ValidFormat<int>("%1-d"), //
ValidFormat<std::string, int>("%*s"), //
- ValidFormat<int>("%*d"), //
+ ValidFormat<int>("%*d"), //
ValidFormat<std::string>("%p"), //
- ValidFormat<int (*)(int)>("%d"), //
-
- ValidFormat<>("%3$d"), //
- ValidFormat<>("%1$r"), //
- ValidFormat<int>("%1$s"), //
- ValidFormat<int>("%1$.1.d"), //
- ValidFormat<int>("%1$*2$1d"), //
- ValidFormat<int>("%1$1-d"), //
+ ValidFormat<int (*)(int)>("%d"), //
+
+ ValidFormat<>("%3$d"), //
+ ValidFormat<>("%1$r"), //
+ ValidFormat<int>("%1$s"), //
+ ValidFormat<int>("%1$.1.d"), //
+ ValidFormat<int>("%1$*2$1d"), //
+ ValidFormat<int>("%1$1-d"), //
ValidFormat<std::string, int>("%2$*1$s"), //
ValidFormat<std::string>("%1$p"),
@@ -148,5 +148,5 @@ TEST(StrFormatChecker, LongFormat) {
} // namespace
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index 95d57b67..751bfc34 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -1,6 +1,7 @@
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
+#include <cctype>
#include <cmath>
#include <string>
@@ -8,7 +9,7 @@
#include "absl/strings/internal/str_format/bind.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -33,7 +34,9 @@ std::string LengthModFor(long long) { return "ll"; } // NOLINT
std::string LengthModFor(unsigned long long) { return "ll"; } // NOLINT
std::string EscCharImpl(int v) {
- if (isprint(v)) return std::string(1, static_cast<char>(v));
+ if (std::isprint(static_cast<unsigned char>(v))) {
+ return std::string(1, static_cast<char>(v));
+ }
char buf[64];
int n = snprintf(buf, sizeof(buf), "\\%#.2x",
static_cast<unsigned>(v & 0xff));
@@ -156,7 +159,7 @@ TEST_F(FormatConvertTest, StringPrecision) {
}
TEST_F(FormatConvertTest, Pointer) {
-#if _MSC_VER
+#ifdef _MSC_VER
// MSVC's printf implementation prints pointers differently. We can't easily
// compare our implementation to theirs.
return;
@@ -233,7 +236,7 @@ TEST_F(FormatConvertTest, Enum) {
template <typename T>
class TypedFormatConvertTest : public FormatConvertTest { };
-TYPED_TEST_CASE_P(TypedFormatConvertTest);
+TYPED_TEST_SUITE_P(TypedFormatConvertTest);
std::vector<std::string> AllFlagCombinations() {
const char kFlags[] = {'-', '#', '0', '+', ' '};
@@ -364,6 +367,18 @@ typedef ::testing::Types<
AllIntTypes;
INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes,
TypedFormatConvertTest, AllIntTypes);
+
+TEST_F(FormatConvertTest, VectorBool) {
+ // Make sure vector<bool>'s values behave as bools.
+ std::vector<bool> v = {true, false};
+ const std::vector<bool> cv = {true, false};
+ EXPECT_EQ("1,0,1,0",
+ FormatPack(UntypedFormatSpecImpl("%d,%d,%d,%d"),
+ absl::Span<const FormatArgImpl>(
+ {FormatArgImpl(v[0]), FormatArgImpl(v[1]),
+ FormatArgImpl(cv[0]), FormatArgImpl(cv[1])})));
+}
+
TEST_F(FormatConvertTest, Uint128) {
absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979;
absl::uint128 max = absl::Uint128Max();
@@ -390,7 +405,7 @@ TEST_F(FormatConvertTest, Uint128) {
}
TEST_F(FormatConvertTest, Float) {
-#if _MSC_VER
+#ifdef _MSC_VER
// MSVC has a different rounding policy than us so we can't test our
// implementation against the native one there.
return;
@@ -573,5 +588,5 @@ TEST_F(FormatConvertTest, ExpectedFailures) {
} // namespace
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/extension.cc b/absl/strings/internal/str_format/extension.cc
index e3b41c82..1a0c4172 100644
--- a/absl/strings/internal/str_format/extension.cc
+++ b/absl/strings/internal/str_format/extension.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
// clang-format off
@@ -82,5 +82,5 @@ bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) {
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/extension.h b/absl/strings/internal/str_format/extension.h
index d401b4ed..4fbe4a06 100644
--- a/absl/strings/internal/str_format/extension.h
+++ b/absl/strings/internal/str_format/extension.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -13,7 +13,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-//
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
@@ -29,7 +28,7 @@
class Cord;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
@@ -361,7 +360,7 @@ enum class Conv : uint64_t {
integral = d | i | u | o | x | X,
floating = a | e | f | g | A | E | F | G,
numeric = integral | floating,
- string = s, // absl:ignore(std::string)
+ string = s,
pointer = p
};
@@ -408,7 +407,7 @@ inline size_t Excess(size_t used, size_t capacity) {
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
diff --git a/absl/strings/internal/str_format/extension_test.cc b/absl/strings/internal/str_format/extension_test.cc
index 224fc923..4e23fefb 100644
--- a/absl/strings/internal/str_format/extension_test.cc
+++ b/absl/strings/internal/str_format/extension_test.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,6 +18,7 @@
#include <random>
#include <string>
+
#include "absl/strings/str_format.h"
#include "gtest/gtest.h"
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index 7b617689..a0484feb 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -6,8 +6,10 @@
#include <cmath>
#include <string>
+#include "absl/base/config.h"
+
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -335,7 +337,7 @@ bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp))
return true;
-#if defined(__SIZEOF_INT128__)
+#if defined(ABSL_HAVE_INTRINSIC_INT128)
// If that is not enough, try with __uint128_t.
return CanFitMantissa<Float, __uint128_t>() &&
FloatToBufferImpl<__uint128_t, Float, mode>(
@@ -481,5 +483,5 @@ bool ConvertFloatImpl(double v, const ConversionSpec &conv,
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/float_conversion.h b/absl/strings/internal/str_format/float_conversion.h
index 280c471a..5d76ce2b 100644
--- a/absl/strings/internal/str_format/float_conversion.h
+++ b/absl/strings/internal/str_format/float_conversion.h
@@ -4,7 +4,7 @@
#include "absl/strings/internal/str_format/extension.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
bool ConvertFloatImpl(float v, const ConversionSpec &conv,
@@ -17,7 +17,7 @@ bool ConvertFloatImpl(long double v, const ConversionSpec &conv,
FormatSinkImpl *sink);
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
diff --git a/absl/strings/internal/str_format/output.cc b/absl/strings/internal/str_format/output.cc
index 010bf341..d5ead8d5 100644
--- a/absl/strings/internal/str_format/output.cc
+++ b/absl/strings/internal/str_format/output.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include <cstring>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
@@ -68,5 +68,5 @@ void FILERawSink::Write(string_view v) {
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/output.h b/absl/strings/internal/str_format/output.h
index 0f3ab349..ba847471 100644
--- a/absl/strings/internal/str_format/output.h
+++ b/absl/strings/internal/str_format/output.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -31,7 +31,7 @@
class Cord;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
// RawSink implementation that writes into a char* buffer.
@@ -97,7 +97,7 @@ auto InvokeFlush(T* out, string_view s)
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_
diff --git a/absl/strings/internal/str_format/output_test.cc b/absl/strings/internal/str_format/output_test.cc
index 0a014cac..5c3c4afb 100644
--- a/absl/strings/internal/str_format/output_test.cc
+++ b/absl/strings/internal/str_format/output_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,24 +17,17 @@
#include <sstream>
#include <string>
-
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
TEST(InvokeFlush, String) {
std::string str = "ABC";
str_format_internal::InvokeFlush(&str, "DEF");
EXPECT_EQ(str, "ABCDEF");
-
-#if UTIL_FORMAT_HAS_GLOBAL_STRING
- std::string str2 = "ABC";
- str_format_internal::InvokeFlush(&str2, "DEF");
- EXPECT_EQ(str2, "ABCDEF");
-#endif // UTIL_FORMAT_HAS_GLOBAL_STRING
}
TEST(InvokeFlush, Stream) {
@@ -75,6 +68,6 @@ TEST(BufferRawSink, Limits) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/parser.cc b/absl/strings/internal/str_format/parser.cc
index 119a711e..4b8ca4d2 100644
--- a/absl/strings/internal/str_format/parser.cc
+++ b/absl/strings/internal/str_format/parser.cc
@@ -14,8 +14,46 @@
#include <unordered_set>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
+
+using CC = ConversionChar::Id;
+using LM = LengthMod::Id;
+ABSL_CONST_INIT const ConvTag kTags[256] = {
+ {}, {}, {}, {}, {}, {}, {}, {}, // 00-07
+ {}, {}, {}, {}, {}, {}, {}, {}, // 08-0f
+ {}, {}, {}, {}, {}, {}, {}, {}, // 10-17
+ {}, {}, {}, {}, {}, {}, {}, {}, // 18-1f
+ {}, {}, {}, {}, {}, {}, {}, {}, // 20-27
+ {}, {}, {}, {}, {}, {}, {}, {}, // 28-2f
+ {}, {}, {}, {}, {}, {}, {}, {}, // 30-37
+ {}, {}, {}, {}, {}, {}, {}, {}, // 38-3f
+ {}, CC::A, {}, CC::C, {}, CC::E, CC::F, CC::G, // @ABCDEFG
+ {}, {}, {}, {}, LM::L, {}, {}, {}, // HIJKLMNO
+ {}, {}, {}, CC::S, {}, {}, {}, {}, // PQRSTUVW
+ CC::X, {}, {}, {}, {}, {}, {}, {}, // XYZ[\]^_
+ {}, CC::a, {}, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg
+ LM::h, CC::i, LM::j, {}, LM::l, {}, CC::n, CC::o, // hijklmno
+ CC::p, LM::q, {}, CC::s, LM::t, CC::u, {}, {}, // pqrstuvw
+ CC::x, {}, LM::z, {}, {}, {}, {}, {}, // xyz{|}!
+ {}, {}, {}, {}, {}, {}, {}, {}, // 80-87
+ {}, {}, {}, {}, {}, {}, {}, {}, // 88-8f
+ {}, {}, {}, {}, {}, {}, {}, {}, // 90-97
+ {}, {}, {}, {}, {}, {}, {}, {}, // 98-9f
+ {}, {}, {}, {}, {}, {}, {}, {}, // a0-a7
+ {}, {}, {}, {}, {}, {}, {}, {}, // a8-af
+ {}, {}, {}, {}, {}, {}, {}, {}, // b0-b7
+ {}, {}, {}, {}, {}, {}, {}, {}, // b8-bf
+ {}, {}, {}, {}, {}, {}, {}, {}, // c0-c7
+ {}, {}, {}, {}, {}, {}, {}, {}, // c8-cf
+ {}, {}, {}, {}, {}, {}, {}, {}, // d0-d7
+ {}, {}, {}, {}, {}, {}, {}, {}, // d8-df
+ {}, {}, {}, {}, {}, {}, {}, {}, // e0-e7
+ {}, {}, {}, {}, {}, {}, {}, {}, // e8-ef
+ {}, {}, {}, {}, {}, {}, {}, {}, // f0-f7
+ {}, {}, {}, {}, {}, {}, {}, {}, // f8-ff
+};
+
namespace {
bool CheckFastPathSetting(const UnboundConversion& conv) {
@@ -37,60 +75,17 @@ bool CheckFastPathSetting(const UnboundConversion& conv) {
return should_be_basic == conv.flags.basic;
}
-// Keep a single table for all the conversion chars and length modifiers.
-// We invert the length modifiers to make them negative so that we can easily
-// test for them.
-// Everything else is `none`, which is a negative constant.
-using CC = ConversionChar::Id;
-using LM = LengthMod::Id;
-static constexpr std::int8_t none = -128;
-static constexpr std::int8_t kIds[] = {
- none, none, none, none, none, none, none, none, // 00-07
- none, none, none, none, none, none, none, none, // 08-0f
- none, none, none, none, none, none, none, none, // 10-17
- none, none, none, none, none, none, none, none, // 18-1f
- none, none, none, none, none, none, none, none, // 20-27
- none, none, none, none, none, none, none, none, // 28-2f
- none, none, none, none, none, none, none, none, // 30-37
- none, none, none, none, none, none, none, none, // 38-3f
- none, CC::A, none, CC::C, none, CC::E, CC::F, CC::G, // @ABCDEFG
- none, none, none, none, ~LM::L, none, none, none, // HIJKLMNO
- none, none, none, CC::S, none, none, none, none, // PQRSTUVW
- CC::X, none, none, none, none, none, none, none, // XYZ[\]^_
- none, CC::a, none, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg
- ~LM::h, CC::i, ~LM::j, none, ~LM::l, none, CC::n, CC::o, // hijklmno
- CC::p, ~LM::q, none, CC::s, ~LM::t, CC::u, none, none, // pqrstuvw
- CC::x, none, ~LM::z, none, none, none, none, none, // xyz{|}~!
- none, none, none, none, none, none, none, none, // 80-87
- none, none, none, none, none, none, none, none, // 88-8f
- none, none, none, none, none, none, none, none, // 90-97
- none, none, none, none, none, none, none, none, // 98-9f
- none, none, none, none, none, none, none, none, // a0-a7
- none, none, none, none, none, none, none, none, // a8-af
- none, none, none, none, none, none, none, none, // b0-b7
- none, none, none, none, none, none, none, none, // b8-bf
- none, none, none, none, none, none, none, none, // c0-c7
- none, none, none, none, none, none, none, none, // c8-cf
- none, none, none, none, none, none, none, none, // d0-d7
- none, none, none, none, none, none, none, none, // d8-df
- none, none, none, none, none, none, none, none, // e0-e7
- none, none, none, none, none, none, none, none, // e8-ef
- none, none, none, none, none, none, none, none, // f0-f7
- none, none, none, none, none, none, none, none, // f8-ff
-};
-
template <bool is_positional>
-bool ConsumeConversion(string_view *src, UnboundConversion *conv,
- int *next_arg) {
- const char *pos = src->data();
- const char *const end = pos + src->size();
+const char *ConsumeConversion(const char *pos, const char *const end,
+ UnboundConversion *conv, int *next_arg) {
+ const char* const original_pos = pos;
char c;
// Read the next char into `c` and update `pos`. Returns false if there are
// no more chars to read.
-#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \
- do { \
- if (ABSL_PREDICT_FALSE(pos == end)) return false; \
- c = *pos++; \
+#define ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR() \
+ do { \
+ if (ABSL_PREDICT_FALSE(pos == end)) return nullptr; \
+ c = *pos++; \
} while (0)
const auto parse_digits = [&] {
@@ -100,10 +95,11 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv,
// digit doesn't match the expected characters.
int num_digits = std::numeric_limits<int>::digits10;
for (;;) {
- if (ABSL_PREDICT_FALSE(pos == end || !num_digits)) break;
+ if (ABSL_PREDICT_FALSE(pos == end)) break;
c = *pos++;
if (!std::isdigit(c)) break;
--num_digits;
+ if (ABSL_PREDICT_FALSE(!num_digits)) break;
digits = 10 * digits + c - '0';
}
return digits;
@@ -111,10 +107,10 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv,
if (is_positional) {
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
- if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false;
+ if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
conv->arg_position = parse_digits();
assert(conv->arg_position > 0);
- if (ABSL_PREDICT_FALSE(c != '$')) return false;
+ if (ABSL_PREDICT_FALSE(c != '$')) return nullptr;
}
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
@@ -129,10 +125,9 @@ bool ConsumeConversion(string_view *src, UnboundConversion *conv,
conv->flags.basic = false;
for (; c <= '0';) {
- // FIXME: We might be able to speed this up reusing the kIds lookup table
- // from above.
- // It might require changing Flags to be a plain integer where we can |= a
- // value.
+ // FIXME: We might be able to speed this up reusing the lookup table from
+ // above. It might require changing Flags to be a plain integer where we
+ // can |= a value.
switch (c) {
case '-':
conv->flags.left = true;
@@ -160,20 +155,20 @@ flags_done:
if (c >= '0') {
int maybe_width = parse_digits();
if (!is_positional && c == '$') {
- if (ABSL_PREDICT_FALSE(*next_arg != 0)) return false;
+ if (ABSL_PREDICT_FALSE(*next_arg != 0)) return nullptr;
// Positional conversion.
*next_arg = -1;
conv->flags = Flags();
conv->flags.basic = true;
- return ConsumeConversion<true>(src, conv, next_arg);
+ return ConsumeConversion<true>(original_pos, end, conv, next_arg);
}
conv->width.set_value(maybe_width);
} else if (c == '*') {
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
if (is_positional) {
- if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false;
+ if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
conv->width.set_from_arg(parse_digits());
- if (ABSL_PREDICT_FALSE(c != '$')) return false;
+ if (ABSL_PREDICT_FALSE(c != '$')) return nullptr;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
} else {
conv->width.set_from_arg(++*next_arg);
@@ -188,9 +183,9 @@ flags_done:
} else if (c == '*') {
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
if (is_positional) {
- if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return false;
+ if (ABSL_PREDICT_FALSE(c < '1' || c > '9')) return nullptr;
conv->precision.set_from_arg(parse_digits());
- if (c != '$') return false;
+ if (c != '$') return nullptr;
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
} else {
conv->precision.set_from_arg(++*next_arg);
@@ -201,14 +196,14 @@ flags_done:
}
}
- std::int8_t id = kIds[static_cast<unsigned char>(c)];
+ auto tag = GetTagForChar(c);
- if (id < 0) {
- if (ABSL_PREDICT_FALSE(id == none)) return false;
+ if (ABSL_PREDICT_FALSE(!tag.is_conv())) {
+ if (ABSL_PREDICT_FALSE(!tag.is_length())) return nullptr;
// It is a length modifier.
using str_format_internal::LengthMod;
- LengthMod length_mod = LengthMod::FromId(static_cast<LM>(~id));
+ LengthMod length_mod = tag.as_length();
ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR();
if (c == 'h' && length_mod.id() == LengthMod::h) {
conv->length_mod = LengthMod::FromId(LengthMod::hh);
@@ -219,25 +214,24 @@ flags_done:
} else {
conv->length_mod = length_mod;
}
- id = kIds[static_cast<unsigned char>(c)];
- if (ABSL_PREDICT_FALSE(id < 0)) return false;
+ tag = GetTagForChar(c);
+ if (ABSL_PREDICT_FALSE(!tag.is_conv())) return nullptr;
}
assert(CheckFastPathSetting(*conv));
(void)(&CheckFastPathSetting);
- conv->conv = ConversionChar::FromId(static_cast<CC>(id));
+ conv->conv = tag.as_conv();
if (!is_positional) conv->arg_position = ++*next_arg;
- *src = string_view(pos, end - pos);
- return true;
+ return pos;
}
} // namespace
-bool ConsumeUnboundConversion(string_view *src, UnboundConversion *conv,
- int *next_arg) {
- if (*next_arg < 0) return ConsumeConversion<true>(src, conv, next_arg);
- return ConsumeConversion<false>(src, conv, next_arg);
+const char *ConsumeUnboundConversion(const char *p, const char *end,
+ UnboundConversion *conv, int *next_arg) {
+ if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg);
+ return ConsumeConversion<false>(p, end, conv, next_arg);
}
struct ParsedFormatBase::ParsedFormatConsumer {
@@ -307,5 +301,5 @@ bool ParsedFormatBase::MatchesConversions(
}
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_format/parser.h b/absl/strings/internal/str_format/parser.h
index 9842c117..d3357fde 100644
--- a/absl/strings/internal/str_format/parser.h
+++ b/absl/strings/internal/str_format/parser.h
@@ -16,7 +16,7 @@
#include "absl/strings/internal/str_format/extension.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
// The analyzed properties of a single specified conversion.
@@ -64,17 +64,45 @@ struct UnboundConversion {
ConversionChar conv;
};
-// Consume conversion spec prefix (not including '%') of '*src' if valid.
+// Consume conversion spec prefix (not including '%') of [p, end) if valid.
// Examples of valid specs would be e.g.: "s", "d", "-12.6f".
-// If valid, the front of src is advanced such that src becomes the
-// part following the conversion spec, and the spec part is broken down and
-// returned in 'conv'.
-// If invalid, returns false and leaves 'src' unmodified.
-// For example:
-// Given "d9", returns "d", and leaves src="9",
-// Given "!", returns "" and leaves src="!".
-bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv,
- int* next_arg);
+// If valid, it returns the first character following the conversion spec,
+// and the spec part is broken down and returned in 'conv'.
+// If invalid, returns nullptr.
+const char* ConsumeUnboundConversion(const char* p, const char* end,
+ UnboundConversion* conv, int* next_arg);
+
+// Helper tag class for the table below.
+// It allows fast `char -> ConversionChar/LengthMod` checking and conversions.
+class ConvTag {
+ public:
+ constexpr ConvTag(ConversionChar::Id id) : tag_(id) {} // NOLINT
+ // We invert the length modifiers to make them negative so that we can easily
+ // test for them.
+ constexpr ConvTag(LengthMod::Id id) : tag_(~id) {} // NOLINT
+ // Everything else is -128, which is negative to make is_conv() simpler.
+ constexpr ConvTag() : tag_(-128) {}
+
+ bool is_conv() const { return tag_ >= 0; }
+ bool is_length() const { return tag_ < 0 && tag_ != -128; }
+ ConversionChar as_conv() const {
+ assert(is_conv());
+ return ConversionChar::FromId(static_cast<ConversionChar::Id>(tag_));
+ }
+ LengthMod as_length() const {
+ assert(is_length());
+ return LengthMod::FromId(static_cast<LengthMod::Id>(~tag_));
+ }
+
+ private:
+ std::int8_t tag_;
+};
+
+extern const ConvTag kTags[256];
+// Keep a single table for all the conversion chars and length modifiers.
+inline ConvTag GetTagForChar(char c) {
+ return kTags[static_cast<unsigned char>(c)];
+}
// Parse the format string provided in 'src' and pass the identified items into
// 'consumer'.
@@ -89,51 +117,53 @@ bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv,
template <typename Consumer>
bool ParseFormatString(string_view src, Consumer consumer) {
int next_arg = 0;
- while (!src.empty()) {
- const char* percent =
- static_cast<const char*>(memchr(src.data(), '%', src.size()));
+ const char* p = src.data();
+ const char* const end = p + src.size();
+ while (p != end) {
+ const char* percent = static_cast<const char*>(memchr(p, '%', end - p));
if (!percent) {
// We found the last substring.
- return consumer.Append(src);
+ return consumer.Append(string_view(p, end - p));
}
// We found a percent, so push the text run then process the percent.
- size_t percent_loc = percent - src.data();
- if (!consumer.Append(string_view(src.data(), percent_loc))) return false;
- if (percent + 1 >= src.data() + src.size()) return false;
-
- UnboundConversion conv;
-
- switch (percent[1]) {
- case '%':
- if (!consumer.Append("%")) return false;
- src.remove_prefix(percent_loc + 2);
- continue;
-
-#define PARSER_CASE(ch) \
- case #ch[0]: \
- src.remove_prefix(percent_loc + 2); \
- conv.conv = ConversionChar::FromId(ConversionChar::ch); \
- conv.arg_position = ++next_arg; \
- break;
- ABSL_CONVERSION_CHARS_EXPAND_(PARSER_CASE, );
-#undef PARSER_CASE
-
- default:
- src.remove_prefix(percent_loc + 1);
- if (!ConsumeUnboundConversion(&src, &conv, &next_arg)) return false;
- break;
- }
- if (next_arg == 0) {
- // This indicates an error in the format std::string.
- // The only way to get next_arg == 0 is to have a positional argument
- // first which sets next_arg to -1 and then a non-positional argument
- // which does ++next_arg.
- // Checking here seems to be the cheapeast place to do it.
+ if (ABSL_PREDICT_FALSE(!consumer.Append(string_view(p, percent - p)))) {
return false;
}
- if (!consumer.ConvertOne(
- conv, string_view(percent + 1, src.data() - (percent + 1)))) {
- return false;
+ if (ABSL_PREDICT_FALSE(percent + 1 >= end)) return false;
+
+ auto tag = GetTagForChar(percent[1]);
+ if (tag.is_conv()) {
+ if (ABSL_PREDICT_FALSE(next_arg < 0)) {
+ // This indicates an error in the format std::string.
+ // The only way to get `next_arg < 0` here is to have a positional
+ // argument first which sets next_arg to -1 and then a non-positional
+ // argument.
+ return false;
+ }
+ p = percent + 2;
+
+ // Keep this case separate from the one below.
+ // ConvertOne is more efficient when the compiler can see that the `basic`
+ // flag is set.
+ UnboundConversion conv;
+ conv.conv = tag.as_conv();
+ conv.arg_position = ++next_arg;
+ if (ABSL_PREDICT_FALSE(
+ !consumer.ConvertOne(conv, string_view(percent + 1, 1)))) {
+ return false;
+ }
+ } else if (percent[1] != '%') {
+ UnboundConversion conv;
+ p = ConsumeUnboundConversion(percent + 1, end, &conv, &next_arg);
+ if (ABSL_PREDICT_FALSE(p == nullptr)) return false;
+ if (ABSL_PREDICT_FALSE(!consumer.ConvertOne(
+ conv, string_view(percent + 1, p - (percent + 1))))) {
+ return false;
+ }
+ } else {
+ if (ABSL_PREDICT_FALSE(!consumer.Append("%"))) return false;
+ p = percent + 2;
+ continue;
}
}
return true;
@@ -288,7 +318,7 @@ class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
: ParsedFormatBase(s, allow_ignored, {C...}) {}
};
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
diff --git a/absl/strings/internal/str_format/parser_test.cc b/absl/strings/internal/str_format/parser_test.cc
index 14d90344..d77a8ea5 100644
--- a/absl/strings/internal/str_format/parser_test.cc
+++ b/absl/strings/internal/str_format/parser_test.cc
@@ -1,15 +1,19 @@
#include "absl/strings/internal/str_format/parser.h"
#include <string.h>
+
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/macros.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace str_format_internal {
namespace {
+using testing::Pair;
+
TEST(LengthModTest, Names) {
struct Expectation {
int line;
@@ -64,20 +68,21 @@ TEST(ConversionCharTest, Names) {
class ConsumeUnboundConversionTest : public ::testing::Test {
public:
- typedef UnboundConversion Props;
- string_view Consume(string_view* src) {
+ std::pair<string_view, string_view> Consume(string_view src) {
int next = 0;
- const char* prev_begin = src->data();
o = UnboundConversion(); // refresh
- ConsumeUnboundConversion(src, &o, &next);
- return {prev_begin, static_cast<size_t>(src->data() - prev_begin)};
+ const char* p = ConsumeUnboundConversion(
+ src.data(), src.data() + src.size(), &o, &next);
+ if (!p) return {{}, src};
+ return {string_view(src.data(), p - src.data()),
+ string_view(p, src.data() + src.size() - p)};
}
bool Run(const char *fmt, bool force_positional = false) {
- string_view src = fmt;
int next = force_positional ? -1 : 0;
o = UnboundConversion(); // refresh
- return ConsumeUnboundConversion(&src, &o, &next) && src.empty();
+ return ConsumeUnboundConversion(fmt, fmt + strlen(fmt), &o, &next) ==
+ fmt + strlen(fmt);
}
UnboundConversion o;
};
@@ -105,11 +110,7 @@ TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) {
};
for (const auto& e : kExpect) {
SCOPED_TRACE(e.line);
- string_view src = e.src;
- EXPECT_EQ(e.src, src);
- string_view out = Consume(&src);
- EXPECT_EQ(e.out, out);
- EXPECT_EQ(e.src_post, src);
+ EXPECT_THAT(Consume(e.src), Pair(e.out, e.src_post));
}
}
@@ -247,6 +248,8 @@ TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) {
EXPECT_FALSE(Run("1000000000.999999999d"));
EXPECT_FALSE(Run("999999999.1000000000d"));
+ EXPECT_FALSE(Run("9999999999d"));
+ EXPECT_FALSE(Run(".9999999999d"));
}
TEST_F(ConsumeUnboundConversionTest, Flags) {
@@ -387,5 +390,5 @@ TEST_F(ParsedFormatTest, ParsingFlagOrder) {
} // namespace
} // namespace str_format_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/str_join_internal.h b/absl/strings/internal/str_join_internal.h
index 90b06d6f..02787dd1 100644
--- a/absl/strings/internal/str_join_internal.h
+++ b/absl/strings/internal/str_join_internal.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -43,7 +43,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
//
@@ -194,7 +194,7 @@ struct DefaultFormatter<std::unique_ptr<ValueType>>
// and formats each element using the provided Formatter object.
template <typename Iterator, typename Formatter>
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
- Formatter&& f) {
+ Formatter&& f) {
std::string result;
absl::string_view sep("");
for (Iterator it = start; it != end; ++it) {
@@ -213,7 +213,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
// This is an overload of the previous JoinAlgorithm() function. Here the
// Formatter argument is of type NoFormatter. Since NoFormatter is an internal
// type, this overload is only invoked when strings::Join() is called with a
-// range of string-like objects (e.g., string, absl::string_view), and an
+// range of string-like objects (e.g., std::string, absl::string_view), and an
// explicit Formatter argument was NOT specified.
//
// The optimization is that the needed space will be reserved in the output
@@ -225,7 +225,7 @@ template <typename Iterator,
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>::value>::type>
std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
- NoFormatter) {
+ NoFormatter) {
std::string result;
if (start != end) {
// Sums size
@@ -277,14 +277,15 @@ struct JoinTupleLoop<N, N> {
template <typename... T, typename Formatter>
std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep,
- Formatter&& fmt) {
+ Formatter&& fmt) {
std::string result;
JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt);
return result;
}
template <typename Iterator>
-std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) {
+std::string JoinRange(Iterator first, Iterator last,
+ absl::string_view separator) {
// No formatter was explicitly given, so a default must be chosen.
typedef typename std::iterator_traits<Iterator>::value_type ValueType;
typedef typename DefaultFormatter<ValueType>::Type Formatter;
@@ -293,7 +294,7 @@ std::string JoinRange(Iterator first, Iterator last, absl::string_view separator
template <typename Range, typename Formatter>
std::string JoinRange(const Range& range, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
using std::begin;
using std::end;
return JoinAlgorithm(begin(range), end(range), separator, fmt);
@@ -307,7 +308,7 @@ std::string JoinRange(const Range& range, absl::string_view separator) {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
diff --git a/absl/strings/internal/str_split_internal.h b/absl/strings/internal/str_split_internal.h
index 2300193a..92a678e0 100644
--- a/absl/strings/internal/str_split_internal.h
+++ b/absl/strings/internal/str_split_internal.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -47,7 +47,7 @@
#endif // _GLIBCXX_DEBUG
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// This class is implicitly constructible from everything that absl::string_view
@@ -97,8 +97,8 @@ ConvertibleToStringView(std::string&& s) // NOLINT(runtime/explicit)
}
}
- // Holds the data moved from temporary std::string arguments. Declared first so
- // that 'value' can refer to 'copy_'.
+ // Holds the data moved from temporary std::string arguments. Declared first
+ // so that 'value' can refer to 'copy_'.
std::string copy_;
absl::string_view value_;
};
@@ -377,10 +377,10 @@ class Splitter {
// Partial specialization for a std::vector<std::string>.
//
- // Optimized for the common case of splitting to a std::vector<std::string>. In
- // this case we first split the results to a std::vector<absl::string_view> so
- // the returned std::vector<std::string> can have space reserved to avoid std::string
- // moves.
+ // Optimized for the common case of splitting to a std::vector<std::string>.
+ // In this case we first split the results to a std::vector<absl::string_view>
+ // so the returned std::vector<std::string> can have space reserved to avoid
+ // std::string moves.
template <typename A>
struct ConvertToContainer<std::vector<std::string, A>, std::string, false> {
std::vector<std::string, A> operator()(const Splitter& splitter) const {
@@ -449,7 +449,7 @@ class Splitter {
};
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
diff --git a/absl/strings/internal/utf8.cc b/absl/strings/internal/utf8.cc
index c6ab0d52..fe4a9beb 100644
--- a/absl/strings/internal/utf8.cc
+++ b/absl/strings/internal/utf8.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "absl/strings/internal/utf8.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
@@ -49,5 +49,5 @@ size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) {
}
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/internal/utf8.h b/absl/strings/internal/utf8.h
index 59c4f5b4..b1bb954e 100644
--- a/absl/strings/internal/utf8.h
+++ b/absl/strings/internal/utf8.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -13,7 +13,6 @@
// limitations under the License.
//
// UTF8 utilities, implemented to reduce dependencies.
-//
#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_
#define ABSL_STRINGS_INTERNAL_UTF8_H_
@@ -22,7 +21,7 @@
#include <cstdint>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes
@@ -43,7 +42,7 @@ enum { kMaxEncodedUTF8Size = 4 };
size_t EncodeUTF8Char(char *buffer, char32_t utf8_char);
} // namespace strings_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_UTF8_H_
diff --git a/absl/strings/internal/utf8_test.cc b/absl/strings/internal/utf8_test.cc
index 64cec70d..88dd5036 100644
--- a/absl/strings/internal/utf8_test.cc
+++ b/absl/strings/internal/utf8_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,12 +22,17 @@
namespace {
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
TEST(EncodeUTF8Char, BasicFunction) {
std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"},
- {0x00A3, u8"\u00A3"},
- {0x00010000, u8"\U00010000"},
- {0x0000FFFF, u8"\U0000FFFF"},
- {0x0010FFFD, u8"\U0010FFFD"}};
+ {0x00A3, u8"\u00A3"},
+ {0x00010000, u8"\U00010000"},
+ {0x0000FFFF, u8"\U0000FFFF"},
+ {0x0010FFFD, u8"\U0010FFFD"}};
for (auto &test : tests) {
char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'};
@@ -53,5 +58,9 @@ TEST(EncodeUTF8Char, BasicFunction) {
EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1),
absl::strings_internal::kMaxEncodedUTF8Size);
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif // !defined(__cpp_char8_t)
} // namespace
diff --git a/absl/strings/match.cc b/absl/strings/match.cc
index 12ba8edf..01ed1f15 100644
--- a/absl/strings/match.cc
+++ b/absl/strings/match.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,16 +17,7 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
-inline namespace lts_2018_12_18 {
-
-namespace {
-bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
- return (piece1.size() == piece2.size() &&
- 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
- piece1.size()));
- // memcasecmp uses ascii_tolower().
-}
-} // namespace
+inline namespace lts_2019_08_08 {
bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
return (piece1.size() == piece2.size() &&
@@ -37,13 +28,13 @@ bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) {
bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) {
return (text.size() >= prefix.size()) &&
- CaseEqual(text.substr(0, prefix.size()), prefix);
+ EqualsIgnoreCase(text.substr(0, prefix.size()), prefix);
}
bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) {
return (text.size() >= suffix.size()) &&
- CaseEqual(text.substr(text.size() - suffix.size()), suffix);
+ EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/match.h b/absl/strings/match.h
index 5805207c..15fdc0c8 100644
--- a/absl/strings/match.h
+++ b/absl/strings/match.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,7 +38,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// StrContains()
//
@@ -63,8 +63,7 @@ inline bool EndsWith(absl::string_view text, absl::string_view suffix) {
return suffix.empty() ||
(text.size() >= suffix.size() &&
memcmp(text.data() + (text.size() - suffix.size()), suffix.data(),
- suffix.size()) == 0
- );
+ suffix.size()) == 0);
}
// EqualsIgnoreCase()
@@ -75,17 +74,17 @@ bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2);
// StartsWithIgnoreCase()
//
-// Returns whether a given ASCII string `text` starts with `starts_with`,
+// Returns whether a given ASCII string `text` starts with `prefix`,
// ignoring case in the comparison.
bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix);
// EndsWithIgnoreCase()
//
-// Returns whether a given ASCII string `text` ends with `ends_with`, ignoring
+// Returns whether a given ASCII string `text` ends with `suffix`, ignoring
// case in the comparison.
bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_MATCH_H_
diff --git a/absl/strings/match_test.cc b/absl/strings/match_test.cc
index c21e00bf..4c313dda 100644
--- a/absl/strings/match_test.cc
+++ b/absl/strings/match_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,7 @@
namespace {
TEST(MatchTest, StartsWith) {
- const std::string s1("123" "\0" "456", 7);
+ const std::string s1("123\0abc", 7);
const absl::string_view a("foobar");
const absl::string_view b(s1);
const absl::string_view e;
@@ -36,7 +36,7 @@ TEST(MatchTest, StartsWith) {
}
TEST(MatchTest, EndsWith) {
- const std::string s1("123" "\0" "456", 7);
+ const std::string s1("123\0abc", 7);
const absl::string_view a("foobar");
const absl::string_view b(s1);
const absl::string_view e;
diff --git a/absl/strings/numbers.cc b/absl/strings/numbers.cc
index 4c3ddb34..2bac4adc 100644
--- a/absl/strings/numbers.cc
+++ b/absl/strings/numbers.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -35,18 +35,19 @@
#include "absl/strings/ascii.h"
#include "absl/strings/charconv.h"
#include "absl/strings/internal/memutil.h"
+#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
-bool SimpleAtof(absl::string_view str, float* value) {
- *value = 0.0;
+bool SimpleAtof(absl::string_view str, float* out) {
+ *out = 0.0;
str = StripAsciiWhitespace(str);
if (!str.empty() && str[0] == '+') {
str.remove_prefix(1);
}
- auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
if (result.ec == std::errc::invalid_argument) {
return false;
}
@@ -54,25 +55,25 @@ bool SimpleAtof(absl::string_view str, float* value) {
// not all non-whitespace characters consumed
return false;
}
- // from_chars() with DR 3801's current wording will return max() on
+ // from_chars() with DR 3081's current wording will return max() on
// overflow. SimpleAtof returns infinity instead.
if (result.ec == std::errc::result_out_of_range) {
- if (*value > 1.0) {
- *value = std::numeric_limits<float>::infinity();
- } else if (*value < -1.0) {
- *value = -std::numeric_limits<float>::infinity();
+ if (*out > 1.0) {
+ *out = std::numeric_limits<float>::infinity();
+ } else if (*out < -1.0) {
+ *out = -std::numeric_limits<float>::infinity();
}
}
return true;
}
-bool SimpleAtod(absl::string_view str, double* value) {
- *value = 0.0;
+bool SimpleAtod(absl::string_view str, double* out) {
+ *out = 0.0;
str = StripAsciiWhitespace(str);
if (!str.empty() && str[0] == '+') {
str.remove_prefix(1);
}
- auto result = absl::from_chars(str.data(), str.data() + str.size(), *value);
+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *out);
if (result.ec == std::errc::invalid_argument) {
return false;
}
@@ -80,13 +81,13 @@ bool SimpleAtod(absl::string_view str, double* value) {
// not all non-whitespace characters consumed
return false;
}
- // from_chars() with DR 3801's current wording will return max() on
+ // from_chars() with DR 3081's current wording will return max() on
// overflow. SimpleAtod returns infinity instead.
if (result.ec == std::errc::result_out_of_range) {
- if (*value > 1.0) {
- *value = std::numeric_limits<double>::infinity();
- } else if (*value < -1.0) {
- *value = -std::numeric_limits<double>::infinity();
+ if (*out > 1.0) {
+ *out = std::numeric_limits<double>::infinity();
+ } else if (*out < -1.0) {
+ *out = -std::numeric_limits<double>::infinity();
}
}
return true;
@@ -94,14 +95,6 @@ bool SimpleAtod(absl::string_view str, double* value) {
namespace {
-// TODO(rogeeff): replace with the real released thing once we figure out what
-// it is.
-inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) {
- return (piece1.size() == piece2.size() &&
- 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(),
- piece1.size()));
-}
-
// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the
// range 0 <= i < 100, and buf must have space for two characters. Example:
// char buf[2];
@@ -137,18 +130,18 @@ inline void PutTwoDigits(size_t i, char* buf) {
} // namespace
-bool SimpleAtob(absl::string_view str, bool* value) {
- ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr.");
- if (CaseEqual(str, "true") || CaseEqual(str, "t") ||
- CaseEqual(str, "yes") || CaseEqual(str, "y") ||
- CaseEqual(str, "1")) {
- *value = true;
+bool SimpleAtob(absl::string_view str, bool* 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") ||
+ EqualsIgnoreCase(str, "1")) {
+ *out = true;
return true;
}
- if (CaseEqual(str, "false") || CaseEqual(str, "f") ||
- CaseEqual(str, "no") || CaseEqual(str, "n") ||
- CaseEqual(str, "0")) {
- *value = false;
+ if (EqualsIgnoreCase(str, "false") || EqualsIgnoreCase(str, "f") ||
+ EqualsIgnoreCase(str, "no") || EqualsIgnoreCase(str, "n") ||
+ EqualsIgnoreCase(str, "0")) {
+ *out = false;
return true;
}
return false;
@@ -910,5 +903,5 @@ bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) {
}
} // namespace numbers_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/numbers.h b/absl/strings/numbers.h
index 250d2603..e9878016 100644
--- a/absl/strings/numbers.h
+++ b/absl/strings/numbers.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -38,48 +38,53 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// SimpleAtoi()
//
// Converts the given string into an integer value, returning `true` if
// successful. The string must reflect a base-10 integer (optionally followed or
// preceded by ASCII whitespace) whose value falls within the range of the
-// integer type.
+// integer type. If any errors are encountered, this function returns `false`,
+// leaving `out` in an unspecified state.
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out);
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out);
// SimpleAtof()
//
// Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a float, which may be rounded on overflow or underflow.
-// See http://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`.
-ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value);
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`. 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, float* out);
// SimpleAtod()
//
// Converts the given string (optionally followed or preceded by ASCII
// whitespace) into a double, which may be rounded on overflow or underflow.
-// See http://en.cppreference.com/w/c/string/byte/strtof for details about the
-// allowed formats for `str`.
-ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value);
+// See https://en.cppreference.com/w/c/string/byte/strtof for details about the
+// allowed formats for `str`. 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, double* out);
// SimpleAtob()
//
// Converts the given string into a boolean, returning `true` if successful.
// The following case-insensitive strings are interpreted as boolean `true`:
// "true", "t", "yes", "y", "1". The following case-insensitive strings
-// are interpreted as boolean `false`: "false", "f", "no", "n", "0".
-ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value);
+// 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, bool* out);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// End of public API. Implementation details follow.
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace numbers_internal {
// safe_strto?() functions for implementing SimpleAtoi()
@@ -178,11 +183,11 @@ ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out,
// preceded by ASCII whitespace, with a value in the range of the corresponding
// integer type.
template <typename int_type>
-ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out) {
- return numbers_internal::safe_strtoi_base(s, out, 10);
+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
+ return numbers_internal::safe_strtoi_base(str, out, 10);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_NUMBERS_H_
diff --git a/absl/strings/numbers_benchmark.cc b/absl/strings/numbers_benchmark.cc
index 0570b758..54dbedd3 100644
--- a/absl/strings/numbers_benchmark.cc
+++ b/absl/strings/numbers_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/numbers_test.cc b/absl/strings/numbers_test.cc
index 099326c2..77d7e783 100644
--- a/absl/strings/numbers_test.cc
+++ b/absl/strings/numbers_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -191,7 +191,8 @@ void CheckUInt64(uint64_t x) {
EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x;
char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]);
- EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x;
+ EXPECT_EQ(expected, std::string(&buffer[1], generic_actual))
+ << " Input " << x;
char* my_actual =
absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]);
@@ -712,7 +713,7 @@ TEST(stringtest, safe_strtou64_base_length_delimited) {
}
}
-// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC,
+// feenableexcept() and fedisableexcept() are missing on macOS, MSVC,
// and WebAssembly.
#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
#define ABSL_MISSING_FEENABLEEXCEPT 1
@@ -784,7 +785,7 @@ void ExhaustiveFloat(uint32_t cases, R&& runnable) {
if (iters_per_float == 0) iters_per_float = 1;
for (float f : floats) {
if (f == last) continue;
- float testf = nextafter(last, std::numeric_limits<float>::max());
+ float testf = std::nextafter(last, std::numeric_limits<float>::max());
runnable(testf);
runnable(-testf);
last = testf;
@@ -798,7 +799,7 @@ void ExhaustiveFloat(uint32_t cases, R&& runnable) {
last = testf;
}
}
- testf = nextafter(f, 0.0f);
+ testf = std::nextafter(f, 0.0f);
if (testf > last) {
runnable(testf);
runnable(-testf);
@@ -879,8 +880,8 @@ TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) {
char buf[kSixDigitsToBufferSize];
ABSL_RAW_LOG(
INFO, "%s",
- absl::StrCat("Exp ", exponent, " powten=", powten, "(",
- powten, ") (",
+ absl::StrCat("Exp ", exponent, " powten=", powten, "(", powten,
+ ") (",
std::string(buf, SixDigitsToBuffer(powten, buf)), ")")
.c_str());
}
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc
index 2f2e5315..73b9e0ba 100644
--- a/absl/strings/str_cat.cc
+++ b/absl/strings/str_cat.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/strings/internal/resize_uninitialized.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
AlphaNum::AlphaNum(Hex hex) {
char* const end = &digits_[numbers_internal::kFastToBufferSize];
@@ -79,7 +79,7 @@ AlphaNum::AlphaNum(Dec dec) {
// ----------------------------------------------------------------------
// StrCat()
-// This merges the given strings or integers, with no delimiter. This
+// This merges the given strings or integers, with no delimiter. This
// is designed to be the fastest possible way to construct a string out
// of a mix of raw C strings, string_views, strings, and integer values.
// ----------------------------------------------------------------------
@@ -90,7 +90,9 @@ static char* Append(char* 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();
- memcpy(out, x.data(), x.size());
+ if (x.size() != 0) {
+ memcpy(out, x.data(), x.size());
+ }
return after;
}
@@ -120,7 +122,7 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
}
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
- const AlphaNum& d) {
+ const AlphaNum& d) {
std::string result;
strings_internal::STLStringResizeUninitialized(
&result, a.size() + b.size() + c.size() + d.size());
@@ -147,8 +149,10 @@ std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
char* out = begin;
for (const absl::string_view piece : pieces) {
const size_t this_size = piece.size();
- memcpy(out, piece.data(), this_size);
- out += this_size;
+ if (this_size != 0) {
+ memcpy(out, piece.data(), this_size);
+ out += this_size;
+ }
}
assert(out == begin + result.size());
return result;
@@ -177,8 +181,10 @@ void AppendPieces(std::string* dest,
char* out = begin + old_size;
for (const absl::string_view piece : pieces) {
const size_t this_size = piece.size();
- memcpy(out, piece.data(), this_size);
- out += this_size;
+ if (this_size != 0) {
+ memcpy(out, piece.data(), this_size);
+ out += this_size;
+ }
}
assert(out == begin + dest->size());
}
@@ -237,5 +243,5 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
assert(out == begin + dest->size());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/str_cat.h b/absl/strings/str_cat.h
index edda40ad..c2700475 100644
--- a/absl/strings/str_cat.h
+++ b/absl/strings/str_cat.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -37,12 +37,12 @@
// attempt to pass ':' instead of ":" might result in a 58 ending up in your
// result.
//
-// Bools convert to "0" or "1".
+// Bools convert to "0" or "1". Pointers to types other than `char *` are not
+// valid inputs. No output is generated for null `char *` pointers.
//
// Floating point numbers are formatted with six-digit precision, which is
// the default for "std::cout <<" or printf "%g" (the same as "%.6g").
//
-//
// You can convert to hexadecimal output rather than decimal output using the
// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
@@ -57,13 +57,14 @@
#include <cstdint>
#include <string>
#include <type_traits>
+#include <vector>
#include "absl/base/port.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
// AlphaNumBuffer allows a way to pass a string to StrCat without having to do
@@ -79,8 +80,8 @@ struct AlphaNumBuffer {
// Enum that specifies the number of significant digits to return in a `Hex` or
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
-// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
-// would produce hexadecimal strings such as " A"," F".
+// would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
+// would produce hexadecimal strings such as " a"," f".
enum PadSpec : uint8_t {
kNoPad = 1,
kZeroPad2,
@@ -246,6 +247,7 @@ class AlphaNum {
AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit)
AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit)
+
template <typename Allocator>
AlphaNum( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
@@ -269,6 +271,17 @@ class AlphaNum {
AlphaNum(T e) // NOLINT(runtime/explicit)
: AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
+ // vector<bool>::reference and const_reference require special help to
+ // convert to `AlphaNum` because it requires two user defined conversions.
+ template <
+ typename T,
+ typename std::enable_if<
+ std::is_class<T>::value &&
+ (std::is_same<T, std::vector<bool>::reference>::value ||
+ std::is_same<T, std::vector<bool>::const_reference>::value)>::type* =
+ nullptr>
+ AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} // NOLINT(runtime/explicit)
+
private:
absl::string_view piece_;
char digits_[numbers_internal::kFastToBufferSize];
@@ -318,16 +331,15 @@ ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) {
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);
+ const AlphaNum& c);
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
- const AlphaNum& c, const AlphaNum& d);
+ 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) {
+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) {
return strings_internal::CatPieces(
{a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(),
static_cast<const AlphaNum&>(args).Piece()...});
@@ -345,18 +357,18 @@ ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum
// not try to check each of its input arguments to be sure that they are not
// a subset of the string being appended to. That is, while this will work:
//
-// string s = "foo";
+// std::string s = "foo";
// s += s;
//
// This output is undefined:
//
-// string s = "foo";
+// std::string s = "foo";
// StrAppend(&s, s);
//
// This output is undefined as well, since `absl::string_view` does not own its
// data:
//
-// string s = "foobar";
+// std::string s = "foobar";
// absl::string_view p = s;
// StrAppend(&s, p);
@@ -389,7 +401,7 @@ SixDigits(double d) {
return result;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STR_CAT_H_
diff --git a/absl/strings/str_cat_benchmark.cc b/absl/strings/str_cat_benchmark.cc
index b6df9e30..14c63b3f 100644
--- a/absl/strings/str_cat_benchmark.cc
+++ b/absl/strings/str_cat_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/str_cat_test.cc b/absl/strings/str_cat_test.cc
index 07141072..29db9c02 100644
--- a/absl/strings/str_cat_test.cc
+++ b/absl/strings/str_cat_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,6 +18,7 @@
#include <cstdint>
#include <string>
+#include <vector>
#include "gtest/gtest.h"
#include "absl/strings/substitute.h"
@@ -106,11 +107,7 @@ TEST(StrCat, Enums) {
TEST(StrCat, Basics) {
std::string result;
- std::string strs[] = {
- "Hello",
- "Cruel",
- "World"
- };
+ std::string strs[] = {"Hello", "Cruel", "World"};
std::string stdstrs[] = {
"std::Hello",
@@ -164,9 +161,10 @@ TEST(StrCat, Basics) {
result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!");
EXPECT_EQ(result, "12345678910, 10987654321!");
- std::string one = "1"; // Actually, it's the size of this std::string that we want; a
- // 64-bit build distinguishes between size_t and uint64_t,
- // even though they're both unsigned 64-bit values.
+ std::string one =
+ "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
result = absl::StrCat("And a ", one.size(), " and a ",
&result[2] - &result[0], " and a ", one, " 2 3 4", "!");
EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!");
@@ -306,11 +304,7 @@ TEST(StrCat, MaxArgs) {
TEST(StrAppend, Basics) {
std::string result = "existing text";
- std::string strs[] = {
- "Hello",
- "Cruel",
- "World"
- };
+ std::string strs[] = {"Hello", "Cruel", "World"};
std::string stdstrs[] = {
"std::Hello",
@@ -365,9 +359,10 @@ TEST(StrAppend, Basics) {
absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!");
EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!");
- std::string one = "1"; // Actually, it's the size of this std::string that we want; a
- // 64-bit build distinguishes between size_t and uint64_t,
- // even though they're both unsigned 64-bit values.
+ std::string one =
+ "1"; // Actually, it's the size of this std::string that we want; a
+ // 64-bit build distinguishes between size_t and uint64_t,
+ // even though they're both unsigned 64-bit values.
old_size = result.size();
absl::StrAppend(&result, "And a ", one.size(), " and a ",
&result[2] - &result[0], " and a ", one, " 2 3 4", "!");
@@ -401,6 +396,32 @@ TEST(StrAppend, Basics) {
"No limit thanks to C++11's variadic templates");
}
+TEST(StrCat, VectorBoolReferenceTypes) {
+ std::vector<bool> v;
+ v.push_back(true);
+ v.push_back(false);
+ std::vector<bool> const& cv = v;
+ // Test that vector<bool>::reference and vector<bool>::const_reference
+ // are handled as if the were really bool types and not the proxy types
+ // they really are.
+ std::string result = absl::StrCat(v[0], v[1], cv[0], cv[1]); // NOLINT
+ EXPECT_EQ(result, "1010");
+}
+
+// Passing nullptr to memcpy is undefined behavior and this test
+// provides coverage of codepaths that handle empty strings with nullptrs.
+TEST(StrCat, AvoidsMemcpyWithNullptr) {
+ EXPECT_EQ(absl::StrCat(42, absl::string_view{}), "42");
+
+ // Cover CatPieces code.
+ EXPECT_EQ(absl::StrCat(1, 2, 3, 4, 5, absl::string_view{}), "12345");
+
+ // Cover AppendPieces.
+ std::string result;
+ absl::StrAppend(&result, 1, 2, 3, 4, 5, absl::string_view{});
+ EXPECT_EQ(result, "12345");
+}
+
#ifdef GTEST_HAS_DEATH_TEST
TEST(StrAppend, Death) {
std::string s = "self";
diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h
index 7b19d411..b4d1b7bd 100644
--- a/absl/strings/str_format.h
+++ b/absl/strings/str_format.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,11 +20,13 @@
// The `str_format` library is a typesafe replacement for the family of
// `printf()` string formatting routines within the `<cstdio>` standard library
// header. Like the `printf` family, the `str_format` uses a "format string" to
-// perform argument substitutions based on types.
+// perform argument substitutions based on types. See the `FormatSpec` section
+// below for format string documentation.
//
// Example:
//
-// string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars);
+// std::string s = absl::StrFormat(
+// "%s %s You have $%d!", "Hello", name, dollars);
//
// The library consists of the following basic utilities:
//
@@ -49,7 +51,7 @@
// * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled
// format string for a specific set of type(s), and which can be passed
// between API boundaries. (The `FormatSpec` type should not be used
-// directly.)
+// directly except as an argument type for wrapper functions.)
//
// The `str_format` library provides the ability to output its format strings to
// arbitrary sink types:
@@ -66,6 +68,7 @@
// In addition, the `str_format` library provides extension points for
// augmenting formatting to new types. These extensions are fully documented
// within the `str_format_extension.h` header file.
+
#ifndef ABSL_STRINGS_STR_FORMAT_H_
#define ABSL_STRINGS_STR_FORMAT_H_
@@ -79,7 +82,7 @@
#include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// UntypedFormatSpec
//
@@ -90,7 +93,7 @@ inline namespace lts_2018_12_18 {
// Example:
//
// absl::UntypedFormatSpec format("%d");
-// string out;
+// std::string out;
// CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)}));
class UntypedFormatSpec {
public:
@@ -136,8 +139,8 @@ str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) {
// Example:
//
// int n = 0;
-// string s = absl::StrFormat("%s%d%n", "hello", 123,
-// absl::FormatCountCapture(&n));
+// std::string s = absl::StrFormat("%s%d%n", "hello", 123,
+// absl::FormatCountCapture(&n));
// EXPECT_EQ(8, n);
class FormatCountCapture {
public:
@@ -157,10 +160,15 @@ class FormatCountCapture {
// FormatSpec
//
// The `FormatSpec` type defines the makeup of a format string within the
-// `str_format` library. You should not need to use or manipulate this type
-// directly. A `FormatSpec` is a variadic class template that is evaluated at
-// compile-time, according to the format string and arguments that are passed
-// to it.
+// `str_format` library. It is a variadic class template that is evaluated at
+// compile-time, according to the format string and arguments that are passed to
+// it.
+//
+// You should not need to manipulate this type directly. You should only name it
+// if you are writing wrapper functions which accept format arguments that will
+// be provided unmodified to functions in this library. Such a wrapper function
+// might be a class method that provides format arguments and/or internally uses
+// the result of formatting.
//
// For a `FormatSpec` to be valid at compile-time, it must be provided as
// either:
@@ -187,7 +195,7 @@ class FormatCountCapture {
// A format string generally follows the POSIX syntax as used within the POSIX
// `printf` specification.
//
-// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.)
+// (See http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html.)
//
// In specific, the `FormatSpec` supports the following type specifiers:
// * `c` for characters
@@ -206,6 +214,11 @@ class FormatCountCapture {
// written to this point. The resulting value must be captured within an
// `absl::FormatCountCapture` type.
//
+// Implementation-defined behavior:
+// * A null pointer provided to "%s" or "%p" is output as "(nil)".
+// * A non-null pointer provided to "%p" is output in hex as if by %#x or
+// %#lx.
+//
// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned
// counterpart before formatting.
//
@@ -221,10 +234,10 @@ class FormatCountCapture {
// "%e", .01 -> "1.00000e-2"
// "%a", -3.0 -> "-0x1.8p+1"
// "%g", .01 -> "1e-2"
-// "%p", *int -> "0x7ffdeb6ad2a4"
+// "%p", (void*)&value -> "0x7ffdeb6ad2a4"
//
// int n = 0;
-// string s = absl::StrFormat(
+// std::string s = absl::StrFormat(
// "%s%d%n", "hello", 123, absl::FormatCountCapture(&n));
// EXPECT_EQ(8, n);
//
@@ -291,14 +304,14 @@ using ParsedFormat = str_format_internal::ExtendedParsedFormat<
//
// Example:
//
-// string s = absl::StrFormat(
+// std::string s = absl::StrFormat(
// "Welcome to %s, Number %d!", "The Village", 6);
// EXPECT_EQ("Welcome to The Village, Number 6!", s);
//
// 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) {
+ const Args&... args) {
return str_format_internal::FormatPack(
str_format_internal::UntypedFormatSpecImpl::Extract(format),
{str_format_internal::FormatArgImpl(args)...});
@@ -312,11 +325,12 @@ ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format,
//
// Example:
//
-// string orig("For example PI is approximately ");
+// std::string orig("For example PI is approximately ");
// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14);
template <typename... Args>
-std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format,
- const Args&... args) {
+std::string& StrAppendFormat(std::string* dst,
+ const FormatSpec<Args...>& format,
+ const Args&... args) {
return str_format_internal::AppendPack(
dst, str_format_internal::UntypedFormatSpecImpl::Extract(format),
{str_format_internal::FormatArgImpl(args)...});
@@ -435,7 +449,8 @@ class FormatRawSink {
// `absl::FormatRawSink` interface), using a format string and zero or more
// additional arguments.
//
-// By default, `string` and `std::ostream` are supported as destination objects.
+// By default, `std::string` and `std::ostream` are supported as destination
+// objects. If a `std::string` is used the formatted string is appended to it.
//
// `absl::Format()` is a generic version of `absl::StrFormat(), for custom
// sinks. The format string, like format strings for `StrFormat()`, is checked
@@ -484,9 +499,10 @@ using FormatArg = str_format_internal::FormatArgImpl;
//
// Example:
//
-// std::optional<string> FormatDynamic(const string& in_format,
-// const vector<string>& in_args) {
-// string out;
+// std::optional<std::string> FormatDynamic(
+// const std::string& in_format,
+// const vector<std::string>& in_args) {
+// std::string out;
// std::vector<absl::FormatArg> args;
// for (const auto& v : in_args) {
// // It is important that 'v' is a reference to the objects in in_args.
@@ -509,6 +525,7 @@ ABSL_MUST_USE_RESULT inline bool FormatUntyped(
str_format_internal::UntypedFormatSpecImpl::Extract(format), args);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_STRINGS_STR_FORMAT_H_
diff --git a/absl/strings/str_format_test.cc b/absl/strings/str_format_test.cc
index 77b8647f..bb0f58bf 100644
--- a/absl/strings/str_format_test.cc
+++ b/absl/strings/str_format_test.cc
@@ -10,11 +10,11 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
using str_format_internal::FormatArgImpl;
-class FormatEntryPointTest : public ::testing::Test { };
+using FormatEntryPointTest = ::testing::Test;
TEST_F(FormatEntryPointTest, Format) {
std::string sink;
@@ -31,8 +31,8 @@ TEST_F(FormatEntryPointTest, UntypedFormat) {
"",
"a",
"%80d",
-#if !defined(_MSC_VER) && !defined(__ANDROID__)
- // MSVC and Android don't support positional syntax.
+#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
+ // MSVC, NaCL and Android don't support positional syntax.
"complicated multipart %% %1$d format %1$0999d",
#endif // _MSC_VER
};
@@ -154,17 +154,20 @@ TEST_F(FormatEntryPointTest, Stream) {
"",
"a",
"%80d",
-#if !defined(_MSC_VER) && !defined(__ANDROID__)
- // MSVC doesn't support positional syntax.
+ "%d %u %c %s %f %g",
+#if !defined(_MSC_VER) && !defined(__ANDROID__) && !defined(__native_client__)
+ // MSVC, NaCL and Android don't support positional syntax.
"complicated multipart %% %1$d format %1$080d",
#endif // _MSC_VER
};
std::string buf(4096, '\0');
for (const auto& fmt : formats) {
- const auto parsed = ParsedFormat<'d'>::NewAllowIgnored(fmt);
+ const auto parsed =
+ ParsedFormat<'d', 'u', 'c', 's', 'f', 'g'>::NewAllowIgnored(fmt);
std::ostringstream oss;
- oss << StreamFormat(*parsed, 123);
- int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), 123);
+ oss << StreamFormat(*parsed, 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
+ int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), //
+ 123, 3, 49, "multistreaming!!!", 1.01, 1.01);
ASSERT_TRUE(oss) << fmt;
ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size())
<< fmt_result;
@@ -272,7 +275,7 @@ TEST_F(FormatEntryPointTest, FPrintFError) {
EXPECT_EQ(errno, EBADF);
}
-#if __GLIBC__
+#ifdef __GLIBC__
TEST_F(FormatEntryPointTest, FprintfTooLarge) {
std::FILE* f = std::fopen("/dev/null", "w");
int width = 2000000000;
@@ -342,7 +345,7 @@ TEST(StrFormat, BehavesAsDocumented) {
EXPECT_EQ(StrFormat("%c", int{'a'}), "a");
EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT
EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a");
- // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
+ // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++"
// Formats std::string, char*, string_view, and Cord.
EXPECT_EQ(StrFormat("%s", "C"), "C");
EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++");
@@ -459,7 +462,7 @@ std::string SummarizeParsedFormat(const ParsedFormatBase& pc) {
return out;
}
-class ParsedFormatTest : public testing::Test {};
+using ParsedFormatTest = ::testing::Test;
TEST_F(ParsedFormatTest, SimpleChecked) {
EXPECT_EQ("[ABC]{d:1$d}[DEF]",
@@ -601,28 +604,46 @@ TEST_F(ParsedFormatTest, RegressionMixPositional) {
EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o")));
}
+using FormatWrapperTest = ::testing::Test;
+
+// Plain wrapper for StrFormat.
+template <typename... Args>
+std::string WrappedFormat(const absl::FormatSpec<Args...>& format,
+ const Args&... args) {
+ return StrFormat(format, args...);
+}
+
+TEST_F(FormatWrapperTest, ConstexprStringFormat) {
+ EXPECT_EQ(WrappedFormat("%s there", "hello"), "hello there");
+}
+
+TEST_F(FormatWrapperTest, ParsedFormat) {
+ ParsedFormat<'s'> format("%s there");
+ EXPECT_EQ(WrappedFormat(format, "hello"), "hello there");
+}
+
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// Some codegen thunks that we can use to easily dump the generated assembly for
// different StrFormat calls.
-std::string CodegenAbslStrFormatInt(int i) { // NOLINT
+std::string CodegenAbslStrFormatInt(int i) { // NOLINT
return absl::StrFormat("%d", i);
}
std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
- int64_t i64) { // NOLINT
+ int64_t i64) { // NOLINT
return absl::StrFormat("%d %s %d", i, s, i64);
}
-void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
+void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
absl::StrAppendFormat(out, "%d", i);
}
void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
- const std::string& s,
- int64_t i64) { // NOLINT
+ const std::string& s,
+ int64_t i64) { // NOLINT
absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
}
diff --git a/absl/strings/str_join.h b/absl/strings/str_join.h
index dc476a22..c6c0c98a 100644
--- a/absl/strings/str_join.h
+++ b/absl/strings/str_join.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,13 +18,13 @@
// -----------------------------------------------------------------------------
//
// This header file contains functions for joining a range of elements and
-// returning the result as a string. StrJoin operations are specified by passing
-// a range, a separator string to use between the elements joined, and an
-// optional Formatter responsible for converting each argument in the range to a
-// string. If omitted, a default `AlphaNumFormatter()` is called on the elements
-// to be joined, using the same formatting that `absl::StrCat()` uses. This
-// package defines a number of default formatters, and you can define your own
-// implementations.
+// returning the result as a std::string. StrJoin operations are specified by
+// passing a range, a separator string to use between the elements joined, and
+// an optional Formatter responsible for converting each argument in the range
+// to a string. If omitted, a default `AlphaNumFormatter()` is called on the
+// elements to be joined, using the same formatting that `absl::StrCat()` uses.
+// This package defines a number of default formatters, and you can define your
+// own implementations.
//
// Ranges are specified by passing a container with `std::begin()` and
// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a
@@ -37,8 +37,8 @@
//
// Example:
//
-// std::vector<string> v = {"foo", "bar", "baz"};
-// string s = absl::StrJoin(v, "-");
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// See comments on the `absl::StrJoin()` function for more examples.
@@ -60,23 +60,23 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// Concept: Formatter
// -----------------------------------------------------------------------------
//
// A Formatter is a function object that is responsible for formatting its
-// argument as a string and appending it to a given output string. Formatters
-// may be implemented as function objects, lambdas, or normal functions. You may
-// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary
-// types.
+// argument as a string and appending it to a given output std::string.
+// Formatters may be implemented as function objects, lambdas, or normal
+// functions. You may provide your own Formatter to enable `absl::StrJoin()` to
+// work with arbitrary types.
//
// The following is an example of a custom Formatter that simply uses
-// `std::to_string()` to format an integer as a string.
+// `std::to_string()` to format an integer as a std::string.
//
// struct MyFormatter {
-// void operator()(string* out, int i) const {
+// void operator()(std::string* out, int i) const {
// out->append(std::to_string(i));
// }
// };
@@ -85,7 +85,7 @@ inline namespace lts_2018_12_18 {
// argument to `absl::StrJoin()`:
//
// std::vector<int> v = {1, 2, 3, 4};
-// string s = absl::StrJoin(v, "-", MyFormatter());
+// std::string s = absl::StrJoin(v, "-", MyFormatter());
// EXPECT_EQ("1-2-3-4", s);
//
// The following standard formatters are provided within this file:
@@ -157,7 +157,7 @@ DereferenceFormatter() {
// StrJoin()
// -----------------------------------------------------------------------------
//
-// Joins a range of elements and returns the result as a string.
+// Joins a range of elements and returns the result as a std::string.
// `absl::StrJoin()` takes a range, a separator string to use between the
// elements joined, and an optional Formatter responsible for converting each
// argument in the range to a string.
@@ -168,22 +168,22 @@ DereferenceFormatter() {
// Example 1:
// // Joins a collection of strings. This pattern also works with a collection
// // of `absl::string_view` or even `const char*`.
-// std::vector<string> v = {"foo", "bar", "baz"};
-// string s = absl::StrJoin(v, "-");
+// std::vector<std::string> v = {"foo", "bar", "baz"};
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// Example 2:
// // Joins the values in the given `std::initializer_list<>` specified using
// // brace initialization. This pattern also works with an initializer_list
// // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
-// string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
+// std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
// EXPECT_EQ("foo-bar-baz", s);
//
// Example 3:
// // Joins a collection of ints. This pattern also works with floats,
// // doubles, int64s -- any `StrCat()`-compatible type.
// std::vector<int> v = {1, 2, 3, -4};
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3--4", s);
//
// Example 4:
@@ -194,7 +194,7 @@ DereferenceFormatter() {
// // `std::vector<int*>`.
// int x = 1, y = 2, z = 3;
// std::vector<int*> v = {&x, &y, &z};
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3", s);
//
// Example 5:
@@ -203,65 +203,65 @@ DereferenceFormatter() {
// v.emplace_back(new int(1));
// v.emplace_back(new int(2));
// v.emplace_back(new int(3));
-// string s = absl::StrJoin(v, "-");
+// std::string s = absl::StrJoin(v, "-");
// EXPECT_EQ("1-2-3", s);
//
// Example 6:
// // Joins a `std::map`, with each key-value pair separated by an equals
// // sign. This pattern would also work with, say, a
// // `std::vector<std::pair<>>`.
-// std::map<string, int> m = {
+// std::map<std::string, int> m = {
// std::make_pair("a", 1),
// std::make_pair("b", 2),
// std::make_pair("c", 3)};
-// string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
+// std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
// EXPECT_EQ("a=1,b=2,c=3", s);
//
// Example 7:
// // These examples show how `absl::StrJoin()` handles a few common edge
// // cases:
-// std::vector<string> v_empty;
+// std::vector<std::string> v_empty;
// EXPECT_EQ("", absl::StrJoin(v_empty, "-"));
//
-// std::vector<string> v_one_item = {"foo"};
+// std::vector<std::string> v_one_item = {"foo"};
// EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-"));
//
-// std::vector<string> v_empty_string = {""};
+// std::vector<std::string> v_empty_string = {""};
// EXPECT_EQ("", absl::StrJoin(v_empty_string, "-"));
//
-// std::vector<string> v_one_item_empty_string = {"a", ""};
+// std::vector<std::string> v_one_item_empty_string = {"a", ""};
// EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-"));
//
-// std::vector<string> v_two_empty_string = {"", ""};
+// std::vector<std::string> v_two_empty_string = {"", ""};
// EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-"));
//
// Example 8:
// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
-// // a string using the `absl::AlphaNum` class.
-// string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
+// // a std::string using the `absl::AlphaNum` class.
+// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
// EXPECT_EQ("123-abc-0.456", s);
template <typename Iterator, typename Formatter>
std::string StrJoin(Iterator start, Iterator end, absl::string_view sep,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinAlgorithm(start, end, sep, fmt);
}
template <typename Range, typename Formatter>
std::string StrJoin(const Range& range, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinRange(range, separator, fmt);
}
template <typename T, typename Formatter>
std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinRange(il, separator, fmt);
}
template <typename... T, typename Formatter>
std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
- Formatter&& fmt) {
+ Formatter&& fmt) {
return strings_internal::JoinAlgorithm(value, separator, fmt);
}
@@ -276,16 +276,18 @@ std::string StrJoin(const Range& range, absl::string_view separator) {
}
template <typename T>
-std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) {
+std::string StrJoin(std::initializer_list<T> il,
+ absl::string_view separator) {
return strings_internal::JoinRange(il, separator);
}
template <typename... T>
-std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) {
+std::string StrJoin(const std::tuple<T...>& value,
+ absl::string_view separator) {
return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STR_JOIN_H_
diff --git a/absl/strings/str_join_benchmark.cc b/absl/strings/str_join_benchmark.cc
index 7fb0e497..d6f689ff 100644
--- a/absl/strings/str_join_benchmark.cc
+++ b/absl/strings/str_join_benchmark.cc
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -58,7 +58,8 @@ void BM_Join2_KeysAndValues(benchmark::State& state) {
const int string_len = state.range(0);
const int num_pairs = state.range(1);
const std::string s(string_len, 'x');
- const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42));
+ const std::vector<std::pair<std::string, int>> v(num_pairs,
+ std::make_pair(s, 42));
for (auto _ : state) {
std::string s = absl::StrJoin(v, ",", absl::PairFormatter("="));
benchmark::DoNotOptimize(s);
diff --git a/absl/strings/str_join_test.cc b/absl/strings/str_join_test.cc
index c941f9c8..921d9c2b 100644
--- a/absl/strings/str_join_test.cc
+++ b/absl/strings/str_join_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -118,7 +118,7 @@ TEST(StrJoin, APIExamples) {
{
// A std::map, which is a collection of std::pair<>s.
- std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} };
+ std::map<std::string, int> m = {{"a", 1}, {"b", 2}, {"c", 3}};
EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("=")));
}
@@ -140,7 +140,8 @@ TEST(StrJoin, APIExamples) {
}
{
- // A range of 1 element gives a std::string with that element but no separator.
+ // A range of 1 element gives a std::string with that element but no
+ // separator.
std::vector<std::string> v = {"foo"};
EXPECT_EQ("foo", absl::StrJoin(v, "-"));
}
@@ -173,9 +174,10 @@ TEST(StrJoin, APIExamples) {
TEST(StrJoin, CustomFormatter) {
std::vector<std::string> v{"One", "Two", "Three"};
{
- std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
- absl::StrAppend(out, "(", in, ")");
- });
+ std::string joined =
+ absl::StrJoin(v, "", [](std::string* out, const std::string& in) {
+ absl::StrAppend(out, "(", in, ")");
+ });
EXPECT_EQ("(One)(Two)(Three)", joined);
}
{
diff --git a/absl/strings/str_replace.cc b/absl/strings/str_replace.cc
index 72a0b584..3bd8bae1 100644
--- a/absl/strings/str_replace.cc
+++ b/absl/strings/str_replace.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "absl/strings/str_cat.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace strings_internal {
using FixedMapping =
@@ -69,13 +69,14 @@ int ApplySubstitutions(
// aren't inlined.
std::string StrReplaceAll(absl::string_view s,
- strings_internal::FixedMapping replacements) {
+ strings_internal::FixedMapping replacements) {
return StrReplaceAll<strings_internal::FixedMapping>(s, replacements);
}
-int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) {
+int StrReplaceAll(strings_internal::FixedMapping replacements,
+ std::string* target) {
return StrReplaceAll<strings_internal::FixedMapping>(replacements, target);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/str_replace.h b/absl/strings/str_replace.h
index a963f91e..cb995456 100644
--- a/absl/strings/str_replace.h
+++ b/absl/strings/str_replace.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -29,12 +29,12 @@
//
// Example:
//
-// string html_escaped = absl::StrReplaceAll(user_input, {
-// {"&", "&amp;"},
-// {"<", "&lt;"},
-// {">", "&gt;"},
-// {"\"", "&quot;"},
-// {"'", "&#39;"}});
+// std::string html_escaped = absl::StrReplaceAll(user_input, {
+// {"&", "&amp;"},
+// {"<", "&lt;"},
+// {">", "&gt;"},
+// {"\"", "&quot;"},
+// {"'", "&#39;"}});
#ifndef ABSL_STRINGS_STR_REPLACE_H_
#define ABSL_STRINGS_STR_REPLACE_H_
@@ -46,7 +46,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// StrReplaceAll()
//
@@ -59,10 +59,11 @@ inline namespace lts_2018_12_18 {
//
// Example:
//
-// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
-// {{"$count", absl::StrCat(5)},
-// {"$who", "Bob"},
-// {"#Noun", "Apples"}});
+// std::string s = absl::StrReplaceAll(
+// "$who bought $count #Noun. Thanks $who!",
+// {{"$count", absl::StrCat(5)},
+// {"$who", "Bob"},
+// {"#Noun", "Apples"}});
// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
ABSL_MUST_USE_RESULT std::string StrReplaceAll(
absl::string_view s,
@@ -79,20 +80,22 @@ ABSL_MUST_USE_RESULT std::string StrReplaceAll(
// replacements["$who"] = "Bob";
// replacements["$count"] = "5";
// replacements["#Noun"] = "Apples";
-// string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
-// replacements);
+// std::string s = absl::StrReplaceAll(
+// "$who bought $count #Noun. Thanks $who!",
+// replacements);
// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
//
// // A std::vector of std::pair elements can be more efficient.
-// std::vector<std::pair<const absl::string_view, string>> replacements;
+// std::vector<std::pair<const absl::string_view, std::string>> replacements;
// replacements.push_back({"&", "&amp;"});
// replacements.push_back({"<", "&lt;"});
// replacements.push_back({">", "&gt;"});
-// string s = absl::StrReplaceAll("if (ptr < &foo)",
+// std::string s = absl::StrReplaceAll("if (ptr < &foo)",
// replacements);
// EXPECT_EQ("if (ptr &lt; &amp;foo)", s);
template <typename StrToStrMapping>
-std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements);
+std::string StrReplaceAll(absl::string_view s,
+ const StrToStrMapping& replacements);
// Overload of `StrReplaceAll()` to replace character sequences within a given
// output string *in place* with replacements provided within an initializer
@@ -100,7 +103,7 @@ std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacemen
//
// Example:
//
-// string s = std::string("$who bought $count #Noun. Thanks $who!");
+// std::string s = std::string("$who bought $count #Noun. Thanks $who!");
// int count;
// count = absl::StrReplaceAll({{"$count", absl::StrCat(5)},
// {"$who", "Bob"},
@@ -118,7 +121,7 @@ int StrReplaceAll(
//
// Example:
//
-// string s = std::string("if (ptr < &foo)");
+// std::string s = std::string("if (ptr < &foo)");
// int count = absl::StrReplaceAll({{"&", "&amp;"},
// {"<", "&lt;"},
// {">", "&gt;"}}, &s);
@@ -188,7 +191,8 @@ int ApplySubstitutions(absl::string_view s,
} // namespace strings_internal
template <typename StrToStrMapping>
-std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) {
+std::string StrReplaceAll(absl::string_view s,
+ const StrToStrMapping& replacements) {
auto subs = strings_internal::FindSubstitutions(s, replacements);
std::string result;
result.reserve(s.size());
@@ -209,7 +213,7 @@ int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) {
return substitutions;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STR_REPLACE_H_
diff --git a/absl/strings/str_replace_benchmark.cc b/absl/strings/str_replace_benchmark.cc
index 8386f2e6..95b2dc10 100644
--- a/absl/strings/str_replace_benchmark.cc
+++ b/absl/strings/str_replace_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -54,7 +54,7 @@ void SetUpStrings() {
size_t r = 0;
big_string = new std::string(1000 * 1000, ' ');
for (std::string phrase : {"the quick brown fox jumped over the lazy dogs",
- "pack my box with the five dozen liquor jugs"}) {
+ "pack my box with the five dozen liquor jugs"}) {
for (int i = 0; i < 10 * 1000; ++i) {
r = r * 237 + 41; // not very random.
memcpy(&(*big_string)[r % (big_string->size() - phrase.size())],
@@ -108,11 +108,11 @@ void BM_StrReplaceAll(benchmark::State& state) {
std::string src = *big_string;
for (auto _ : state) {
std::string dest = absl::StrReplaceAll(src, {{"the", "box"},
- {"brown", "quick"},
- {"jumped", "liquored"},
- {"dozen", "brown"},
- {"lazy", "pack"},
- {"liquor", "shakes"}});
+ {"brown", "quick"},
+ {"jumped", "liquored"},
+ {"dozen", "brown"},
+ {"lazy", "pack"},
+ {"liquor", "shakes"}});
ABSL_RAW_CHECK(dest == *after_replacing_many,
"not benchmarking intended behavior");
}
diff --git a/absl/strings/str_replace_test.cc b/absl/strings/str_replace_test.cc
index 5d003a22..1ca23aff 100644
--- a/absl/strings/str_replace_test.cc
+++ b/absl/strings/str_replace_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -148,7 +148,7 @@ TEST(StrReplaceAll, ManyReplacementsInMap) {
replacements["$count"] = "5";
replacements["#Noun"] = "Apples";
std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!",
- replacements);
+ replacements);
EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s);
}
diff --git a/absl/strings/str_split.cc b/absl/strings/str_split.cc
index cd90425f..f1e03717 100644
--- a/absl/strings/str_split.cc
+++ b/absl/strings/str_split.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,7 +27,7 @@
#include "absl/strings/ascii.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -135,5 +135,5 @@ absl::string_view ByLength::Find(absl::string_view text,
return absl::string_view(substr.data() + length_, 0);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/str_split.h b/absl/strings/str_split.h
index 9483b30e..463ca008 100644
--- a/absl/strings/str_split.h
+++ b/absl/strings/str_split.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -49,7 +49,7 @@
#include "absl/strings/strip.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
//------------------------------------------------------------------------------
// Delimiters
@@ -72,23 +72,23 @@ inline namespace lts_2018_12_18 {
// - `ByLength`
// - `MaxSplits`
//
-//
-// A Delimiter's Find() member function will be passed the input text that is to
-// be split and the position to begin searching for the next delimiter in the
-// input text. The returned absl::string_view should refer to the next
-// occurrence (after pos) of the represented delimiter; this returned
-// absl::string_view represents the next location where the input string should
-// be broken. The returned absl::string_view may be zero-length if the Delimiter
-// does not represent a part of the string (e.g., a fixed-length delimiter). If
-// no delimiter is found in the given text, a zero-length absl::string_view
-// referring to text.end() should be returned (e.g.,
-// absl::string_view(text.end(), 0)). It is important that the returned
-// absl::string_view always be within the bounds of input text given as an
+// A Delimiter's `Find()` member function will be passed an input `text` that is
+// to be split and a position (`pos`) to begin searching for the next delimiter
+// in `text`. The returned absl::string_view should refer to the next occurrence
+// (after `pos`) of the represented delimiter; this returned absl::string_view
+// represents the next location where the input `text` should be broken.
+//
+// The returned absl::string_view may be zero-length if the Delimiter does not
+// represent a part of the string (e.g., a fixed-length delimiter). If no
+// delimiter is found in the input `text`, a zero-length absl::string_view
+// referring to `text.end()` should be returned (e.g.,
+// `text.substr(text.size())`). It is important that the returned
+// absl::string_view always be within the bounds of the input `text` given as an
// argument--it must not refer to a string that is physically located outside of
// the given string.
//
// The following example is a simple Delimiter object that is created with a
-// single char and will look for that char in the text passed to the Find()
+// single char and will look for that char in the text passed to the `Find()`
// function:
//
// struct SimpleDelimiter {
@@ -97,9 +97,9 @@ inline namespace lts_2018_12_18 {
// absl::string_view Find(absl::string_view text, size_t pos) {
// auto found = text.find(c_, pos);
// if (found == absl::string_view::npos)
-// return absl::string_view(text.end(), 0);
+// return text.substr(text.size());
//
-// return absl::string_view(text, found, 1);
+// return text.substr(found, 1);
// }
// };
@@ -132,8 +132,7 @@ class ByString {
// ByChar
//
// A single character delimiter. `ByChar` is functionally equivalent to a
-// 1-char string within a `ByString` delimiter, but slightly more
-// efficient.
+// 1-char string within a `ByString` delimiter, but slightly more efficient.
//
// Example:
//
@@ -414,10 +413,10 @@ struct SkipWhitespace {
//
// The `StrSplit()` function adapts the returned collection to the collection
// specified by the caller (e.g. `std::vector` above). The returned collections
-// may contain `string`, `absl::string_view` (in which case the original string
-// being split must ensure that it outlives the collection), or any object that
-// can be explicitly created from an `absl::string_view`. This behavior works
-// for:
+// may contain `std::string`, `absl::string_view` (in which case the original
+// string being split must ensure that it outlives the collection), or any
+// object that can be explicitly created from an `absl::string_view`. This
+// behavior works for:
//
// 1) All standard STL containers including `std::vector`, `std::list`,
// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
@@ -461,7 +460,7 @@ struct SkipWhitespace {
// Example:
//
// // Stores first two split strings as the members in a std::pair.
-// std::pair<string, string> p = absl::StrSplit("a,b,c", ',');
+// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
// // p.first == "a", p.second == "b" // "c" is omitted.
//
// The `StrSplit()` function can be used multiple times to perform more
@@ -471,7 +470,7 @@ struct SkipWhitespace {
//
// // The input string "a=b=c,d=e,f=,g" becomes
// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" }
-// std::map<string, string> m;
+// std::map<std::string, std::string> m;
// for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) {
// m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1)));
// }
@@ -508,7 +507,7 @@ StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
std::move(text), DelimiterType(d), std::move(p));
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STR_SPLIT_H_
diff --git a/absl/strings/str_split_benchmark.cc b/absl/strings/str_split_benchmark.cc
index 0ac297c8..f38dfcfe 100644
--- a/absl/strings/str_split_benchmark.cc
+++ b/absl/strings/str_split_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -44,6 +44,29 @@ void BM_Split2StringView(benchmark::State& state) {
}
BENCHMARK_RANGE(BM_Split2StringView, 0, 1 << 20);
+static const absl::string_view kDelimiters = ";:,.";
+
+std::string MakeMultiDelimiterTestString(int desired_length) {
+ static const int kAverageValueLen = 25;
+ std::string test(desired_length * kAverageValueLen, 'x');
+ for (int i = 0; i * kAverageValueLen < test.size(); ++i) {
+ // Cycle through a variety of delimiters.
+ test[i * kAverageValueLen] = kDelimiters[i % kDelimiters.size()];
+ }
+ return test;
+}
+
+// Measure StrSplit with ByAnyChar with four delimiters to choose from.
+void BM_Split2StringViewByAnyChar(benchmark::State& state) {
+ std::string test = MakeMultiDelimiterTestString(state.range(0));
+ for (auto _ : state) {
+ std::vector<absl::string_view> result =
+ absl::StrSplit(test, absl::ByAnyChar(kDelimiters));
+ benchmark::DoNotOptimize(result);
+ }
+}
+BENCHMARK_RANGE(BM_Split2StringViewByAnyChar, 0, 1 << 20);
+
void BM_Split2StringViewLifted(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
std::vector<absl::string_view> result;
@@ -69,7 +92,8 @@ BENCHMARK_RANGE(BM_Split2String, 0, 1 << 20);
void BM_Split2SplitStringUsing(benchmark::State& state) {
std::string test = MakeTestString(state.range(0));
for (auto _ : state) {
- std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty());
+ std::vector<std::string> result =
+ absl::StrSplit(test, ';', absl::SkipEmpty());
benchmark::DoNotOptimize(result);
}
}
diff --git a/absl/strings/str_split_test.cc b/absl/strings/str_split_test.cc
index caa88277..02f27bc4 100644
--- a/absl/strings/str_split_test.cc
+++ b/absl/strings/str_split_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -40,8 +40,8 @@ using ::testing::UnorderedElementsAre;
TEST(Split, TraitsTest) {
static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value,
"");
- static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value,
- "");
+ static_assert(
+ !absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, "");
static_assert(absl::strings_internal::SplitterIsConvertibleTo<
std::vector<std::string>>::value,
"");
@@ -71,8 +71,8 @@ TEST(Split, TraitsTest) {
// namespaces just like callers will need to use.
TEST(Split, APIExamples) {
{
- // Passes std::string delimiter. Assumes the default of Literal.
- std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
+ // Passes std::string delimiter. Assumes the default of ByString.
+ std::vector<std::string> v = absl::StrSplit("a,b,c", ","); // NOLINT
EXPECT_THAT(v, ElementsAre("a", "b", "c"));
// Equivalent to...
@@ -97,17 +97,6 @@ TEST(Split, APIExamples) {
}
{
- // Same as above, but using std::string
- std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
- EXPECT_THAT(v, ElementsAre("a", "b", "c"));
-
- // Equivalent to...
- using absl::ByChar;
- v = absl::StrSplit("a,b,c", ByChar(','));
- EXPECT_THAT(v, ElementsAre("a", "b", "c"));
- }
-
- {
// Uses the Literal std::string "=>" as the delimiter.
const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>");
EXPECT_THAT(v, ElementsAre("a", "b", "c"));
@@ -182,7 +171,8 @@ TEST(Split, APIExamples) {
{
// Uses the SkipWhitespace predicate.
using absl::SkipWhitespace;
- std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace());
+ std::vector<std::string> v =
+ absl::StrSplit(" a , ,,b,", ',', SkipWhitespace());
EXPECT_THAT(v, ElementsAre(" a ", "b"));
}
@@ -215,7 +205,8 @@ TEST(Split, APIExamples) {
{
// Results stored in a std::multimap.
- std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ',');
+ std::multimap<std::string, std::string> m =
+ absl::StrSplit("a,1,b,2,a,3", ',');
EXPECT_EQ(3, m.size());
auto it = m.find("a");
EXPECT_EQ("1", it->second);
@@ -271,7 +262,8 @@ TEST(SplitIterator, Basics) {
EXPECT_EQ("a", *it); // tests dereference
++it; // tests preincrement
EXPECT_NE(it, end);
- EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr
+ EXPECT_EQ("b",
+ std::string(it->data(), it->size())); // tests dereference as ptr
it++; // tests postincrement
EXPECT_EQ(it, end);
}
@@ -295,7 +287,8 @@ TEST(SplitIterator, Predicate) {
EXPECT_EQ("a", *it); // tests dereference
++it; // tests preincrement -- "b" should be skipped here.
EXPECT_NE(it, end);
- EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr
+ EXPECT_EQ("c",
+ std::string(it->data(), it->size())); // tests dereference as ptr
it++; // tests postincrement
EXPECT_EQ(it, end);
}
@@ -421,10 +414,13 @@ TEST(Splitter, ConversionOperator) {
TestMapConversionOperator<std::map<std::string, std::string>>(splitter);
TestMapConversionOperator<
std::multimap<absl::string_view, absl::string_view>>(splitter);
- TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter);
- TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter);
+ TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(
+ splitter);
+ TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(
+ splitter);
TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter);
- TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter);
+ TestMapConversionOperator<std::unordered_map<std::string, std::string>>(
+ splitter);
// Tests conversion to std::pair
@@ -568,10 +564,9 @@ TEST(Split, AcceptsCertainTemporaries) {
}
TEST(Split, Temporary) {
- // Use a std::string longer than the small-std::string-optimization length, so that when
- // the temporary is destroyed, if the splitter keeps a reference to the
- // std::string's contents, it'll reference freed memory instead of just dead
- // on-stack memory.
+ // Use a std::string longer than the SSO length, so that when the temporary is
+ // destroyed, if the splitter keeps a reference to the std::string's contents,
+ // it'll reference freed memory instead of just dead on-stack memory.
const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u";
EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input))
<< "Input should be larger than fits on the stack.";
@@ -647,6 +642,11 @@ TEST(Split, StringDelimiter) {
}
}
+#if !defined(__cpp_char8_t)
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++2a-compat"
+#endif
TEST(Split, UTF8) {
// Tests splitting utf8 strings and utf8 delimiters.
std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5";
@@ -673,6 +673,10 @@ TEST(Split, UTF8) {
EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere"));
}
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+#endif // !defined(__cpp_char8_t)
TEST(Split, EmptyStringDelimiter) {
{
@@ -782,7 +786,7 @@ static bool IsFoundAt(absl::string_view text, Delimiter d, int expected_pos) {
}
//
-// Tests for Literal
+// Tests for ByString
//
// Tests using any delimiter that represents a single comma.
@@ -802,7 +806,7 @@ void TestComma(Delimiter d) {
EXPECT_FALSE(IsFoundAt(";", d, -1));
}
-TEST(Delimiter, Literal) {
+TEST(Delimiter, ByString) {
using absl::ByString;
TestComma(ByString(","));
diff --git a/absl/strings/string_view.cc b/absl/strings/string_view.cc
index 3620ff44..9d241e51 100644
--- a/absl/strings/string_view.cc
+++ b/absl/strings/string_view.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "absl/strings/internal/memutil.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
void WritePadding(std::ostream& o, size_t pad) {
@@ -78,18 +78,6 @@ std::ostream& operator<<(std::ostream& o, string_view piece) {
return o;
}
-string_view::size_type string_view::copy(char* buf, size_type n,
- size_type pos) const {
- size_type ulen = length_;
- assert(pos <= ulen);
- size_type rlen = std::min(ulen - pos, n);
- if (rlen > 0) {
- const char* start = ptr_ + pos;
- std::copy(start, start + rlen, buf);
- }
- return rlen;
-}
-
string_view::size_type string_view::find(string_view s, size_type pos) const
noexcept {
if (empty() || pos > length_) {
@@ -229,7 +217,7 @@ string_view::size_type string_view::find_last_not_of(char c,
// member definitions that are required by the C++ standard, resulting in
// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks
// MSVC to choose only one definition for the symbol it decorates. See details
-// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
+// at https://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx
#ifdef _MSC_VER
#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany)
#else
@@ -241,7 +229,7 @@ constexpr string_view::size_type string_view::npos;
ABSL_STRING_VIEW_SELECTANY
constexpr string_view::size_type string_view::kMaxSize;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_STRING_VIEW
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index df6f1ae4..3a0a4609 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,12 +32,12 @@
#ifdef ABSL_HAVE_STD_STRING_VIEW
-#include <string_view>
+#include <string_view> // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::string_view;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_STRING_VIEW
@@ -52,10 +52,11 @@ using std::string_view;
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
+#include "absl/base/optimization.h"
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// absl::string_view
//
@@ -104,7 +105,6 @@ inline namespace lts_2018_12_18 {
// example, when splitting a string, `std::vector<absl::string_view>` is a
// natural data type for the output.
//
-//
// When constructed from a source which is nul-terminated, the `string_view`
// itself will not include the nul-terminator unless a specific size (including
// the nul) is passed to the constructor. As a result, common idioms that work
@@ -176,19 +176,9 @@ class string_view {
// Implicit constructor of a `string_view` from nul-terminated `str`. When
// accepting possibly null strings, use `absl::NullSafeStringView(str)`
// instead (see below).
-#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \
- (defined(__GNUC__) && !defined(__clang__))
- // GCC has __builtin_strlen according to
- // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but
- // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above.
- // __builtin_strlen is constexpr.
constexpr string_view(const char* str) // NOLINT(runtime/explicit)
: ptr_(str),
- length_(CheckLengthInternal(str ? __builtin_strlen(str) : 0)) {}
-#else
- constexpr string_view(const char* str) // NOLINT(runtime/explicit)
- : ptr_(str), length_(CheckLengthInternal(str ? strlen(str) : 0)) {}
-#endif
+ length_(str ? CheckLengthInternal(StrlenInternal(str)) : 0) {}
// Implicit constructor of a `string_view` from a `const char*` and length.
constexpr string_view(const char* data, size_type len)
@@ -280,7 +270,7 @@ class string_view {
// Checks if the `string_view` is empty (refers to no characters).
constexpr bool empty() const noexcept { return length_ == 0; }
- // std::string:view::operator[]
+ // string_view::operator[]
//
// Returns the ith element of an `string_view` using the array operator.
// Note that this operator does not perform any bounds checking.
@@ -348,7 +338,17 @@ class string_view {
//
// Copies the contents of the `string_view` at offset `pos` and length `n`
// into `buf`.
- size_type copy(char* buf, size_type n, size_type pos = 0) const;
+ size_type copy(char* buf, size_type n, size_type pos = 0) const {
+ if (ABSL_PREDICT_FALSE(pos > length_)) {
+ base_internal::ThrowStdOutOfRange("absl::string_view::copy");
+ }
+ size_type rlen = (std::min)(length_ - pos, n);
+ if (rlen > 0) {
+ const char* start = ptr_ + pos;
+ std::copy(start, start + rlen, buf);
+ }
+ return rlen;
+ }
// string_view::substr()
//
@@ -358,7 +358,7 @@ class string_view {
string_view substr(size_type pos, size_type n = npos) const {
if (ABSL_PREDICT_FALSE(pos > length_))
base_internal::ThrowStdOutOfRange("absl::string_view::substr");
- n = std::min(n, length_ - pos);
+ n = (std::min)(n, length_ - pos);
return string_view(ptr_ + pos, n);
}
@@ -371,7 +371,7 @@ class string_view {
// on the respective sizes of the two `string_view`s to determine which is
// smaller, equal, or greater.
int compare(string_view x) const noexcept {
- auto min_length = std::min(length_, x.length_);
+ auto min_length = (std::min)(length_, x.length_);
if (min_length > 0) {
int r = memcmp(ptr_, x.ptr_, min_length);
if (r < 0) return -1;
@@ -499,6 +499,24 @@ class string_view {
return ABSL_ASSERT(len <= kMaxSize), len;
}
+ static constexpr size_type StrlenInternal(const char* str) {
+#if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__)
+ // MSVC 2017+ can evaluate this at compile-time.
+ const char* begin = str;
+ while (*str != '\0') ++str;
+ return str - begin;
+#elif ABSL_HAVE_BUILTIN(__builtin_strlen) || \
+ (defined(__GNUC__) && !defined(__clang__))
+ // GCC has __builtin_strlen according to
+ // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html, but
+ // ABSL_HAVE_BUILTIN doesn't detect that, so we use the extra checks above.
+ // __builtin_strlen is constexpr.
+ return __builtin_strlen(str);
+#else
+ return str ? strlen(str) : 0;
+#endif
+ }
+
const char* ptr_;
size_type length_;
};
@@ -511,6 +529,7 @@ inline bool operator==(string_view x, string_view y) noexcept {
if (len != y.size()) {
return false;
}
+
return x.data() == y.data() || len <= 0 ||
memcmp(x.data(), y.data(), len) == 0;
}
@@ -520,7 +539,7 @@ inline bool operator!=(string_view x, string_view y) noexcept {
}
inline bool operator<(string_view x, string_view y) noexcept {
- auto min_size = std::min(x.size(), y.size());
+ auto min_size = (std::min)(x.size(), y.size());
const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size);
return (r < 0) || (r == 0 && x.size() < y.size());
}
@@ -538,13 +557,13 @@ inline bool operator>=(string_view x, string_view y) noexcept {
// IO Insertion Operator
std::ostream& operator<<(std::ostream& o, string_view piece);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_STRING_VIEW
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// ClippedSubstr()
//
@@ -552,7 +571,7 @@ inline namespace lts_2018_12_18 {
// Provided because std::string_view::substr throws if `pos > size()`
inline string_view ClippedSubstr(string_view s, size_t pos,
size_t n = string_view::npos) {
- pos = std::min(pos, static_cast<size_t>(s.size()));
+ pos = (std::min)(pos, static_cast<size_t>(s.size()));
return s.substr(pos, n);
}
@@ -565,7 +584,7 @@ inline string_view NullSafeStringView(const char* p) {
return p ? string_view(p) : string_view();
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STRING_VIEW_H_
diff --git a/absl/strings/string_view_benchmark.cc b/absl/strings/string_view_benchmark.cc
index f4420320..46909cb0 100644
--- a/absl/strings/string_view_benchmark.cc
+++ b/absl/strings/string_view_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/strings/string_view_test.cc b/absl/strings/string_view_test.cc
index ed34ed83..22d43536 100644
--- a/absl/strings/string_view_test.cc
+++ b/absl/strings/string_view_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -284,9 +284,10 @@ TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) {
}
#undef COMPARE
-// Sadly, our users often confuse string::npos with absl::string_view::npos;
-// So much so that we test here that they are the same. They need to
-// both be unsigned, and both be the maximum-valued integer of their type.
+// Sadly, our users often confuse std::string::npos with
+// absl::string_view::npos; So much so that we test here that they are the same.
+// They need to both be unsigned, and both be the maximum-valued integer of
+// their type.
template <typename T>
struct is_type {
@@ -368,6 +369,11 @@ TEST(StringViewTest, STL1) {
EXPECT_EQ(buf[1], c[1]);
EXPECT_EQ(buf[2], c[2]);
EXPECT_EQ(buf[3], a[3]);
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(a.copy(buf, 1, 27), std::out_of_range);
+#else
+ EXPECT_DEATH(a.copy(buf, 1, 27), "absl::string_view::copy");
+#endif
}
// Separated from STL1() because some compilers produce an overly
@@ -755,7 +761,6 @@ TEST(StringViewTest, Remove) {
std::string s1("123");
s1 += '\0';
s1 += "456";
- absl::string_view b(s1);
absl::string_view e;
std::string s2;
@@ -941,6 +946,11 @@ TEST(StringViewTest, ConstexprCompiles) {
#error GCC/clang should have constexpr string_view.
#endif
+// MSVC 2017+ should be able to construct a constexpr string_view from a cstr.
+#if defined(_MSC_VER) && _MSC_VER >= 1910
+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1
+#endif
+
#endif // ABSL_HAVE_STD_STRING_VIEW
#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR
@@ -995,8 +1005,8 @@ TEST(StringViewTest, ConstexprCompiles) {
TEST(StringViewTest, Noexcept) {
EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
const std::string&>::value));
- EXPECT_TRUE(
- (std::is_nothrow_constructible<absl::string_view, const std::string&>::value));
+ EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view,
+ const std::string&>::value));
EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value);
constexpr absl::string_view sp;
EXPECT_TRUE(noexcept(sp.begin()));
diff --git a/absl/strings/strip.h b/absl/strings/strip.h
index 059f57b7..8e2ae422 100644
--- a/absl/strings/strip.h
+++ b/absl/strings/strip.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,7 +30,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// ConsumePrefix()
//
@@ -85,7 +85,7 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix(
return str;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_STRIP_H_
diff --git a/absl/strings/strip_test.cc b/absl/strings/strip_test.cc
index 40c4c607..e4e00cb6 100644
--- a/absl/strings/strip_test.cc
+++ b/absl/strings/strip_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,9 +27,6 @@
namespace {
-using testing::ElementsAre;
-using testing::IsEmpty;
-
TEST(Strip, ConsumePrefixOneChar) {
absl::string_view input("abc");
EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
diff --git a/absl/strings/substitute.cc b/absl/strings/substitute.cc
index b70e70e8..6bc9641d 100644
--- a/absl/strings/substitute.cc
+++ b/absl/strings/substitute.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/strings/string_view.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace substitute_internal {
void SubstituteAndAppendArray(std::string* output, absl::string_view format,
@@ -168,5 +168,5 @@ Arg::Arg(Dec dec) {
}
} // namespace substitute_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/strings/substitute.h b/absl/strings/substitute.h
index 43d73ad7..3ba7f4d3 100644
--- a/absl/strings/substitute.h
+++ b/absl/strings/substitute.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -35,19 +35,21 @@
// and single digit positional ids to indicate which substitution arguments to
// use at that location within the format string.
//
+// A '$$' sequence in the format string causes a literal '$' character to be
+// output.
+//
// Example 1:
-// string s = Substitute("$1 purchased $0 $2. Thanks $1!",
-// 5, "Bob", "Apples");
-// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s);
+// std::string s = Substitute("$1 purchased $0 $2 for $$10. Thanks $1!",
+// 5, "Bob", "Apples");
+// EXPECT_EQ("Bob purchased 5 Apples for $10. Thanks Bob!", s);
//
// Example 2:
-// string s = "Hi. ";
+// std::string s = "Hi. ";
// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s);
//
-//
// Supported types:
-// * absl::string_view, string, const char* (null is equivalent to "")
+// * absl::string_view, std::string, const char* (null is equivalent to "")
// * int32_t, int64_t, uint32_t, uint64
// * float, double
// * bool (Printed as "true" or "false")
@@ -70,6 +72,8 @@
#include <cstring>
#include <string>
+#include <type_traits>
+#include <vector>
#include "absl/base/macros.h"
#include "absl/base/port.h"
@@ -82,7 +86,7 @@
#include "absl/strings/strip.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace substitute_internal {
// Arg
@@ -153,6 +157,17 @@ class Arg {
Arg(Hex hex); // NOLINT(runtime/explicit)
Arg(Dec dec); // NOLINT(runtime/explicit)
+ // vector<bool>::reference and const_reference require special help to
+ // convert to `AlphaNum` 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>
+ 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(const void* value); // NOLINT(runtime/explicit)
@@ -457,7 +472,7 @@ void SubstituteAndAppend(
// Example:
// template <typename... Args>
// void VarMsg(absl::string_view format, const Args&... args) {
-// string s = absl::Substitute(format, args...);
+// std::string s = absl::Substitute(format, args...);
ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) {
std::string result;
@@ -575,70 +590,70 @@ std::string Substitute(const char* format, const substitute_internal::Arg& a0)
"contains one of $1-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1)
+ const substitute_internal::Arg& a1)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3,
"There were 2 substitution arguments given, but "
"this format std::string is either missing its $0/$1, or "
"contains one of $2-$9");
std::string Substitute(const char* format, const substitute_internal::Arg& a0,
- const substitute_internal::Arg& a1,
- const substitute_internal::Arg& a2)
+ const substitute_internal::Arg& a1,
+ const substitute_internal::Arg& a2)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7,
"There were 3 substitution arguments given, but "
"this format std::string is either missing its $0/$1/$2, or "
"contains one of $3-$9");
std::string Substitute(const char* 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& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15,
"There were 4 substitution arguments given, but "
"this format std::string is either missing its $0-$3, or "
"contains one of $4-$9");
std::string Substitute(const char* 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& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31,
"There were 5 substitution arguments given, but "
"this format std::string is either missing its $0-$4, or "
"contains one of $5-$9");
std::string Substitute(const char* 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& a1,
+ const substitute_internal::Arg& a2,
+ const substitute_internal::Arg& a3,
+ const substitute_internal::Arg& a4,
+ const substitute_internal::Arg& a5)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63,
"There were 6 substitution arguments given, but "
"this format std::string is either missing its $0-$5, or "
"contains one of $6-$9");
std::string Substitute(const char* 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)
+ 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)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127,
"There were 7 substitution arguments given, but "
"this format std::string is either missing its $0-$6, or "
"contains one of $7-$9");
std::string Substitute(const char* 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,
- const substitute_internal::Arg& a7)
+ 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,
+ const substitute_internal::Arg& a7)
ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255,
"There were 8 substitution arguments given, but "
"this format std::string is either missing its $0-$7, or "
@@ -667,7 +682,7 @@ std::string Substitute(
"format std::string doesn't contain all of $0 through $9");
#endif // ABSL_BAD_CALL_IF
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_STRINGS_SUBSTITUTE_H_
diff --git a/absl/strings/substitute_test.cc b/absl/strings/substitute_test.cc
index 144df01e..e27abb17 100644
--- a/absl/strings/substitute_test.cc
+++ b/absl/strings/substitute_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,6 +15,7 @@
#include "absl/strings/substitute.h"
#include <cstdint>
+#include <vector>
#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
@@ -172,6 +173,17 @@ TEST(SubstituteTest, SubstituteAndAppend) {
EXPECT_EQ("a b c d e f g h i j", str);
}
+TEST(SubstituteTest, VectorBoolRef) {
+ std::vector<bool> v = {true, false};
+ const auto& cv = v;
+ EXPECT_EQ("true false true false",
+ absl::Substitute("$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]));
+
+ std::string str = "Logic be like: ";
+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", v[0], v[1], cv[0], cv[1]);
+ EXPECT_EQ("Logic be like: true false true false", str);
+}
+
#ifdef GTEST_HAS_DEATH_TEST
TEST(SubstituteDeathTest, SubstituteDeath) {
diff --git a/absl/synchronization/BUILD.bazel b/absl/synchronization/BUILD.bazel
index e63b1d16..fca8cb69 100644
--- a/absl/synchronization/BUILD.bazel
+++ b/absl/synchronization/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -34,6 +35,7 @@ cc_library(
"internal/graphcycles.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -69,9 +71,14 @@ cc_library(
"notification.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = select({
+ "//absl:windows": [],
+ "//conditions:default": ["-pthread"],
+ }) + ABSL_DEFAULT_LINKOPTS,
deps = [
":graphcycles_internal",
"//absl/base",
+ "//absl/base:atomic_hook",
"//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers",
@@ -88,9 +95,7 @@ cc_test(
size = "small",
srcs = ["barrier_test.cc"],
copts = ABSL_TEST_COPTS,
- tags = [
- "no_test_wasm",
- ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":synchronization",
"//absl/time",
@@ -103,9 +108,7 @@ cc_test(
size = "small",
srcs = ["blocking_counter_test.cc"],
copts = ABSL_TEST_COPTS,
- tags = [
- "no_test_wasm",
- ],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":synchronization",
"//absl/time",
@@ -118,6 +121,7 @@ cc_test(
size = "medium",
srcs = ["internal/graphcycles_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":graphcycles_internal",
"//absl/base",
@@ -130,6 +134,7 @@ cc_test(
name = "graphcycles_benchmark",
srcs = ["internal/graphcycles_benchmark.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"benchmark",
],
@@ -144,6 +149,7 @@ cc_library(
name = "thread_pool",
testonly = 1,
hdrs = ["internal/thread_pool.h"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
@@ -158,6 +164,7 @@ cc_test(
size = "large",
srcs = ["mutex_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
shard_count = 25,
deps = [
":synchronization",
@@ -174,7 +181,8 @@ cc_library(
name = "mutex_benchmark_common",
testonly = 1,
srcs = ["mutex_benchmark.cc"],
- copts = ABSL_DEFAULT_COPTS,
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/synchronization:__pkg__",
],
@@ -182,7 +190,6 @@ cc_library(
":synchronization",
":thread_pool",
"//absl/base",
- "//absl/base:base_internal",
"@com_github_google_benchmark//:benchmark_main",
],
alwayslink = 1,
@@ -192,6 +199,7 @@ cc_binary(
name = "mutex_benchmark",
testonly = 1,
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
":mutex_benchmark_common",
@@ -203,6 +211,7 @@ cc_test(
size = "small",
srcs = ["notification_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":synchronization",
"//absl/time",
@@ -215,6 +224,7 @@ cc_library(
testonly = 1,
srcs = ["internal/per_thread_sem_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":synchronization",
"//absl/base",
@@ -229,7 +239,7 @@ cc_test(
name = "per_thread_sem_test",
size = "medium",
copts = ABSL_TEST_COPTS,
- tags = ["no_test_wasm"],
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":per_thread_sem_test_common",
":synchronization",
@@ -246,10 +256,7 @@ cc_test(
"lifetime_test.cc",
],
copts = ABSL_TEST_COPTS,
- linkopts = select({
- "//absl:windows": [],
- "//conditions:default": ["-pthread"],
- }),
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_ios_x86_64"],
deps = [
":synchronization",
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index de0d7b7d..4b708823 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,142 +14,185 @@
# limitations under the License.
#
-list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS
- "barrier.h"
- "blocking_counter.h"
- "mutex.h"
- "notification.h"
+absl_cc_library(
+ NAME
+ graphcycles_internal
+ HDRS
+ "internal/graphcycles.h"
+ SRCS
+ "internal/graphcycles.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::base_internal
+ absl::core_headers
+ absl::malloc_internal
)
-
-list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS
- "internal/create_thread_identity.h"
- "internal/graphcycles.h"
- "internal/kernel_timeout.h"
- "internal/per_thread_sem.h"
- "internal/thread_pool.h"
- "internal/waiter.h"
-)
-
-
-
-# synchronization library
-list(APPEND SYNCHRONIZATION_SRC
- "barrier.cc"
- "blocking_counter.cc"
- "internal/create_thread_identity.cc"
- "internal/per_thread_sem.cc"
- "internal/waiter.cc"
- "internal/graphcycles.cc"
- "notification.cc"
- "mutex.cc"
-)
-
-set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
-
-absl_library(
- TARGET
- absl_synchronization
- SOURCES
- ${SYNCHRONIZATION_SRC}
- PUBLIC_LIBRARIES
- ${SYNCHRONIZATION_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
synchronization
+ HDRS
+ "barrier.h"
+ "blocking_counter.h"
+ "internal/create_thread_identity.h"
+ "internal/kernel_timeout.h"
+ "internal/mutex_nonprod.inc"
+ "internal/per_thread_sem.h"
+ "internal/waiter.h"
+ "mutex.h"
+ "notification.h"
+ SRCS
+ "barrier.cc"
+ "blocking_counter.cc"
+ "internal/create_thread_identity.cc"
+ "internal/per_thread_sem.cc"
+ "internal/waiter.cc"
+ "notification.cc"
+ "mutex.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::graphcycles_internal
+ absl::atomic_hook
+ absl::base
+ absl::base_internal
+ absl::config
+ absl::core_headers
+ absl::dynamic_annotations
+ absl::malloc_internal
+ absl::stacktrace
+ absl::symbolize
+ absl::time
+ Threads::Threads
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-
-# test barrier_test
-set(BARRIER_TEST_SRC "barrier_test.cc")
-set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
barrier_test
- SOURCES
- ${BARRIER_TEST_SRC}
- PUBLIC_LIBRARIES
- ${BARRIER_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "barrier_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test blocking_counter_test
-set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc")
-set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
blocking_counter_test
- SOURCES
- ${BLOCKING_COUNTER_TEST_SRC}
- PUBLIC_LIBRARIES
- ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "blocking_counter_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test graphcycles_test
-set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc")
-set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
graphcycles_test
- SOURCES
- ${GRAPHCYCLES_TEST_SRC}
- PUBLIC_LIBRARIES
- ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/graphcycles_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::graphcycles_internal
+ absl::base
+ absl::core_headers
+ gmock_main
)
+absl_cc_library(
+ NAME
+ thread_pool
+ HDRS
+ "internal/thread_pool.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::synchronization
+ absl::core_headers
+ TESTONLY
+)
-# test mutex_test
-set(MUTEX_TEST_SRC "mutex_test.cc")
-set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
mutex_test
- SOURCES
- ${MUTEX_TEST_SRC}
- PUBLIC_LIBRARIES
- ${MUTEX_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "mutex_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::thread_pool
+ absl::base
+ absl::core_headers
+ absl::memory
+ absl::time
+ gmock_main
)
-
-# test notification_test
-set(NOTIFICATION_TEST_SRC "notification_test.cc")
-set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
notification_test
- SOURCES
- ${NOTIFICATION_TEST_SRC}
- PUBLIC_LIBRARIES
- ${NOTIFICATION_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "notification_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::time
+ gmock_main
)
-
-# test per_thread_sem_test_common
-set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc")
-set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings)
-
-absl_test(
- TARGET
+absl_cc_library(
+ NAME
per_thread_sem_test_common
- SOURCES
- ${PER_THREAD_SEM_TEST_COMMON_SRC}
- PUBLIC_LIBRARIES
- ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES}
+ SRCS
+ "internal/per_thread_sem_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::base
+ absl::strings
+ absl::time
+ gmock
+ TESTONLY
)
+absl_cc_test(
+ NAME
+ per_thread_sem_test
+ SRCS
+ "internal/per_thread_sem_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::per_thread_sem_test_common
+ absl::synchronization
+ absl::base
+ absl::strings
+ absl::time
+ gmock_main
+)
-
-
-
-
-
+absl_cc_test(
+ NAME
+ lifetime_test
+ SRCS
+ "lifetime_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::synchronization
+ absl::base
+ absl::core_headers
+)
diff --git a/absl/synchronization/barrier.cc b/absl/synchronization/barrier.cc
index ee66c240..72089c52 100644
--- a/absl/synchronization/barrier.cc
+++ b/absl/synchronization/barrier.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Return whether int *arg is zero.
static bool IsZero(void *arg) {
@@ -48,5 +48,5 @@ bool Barrier::Block() {
return this->num_to_exit_ == 0;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/barrier.h b/absl/synchronization/barrier.h
index 77ac3602..53d5ca26 100644
--- a/absl/synchronization/barrier.h
+++ b/absl/synchronization/barrier.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Barrier
//
@@ -74,6 +74,6 @@ class Barrier {
int num_to_exit_ GUARDED_BY(lock_);
};
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_BARRIER_H_
diff --git a/absl/synchronization/barrier_test.cc b/absl/synchronization/barrier_test.cc
index d6cababd..bfc6cb18 100644
--- a/absl/synchronization/barrier_test.cc
+++ b/absl/synchronization/barrier_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/synchronization/blocking_counter.cc b/absl/synchronization/blocking_counter.cc
index 82d889a9..c6968973 100644
--- a/absl/synchronization/blocking_counter.cc
+++ b/absl/synchronization/blocking_counter.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Return whether int *arg is zero.
static bool IsZero(void *arg) {
@@ -53,5 +53,5 @@ void BlockingCounter::Wait() {
// after we return from this method.
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/blocking_counter.h b/absl/synchronization/blocking_counter.h
index 554e396c..5dab5a94 100644
--- a/absl/synchronization/blocking_counter.h
+++ b/absl/synchronization/blocking_counter.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// BlockingCounter
//
@@ -93,7 +93,7 @@ class BlockingCounter {
int num_waiting_ GUARDED_BY(lock_);
};
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_
diff --git a/absl/synchronization/blocking_counter_test.cc b/absl/synchronization/blocking_counter_test.cc
index b3b55dd7..62d98738 100644
--- a/absl/synchronization/blocking_counter_test.cc
+++ b/absl/synchronization/blocking_counter_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
void PauseAndDecreaseCounter(BlockingCounter* counter, int* done) {
@@ -64,5 +64,5 @@ TEST(BlockingCounterTest, BasicFunctionality) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/create_thread_identity.cc b/absl/synchronization/internal/create_thread_identity.cc
index f27f16da..65f6d8fc 100644
--- a/absl/synchronization/internal/create_thread_identity.cc
+++ b/absl/synchronization/internal/create_thread_identity.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,12 +27,13 @@
#include "absl/synchronization/internal/per_thread_sem.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// ThreadIdentity storage is persistent, we maintain a free-list of previously
// released ThreadIdentity objects.
-static base_internal::SpinLock freelist_lock(base_internal::kLinkerInitialized);
+static base_internal::SpinLock freelist_lock(
+ base_internal::kLinkerInitialized);
static base_internal::ThreadIdentity* thread_identity_freelist;
// A per-thread destructor for reclaiming associated ThreadIdentity objects.
@@ -68,6 +69,30 @@ static intptr_t RoundUp(intptr_t addr, intptr_t align) {
return (addr + align - 1) & ~(align - 1);
}
+static void ResetThreadIdentity(base_internal::ThreadIdentity* identity) {
+ base_internal::PerThreadSynch* pts = &identity->per_thread_synch;
+ pts->next = nullptr;
+ pts->skip = nullptr;
+ pts->may_skip = false;
+ pts->waitp = nullptr;
+ pts->suppress_fatal_errors = false;
+ pts->readers = 0;
+ pts->priority = 0;
+ pts->next_priority_read_cycles = 0;
+ pts->state.store(base_internal::PerThreadSynch::State::kAvailable,
+ std::memory_order_relaxed);
+ pts->maybe_unlocking = false;
+ pts->wake = false;
+ pts->cond_waiter = false;
+ pts->all_locks = nullptr;
+ identity->waiter_state = {};
+ identity->blocked_count_ptr = nullptr;
+ identity->ticker.store(0, std::memory_order_relaxed);
+ identity->wait_start.store(0, std::memory_order_relaxed);
+ identity->is_idle.store(false, std::memory_order_relaxed);
+ identity->next = nullptr;
+}
+
static base_internal::ThreadIdentity* NewThreadIdentity() {
base_internal::ThreadIdentity* identity = nullptr;
@@ -91,7 +116,7 @@ static base_internal::ThreadIdentity* NewThreadIdentity() {
RoundUp(reinterpret_cast<intptr_t>(allocation),
base_internal::PerThreadSynch::kAlignment));
}
- memset(identity, 0, sizeof(*identity));
+ ResetThreadIdentity(identity);
return identity;
}
@@ -108,7 +133,7 @@ base_internal::ThreadIdentity* CreateThreadIdentity() {
}
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/create_thread_identity.h b/absl/synchronization/internal/create_thread_identity.h
index 1132d516..d743cc3b 100644
--- a/absl/synchronization/internal/create_thread_identity.h
+++ b/absl/synchronization/internal/create_thread_identity.h
@@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -29,7 +29,7 @@
#include "absl/base/port.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// Allocates and attaches a ThreadIdentity object for the calling thread.
@@ -50,6 +50,7 @@ inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() {
}
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_
diff --git a/absl/synchronization/internal/graphcycles.cc b/absl/synchronization/internal/graphcycles.cc
index 139be0f5..f4fbeadd 100644
--- a/absl/synchronization/internal/graphcycles.cc
+++ b/absl/synchronization/internal/graphcycles.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -44,7 +44,7 @@
// Do not use STL. This module does not use standard memory allocation.
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
namespace {
@@ -691,7 +691,7 @@ int GraphCycles::GetStackTrace(GraphId id, void*** ptr) {
}
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
diff --git a/absl/synchronization/internal/graphcycles.h b/absl/synchronization/internal/graphcycles.h
index 6609ea06..208527c3 100644
--- a/absl/synchronization/internal/graphcycles.h
+++ b/absl/synchronization/internal/graphcycles.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -41,7 +41,7 @@
#include <cstdint>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// Opaque identifier for a graph node.
@@ -133,7 +133,7 @@ class GraphCycles {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif
diff --git a/absl/synchronization/internal/graphcycles_benchmark.cc b/absl/synchronization/internal/graphcycles_benchmark.cc
index a239c25c..54823e0b 100644
--- a/absl/synchronization/internal/graphcycles_benchmark.cc
+++ b/absl/synchronization/internal/graphcycles_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/synchronization/internal/graphcycles_test.cc b/absl/synchronization/internal/graphcycles_test.cc
index 4dc2bdc5..fca86219 100644
--- a/absl/synchronization/internal/graphcycles_test.cc
+++ b/absl/synchronization/internal/graphcycles_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/base/macros.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// We emulate a GraphCycles object with a node vector and an edge vector.
@@ -460,5 +460,5 @@ TEST_F(GraphCyclesTest, ManyEdges) {
}
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/kernel_timeout.h b/absl/synchronization/internal/kernel_timeout.h
index 34ae94ec..e0f01e06 100644
--- a/absl/synchronization/internal/kernel_timeout.h
+++ b/absl/synchronization/internal/kernel_timeout.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -34,7 +34,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
class Futex;
@@ -54,6 +54,7 @@ class KernelTimeout {
// We explicitly do not support other custom formats: timespec, int64_t nanos.
// Unify on this and absl::Time, please.
+
bool has_timeout() const { return ns_ != 0; }
private:
@@ -101,8 +102,8 @@ class KernelTimeout {
if (n < 0) n = 0;
struct timespec abstime;
- int64_t seconds = std::min(n / kNanosPerSecond,
- int64_t{(std::numeric_limits<time_t>::max)()});
+ int64_t seconds = (std::min)(n / kNanosPerSecond,
+ int64_t{(std::numeric_limits<time_t>::max)()});
abstime.tv_sec = static_cast<time_t>(seconds);
abstime.tv_nsec =
static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
@@ -148,6 +149,7 @@ class KernelTimeout {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
diff --git a/absl/synchronization/internal/mutex_nonprod.cc b/absl/synchronization/internal/mutex_nonprod.cc
index 4b0b8bcd..aa1ed83b 100644
--- a/absl/synchronization/internal/mutex_nonprod.cc
+++ b/absl/synchronization/internal/mutex_nonprod.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -31,7 +31,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
namespace {
@@ -316,5 +316,5 @@ bool Condition::Eval() const {
void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
index 0ae4c0ea..ac10879b 100644
--- a/absl/synchronization/internal/mutex_nonprod.inc
+++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -36,7 +36,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class Condition;
namespace synchronization_internal {
@@ -215,6 +215,9 @@ class SynchronizationStorage {
// stack) should use this constructor.
explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
+ constexpr explicit SynchronizationStorage(absl::ConstInitType)
+ : is_dynamic_(false), once_(), space_{{0}} {}
+
SynchronizationStorage(SynchronizationStorage&) = delete;
SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
@@ -254,5 +257,5 @@ class SynchronizationStorage {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/per_thread_sem.cc b/absl/synchronization/internal/per_thread_sem.cc
index 9de2d136..284a5df4 100644
--- a/absl/synchronization/internal/per_thread_sem.cc
+++ b/absl/synchronization/internal/per_thread_sem.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
#include "absl/synchronization/internal/waiter.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) {
@@ -59,7 +59,7 @@ void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) {
}
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
extern "C" {
@@ -91,6 +91,7 @@ ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait(
if (identity->blocked_count_ptr != nullptr) {
identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed);
}
+
identity->is_idle.store(false, std::memory_order_relaxed);
identity->wait_start.store(0, std::memory_order_relaxed);
return !timeout;
diff --git a/absl/synchronization/internal/per_thread_sem.h b/absl/synchronization/internal/per_thread_sem.h
index 6efd5951..5bb0978b 100644
--- a/absl/synchronization/internal/per_thread_sem.h
+++ b/absl/synchronization/internal/per_thread_sem.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -32,7 +32,7 @@
#include "absl/synchronization/internal/kernel_timeout.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class Mutex;
@@ -81,7 +81,7 @@ class PerThreadSem {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
@@ -106,4 +106,5 @@ bool absl::synchronization_internal::PerThreadSem::Wait(
absl::synchronization_internal::KernelTimeout t) {
return AbslInternalPerThreadSemWait(t);
}
+
#endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_
diff --git a/absl/synchronization/internal/per_thread_sem_test.cc b/absl/synchronization/internal/per_thread_sem_test.cc
index 18b2458b..93bc4244 100644
--- a/absl/synchronization/internal/per_thread_sem_test.cc
+++ b/absl/synchronization/internal/per_thread_sem_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,7 +33,7 @@
// primitives which might use PerThreadSem, most notably absl::Mutex.
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
class SimpleSemaphore {
@@ -115,10 +115,9 @@ class PerThreadSemTest : public testing::Test {
min_cycles = std::min(min_cycles, cycles);
total_cycles += cycles;
}
- std::string out =
- StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=",
- absl::SixDigits(static_cast<double>(total_cycles) /
- kNumIterations));
+ std::string out = StrCat(
+ msg, "min cycle count=", min_cycles, " avg cycle count=",
+ absl::SixDigits(static_cast<double>(total_cycles) / kNumIterations));
printf("%s\n", out.c_str());
partner_thread.join();
@@ -153,12 +152,16 @@ TEST_F(PerThreadSemTest, WithTimeout) {
}
TEST_F(PerThreadSemTest, Timeouts) {
- absl::Time timeout = absl::Now() + absl::Milliseconds(50);
+ const absl::Duration delay = absl::Milliseconds(50);
+ const absl::Time start = absl::Now();
+ EXPECT_FALSE(Wait(start + delay));
+ const absl::Duration elapsed = absl::Now() - start;
// Allow for a slight early return, to account for quality of implementation
// issues on various platforms.
const absl::Duration slop = absl::Microseconds(200);
- EXPECT_FALSE(Wait(timeout));
- EXPECT_LE(timeout, absl::Now() + slop);
+ EXPECT_LE(delay - slop, elapsed)
+ << "Wait returned " << delay - elapsed
+ << " early (with " << slop << " slop), start time was " << start;
absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100);
EXPECT_FALSE(Wait(negative_timeout));
@@ -173,5 +176,5 @@ TEST_F(PerThreadSemTest, Timeouts) {
} // namespace
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/thread_pool.h b/absl/synchronization/internal/thread_pool.h
index 66c7546b..8941be68 100644
--- a/absl/synchronization/internal/thread_pool.h
+++ b/absl/synchronization/internal/thread_pool.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,6 +16,7 @@
#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
#include <cassert>
+#include <cstddef>
#include <functional>
#include <queue>
#include <thread> // NOLINT(build/c++11)
@@ -25,7 +26,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// A simple ThreadPool implementation for tests.
@@ -43,7 +44,7 @@ class ThreadPool {
~ThreadPool() {
{
absl::MutexLock l(&mu_);
- for (int i = 0; i < threads_.size(); ++i) {
+ for (size_t i = 0; i < threads_.size(); i++) {
queue_.push(nullptr); // Shutdown signal.
}
}
@@ -86,7 +87,7 @@ class ThreadPool {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_
diff --git a/absl/synchronization/internal/waiter.cc b/absl/synchronization/internal/waiter.cc
index 76fdd861..17c6a506 100644
--- a/absl/synchronization/internal/waiter.cc
+++ b/absl/synchronization/internal/waiter.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -40,13 +40,16 @@
#include <atomic>
#include <cassert>
#include <cstdint>
+#include <new>
+#include <type_traits>
+
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/base/optimization.h"
#include "absl/synchronization/internal/kernel_timeout.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
static void MaybeBecomeIdle() {
@@ -82,6 +85,7 @@ static void MaybeBecomeIdle() {
#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
#endif
#endif
+
class Futex {
public:
static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
@@ -327,6 +331,43 @@ void Waiter::Poke() {
#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32
+class Waiter::WinHelper {
+ public:
+ static SRWLOCK *GetLock(Waiter *w) {
+ return reinterpret_cast<SRWLOCK *>(&w->mu_storage_);
+ }
+
+ static CONDITION_VARIABLE *GetCond(Waiter *w) {
+ return reinterpret_cast<CONDITION_VARIABLE *>(&w->cv_storage_);
+ }
+
+ static_assert(sizeof(SRWLOCK) == sizeof(Waiter::SRWLockStorage),
+ "SRWLockStorage does not have the same size as SRWLOCK");
+ static_assert(
+ alignof(SRWLOCK) == alignof(Waiter::SRWLockStorage),
+ "SRWLockStorage does not have the same alignment as SRWLOCK");
+
+ static_assert(sizeof(CONDITION_VARIABLE) ==
+ sizeof(Waiter::ConditionVariableStorage),
+ "ABSL_CONDITION_VARIABLE_STORAGE does not have the same size "
+ "as CONDITION_VARIABLE");
+ static_assert(alignof(CONDITION_VARIABLE) ==
+ alignof(Waiter::ConditionVariableStorage),
+ "ConditionVariableStorage does not have the same "
+ "alignment as CONDITION_VARIABLE");
+
+ // The SRWLOCK and CONDITION_VARIABLE types must be trivially constuctible
+ // and destructible because we never call their constructors or destructors.
+ static_assert(std::is_trivially_constructible<SRWLOCK>::value,
+ "The SRWLOCK type must be trivially constructible");
+ static_assert(std::is_trivially_constructible<CONDITION_VARIABLE>::value,
+ "The CONDITION_VARIABLE type must be trivially constructible");
+ static_assert(std::is_trivially_destructible<SRWLOCK>::value,
+ "The SRWLOCK type must be trivially destructible");
+ static_assert(std::is_trivially_destructible<CONDITION_VARIABLE>::value,
+ "The CONDITION_VARIABLE type must be trivially destructible");
+};
+
class LockHolder {
public:
explicit LockHolder(SRWLOCK* mu) : mu_(mu) {
@@ -345,14 +386,19 @@ class LockHolder {
};
void Waiter::Init() {
- InitializeSRWLock(&mu_);
- InitializeConditionVariable(&cv_);
+ auto *mu = ::new (static_cast<void *>(&mu_storage_)) SRWLOCK;
+ auto *cv = ::new (static_cast<void *>(&cv_storage_)) CONDITION_VARIABLE;
+ InitializeSRWLock(mu);
+ InitializeConditionVariable(cv);
waiter_count_.store(0, std::memory_order_relaxed);
wakeup_count_.store(0, std::memory_order_relaxed);
}
bool Waiter::Wait(KernelTimeout t) {
- LockHolder h(&mu_);
+ SRWLOCK *mu = WinHelper::GetLock(this);
+ CONDITION_VARIABLE *cv = WinHelper::GetCond(this);
+
+ LockHolder h(mu);
waiter_count_.fetch_add(1, std::memory_order_relaxed);
// Loop until we find a wakeup to consume or timeout.
@@ -370,8 +416,7 @@ bool Waiter::Wait(KernelTimeout t) {
}
// No wakeups available, time to wait.
- if (!SleepConditionVariableSRW(
- &cv_, &mu_, t.InMillisecondsFromNow(), 0)) {
+ if (!SleepConditionVariableSRW(cv, mu, t.InMillisecondsFromNow(), 0)) {
// GetLastError() returns a Win32 DWORD, but we assign to
// unsigned long to simplify the ABSL_RAW_LOG case below. The uniform
// initialization guarantees this is not a narrowing conversion.
@@ -398,11 +443,11 @@ void Waiter::Poke() {
return;
}
// Potentially a waker. Take the lock and check again.
- LockHolder h(&mu_);
+ LockHolder h(WinHelper::GetLock(this));
if (waiter_count_.load(std::memory_order_relaxed) == 0) {
return;
}
- WakeConditionVariable(&cv_);
+ WakeConditionVariable(WinHelper::GetCond(this));
}
#else
@@ -410,5 +455,5 @@ void Waiter::Poke() {
#endif
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/internal/waiter.h b/absl/synchronization/internal/waiter.h
index 2b737260..06032642 100644
--- a/absl/synchronization/internal/waiter.h
+++ b/absl/synchronization/internal/waiter.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,9 +18,7 @@
#include "absl/base/config.h"
-#ifdef _WIN32
-#include <windows.h>
-#else
+#ifndef _WIN32
#include <pthread.h>
#endif
@@ -53,7 +51,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace synchronization_internal {
// Waiter is an OS-specific semaphore.
@@ -124,8 +122,20 @@ class Waiter {
// primivitives. We are using SRWLOCK and CONDITION_VARIABLE
// because they don't require a destructor to release system
// resources.
- SRWLOCK mu_;
- CONDITION_VARIABLE cv_;
+ //
+ // However, we can't include Windows.h in our headers, so we use aligned
+ // storage buffers to define the storage.
+ using SRWLockStorage =
+ typename std::aligned_storage<sizeof(void*), alignof(void*)>::type;
+ using ConditionVariableStorage =
+ typename std::aligned_storage<sizeof(void*), alignof(void*)>::type;
+
+ // WinHelper - Used to define utilities for accessing the lock and
+ // condition variable storage once the types are complete.
+ class WinHelper;
+
+ SRWLockStorage mu_storage_;
+ ConditionVariableStorage cv_storage_;
std::atomic<int> waiter_count_;
std::atomic<int> wakeup_count_;
@@ -135,7 +145,7 @@ class Waiter {
};
} // namespace synchronization_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
index b7360c29..0279c8f8 100644
--- a/absl/synchronization/lifetime_test.cc
+++ b/absl/synchronization/lifetime_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,6 +17,7 @@
#include <type_traits>
#include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
@@ -95,6 +96,10 @@ void TestLocals() {
RunTests(&mutex, &condvar);
}
+// Normal kConstInit usage
+ABSL_CONST_INIT absl::Mutex const_init_mutex(absl::kConstInit);
+void TestConstInitGlobal() { RunTests(&const_init_mutex, nullptr); }
+
// Global variables during start and termination
//
// In a translation unit, static storage duration variables are initialized in
@@ -117,10 +122,53 @@ class OnDestruction {
Function fn_;
};
+// kConstInit
+// Test early usage. (Declaration comes first; definitions must appear after
+// the test runner.)
+extern absl::Mutex early_const_init_mutex;
+// (Normally I'd write this +[], to make the cast-to-function-pointer explicit,
+// but in some MSVC setups we support, lambdas provide conversion operators to
+// different flavors of function pointers, making this trick ambiguous.)
+OnConstruction test_early_const_init([] {
+ RunTests(&early_const_init_mutex, nullptr);
+});
+// This definition appears before test_early_const_init, but it should be
+// initialized first (due to constant initialization). Test that the object
+// actually works when constructed this way.
+ABSL_CONST_INIT absl::Mutex early_const_init_mutex(absl::kConstInit);
+
+// Furthermore, test that the const-init c'tor doesn't stomp over the state of
+// a Mutex. Really, this is a test that the platform under test correctly
+// supports C++11 constant initialization. (The constant-initialization
+// constructors of globals "happen at link time"; memory is pre-initialized,
+// before the constructors of either grab_lock or check_still_locked are run.)
+extern absl::Mutex const_init_sanity_mutex;
+OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS {
+ const_init_sanity_mutex.Lock();
+});
+ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
+OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS {
+ const_init_sanity_mutex.AssertHeld();
+ const_init_sanity_mutex.Unlock();
+});
+
+// Test shutdown usage. (Declarations come first; definitions must appear after
+// the test runner.)
+extern absl::Mutex late_const_init_mutex;
+// OnDestruction is being used here as a global variable, even though it has a
+// non-trivial destructor. This is against the style guide. We're violating
+// that rule here to check that the exception we allow for kConstInit is safe.
+// NOLINTNEXTLINE
+OnDestruction test_late_const_init([] {
+ RunTests(&late_const_init_mutex, nullptr);
+});
+ABSL_CONST_INIT absl::Mutex late_const_init_mutex(absl::kConstInit);
+
} // namespace
int main() {
TestLocals();
+ TestConstInitGlobal();
// Explicitly call exit(0) here, to make it clear that we intend for the
// above global object destructors to run.
std::exit(0);
diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc
index 9f8d6cd7..07f220f5 100644
--- a/absl/synchronization/mutex.cc
+++ b/absl/synchronization/mutex.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -71,7 +71,7 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); }
} // extern "C"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -119,6 +119,10 @@ ABSL_CONST_INIT absl::base_internal::AtomicHook<
} // namespace
+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
+ bool locking, bool trylock,
+ bool read_lock);
+
void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) {
submit_profile_data.Store(fn);
}
@@ -151,7 +155,7 @@ static int Delay(int32_t c, DelayMode mode) {
if (c < limit) {
c++; // spin
} else {
- ABSL_TSAN_MUTEX_PRE_DIVERT(0, 0);
+ ABSL_TSAN_MUTEX_PRE_DIVERT(nullptr, 0);
if (c == limit) { // yield once
AbslInternalMutexYield();
c++;
@@ -159,7 +163,7 @@ static int Delay(int32_t c, DelayMode mode) {
absl::SleepFor(absl::Microseconds(10));
c = 0;
}
- ABSL_TSAN_MUTEX_POST_DIVERT(0, 0);
+ ABSL_TSAN_MUTEX_POST_DIVERT(nullptr, 0);
}
return (c);
}
@@ -234,15 +238,14 @@ enum { // Mutex and CondVar events passed as "ev" to PostSynchEvent
SYNCH_EV_SIGNALALL,
};
-enum { // Event flags
- SYNCH_F_R = 0x01, // reader event
- SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held
- SYNCH_F_ACQ = 0x04, // event is an acquire
+enum { // Event flags
+ SYNCH_F_R = 0x01, // reader event
+ SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held
+ SYNCH_F_TRY = 0x04, // TryLock or ReaderTryLock
+ SYNCH_F_UNLOCK = 0x08, // Unlock or ReaderUnlock
SYNCH_F_LCK_W = SYNCH_F_LCK,
SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R,
- SYNCH_F_ACQ_W = SYNCH_F_ACQ,
- SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R,
};
} // anonymous namespace
@@ -251,21 +254,22 @@ static const struct {
int flags;
const char *msg;
} event_properties[] = {
- { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " },
- { 0, "TryLock failed " },
- { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " },
- { 0, "ReaderTryLock failed " },
- { SYNCH_F_ACQ_W, "Lock blocking " },
- { SYNCH_F_LCK_W, "Lock returning " },
- { SYNCH_F_ACQ_R, "ReaderLock blocking " },
- { SYNCH_F_LCK_R, "ReaderLock returning " },
- { SYNCH_F_LCK_W, "Unlock " },
- { SYNCH_F_LCK_R, "ReaderUnlock " },
- { 0, "Wait on " },
- { 0, "Wait unblocked " },
- { 0, "Signal on " },
- { 0, "SignalAll on " },
+ {SYNCH_F_LCK_W | SYNCH_F_TRY, "TryLock succeeded "},
+ {0, "TryLock failed "},
+ {SYNCH_F_LCK_R | SYNCH_F_TRY, "ReaderTryLock succeeded "},
+ {0, "ReaderTryLock failed "},
+ {0, "Lock blocking "},
+ {SYNCH_F_LCK_W, "Lock returning "},
+ {0, "ReaderLock blocking "},
+ {SYNCH_F_LCK_R, "ReaderLock returning "},
+ {SYNCH_F_LCK_W | SYNCH_F_UNLOCK, "Unlock "},
+ {SYNCH_F_LCK_R | SYNCH_F_UNLOCK, "ReaderUnlock "},
+ {0, "Wait on "},
+ {0, "Wait unblocked "},
+ {0, "Signal on "},
+ {0, "SignalAll on "},
};
+
static absl::base_internal::SpinLock synch_event_mu(
absl::base_internal::kLinkerInitialized);
// protects synch_event
@@ -415,9 +419,26 @@ static void PostSynchEvent(void *obj, int ev) {
ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj,
(e == nullptr ? "" : e->name), buffer);
}
- if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr &&
- e->invariant != nullptr) {
- (*e->invariant)(e->arg);
+ const int flags = event_properties[ev].flags;
+ if ((flags & SYNCH_F_LCK) != 0 && e != nullptr && e->invariant != nullptr) {
+ // Calling the invariant as is causes problems under ThreadSanitizer.
+ // We are currently inside of Mutex Lock/Unlock and are ignoring all
+ // memory accesses and synchronization. If the invariant transitively
+ // synchronizes something else and we ignore the synchronization, we will
+ // get false positive race reports later.
+ // Reuse EvalConditionAnnotated to properly call into user code.
+ struct local {
+ static bool pred(SynchEvent *ev) {
+ (*ev->invariant)(ev->arg);
+ return false;
+ }
+ };
+ Condition cond(&local::pred, e);
+ Mutex *mu = static_cast<Mutex *>(obj);
+ const bool locking = (flags & SYNCH_F_UNLOCK) == 0;
+ const bool trylock = (flags & SYNCH_F_TRY) != 0;
+ const bool read_lock = (flags & SYNCH_F_R) != 0;
+ EvalConditionAnnotated(&cond, mu, locking, trylock, read_lock);
}
UnrefSynchEvent(e);
}
@@ -881,11 +902,15 @@ static PerThreadSynch *Enqueue(PerThreadSynch *head,
// base_internal::CycleClock::Now() is 0.5%.
int policy;
struct sched_param param;
- pthread_getschedparam(pthread_self(), &policy, &param);
- s->priority = param.sched_priority;
- s->next_priority_read_cycles =
- now_cycles +
- static_cast<int64_t>(base_internal::CycleClock::Frequency());
+ const int err = pthread_getschedparam(pthread_self(), &policy, &param);
+ if (err != 0) {
+ ABSL_RAW_LOG(ERROR, "pthread_getschedparam failed: %d", err);
+ } else {
+ s->priority = param.sched_priority;
+ s->next_priority_read_cycles =
+ now_cycles +
+ static_cast<int64_t>(base_internal::CycleClock::Frequency());
+ }
}
if (s->priority > head->priority) { // s's priority is above head's
// try to put s in priority-fifo order, or failing that at the front.
@@ -1080,7 +1105,7 @@ void Mutex::TryRemove(PerThreadSynch *s) {
// if the wait extends past the absolute time specified, even if "s" is still
// on the mutex queue. In this case, remove "s" from the queue and return
// true, otherwise return false.
-void Mutex::Block(PerThreadSynch *s) {
+ABSL_XRAY_LOG_ARGS(1) void Mutex::Block(PerThreadSynch *s) {
while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) {
if (!DecrementSynchSem(this, s, s->waitp->timeout)) {
// After a timeout, we go into a spin loop until we remove ourselves
@@ -1553,7 +1578,7 @@ bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) {
ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how));
this->LockSlowLoop(&waitp, flags);
bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop
- cond.Eval();
+ EvalConditionAnnotated(&cond, this, true, false, how == kShared);
ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0);
return res;
}
@@ -1731,12 +1756,17 @@ void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) {
// Compute cond->Eval() and tell race detectors that we do it under mutex mu.
static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
- bool locking, Mutex::MuHow how) {
+ bool locking, bool trylock,
+ bool read_lock) {
// Delicate annotation dance.
// We are currently inside of read/write lock/unlock operation.
// All memory accesses are ignored inside of mutex operations + for unlock
// operation tsan considers that we've already released the mutex.
bool res = false;
+#ifdef THREAD_SANITIZER
+ const int flags = read_lock ? __tsan_mutex_read_lock : 0;
+ const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
+#endif
if (locking) {
// For lock we pretend that we have finished the operation,
// evaluate the predicate, then unlock the mutex and start locking it again
@@ -1744,24 +1774,26 @@ static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu,
// Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan
// will think the lock acquisition is recursive which will trigger
// deadlock detector.
- ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, tryflags, 0);
res = cond->Eval();
- ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
+ // There is no "try" version of Unlock, so use flags instead of tryflags.
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, tryflags);
} else {
// Similarly, for unlock we pretend that we have unlocked the mutex,
// lock the mutex, evaluate the predicate, and start unlocking it again
// to match the annotation at the end of outer unlock operation.
- ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how));
- ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0);
+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, flags);
+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, flags);
+ ABSL_TSAN_MUTEX_POST_LOCK(mu, flags, 0);
res = cond->Eval();
- ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how));
+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, flags);
}
// Prevent unused param warnings in non-TSAN builds.
static_cast<void>(mu);
- static_cast<void>(how);
+ static_cast<void>(trylock);
+ static_cast<void>(read_lock);
return res;
}
@@ -1807,7 +1839,8 @@ bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond,
v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) +
how->fast_add,
std::memory_order_acquire, std::memory_order_relaxed)) {
- if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) {
+ if (cond == nullptr ||
+ EvalConditionAnnotated(cond, this, true, false, how == kShared)) {
return true;
}
unlock = true;
@@ -1825,7 +1858,8 @@ bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond,
}
this->LockSlowLoop(&waitp, flags);
return waitp.cond != nullptr || // => cond known true from LockSlowLoop
- cond == nullptr || EvalConditionAnnotated(cond, this, true, how);
+ cond == nullptr ||
+ EvalConditionAnnotated(cond, this, true, false, how == kShared);
}
// RAW_CHECK_FMT() takes a condition, a printf-style format string, and
@@ -1842,7 +1876,7 @@ static void CheckForMutexCorruption(intptr_t v, const char* label) {
// Test for either of two situations that should not occur in v:
// kMuWriter and kMuReader
// kMuWrWait and !kMuWait
- const intptr_t w = v ^ kMuWait;
+ const uintptr_t w = v ^ kMuWait;
// By flipping that bit, we can now test for:
// kMuWriter and kMuReader in w
// kMuWrWait and kMuWait in w
@@ -1881,7 +1915,8 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
waitp->how->fast_add,
std::memory_order_acquire, std::memory_order_relaxed)) {
if (waitp->cond == nullptr ||
- EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ EvalConditionAnnotated(waitp->cond, this, true, false,
+ waitp->how == kShared)) {
break; // we timed out, or condition true, so return
}
this->UnlockSlow(waitp); // got lock but condition false
@@ -1924,7 +1959,8 @@ void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) {
std::memory_order_release,
std::memory_order_relaxed));
if (waitp->cond == nullptr ||
- EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) {
+ EvalConditionAnnotated(waitp->cond, this, true, false,
+ waitp->how == kShared)) {
break; // we timed out, or condition true, so return
}
this->UnlockSlow(waitp); // got lock but condition false
@@ -2552,7 +2588,7 @@ void CondVar::Wakeup(PerThreadSynch *w) {
}
void CondVar::Signal() {
- ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
intptr_t v;
int c = 0;
for (v = cv_.load(std::memory_order_relaxed); v != 0;
@@ -2581,17 +2617,17 @@ void CondVar::Signal() {
if ((v & kCvEvent) != 0) {
PostSynchEvent(this, SYNCH_EV_SIGNAL);
}
- ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
return;
} else {
c = Delay(c, GENTLE);
}
}
- ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
}
void CondVar::SignalAll () {
- ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_PRE_SIGNAL(nullptr, 0);
intptr_t v;
int c = 0;
for (v = cv_.load(std::memory_order_relaxed); v != 0;
@@ -2618,13 +2654,13 @@ void CondVar::SignalAll () {
if ((v & kCvEvent) != 0) {
PostSynchEvent(this, SYNCH_EV_SIGNALALL);
}
- ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
return;
} else {
c = Delay(c, GENTLE); // try again after a delay
}
}
- ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0);
+ ABSL_TSAN_MUTEX_POST_SIGNAL(nullptr, 0);
}
void ReleasableMutexLock::Release() {
@@ -2685,5 +2721,5 @@ bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) {
a->arg_ == b->arg_ && a->method_ == b->method_;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index ce97707f..d6890099 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -61,6 +61,7 @@
#include <cstdint>
#include <string>
+#include "absl/base/const_init.h"
#include "absl/base/internal/identity.h"
#include "absl/base/internal/low_level_alloc.h"
#include "absl/base/internal/thread_identity.h"
@@ -81,7 +82,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class Condition;
struct SynchWaitParams;
@@ -137,7 +138,27 @@ struct SynchWaitParams;
class LOCKABLE Mutex {
public:
+ // Creates a `Mutex` that is not held by anyone. This constructor is
+ // typically used for Mutexes allocated on the heap or the stack.
+ //
+ // To create `Mutex` instances with static storage duration
+ // (e.g. a namespace-scoped or global variable), see
+ // `Mutex::Mutex(absl::kConstInit)` below instead.
Mutex();
+
+ // Creates a mutex with static storage duration. A global variable
+ // constructed this way avoids the lifetime issues that can occur on program
+ // startup and shutdown. (See absl/base/const_init.h.)
+ //
+ // For Mutexes allocated on the heap and stack, instead use the default
+ // constructor, which can interact more fully with the thread sanitizer.
+ //
+ // Example usage:
+ // namespace foo {
+ // ABSL_CONST_INIT Mutex mu(absl::kConstInit);
+ // }
+ explicit constexpr Mutex(absl::ConstInitType);
+
~Mutex();
// Mutex::Lock()
@@ -880,11 +901,15 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
};
#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
+
#else
inline Mutex::Mutex() : mu_(0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
+inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
+
inline CondVar::CondVar() : cv_(0) {}
#endif
@@ -1015,7 +1040,7 @@ enum class OnDeadlockCycle {
// the manner chosen here.
void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// In some build configurations we pass --detect-odr-violations to the
@@ -1027,4 +1052,5 @@ void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
extern "C" {
void AbslInternalMutexYield();
} // extern "C"
+
#endif // ABSL_SYNCHRONIZATION_MUTEX_H_
diff --git a/absl/synchronization/mutex_benchmark.cc b/absl/synchronization/mutex_benchmark.cc
index 2652bb97..ab188001 100644
--- a/absl/synchronization/mutex_benchmark.cc
+++ b/absl/synchronization/mutex_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc
index b2820e20..9851ac19 100644
--- a/absl/synchronization/mutex_test.cc
+++ b/absl/synchronization/mutex_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -14,7 +14,7 @@
#include "absl/synchronization/mutex.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#endif
@@ -610,9 +610,9 @@ TEST_P(CondVarWaitDeadlock, Test) {
waiter2.reset(); // "join" waiter2
}
-INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
- ::testing::Range(0, 8),
- ::testing::PrintToStringParamName());
+INSTANTIATE_TEST_SUITE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock,
+ ::testing::Range(0, 8),
+ ::testing::PrintToStringParamName());
// --------------------------------------------------------
// Test for fix of bug in DequeueAllWakeable()
@@ -815,7 +815,12 @@ TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS {
// Test that we correctly handle the situation when a lock is
// held and then destroyed (w/o unlocking).
+#ifdef THREAD_SANITIZER
+// TSAN reports errors when locked Mutexes are destroyed.
+TEST(Mutex, DISABLED_LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+#else
TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS {
+#endif
for (int i = 0; i != 10; i++) {
// Create, lock and destroy 10 locks.
const int kNumLocks = 10;
@@ -1030,11 +1035,11 @@ TEST(Mutex, DeadlockDetector) {
class ScopedDisableBazelTestWarnings {
public:
ScopedDisableBazelTestWarnings() {
-#ifdef WIN32
+#ifdef _WIN32
char file[MAX_PATH];
- if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) {
+ if (GetEnvironmentVariableA(kVarName, file, sizeof(file)) < sizeof(file)) {
warnings_output_file_ = file;
- SetEnvironmentVariable(kVarName, nullptr);
+ SetEnvironmentVariableA(kVarName, nullptr);
}
#else
const char *file = getenv(kVarName);
@@ -1047,8 +1052,8 @@ class ScopedDisableBazelTestWarnings {
~ScopedDisableBazelTestWarnings() {
if (!warnings_output_file_.empty()) {
-#ifdef WIN32
- SetEnvironmentVariable(kVarName, warnings_output_file_.c_str());
+#ifdef _WIN32
+ SetEnvironmentVariableA(kVarName, warnings_output_file_.c_str());
#else
setenv(kVarName, warnings_output_file_.c_str(), 0);
#endif
@@ -1062,7 +1067,12 @@ class ScopedDisableBazelTestWarnings {
const char ScopedDisableBazelTestWarnings::kVarName[] =
"TEST_WARNINGS_OUTPUT_FILE";
+#ifdef THREAD_SANITIZER
+// This test intentionally creates deadlocks to test the deadlock detector.
+TEST(Mutex, DISABLED_DeadlockDetectorBazelWarning) {
+#else
TEST(Mutex, DeadlockDetectorBazelWarning) {
+#endif
absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport);
// Cause deadlock detection to detect something, if it's
@@ -1109,7 +1119,12 @@ TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS {
}
}
+#ifdef THREAD_SANITIZER
+// TSAN reports errors when locked Mutexes are destroyed.
+TEST(Mutex, DISABLED_DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+#else
TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS {
+#endif
// Test a scenario where a cached deadlock graph node id in the
// list of held locks is not invalidated when the corresponding
// mutex is deleted.
@@ -1367,8 +1382,8 @@ std::vector<TimeoutTestParam> MakeTimeoutTestParamValues() {
}
// Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`.
-INSTANTIATE_TEST_CASE_P(All, TimeoutTest,
- testing::ValuesIn(MakeTimeoutTestParamValues()));
+INSTANTIATE_TEST_SUITE_P(All, TimeoutTest,
+ testing::ValuesIn(MakeTimeoutTestParamValues()));
TEST_P(TimeoutTest, Await) {
const TimeoutTestParam params = GetParam();
@@ -1548,9 +1563,9 @@ static std::vector<int> AllThreadCountValues() {
class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {};
// Instantiate the above with AllThreadCountOptions().
-INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest,
- ::testing::ValuesIn(AllThreadCountValues()),
- ::testing::PrintToStringParamName());
+INSTANTIATE_TEST_SUITE_P(ThreadCounts, MutexVariableThreadCountTest,
+ ::testing::ValuesIn(AllThreadCountValues()),
+ ::testing::PrintToStringParamName());
// Reduces iterations by some factor for slow platforms
// (determined empirically).
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index 472b7a3e..d691cfca 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
void Notification::Notify() {
MutexLock l(&this->mutex_);
@@ -83,5 +83,5 @@ bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const {
return notified;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 25821b18..8ed7f12a 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -57,7 +57,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// Notification
@@ -110,6 +110,7 @@ class Notification {
std::atomic<bool> notified_yet_; // written under mutex_
};
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
+
#endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_
diff --git a/absl/synchronization/notification_test.cc b/absl/synchronization/notification_test.cc
index d1b66743..a64674ca 100644
--- a/absl/synchronization/notification_test.cc
+++ b/absl/synchronization/notification_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,7 @@
#include "absl/synchronization/mutex.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// A thread-safe class that holds a counter.
class ThreadSafeCounter {
@@ -73,12 +73,16 @@ static void BasicTests(bool notify_before_waiting, Notification* notification) {
EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now()));
const absl::Duration delay = absl::Milliseconds(50);
+ const absl::Time start = absl::Now();
+ EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
+ const absl::Duration elapsed = absl::Now() - start;
+
// Allow for a slight early return, to account for quality of implementation
// issues on various platforms.
const absl::Duration slop = absl::Microseconds(200);
- absl::Time start = absl::Now();
- EXPECT_FALSE(notification->WaitForNotificationWithTimeout(delay));
- EXPECT_LE(start + delay, absl::Now() + slop);
+ EXPECT_LE(delay - slop, elapsed)
+ << "WaitForNotificationWithTimeout returned " << delay - elapsed
+ << " early (with " << slop << " slop), start time was " << start;
ThreadSafeCounter ready_counter;
ThreadSafeCounter done_counter;
@@ -125,5 +129,5 @@ TEST(NotificationTest, SanityTest) {
BasicTests(true, &local_notification2);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index 4d9c01c4..55e83a8c 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,8 +15,9 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -41,6 +42,7 @@ cc_library(
"time.h",
],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base",
"//absl/base:core_headers",
@@ -60,6 +62,7 @@ cc_library(
],
hdrs = ["internal/test_util.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl/time:__pkg__",
],
@@ -82,6 +85,7 @@ cc_test(
"time_zone_test.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":test_util",
":time",
@@ -103,6 +107,7 @@ cc_test(
"time_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"benchmark",
],
@@ -110,6 +115,7 @@ cc_test(
":test_util",
":time",
"//absl/base",
+ "//absl/base:core_headers",
"//absl/hash",
"@com_github_google_benchmark//:benchmark_main",
],
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index 53216cda..59098321 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,85 +14,114 @@
# limitations under the License.
#
-list(APPEND TIME_PUBLIC_HEADERS
- "civil_time.h"
- "clock.h"
- "time.h"
-)
-
-
-list(APPEND TIME_INTERNAL_HEADERS
- "internal/test_util.h"
- "internal/cctz/include/cctz/civil_time.h"
- "internal/cctz/include/cctz/civil_time_detail.h"
- "internal/cctz/include/cctz/time_zone.h"
- "internal/cctz/include/cctz/zone_info_source.h"
-)
-
-list(APPEND TIME_SRC
+absl_cc_library(
+ NAME
+ time
+ HDRS
+ "civil_time.h"
+ "clock.h"
+ "time.h"
+ SRCS
"civil_time.cc"
- "time.cc"
"clock.cc"
"duration.cc"
"format.cc"
- "internal/cctz/src/civil_time_detail.cc"
- "internal/cctz/src/time_zone_fixed.cc"
- "internal/cctz/src/time_zone_fixed.h"
- "internal/cctz/src/time_zone_format.cc"
- "internal/cctz/src/time_zone_if.cc"
- "internal/cctz/src/time_zone_if.h"
- "internal/cctz/src/time_zone_impl.cc"
- "internal/cctz/src/time_zone_impl.h"
- "internal/cctz/src/time_zone_info.cc"
- "internal/cctz/src/time_zone_info.h"
- "internal/cctz/src/time_zone_libc.cc"
- "internal/cctz/src/time_zone_libc.h"
- "internal/cctz/src/time_zone_lookup.cc"
- "internal/cctz/src/time_zone_posix.cc"
- "internal/cctz/src/time_zone_posix.h"
- "internal/cctz/src/tzfile.h"
- "internal/cctz/src/zone_info_source.cc"
- ${TIME_PUBLIC_HEADERS}
- ${TIME_INTERNAL_HEADERS}
+ "internal/get_current_time_chrono.inc"
+ "internal/get_current_time_posix.inc"
+ "time.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base
+ absl::core_headers
+ absl::int128
+ absl::strings
+ absl::civil_time
+ absl::time_zone
+ PUBLIC
)
-set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings)
-absl_library(
- TARGET
- absl_time
- SOURCES
- ${TIME_SRC}
- PUBLIC_LIBRARIES
- ${TIME_PUBLIC_LIBRARIES}
- EXPORT_NAME
- time
+absl_cc_library(
+ NAME
+ civil_time
+ HDRS
+ "internal/cctz/include/cctz/civil_time.h"
+ "internal/cctz/include/cctz/civil_time_detail.h"
+ SRCS
+ "internal/cctz/src/civil_time_detail.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
)
+if(APPLE)
+ find_library(CoreFoundation CoreFoundation)
+endif()
+absl_cc_library(
+ NAME
+ time_zone
+ HDRS
+ "internal/cctz/include/cctz/time_zone.h"
+ "internal/cctz/include/cctz/zone_info_source.h"
+ SRCS
+ "internal/cctz/src/time_zone_fixed.cc"
+ "internal/cctz/src/time_zone_fixed.h"
+ "internal/cctz/src/time_zone_format.cc"
+ "internal/cctz/src/time_zone_if.cc"
+ "internal/cctz/src/time_zone_if.h"
+ "internal/cctz/src/time_zone_impl.cc"
+ "internal/cctz/src/time_zone_impl.h"
+ "internal/cctz/src/time_zone_info.cc"
+ "internal/cctz/src/time_zone_info.h"
+ "internal/cctz/src/time_zone_libc.cc"
+ "internal/cctz/src/time_zone_libc.h"
+ "internal/cctz/src/time_zone_lookup.cc"
+ "internal/cctz/src/time_zone_posix.cc"
+ "internal/cctz/src/time_zone_posix.h"
+ "internal/cctz/src/tzfile.h"
+ "internal/cctz/src/zone_info_source.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ $<$<PLATFORM_ID:Darwin>:${CoreFoundation}>
+)
-#
-## TESTS
-#
-
-# test time_test
-list(APPEND TIME_TEST_SRC
- "civil_time_test.cc"
- "time_test.cc"
- "clock_test.cc"
- "duration_test.cc"
- "format_test.cc"
- "time_test.cc"
- "time_zone_test.cc"
- "internal/test_util.cc"
+absl_cc_library(
+ NAME
+ test_util
+ HDRS
+ "internal/test_util.h"
+ SRCS
+ "internal/test_util.cc"
+ "internal/zoneinfo.inc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::time
+ absl::base
+ absl::time_zone
+ gmock
+ TESTONLY
)
-set(TIME_TEST_PUBLIC_LIBRARIES absl::time)
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
time_test
- SOURCES
- ${TIME_TEST_SRC}
- PUBLIC_LIBRARIES
- ${TIME_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "civil_time_test.cc"
+ "clock_test.cc"
+ "duration_test.cc"
+ "format_test.cc"
+ "time_test.cc"
+ "time_zone_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::test_util
+ absl::time
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::time_zone
+ gmock_main
)
-
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc
index c6fa5469..bf7ba5ab 100644
--- a/absl/time/civil_time.cc
+++ b/absl/time/civil_time.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -39,7 +39,8 @@ std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
cs.hour(), cs.minute(), cs.second());
const TimeZone utc = UTCTimeZone();
// TODO(absl-team): Avoid conversion of fmt std::string.
- return StrCat(cs.year(), FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
+ return StrCat(cs.year(),
+ FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
}
} // namespace
@@ -53,15 +54,9 @@ std::string FormatCivilTime(CivilMinute c) {
std::string FormatCivilTime(CivilHour c) {
return FormatYearAnd("-%m-%dT%H", c);
}
-std::string FormatCivilTime(CivilDay c) {
- return FormatYearAnd("-%m-%d", c);
-}
-std::string FormatCivilTime(CivilMonth c) {
- return FormatYearAnd("-%m", c);
-}
-std::string FormatCivilTime(CivilYear c) {
- return FormatYearAnd("", c);
-}
+std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
+std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
+std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
namespace time_internal {
@@ -86,5 +81,5 @@ std::ostream& operator<<(std::ostream& os, CivilSecond s) {
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/civil_time.h b/absl/time/civil_time.h
index f6cc3ff8..f0be303c 100644
--- a/absl/time/civil_time.h
+++ b/absl/time/civil_time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -66,7 +66,6 @@
//
// // Valid in C++14
// constexpr absl::CivilDay cd(1969, 07, 20);
-//
#ifndef ABSL_TIME_CIVIL_TIME_H_
#define ABSL_TIME_CIVIL_TIME_H_
@@ -77,7 +76,7 @@
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
struct second_tag : cctz::detail::second_tag {};
@@ -372,15 +371,15 @@ using Weekday = time_internal::cctz::weekday;
// GetWeekday()
//
-// Returns the absl::Weekday for the given absl::CivilDay.
+// Returns the absl::Weekday for the given (realigned) civil-time value.
//
// Example:
//
// absl::CivilDay a(2015, 8, 13);
// absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday
//
-inline Weekday GetWeekday(CivilDay cd) {
- return time_internal::cctz::get_weekday(cd);
+inline Weekday GetWeekday(CivilSecond cs) {
+ return time_internal::cctz::get_weekday(cs);
}
// NextWeekday()
@@ -409,9 +408,9 @@ inline Weekday GetWeekday(CivilDay cd) {
//
// absl::CivilDay d = ...
// // Gets the following Thursday if d is not already Thursday
-// absl::CivilDay thurs1 = absl::PrevWeekday(d, absl::Weekday::thursday) + 7;
+// absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday);
// // Gets the previous Thursday if d is not already Thursday
-// absl::CivilDay thurs2 = absl::NextWeekday(d, absl::Weekday::thursday) - 7;
+// absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday);
//
inline CivilDay NextWeekday(CivilDay cd, Weekday wd) {
return CivilDay(time_internal::cctz::next_weekday(cd, wd));
@@ -422,7 +421,7 @@ inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) {
// GetYearDay()
//
-// Returns the day-of-year for the given absl::CivilDay.
+// Returns the day-of-year for the given (realigned) civil-time value.
//
// Example:
//
@@ -431,8 +430,8 @@ inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) {
// absl::CivilDay b(2015, 12, 31);
// int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365
//
-inline int GetYearDay(CivilDay cd) {
- return time_internal::cctz::get_yearday(cd);
+inline int GetYearDay(CivilSecond cs) {
+ return time_internal::cctz::get_yearday(cs);
}
// FormatCivilTime()
@@ -452,7 +451,7 @@ inline int GetYearDay(CivilDay cd) {
// Example:
//
// absl::CivilDay d = absl::CivilDay(1969, 7, 20);
-// string day_string = absl::FormatCivilTime(d); // "1969-07-20"
+// std::string day_string = absl::FormatCivilTime(d); // "1969-07-20"
//
std::string FormatCivilTime(CivilSecond c);
std::string FormatCivilTime(CivilMinute c);
@@ -482,7 +481,7 @@ std::ostream& operator<<(std::ostream& os, CivilSecond s);
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_CIVIL_TIME_H_
diff --git a/absl/time/civil_time_benchmark.cc b/absl/time/civil_time_benchmark.cc
index f30f636d..40869835 100644
--- a/absl/time/civil_time_benchmark.cc
+++ b/absl/time/civil_time_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
index dc83d7a9..03cd1f12 100644
--- a/absl/time/civil_time_test.cc
+++ b/absl/time/civil_time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -616,6 +616,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, ss.hour());
EXPECT_EQ(5, ss.minute());
EXPECT_EQ(6, ss.second());
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(ss));
+ EXPECT_EQ(34, absl::GetYearDay(ss));
absl::CivilMinute mm(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, mm.year());
@@ -624,6 +626,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, mm.hour());
EXPECT_EQ(5, mm.minute());
EXPECT_EQ(0, mm.second());
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(mm));
+ EXPECT_EQ(34, absl::GetYearDay(mm));
absl::CivilHour hh(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, hh.year());
@@ -632,6 +636,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, hh.hour());
EXPECT_EQ(0, hh.minute());
EXPECT_EQ(0, hh.second());
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(hh));
+ EXPECT_EQ(34, absl::GetYearDay(hh));
absl::CivilDay d(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, d.year());
@@ -640,6 +646,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, d.hour());
EXPECT_EQ(0, d.minute());
EXPECT_EQ(0, d.second());
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(d));
+ EXPECT_EQ(34, absl::GetYearDay(d));
absl::CivilMonth m(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, m.year());
@@ -648,6 +656,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, m.hour());
EXPECT_EQ(0, m.minute());
EXPECT_EQ(0, m.second());
+ EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(m));
+ EXPECT_EQ(32, absl::GetYearDay(m));
absl::CivilYear y(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, y.year());
@@ -656,6 +666,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, y.hour());
EXPECT_EQ(0, y.minute());
EXPECT_EQ(0, y.second());
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(y));
+ EXPECT_EQ(1, absl::GetYearDay(y));
}
TEST(CivilTime, Format) {
@@ -1028,7 +1040,7 @@ TEST(CivilTime, LeapYears) {
TEST(CivilTime, FirstThursdayInMonth) {
const absl::CivilDay nov1(2014, 11, 1);
const absl::CivilDay thursday =
- absl::PrevWeekday(nov1, absl::Weekday::thursday) + 7;
+ absl::NextWeekday(nov1 - 1, absl::Weekday::thursday);
EXPECT_EQ("2014-11-06", absl::FormatCivilTime(thursday));
// Bonus: Date of Thanksgiving in the United States
diff --git a/absl/time/clock.cc b/absl/time/clock.cc
index 2915d78b..48dc4450 100644
--- a/absl/time/clock.cc
+++ b/absl/time/clock.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -34,7 +34,7 @@
#include "absl/base/thread_annotations.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
Time Now() {
// TODO(bww): Get a timespec instead so we don't have to divide.
int64_t n = absl::GetCurrentTimeNanos();
@@ -44,7 +44,7 @@ Time Now() {
}
return time_internal::FromUnixDuration(absl::Nanoseconds(n));
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// Decide if we should use the fast GetCurrentTimeNanos() algorithm
@@ -73,11 +73,11 @@ Time Now() {
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
int64_t GetCurrentTimeNanos() {
return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // Use the cyclecounter-based implementation below.
@@ -95,7 +95,7 @@ static int64_t stats_slow_paths;
static int64_t stats_fast_slow_paths;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
// This is a friend wrapper around UnscaledCycleClock::Now()
// (needed to access UnscaledCycleClock).
@@ -384,7 +384,7 @@ static uint64_t UpdateLastSample(
//
// Manually mark this 'noinline' to minimize stack frame size of the fast
// path. Without this, sometimes a compiler may inline this big block of code
-// into the fast past. That causes lots of register spills and reloads that
+// into the fast path. That causes lots of register spills and reloads that
// are unnecessary unless the slow path is taken.
//
// TODO(absl-team): Remove this attribute when our compiler is smart enough
@@ -520,12 +520,12 @@ static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
return estimated_base_ns;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
// Returns the maximum duration that SleepOnce() can sleep for.
@@ -553,7 +553,7 @@ void SleepOnce(absl::Duration to_sleep) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
extern "C" {
diff --git a/absl/time/clock.h b/absl/time/clock.h
index b2941126..a3b9ffe9 100644
--- a/absl/time/clock.h
+++ b/absl/time/clock.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -26,7 +26,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// Now()
//
@@ -50,7 +50,7 @@ int64_t GetCurrentTimeNanos();
// * Returns immediately when passed a nonpositive duration.
void SleepFor(absl::Duration duration);
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
// -----------------------------------------------------------------------------
diff --git a/absl/time/clock_benchmark.cc b/absl/time/clock_benchmark.cc
index 3d3cd9d5..c5c795ec 100644
--- a/absl/time/clock_benchmark.cc
+++ b/absl/time/clock_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,6 +15,8 @@
#if !defined(_WIN32)
#include <sys/time.h>
+#else
+#include <winsock2.h>
#endif // _WIN32
#include <cstdio>
diff --git a/absl/time/clock_test.cc b/absl/time/clock_test.cc
index 707166d0..4bcfc6bc 100644
--- a/absl/time/clock_test.cc
+++ b/absl/time/clock_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/time/duration.cc b/absl/time/duration.cc
index 04669709..6a51baff 100644
--- a/absl/time/duration.cc
+++ b/absl/time/duration.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -49,6 +49,10 @@
//
// Arithmetic overflows/underflows to +/- infinity and saturates.
+#if defined(_MSC_VER)
+#include <winsock2.h> // for timeval
+#endif
+
#include <algorithm>
#include <cassert>
#include <cctype>
@@ -67,7 +71,7 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -750,9 +754,9 @@ void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
} // namespace
-// From Go's doc at http://golang.org/pkg/time/#Duration.String
+// From Go's doc at https://golang.org/pkg/time/#Duration.String
// [FormatDuration] returns a string representing the duration in the
-// form "72h3m0.5s". Leading zero units are omitted. As a special
+// form "72h3m0.5s". Leading zero units are omitted. As a special
// case, durations less than one second format use a smaller unit
// (milli-, micro-, or nanoseconds) to ensure that the leading digit
// is non-zero. The zero duration formats as 0, with no unit.
@@ -856,8 +860,8 @@ bool ConsumeDurationUnit(const char** start, Duration* unit) {
} // namespace
-// From Go's doc at http://golang.org/pkg/time/#ParseDuration
-// [ParseDuration] parses a duration string. A duration string is
+// From Go's doc at https://golang.org/pkg/time/#ParseDuration
+// [ParseDuration] parses a duration string. A duration string is
// a possibly signed sequence of decimal numbers, each with optional
// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
// Valid time units are "ns", "us" "ms", "s", "m", "h".
@@ -902,11 +906,12 @@ bool ParseDuration(const std::string& dur_string, Duration* d) {
*d = dur;
return true;
}
+
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
return ParseDuration(text, dst);
}
std::string UnparseFlag(Duration d) { return FormatDuration(d); }
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
index d5657bd5..83a836c8 100644
--- a/absl/time/duration_benchmark.cc
+++ b/absl/time/duration_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,6 +17,7 @@
#include <ctime>
#include <string>
+#include "absl/base/attributes.h"
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 61f3c5c0..5dce9ac8 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#if defined(_MSC_VER)
+#include <winsock2.h> // for timeval
+#endif
+
#include <chrono> // NOLINT(build/c++11)
#include <cmath>
#include <cstdint>
@@ -1771,7 +1775,7 @@ TEST(Duration, ParseDuration) {
TEST(Duration, FormatParseRoundTrip) {
#define TEST_PARSE_ROUNDTRIP(d) \
do { \
- std::string s = absl::FormatDuration(d); \
+ std::string s = absl::FormatDuration(d); \
absl::Duration dur; \
EXPECT_TRUE(absl::ParseDuration(s, &dur)); \
EXPECT_EQ(d, dur); \
diff --git a/absl/time/format.cc b/absl/time/format.cc
index 6aabcee9..6eb83d7a 100644
--- a/absl/time/format.cc
+++ b/absl/time/format.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
namespace cctz = absl::time_internal::cctz;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
extern const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
@@ -68,7 +68,8 @@ absl::Time Join(const cctz_parts& parts) {
} // namespace
-std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) {
+std::string FormatTime(const std::string& format, absl::Time t,
+ absl::TimeZone tz) {
if (t == absl::InfiniteFuture()) return kInfiniteFutureStr;
if (t == absl::InfinitePast()) return kInfinitePastStr;
const auto parts = Split(t);
@@ -84,15 +85,15 @@ std::string FormatTime(absl::Time t) {
return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
}
-bool ParseTime(const std::string& format, const std::string& input, absl::Time* time,
- std::string* err) {
+bool ParseTime(const std::string& format, const std::string& input,
+ absl::Time* time, std::string* err) {
return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
}
// If the input string does not contain an explicit UTC offset, interpret
// the fields with respect to the given TimeZone.
-bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz,
- absl::Time* time, std::string* err) {
+bool ParseTime(const std::string& format, const std::string& input,
+ absl::TimeZone tz, absl::Time* time, std::string* err) {
const char* data = input.c_str();
while (std::isspace(*data)) ++data;
@@ -137,5 +138,5 @@ std::string UnparseFlag(absl::Time t) {
return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc
index 766f1b39..249c51d8 100644
--- a/absl/time/format_benchmark.cc
+++ b/absl/time/format_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/time/format_test.cc b/absl/time/format_test.cc
index ac8d5ea3..ab1f3059 100644
--- a/absl/time/format_test.cc
+++ b/absl/time/format_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -27,8 +27,8 @@ namespace {
// A helper that tests the given format specifier by itself, and with leading
// and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu").
-void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt,
- const std::string& ans) {
+void TestFormatSpecifier(absl::Time t, absl::TimeZone tz,
+ const std::string& fmt, const std::string& ans) {
EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz));
EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz));
EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz));
@@ -201,7 +201,7 @@ TEST(ParseTime, ErrorCases) {
err.clear();
EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err;
// Exact contents of "err" are platform-dependent because of
- // differences in the strptime implementation between OSX and Linux.
+ // differences in the strptime implementation between macOS and Linux.
EXPECT_FALSE(err.empty());
// Fails because of trailing, unparsed data "blah".
@@ -375,7 +375,8 @@ TEST(FormatParse, RoundTrip) {
// RFC3339, which renders subseconds.
{
absl::Time out;
- const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, lax);
+ const std::string s =
+ absl::FormatTime(absl::RFC3339_full, in + subseconds, lax);
EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
<< s << ": " << err;
EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index e2cfe801..b05c2347 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -4,7 +4,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -16,6 +16,20 @@ package(features = ["-parse_headers"])
licenses(["notice"]) # Apache License
+config_setting(
+ name = "osx",
+ constraint_values = [
+ "@bazel_tools//platforms:osx",
+ ],
+)
+
+config_setting(
+ name = "ios",
+ constraint_values = [
+ "@bazel_tools//platforms:ios",
+ ],
+)
+
### libraries
cc_library(
@@ -62,6 +76,15 @@ cc_library(
"include/cctz/time_zone.h",
"include/cctz/zone_info_source.h",
],
+ linkopts = select({
+ ":osx": [
+ "-framework Foundation",
+ ],
+ ":ios": [
+ "-framework Foundation",
+ ],
+ "//conditions:default": [],
+ }),
visibility = ["//visibility:public"],
deps = [":civil_time"],
)
@@ -98,13 +121,13 @@ cc_test(
cc_test(
name = "time_zone_lookup_test",
size = "small",
+ timeout = "moderate",
srcs = ["src/time_zone_lookup_test.cc"],
data = [":zoneinfo"],
tags = [
"no_test_android_arm",
"no_test_android_arm64",
"no_test_android_x86",
- "no_test_wasm",
],
deps = [
":civil_time",
diff --git a/absl/time/internal/cctz/include/cctz/civil_time.h b/absl/time/internal/cctz/include/cctz/civil_time.h
index 9fabbc3d..df25db07 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -280,7 +280,7 @@ using civil_second = detail::civil_second;
//
using detail::weekday;
-// Returns the weekday for the given civil_day.
+// Returns the weekday for the given civil-time value.
//
// civil_day a(2015, 8, 13);
// weekday wd = get_weekday(a); // wd == weekday::thursday
@@ -307,14 +307,14 @@ using detail::get_weekday;
//
// civil_day d = ...
// // Gets the following Thursday if d is not already Thursday
-// civil_day thurs1 = prev_weekday(d, weekday::thursday) + 7;
+// civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
// // Gets the previous Thursday if d is not already Thursday
-// civil_day thurs2 = next_weekday(d, weekday::thursday) - 7;
+// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
//
using detail::next_weekday;
using detail::prev_weekday;
-// Returns the day-of-year for the given civil_day.
+// Returns the day-of-year for the given civil-time value.
//
// civil_day a(2015, 1, 1);
// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1
@@ -325,7 +325,7 @@ using detail::get_yearday;
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
diff --git a/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
index 289ff499..53e087a2 100644
--- a/absl/time/internal/cctz/include/cctz/civil_time_detail.h
+++ b/absl/time/internal/cctz/include/cctz/civil_time_detail.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,7 @@
#include <type_traits>
// Disable constexpr support unless we are in C++14 mode.
-#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
#define CONSTEXPR_D constexpr // data
#define CONSTEXPR_F constexpr // function
#define CONSTEXPR_M constexpr // member
@@ -32,7 +32,7 @@
#endif
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -387,12 +387,12 @@ class civil_time {
: civil_time(ct.f_) {}
// Factories for the maximum/minimum representable civil_time.
- static CONSTEXPR_F civil_time max() {
- const auto max_year = std::numeric_limits<std::int_least64_t>::max();
+ static CONSTEXPR_F civil_time (max)() {
+ const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
return civil_time(max_year, 12, 31, 23, 59, 59);
}
- static CONSTEXPR_F civil_time min() {
- const auto min_year = std::numeric_limits<std::int_least64_t>::min();
+ static CONSTEXPR_F civil_time (min)() {
+ const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
return civil_time(min_year, 1, 1, 0, 0, 0);
}
@@ -410,7 +410,7 @@ class civil_time {
return *this;
}
CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
- if (n != std::numeric_limits<diff_t>::min()) {
+ if (n != (std::numeric_limits<diff_t>::min)()) {
f_ = step(T{}, f_, -n);
} else {
f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
@@ -536,7 +536,7 @@ enum class weekday {
sunday,
};
-CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
+CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept {
CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
weekday::monday, weekday::tuesday, weekday::wednesday,
weekday::thursday, weekday::friday, weekday::saturday,
@@ -547,30 +547,60 @@ CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept {
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
-1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
};
- year_t wd = 2400 + (cd.year() % 400) - (cd.month() < 3);
+ year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3);
wd += wd / 4 - wd / 100 + wd / 400;
- wd += k_weekday_offsets[cd.month()] + cd.day();
+ wd += k_weekday_offsets[cs.month()] + cs.day();
return k_weekday_by_mon_off[wd % 7 + 6];
}
////////////////////////////////////////////////////////////////////////
CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
- do { cd += 1; } while (get_weekday(cd) != wd);
- return cd;
+ CONSTEXPR_D weekday k_weekdays_forw[14] = {
+ weekday::monday, weekday::tuesday, weekday::wednesday,
+ weekday::thursday, weekday::friday, weekday::saturday,
+ weekday::sunday, weekday::monday, weekday::tuesday,
+ weekday::wednesday, weekday::thursday, weekday::friday,
+ weekday::saturday, weekday::sunday,
+ };
+ weekday base = get_weekday(cd);
+ for (int i = 0;; ++i) {
+ if (base == k_weekdays_forw[i]) {
+ for (int j = i + 1;; ++j) {
+ if (wd == k_weekdays_forw[j]) {
+ return cd + (j - i);
+ }
+ }
+ }
+ }
}
CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
- do { cd -= 1; } while (get_weekday(cd) != wd);
- return cd;
+ CONSTEXPR_D weekday k_weekdays_back[14] = {
+ weekday::sunday, weekday::saturday, weekday::friday,
+ weekday::thursday, weekday::wednesday, weekday::tuesday,
+ weekday::monday, weekday::sunday, weekday::saturday,
+ weekday::friday, weekday::thursday, weekday::wednesday,
+ weekday::tuesday, weekday::monday,
+ };
+ weekday base = get_weekday(cd);
+ for (int i = 0;; ++i) {
+ if (base == k_weekdays_back[i]) {
+ for (int j = i + 1;; ++j) {
+ if (wd == k_weekdays_back[j]) {
+ return cd - (j - i);
+ }
+ }
+ }
+ }
}
-CONSTEXPR_F int get_yearday(const civil_day& cd) noexcept {
+CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept {
CONSTEXPR_D int k_month_offsets[1 + 12] = {
-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
};
- const int feb29 = (cd.month() > 2 && impl::is_leap_year(cd.year()));
- return k_month_offsets[cd.month()] + feb29 + cd.day();
+ const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year()));
+ return k_month_offsets[cs.month()] + feb29 + cs.day();
}
////////////////////////////////////////////////////////////////////////
@@ -586,7 +616,7 @@ std::ostream& operator<<(std::ostream& os, weekday wd);
} // namespace detail
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#undef CONSTEXPR_M
diff --git a/absl/time/internal/cctz/include/cctz/time_zone.h b/absl/time/internal/cctz/include/cctz/time_zone.h
index 0c34393e..f9769c0c 100644
--- a/absl/time/internal/cctz/include/cctz/time_zone.h
+++ b/absl/time/internal/cctz/include/cctz/time_zone.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -73,7 +73,7 @@ split_seconds(const time_point<seconds>& tp) {
//
// See also:
// - http://www.iana.org/time-zones
-// - http://en.wikipedia.org/wiki/Zoneinfo
+// - https://en.wikipedia.org/wiki/Zoneinfo
class time_zone {
public:
time_zone() : time_zone(nullptr) {} // Equivalent to UTC
@@ -381,7 +381,7 @@ inline bool parse(const std::string& fmt, const std::string& input,
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
diff --git a/absl/time/internal/cctz/include/cctz/zone_info_source.h b/absl/time/internal/cctz/include/cctz/zone_info_source.h
index b3274e00..7372c5de 100644
--- a/absl/time/internal/cctz/include/cctz/zone_info_source.h
+++ b/absl/time/internal/cctz/include/cctz/zone_info_source.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,7 +21,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -41,11 +41,11 @@ class ZoneInfoSource {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz_extension {
@@ -94,7 +94,7 @@ extern ZoneInfoSourceFactory zone_info_source_factory;
} // namespace cctz_extension
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index 4498d7d0..a40f504e 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -47,6 +47,56 @@ void BM_Step_Days(benchmark::State& state) {
}
BENCHMARK(BM_Step_Days);
+void BM_GetWeekday(benchmark::State& state) {
+ const cctz::civil_day c(2014, 8, 22);
+ while (state.KeepRunning()) {
+ benchmark::DoNotOptimize(cctz::get_weekday(c));
+ }
+}
+BENCHMARK(BM_GetWeekday);
+
+void BM_NextWeekday(benchmark::State& state) {
+ const cctz::civil_day kStart(2014, 8, 22);
+ const cctz::civil_day kDays[7] = {
+ kStart + 0, kStart + 1, kStart + 2, kStart + 3,
+ kStart + 4, kStart + 5, kStart + 6,
+ };
+ const cctz::weekday kWeekdays[7] = {
+ cctz::weekday::monday, cctz::weekday::tuesday, cctz::weekday::wednesday,
+ cctz::weekday::thursday, cctz::weekday::friday, cctz::weekday::saturday,
+ cctz::weekday::sunday,
+ };
+ while (state.KeepRunningBatch(7 * 7)) {
+ for (const auto from : kDays) {
+ for (const auto to : kWeekdays) {
+ benchmark::DoNotOptimize(cctz::next_weekday(from, to));
+ }
+ }
+ }
+}
+BENCHMARK(BM_NextWeekday);
+
+void BM_PrevWeekday(benchmark::State& state) {
+ const cctz::civil_day kStart(2014, 8, 22);
+ const cctz::civil_day kDays[7] = {
+ kStart + 0, kStart + 1, kStart + 2, kStart + 3,
+ kStart + 4, kStart + 5, kStart + 6,
+ };
+ const cctz::weekday kWeekdays[7] = {
+ cctz::weekday::monday, cctz::weekday::tuesday, cctz::weekday::wednesday,
+ cctz::weekday::thursday, cctz::weekday::friday, cctz::weekday::saturday,
+ cctz::weekday::sunday,
+ };
+ while (state.KeepRunningBatch(7 * 7)) {
+ for (const auto from : kDays) {
+ for (const auto to : kWeekdays) {
+ benchmark::DoNotOptimize(cctz::prev_weekday(from, to));
+ }
+ }
+ }
+}
+BENCHMARK(BM_PrevWeekday);
+
const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez";
const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez";
@@ -357,6 +407,7 @@ const char* const kTimeZoneNames[] = {
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
diff --git a/absl/time/internal/cctz/src/civil_time_detail.cc b/absl/time/internal/cctz/src/civil_time_detail.cc
index e888066d..4df15d55 100644
--- a/absl/time/internal/cctz/src/civil_time_detail.cc
+++ b/absl/time/internal/cctz/src/civil_time_detail.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -19,7 +19,7 @@
#include <sstream>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
namespace detail {
@@ -88,5 +88,5 @@ std::ostream& operator<<(std::ostream& os, weekday wd) {
} // namespace detail
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/civil_time_test.cc b/absl/time/internal/cctz/src/civil_time_test.cc
index 2417a2a9..7d9a1834 100644
--- a/absl/time/internal/cctz/src/civil_time_test.cc
+++ b/absl/time/internal/cctz/src/civil_time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "gtest/gtest.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -38,7 +38,7 @@ std::string Format(const T& t) {
} // namespace
-#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// Construction constexpr tests
TEST(CivilTime, Normal) {
@@ -320,7 +320,7 @@ TEST(CivilTime, YearDay) {
constexpr int yd = get_yearday(cd);
static_assert(yd == 28, "YearDay");
}
-#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910
+#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// The remaining tests do not use constexpr.
@@ -822,6 +822,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, ss.hour());
EXPECT_EQ(5, ss.minute());
EXPECT_EQ(6, ss.second());
+ EXPECT_EQ(weekday::tuesday, get_weekday(ss));
+ EXPECT_EQ(34, get_yearday(ss));
civil_minute mm(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, mm.year());
@@ -830,6 +832,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, mm.hour());
EXPECT_EQ(5, mm.minute());
EXPECT_EQ(0, mm.second());
+ EXPECT_EQ(weekday::tuesday, get_weekday(mm));
+ EXPECT_EQ(34, get_yearday(mm));
civil_hour hh(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, hh.year());
@@ -838,6 +842,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, hh.hour());
EXPECT_EQ(0, hh.minute());
EXPECT_EQ(0, hh.second());
+ EXPECT_EQ(weekday::tuesday, get_weekday(hh));
+ EXPECT_EQ(34, get_yearday(hh));
civil_day d(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, d.year());
@@ -856,6 +862,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, m.hour());
EXPECT_EQ(0, m.minute());
EXPECT_EQ(0, m.second());
+ EXPECT_EQ(weekday::sunday, get_weekday(m));
+ EXPECT_EQ(32, get_yearday(m));
civil_year y(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, y.year());
@@ -864,6 +872,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, y.hour());
EXPECT_EQ(0, y.minute());
EXPECT_EQ(0, y.second());
+ EXPECT_EQ(weekday::thursday, get_weekday(y));
+ EXPECT_EQ(1, get_yearday(y));
}
TEST(CivilTime, OutputStream) {
@@ -1036,7 +1046,7 @@ TEST(CivilTime, LeapYears) {
TEST(CivilTime, FirstThursdayInMonth) {
const civil_day nov1(2014, 11, 1);
- const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7;
+ const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
EXPECT_EQ("2014-11-06", Format(thursday));
// Bonus: Date of Thanksgiving in the United States
@@ -1047,5 +1057,5 @@ TEST(CivilTime, FirstThursdayInMonth) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index 070abd26..aa5af020 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,14 +21,14 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
namespace {
// The prefix used for the internal names of fixed-offset zones.
-const char kFixedOffsetPrefix[] = "Fixed/UTC";
+const char kFixedZonePrefix[] = "Fixed/UTC";
const char kDigits[] = "0123456789";
@@ -56,11 +56,11 @@ bool FixedOffsetFromName(const std::string& name, seconds* offset) {
return true;
}
- const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
- const char* const ep = kFixedOffsetPrefix + prefix_len;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ const char* const ep = kFixedZonePrefix + prefix_len;
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
return false;
- if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
+ if (!std::equal(kFixedZonePrefix, ep, name.begin()))
return false;
const char* np = name.data() + prefix_len;
if (np[0] != '+' && np[0] != '-')
@@ -103,9 +103,9 @@ std::string FixedOffsetToName(const seconds& offset) {
}
int hours = minutes / 60;
minutes %= 60;
- char buf[sizeof(kFixedOffsetPrefix) - 1 + sizeof("-24:00:00")];
- std::strcpy(buf, kFixedOffsetPrefix);
- char* ep = buf + sizeof(kFixedOffsetPrefix) - 1;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ char buf[prefix_len + sizeof("-24:00:00")];
+ char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
*ep++ = sign;
ep = Format02d(ep, hours);
*ep++ = ':';
@@ -119,7 +119,7 @@ std::string FixedOffsetToName(const seconds& offset) {
std::string FixedOffsetToAbbr(const seconds& offset) {
std::string abbr = FixedOffsetToName(offset);
- const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
abbr.erase(0, prefix_len); // +99:99:99
abbr.erase(6, 1); // +99:9999
@@ -136,5 +136,5 @@ std::string FixedOffsetToAbbr(const seconds& offset) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.h b/absl/time/internal/cctz/src/time_zone_fixed.h
index dbb2958e..15ea3bdf 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.h
+++ b/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -45,7 +45,7 @@ std::string FixedOffsetToAbbr(const seconds& offset);
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index 02ecb2cf..ee2ffac0 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -13,13 +13,23 @@
// limitations under the License.
#if !defined(HAS_STRPTIME)
-# if !defined(_MSC_VER)
+# if !defined(_MSC_VER) && !defined(__MINGW32__)
# define HAS_STRPTIME 1 // assume everyone has strptime() except windows
# endif
#endif
+#if defined(HAS_STRPTIME) && HAS_STRPTIME
+# if !defined(_XOPEN_SOURCE)
+# define _XOPEN_SOURCE // Definedness suffices for strptime.
+# endif
+#endif
+
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+// Include time.h directly since, by C++ standards, ctime doesn't have to
+// declare strptime.
+#include <time.h>
+
#include <cctype>
#include <chrono>
#include <cstddef>
@@ -38,7 +48,7 @@
#include "time_zone_if.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
namespace detail {
@@ -73,7 +83,7 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
}
- switch (get_weekday(civil_day(al.cs))) {
+ switch (get_weekday(al.cs)) {
case weekday::sunday:
tm.tm_wday = 0;
break;
@@ -96,7 +106,7 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
tm.tm_wday = 6;
break;
}
- tm.tm_yday = get_yearday(civil_day(al.cs)) - 1;
+ tm.tm_yday = get_yearday(al.cs) - 1;
tm.tm_isdst = al.is_dst ? 1 : 0;
return tm;
}
@@ -150,15 +160,25 @@ char* FormatOffset(char* ep, int offset, const char* mode) {
offset = -offset; // bounded by 24h so no overflow
sign = '-';
}
- char sep = mode[0];
- if (sep != '\0' && mode[1] == '*') {
- ep = Format02d(ep, offset % 60);
+ const int seconds = offset % 60;
+ const int minutes = (offset /= 60) % 60;
+ const int hours = offset /= 60;
+ const char sep = mode[0];
+ const bool ext = (sep != '\0' && mode[1] == '*');
+ const bool ccc = (ext && mode[2] == ':');
+ if (ext && (!ccc || seconds != 0)) {
+ ep = Format02d(ep, seconds);
*--ep = sep;
+ } else {
+ // If we're not rendering seconds, sub-minute negative offsets
+ // should get a positive sign (e.g., offset=-10s => "+00:00").
+ if (hours == 0 && minutes == 0) sign = '+';
+ }
+ if (!ccc || minutes != 0 || seconds != 0) {
+ ep = Format02d(ep, minutes);
+ if (sep != '\0') *--ep = sep;
}
- int minutes = offset / 60;
- ep = Format02d(ep, minutes % 60);
- if (sep != '\0') *--ep = sep;
- ep = Format02d(ep, minutes / 60);
+ ep = Format02d(ep, hours);
*--ep = sign;
return ep;
}
@@ -385,6 +405,44 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
continue;
}
+ // More complex specifiers that we handle ourselves.
+ if (*cur == ':' && cur + 1 != end) {
+ if (*(cur + 1) == 'z') {
+ // Formats %:z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 2;
+ continue;
+ }
+ if (*(cur + 1) == ':' && cur + 2 != end) {
+ if (*(cur + 2) == 'z') {
+ // Formats %::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 3;
+ continue;
+ }
+ if (*(cur + 2) == ':' && cur + 3 != end) {
+ if (*(cur + 3) == 'z') {
+ // Formats %:::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*:");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 4;
+ continue;
+ }
+ }
+ }
+ }
+
// Loop if there is no E modifier.
if (*cur != 'E' || ++cur == end) continue;
@@ -669,17 +727,27 @@ bool parse(const std::string& format, const std::string& input,
&percent_s);
if (data != nullptr) saw_percent_s = true;
continue;
+ case ':':
+ if (fmt[0] == 'z' ||
+ (fmt[0] == ':' &&
+ (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
+ data = ParseOffset(data, ":", &offset);
+ if (data != nullptr) saw_offset = true;
+ fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
+ continue;
+ }
+ break;
case '%':
data = (*data == '%' ? data + 1 : nullptr);
continue;
case 'E':
- if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) {
+ if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
data = ParseOffset(data, ":", &offset);
if (data != nullptr) saw_offset = true;
- fmt += (*fmt == 'z') ? 1 : 2;
+ fmt += (fmt[0] == 'z') ? 1 : 2;
continue;
}
- if (*fmt == '*' && *(fmt + 1) == 'S') {
+ if (fmt[0] == '*' && fmt[1] == 'S') {
data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
if (data != nullptr && *data == '.') {
data = ParseSubSeconds(data + 1, &subseconds);
@@ -687,14 +755,14 @@ bool parse(const std::string& format, const std::string& input,
fmt += 2;
continue;
}
- if (*fmt == '*' && *(fmt + 1) == 'f') {
+ if (fmt[0] == '*' && fmt[1] == 'f') {
if (data != nullptr && std::isdigit(*data)) {
data = ParseSubSeconds(data, &subseconds);
}
fmt += 2;
continue;
}
- if (*fmt == '4' && *(fmt + 1) == 'Y') {
+ if (fmt[0] == '4' && fmt[1] == 'Y') {
const char* bp = data;
data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
if (data != nullptr) {
@@ -849,5 +917,5 @@ bool parse(const std::string& format, const std::string& input,
} // namespace detail
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 260c56ad..49737445 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -26,7 +26,7 @@
namespace chrono = std::chrono;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -65,17 +65,6 @@ void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
}
-// These tests sometimes run on platforms that have zoneinfo data so old
-// that the transition we are attempting to check does not exist, most
-// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
-// time_zone::version() so, in cases where we've learned that it matters,
-// we can make the check conditionally.
-int VersionCmp(time_zone tz, const std::string& target) {
- std::string version = tz.version();
- if (version.empty() && !target.empty()) return 1; // unknown > known
- return version.compare(target);
-}
-
} // namespace
//
@@ -175,7 +164,9 @@ TEST(Format, PosixConversions) {
TestFormatSpecifier(tp, tz, "%M", "00");
TestFormatSpecifier(tp, tz, "%S", "00");
TestFormatSpecifier(tp, tz, "%U", "00");
+#if !defined(__EMSCRIPTEN__)
TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday
+#endif
TestFormatSpecifier(tp, tz, "%W", "00");
TestFormatSpecifier(tp, tz, "%y", "70");
TestFormatSpecifier(tp, tz, "%Y", "1970");
@@ -437,51 +428,165 @@ TEST(Format, CompareExtendSecondsVsSubseconds) {
}
TEST(Format, ExtendedOffset) {
- auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
- time_zone tz = utc_time_zone();
+ auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("America/New_York", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "-05:00");
-
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "-08:00");
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz));
- TestFormatSpecifier(tp, tz, "%Ez", "+10:00");
+ tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
- EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz));
- // The true offset is -00:44:30 but %z only gives (truncated) minutes.
- TestFormatSpecifier(tp, tz, "%z", "-0044");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:44");
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
}
TEST(Format, ExtendedSecondOffset) {
- const time_zone utc = utc_time_zone();
- time_point<chrono::seconds> tp;
- time_zone tz;
-
- EXPECT_TRUE(load_time_zone("America/New_York", &tz));
- tp = convert(civil_second(1883, 11, 18, 16, 59, 59), utc);
- if (tz.lookup(tp).offset == -5 * 60 * 60) {
- // It looks like the tzdata is only 32 bit (probably macOS),
- // which bottoms out at 1901-12-13T20:45:52+00:00.
- } else {
- TestFormatSpecifier(tp, tz, "%E*z", "-04:56:02");
- TestFormatSpecifier(tp, tz, "%Ez", "-04:56");
- }
- tp += chrono::seconds(1);
- TestFormatSpecifier(tp, tz, "%E*z", "-05:00:00");
-
- EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz));
- tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc);
- if (VersionCmp(tz, "2016g") >= 0) {
- TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
- TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
- }
- tp += chrono::seconds(1);
- TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00");
+ const auto tp = chrono::system_clock::from_time_t(0);
+
+ auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00");
+
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
+
+ tz = fixed_time_zone(-chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
}
TEST(Format, ExtendedYears) {
@@ -1161,25 +1266,6 @@ TEST(Parse, ExtendedOffset) {
const time_zone utc = utc_time_zone();
time_point<absl::time_internal::cctz::seconds> tp;
- // %z against +-HHMM.
- EXPECT_TRUE(parse("%z", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%z", "-123", utc, &tp));
-
- // %z against +-HH.
- EXPECT_TRUE(parse("%z", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%z", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%z", "-1", utc, &tp));
-
- // %Ez against +-HH:MM.
EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
@@ -1188,91 +1274,70 @@ TEST(Parse, ExtendedOffset) {
EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
- // %Ez against +-HHMM.
- EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-123", utc, &tp));
-
- // %Ez against +-HH.
- EXPECT_TRUE(parse("%Ez", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-1", utc, &tp));
+ for (auto fmt : {"%Ez", "%z"}) {
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
}
TEST(Parse, ExtendedSecondOffset) {
const time_zone utc = utc_time_zone();
time_point<absl::time_internal::cctz::seconds> tp;
- // %Ez against +-HH:MM:SS.
- EXPECT_TRUE(parse("%Ez", "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12:34:5", utc, &tp));
-
- // %Ez against +-HHMMSS.
- EXPECT_TRUE(parse("%Ez", "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12345", utc, &tp));
-
- // %E*z against +-HH:MM:SS.
- EXPECT_TRUE(parse("%E*z", "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12:34:5", utc, &tp));
-
- // %E*z against +-HHMMSS.
- EXPECT_TRUE(parse("%E*z", "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12345", utc, &tp));
-
- // %E*z against +-HH:MM.
- EXPECT_TRUE(parse("%E*z", "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-12:3", utc, &tp));
-
- // %E*z against +-HHMM.
- EXPECT_TRUE(parse("%E*z", "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-123", utc, &tp));
-
- // %E*z against +-HH.
- EXPECT_TRUE(parse("%E*z", "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%E*z", "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse("%E*z", "-1", utc, &tp));
+ for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
+ EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
}
TEST(Parse, ExtendedYears) {
@@ -1391,6 +1456,10 @@ TEST(FormatParse, RoundTrip) {
#if defined(_WIN32) || defined(_WIN64)
// Initial investigations indicate the %c does not roundtrip on Windows.
// TODO: Figure out what is going on here (perhaps a locale problem).
+#elif defined(__EMSCRIPTEN__)
+ // strftime() and strptime() use different defintions for "%c" under
+ // emscripten (see https://github.com/kripken/emscripten/pull/7491),
+ // causing its round-trip test to fail.
#else
// Even though we don't know what %c will produce, it should roundtrip,
// but only in the 0-offset timezone.
@@ -1424,5 +1493,5 @@ TEST(FormatParse, RoundTripDistantPast) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
index f7c36b2b..75d23da5 100644
--- a/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -17,7 +17,7 @@
#include "time_zone_libc.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -39,5 +39,5 @@ TimeZoneIf::~TimeZoneIf() {}
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_if.h b/absl/time/internal/cctz/src/time_zone_if.h
index 9886f2c5..0081d990 100644
--- a/absl/time/internal/cctz/src/time_zone_if.h
+++ b/absl/time/internal/cctz/src/time_zone_if.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -68,7 +68,7 @@ inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index a4e42916..60911f0b 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "time_zone_fixed.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -106,5 +106,5 @@ const time_zone::Impl* time_zone::Impl::UTCImpl() {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_impl.h b/absl/time/internal/cctz/src/time_zone_impl.h
index 7da2e99d..33d3f6bd 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.h
+++ b/absl/time/internal/cctz/src/time_zone_impl.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
#include "time_zone_info.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -86,7 +86,7 @@ class time_zone::Impl {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index e19d1d2d..b45d82fa 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,7 +25,7 @@
// a grain of salt.
//
// For more information see tzfile(5), http://www.iana.org/time-zones, or
-// http://en.wikipedia.org/wiki/Zoneinfo.
+// https://en.wikipedia.org/wiki/Zoneinfo.
//
// Note that we assume the proleptic Gregorian calendar and 60-second
// minutes throughout.
@@ -50,7 +50,7 @@
#include "time_zone_posix.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -240,8 +240,8 @@ bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
leapcnt = static_cast<std::size_t>(v);
if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
ttisstdcnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_ttisgmtcnt)) < 0) return false;
- ttisgmtcnt = static_cast<std::size_t>(v);
+ if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false;
+ ttisutcnt = static_cast<std::size_t>(v);
return true;
}
@@ -254,7 +254,7 @@ std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
len += 1 * charcnt; // abbreviations
len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC
len += 1 * ttisstdcnt; // UTC/local indicators
- len += 1 * ttisgmtcnt; // standard/wall indicators
+ len += 1 * ttisutcnt; // standard/wall indicators
return len;
}
@@ -428,7 +428,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
}
if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
return false;
- if (hdr.ttisgmtcnt != 0 && hdr.ttisgmtcnt != hdr.typecnt)
+ if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
return false;
// Read the data into a local buffer.
@@ -499,16 +499,16 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
// that isn't the case here (see "zic -p").
bp += (8 + 4) * hdr.leapcnt; // leap-time + TAI-UTC
bp += 1 * hdr.ttisstdcnt; // UTC/local indicators
- bp += 1 * hdr.ttisgmtcnt; // standard/wall indicators
+ bp += 1 * hdr.ttisutcnt; // standard/wall indicators
assert(bp == tbuf.data() + tbuf.size());
future_spec_.clear();
if (tzh.tzh_version[0] != '\0') {
// Snarf up the NL-enclosed future POSIX spec. Note
// that version '3' files utilize an extended format.
- auto get_char = [](ZoneInfoSource* zip) -> int {
+ auto get_char = [](ZoneInfoSource* azip) -> int {
unsigned char ch; // all non-EOF results are positive
- return (zip->Read(&ch, 1) == 1) ? ch : EOF;
+ return (azip->Read(&ch, 1) == 1) ? ch : EOF;
};
if (get_char(zip) != '\n')
return false;
@@ -683,7 +683,6 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
// Use of the "file:" prefix is intended for testing purposes only.
if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
-#if defined(__ANDROID__)
// See Android's libc/tzcode/bionic.cpp for additional information.
for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
"/system/usr/share/zoneinfo/tzdata"}) {
@@ -718,7 +717,7 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
}
}
}
-#endif // __ANDROID__
+
return nullptr;
}
@@ -922,7 +921,7 @@ bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
++begin;
}
std::int_fast64_t unix_time = ToUnixSeconds(tp);
- const Transition target = { unix_time };
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::upper_bound(begin, end, target,
Transition::ByUnixTime());
for (; tr != end; ++tr) { // skip no-op transitions
@@ -957,7 +956,7 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
}
unix_time += 1; // ceils
}
- const Transition target = { unix_time };
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::lower_bound(begin, end, target,
Transition::ByUnixTime());
for (; tr != begin; --tr) { // skip no-op transitions
@@ -974,5 +973,5 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_info.h b/absl/time/internal/cctz/src/time_zone_info.h
index e7a7d02f..c724fa8f 100644
--- a/absl/time/internal/cctz/src/time_zone_info.h
+++ b/absl/time/internal/cctz/src/time_zone_info.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "tzfile.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -89,7 +89,7 @@ class TimeZoneInfo : public TimeZoneIf {
std::size_t charcnt; // zone abbreviation characters
std::size_t leapcnt; // leap seconds (we expect none)
std::size_t ttisstdcnt; // UTC/local indicators (unused)
- std::size_t ttisgmtcnt; // standard/wall indicators (unused)
+ std::size_t ttisutcnt; // standard/wall indicators (unused)
bool Build(const tzhead& tzh);
std::size_t DataLength(std::size_t time_len) const;
@@ -132,7 +132,7 @@ class TimeZoneInfo : public TimeZoneIf {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 3dd75b50..cfe7d55c 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -21,70 +21,87 @@
#include <chrono>
#include <ctime>
#include <limits>
-#include <tuple>
#include <utility>
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
namespace {
-// .first is seconds east of UTC; .second is the time-zone abbreviation.
-using OffsetAbbr = std::pair<int, const char*>;
-
-// Defines a function that can be called as follows:
-//
-// std::tm tm = ...;
-// OffsetAbbr off_abbr = get_offset_abbr(tm);
-//
#if defined(_WIN32) || defined(_WIN64)
// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = _timezone + (is_dst ? _dstbias : 0);
- const char* abbr = _tzname[is_dst];
- return {off, abbr};
+ return _timezone + (is_dst ? _dstbias : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return _tzname[is_dst];
}
#elif defined(__sun)
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = is_dst ? altzone : timezone;
- const char* abbr = tzname[is_dst];
- return {off, abbr};
+ return is_dst ? altzone : timezone;
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return tzname[is_dst];
}
#elif defined(__native_client__) || defined(__myriad2__) || \
defined(__EMSCRIPTEN__)
// Uses the globals: 'timezone' and 'tzname'.
-OffsetAbbr get_offset_abbr(const std::tm& tm) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return _timezone + (is_dst ? 60 * 60 : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
const bool is_dst = tm.tm_isdst > 0;
- const int off = _timezone + (is_dst ? 60 * 60 : 0);
- const char* abbr = tzname[is_dst];
- return {off, abbr};
+ return tzname[is_dst];
+}
+#else
+// Adapt to different spellings of the struct std::tm extension fields.
+#if defined(tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
+}
+#elif defined(__tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
+}
+#else
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
+}
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
+}
+#endif // tm_gmtoff
+#if defined(tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
+}
+#elif defined(__tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
}
#else
-//
-// Returns an OffsetAbbr using std::tm fields with various spellings.
-//
-#if !defined(tm_gmtoff) && !defined(tm_zone)
template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr,
- decltype(&T::tm_zone) = nullptr) {
- return {tm.tm_gmtoff, tm.tm_zone};
+auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
}
-#endif // !defined(tm_gmtoff) && !defined(tm_zone)
-#if !defined(__tm_gmtoff) && !defined(__tm_zone)
template <typename T>
-OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr,
- decltype(&T::__tm_zone) = nullptr) {
- return {tm.__tm_gmtoff, tm.__tm_zone};
+auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
}
-#endif // !defined(__tm_gmtoff) && !defined(__tm_zone)
+#endif // tm_zone
#endif
inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
@@ -127,7 +144,7 @@ bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
return false;
}
}
- *off = get_offset_abbr(tm).first;
+ *off = static_cast<int>(tm_gmtoff(tm));
return true;
}
@@ -138,7 +155,7 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
while (lo + 1 != hi) {
const std::time_t mid = lo + (hi - lo) / 2;
if (std::tm* tmp = local_time(&mid, &tm)) {
- if (get_offset_abbr(*tmp).first == offset) {
+ if (tm_gmtoff(*tmp) == offset) {
hi = mid;
} else {
lo = mid;
@@ -148,7 +165,7 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
// ignoring all failed conversions. Slow, but never really happens.
while (++lo != hi) {
if (std::tm* tmp = local_time(&lo, &tm)) {
- if (get_offset_abbr(*tmp).first == offset) break;
+ if (tm_gmtoff(*tmp) == offset) break;
}
}
return lo;
@@ -194,8 +211,8 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime(
const year_t year = tmp->tm_year + year_t{1900};
al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- std::tie(al.offset, al.abbr) = get_offset_abbr(*tmp);
- if (!local_) al.abbr = "UTC"; // as expected by cctz
+ al.offset = static_cast<int>(tm_gmtoff(*tmp));
+ al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
al.is_dst = tmp->tm_isdst > 0;
return al;
}
@@ -268,13 +285,13 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
-bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
-bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
@@ -288,5 +305,5 @@ std::string TimeZoneLibC::Description() const {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_libc.h b/absl/time/internal/cctz/src/time_zone_libc.h
index 67372d45..4b1ccb06 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.h
+++ b/absl/time/internal/cctz/src/time_zone_libc.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include "time_zone_if.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -49,7 +49,7 @@ class TimeZoneLibC : public TimeZoneIf {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index 711d705a..772a9375 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,10 +16,16 @@
#if defined(__ANDROID__)
#include <sys/system_properties.h>
-#if __ANDROID_API__ >= 21
+#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
#include <dlfcn.h>
#endif
#endif
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CFTimeZone.h>
+#include <vector>
+#endif
+
#include <cstdlib>
#include <cstring>
#include <string>
@@ -28,11 +34,11 @@
#include "time_zone_impl.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
-#if defined(__ANDROID__) && __ANDROID_API__ >= 21
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
namespace {
// Android 'L' removes __system_property_get() from the NDK, however
// it is still a hidden symbol in libc so we use dlsym() to access it.
@@ -117,6 +123,25 @@ time_zone fixed_time_zone(const seconds& offset) {
time_zone local_time_zone() {
const char* zone = ":localtime";
+#if defined(__ANDROID__)
+ char sysprop[PROP_VALUE_MAX];
+ if (__system_property_get("persist.sys.timezone", sysprop) > 0) {
+ zone = sysprop;
+ }
+#endif
+#if defined(__APPLE__)
+ std::vector<char> buffer;
+ CFTimeZoneRef tz_default = CFTimeZoneCopyDefault();
+ if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex length = CFStringGetLength(tz_name);
+ buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1);
+ if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) {
+ zone = &buffer[0];
+ }
+ }
+ CFRelease(tz_default);
+#endif
// Allow ${TZ} to override to default zone.
char* tz_env = nullptr;
@@ -125,12 +150,6 @@ time_zone local_time_zone() {
#else
tz_env = std::getenv("TZ");
#endif
-#if defined(__ANDROID__)
- char sysprop[PROP_VALUE_MAX];
- if (tz_env == nullptr)
- if (__system_property_get("persist.sys.timezone", sysprop) > 0)
- tz_env = sysprop;
-#endif
if (tz_env) zone = tz_env;
// We only support the "[:]<zone-name>" form.
@@ -166,5 +185,5 @@ time_zone local_time_zone() {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
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 e0e355ee..1bef7708 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -29,7 +29,7 @@
namespace chrono = std::chrono;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -338,6 +338,7 @@ const char* const kTimeZoneNames[] = {
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
@@ -667,6 +668,7 @@ int VersionCmp(time_zone tz, const std::string& target) {
} // namespace
+#if !defined(__EMSCRIPTEN__)
TEST(TimeZones, LoadZonesConcurrently) {
std::promise<void> ready_promise;
std::shared_future<void> ready_future(ready_promise.get_future());
@@ -714,6 +716,7 @@ TEST(TimeZones, LoadZonesConcurrently) {
}
EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
}
+#endif
TEST(TimeZone, NamedTimeZones) {
const time_zone utc = utc_time_zone();
@@ -834,7 +837,7 @@ TEST(BreakTime, LocalTimeInUTC) {
const time_zone tz = utc_time_zone();
const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInUTCUnaligned) {
@@ -842,7 +845,7 @@ TEST(BreakTime, LocalTimeInUTCUnaligned) {
const auto tp =
chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimePosix) {
@@ -850,7 +853,7 @@ TEST(BreakTime, LocalTimePosix) {
const time_zone tz = utc_time_zone();
const auto tp = chrono::system_clock::from_time_t(536457599);
ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneImpl, LocalTimeInFixed) {
@@ -860,28 +863,28 @@ TEST(TimeZoneImpl, LocalTimeInFixed) {
const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
"-083347");
- EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInNewYork) {
const time_zone tz = LoadZone("America/New_York");
const auto tp = chrono::system_clock::from_time_t(45);
ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
- EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInMTV) {
const time_zone tz = LoadZone("America/Los_Angeles");
const auto tp = chrono::system_clock::from_time_t(1380855729);
ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
- EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInSydney) {
const time_zone tz = LoadZone("Australia/Sydney");
const auto tp = chrono::system_clock::from_time_t(90);
ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
- EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(MakeTime, TimePointResolution) {
@@ -1019,7 +1022,7 @@ TEST(MakeTime, LocalTimeLibC) {
// 1) we know how to change the time zone used by localtime()/mktime(),
// 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
// 3) we have some idea about how mktime() behaves during transitions.
-#if defined(__linux__)
+#if defined(__linux__) && !defined(__ANDROID__)
const char* const ep = getenv("TZ");
std::string tz_name = (ep != nullptr) ? ep : "";
for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
@@ -1272,10 +1275,10 @@ TEST(TimeZoneEdgeCase, PacificApia) {
// 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
- EXPECT_EQ(363, get_yearday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(363, get_yearday(convert(tp, tz)));
tp += absl::time_internal::cctz::seconds(1);
ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
- EXPECT_EQ(365, get_yearday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(365, get_yearday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, AfricaCairo) {
@@ -1397,10 +1400,10 @@ TEST(TimeZoneEdgeCase, NegativeYear) {
const time_zone tz = utc_time_zone();
auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::saturday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
tp -= absl::time_internal::cctz::seconds(1);
ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::friday, get_weekday(civil_day(convert(tp, tz))));
+ EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, UTC32bitLimit) {
@@ -1431,5 +1434,5 @@ TEST(TimeZoneEdgeCase, UTC5DigitYear) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
index 960133d7..d1f8ecbe 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.cc
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,7 +20,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -101,9 +101,9 @@ const char* ParseDateTime(const char* p, PosixTransition* res) {
int weekday = 0;
if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
res->date.fmt = PosixTransition::M;
- res->date.m.month = static_cast<int_fast8_t>(month);
- res->date.m.week = static_cast<int_fast8_t>(week);
- res->date.m.weekday = static_cast<int_fast8_t>(weekday);
+ res->date.m.month = static_cast<std::int_fast8_t>(month);
+ res->date.m.week = static_cast<std::int_fast8_t>(week);
+ res->date.m.weekday = static_cast<std::int_fast8_t>(weekday);
}
}
}
@@ -111,13 +111,13 @@ const char* ParseDateTime(const char* p, PosixTransition* res) {
int day = 0;
if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::J;
- res->date.j.day = static_cast<int_fast16_t>(day);
+ res->date.j.day = static_cast<std::int_fast16_t>(day);
}
} else {
int day = 0;
if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::N;
- res->date.j.day = static_cast<int_fast16_t>(day);
+ res->date.n.day = static_cast<std::int_fast16_t>(day);
}
}
}
@@ -153,5 +153,5 @@ bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h
index 84c39afb..07e3427a 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.h
+++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -56,7 +56,7 @@
#include <string>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -124,7 +124,7 @@ bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
diff --git a/absl/time/internal/cctz/src/tzfile.h b/absl/time/internal/cctz/src/tzfile.h
index 4485ba55..51b1f1f3 100644
--- a/absl/time/internal/cctz/src/tzfile.h
+++ b/absl/time/internal/cctz/src/tzfile.h
@@ -33,6 +33,9 @@
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
+
+/* See Internet RFC 8536 for more details about the following format. */
+
/*
** Each file begins with. . .
*/
@@ -43,7 +46,7 @@ struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
char tzh_reserved[15]; /* reserved; must be zero */
- char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
@@ -66,14 +69,15 @@ struct tzhead {
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
** time is standard time, if 0,
-** transition time is wall clock time
-** if absent, transition times are
-** assumed to be wall clock time
-** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition
-** time is UT, if 0,
-** transition time is local time
-** if absent, transition times are
+** transition time is local (wall clock)
+** time; if absent, transition times are
** assumed to be local time
+** tzh_ttisutcnt (char)s indexed by type; if 1, transition
+** time is UT, if 0, transition time is
+** local time; if absent, transition
+** times are assumed to be local time.
+** When this is 1, the corresponding
+** std/wall indicator must also be 1.
*/
/*
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index 61669e7a..b64950cb 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,7 @@
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz {
@@ -25,11 +25,11 @@ std::string ZoneInfoSource::Version() const { return std::string(); }
} // namespace cctz
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz_extension {
@@ -49,35 +49,33 @@ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
// A "weak" definition for cctz_extension::zone_info_source_factory.
// The user may override this with their own "strong" definition (see
// zone_info_source.h).
-#if defined(_MSC_VER)
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+#if __has_attribute(weak) || defined(__GNUC__)
+ZoneInfoSourceFactory zone_info_source_factory
+ __attribute__((weak)) = DefaultFactory;
+#elif defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
extern ZoneInfoSourceFactory zone_info_source_factory;
extern ZoneInfoSourceFactory default_factory;
ZoneInfoSourceFactory default_factory = DefaultFactory;
#if defined(_M_IX86)
#pragma comment( \
linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@lts_2018_12_18@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZA=?default_factory@cctz_extension@time_internal@lts_2018_12_18@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64)
+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@lts_2019_08_08@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZA=?default_factory@cctz_extension@time_internal@lts_2019_08_08@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZA")
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
#pragma comment( \
linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@lts_2018_12_18@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZEA=?default_factory@cctz_extension@time_internal@lts_2018_12_18@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2018_12_18@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZEA")
+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@lts_2019_08_08@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZEA=?default_factory@cctz_extension@time_internal@lts_2019_08_08@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@6@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@lts_2019_08_08@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@6@@ZEA")
#else
#error Unsupported MSVC platform
-#endif
-#else // _MSC_VER
-#if !defined(__has_attribute)
-#define __has_attribute(x) 0
-#endif
-#if __has_attribute(weak) || defined(__GNUC__)
-ZoneInfoSourceFactory zone_info_source_factory
- __attribute__((weak)) = DefaultFactory;
+#endif // _M_<PLATFORM>
#else
// Make it a "strong" definition if we have no other choice.
ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
#endif
-#endif // _MSC_VER
} // namespace cctz_extension
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index ac954d74..8d4a43ba 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2018g-9-gf0d2759
+2019b
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
index eaaa818f..697b9933 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
index a5867a67..ae043423 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
index 0272fa1b..d3f81962 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index 4c570548..245f4ebe 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
index dd75e3e6..850c8f06 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index 0ea02535..a91f65f2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
index b8b9270a..b1c425da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
index 83eca03a..625b1acc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
index 549dae27..8ee8cb92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
index 31cfad77..52753c0f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo
index 31cfad77..52753c0f 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/Africa/Maseru b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
index b8b9270a..b1c425da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
index b8b9270a..b1c425da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
index 2a154f46..6d688502 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
index 8779590e..a968845e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
index cbdc0450..0c80137c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
index d2a64bd1..59f3759c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
index bd885315..07b393bb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
index 0cd8ffba..427fa563 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
index 67661856..abecd137 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
index bc9a5228..49381b41 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
index dfebfb99..260f86a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
index b798105e..0ae222a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
index b798105e..0ae222a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
index 5df3cf6e..da4c23a5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
index 7d2ba91c..604b8566 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
index 7654aebf..2218e36b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
index 10323564..f9e677f1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
index 3c849fce..c36587e1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
index a4b71c1f..0e797f22 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
index 948a3901..2698495b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
index acfbbe43..fe50f621 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
index 085fc9cc..c954000b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
index 1fc32567..3643628a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
index d3b318d2..f7ab6efc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion
index 831bf843..2f3bbda6 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 b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
index 143eafc2..15808d30 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia
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 cd531078..896af3f5 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/Barbados b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
index 7bb7ac4d..9b90e306 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
index ab3c8a67..60b5924d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
index fd693214..851051ae 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Belize
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
index 69e17a00..978c3310 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
index b7ded8e6..b2647d7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
index dfebfb99..260f86a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
index 495ef456..81206247 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun
index de6930cd..f907f0a5 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/Caracas b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
index 9abd028f..eedf725e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
index b798105e..0ae222a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
index ff596578..e5bc06fd 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
index 55b08346..9964b9a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua
index b2687241..8ed5f93b 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/Cordoba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
index 5df3cf6e..da4c23a5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
index 525a67ea..37cb85e4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
index 0fba7417..ca648573 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Creston
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
index 8a4ee7d0..9bea3d40 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
index d3b318d2..f7ab6efc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
index 99b7d06e..39d6daeb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
index ac774e83..e2f22304 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
index e637170a..be57dc20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
index 4597a621..b9bb063b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
index 6118b5ce..407138ca 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
index bf087a0e..0559a7a4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
index d1dd2faf..d5dab149 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
index 8186060a..b69ac451 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Havana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo
index 26c269d9..791a9fa2 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/Inuvik b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
index e107dc44..87bb3552 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
index 162306f8..2a9b7fd5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
index 7d2ba91c..604b8566 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
index d3b318d2..f7ab6efc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
index 5e5fec56..a1013724 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
index d9fec371..3c6529b7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lima
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
index d3b318d2..f7ab6efc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
index fec8a8bf..bc8b951d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
index 69256c63..e0242bff 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Managua
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
index b10241e6..63d58f80 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
index 79716de5..8df43dcf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
index 5c59984d..047968df 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan
index 43ee12d8..e4a78574 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/Mendoza b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
index 10323564..f9e677f1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/absl/time/internal/cctz/testdata/zoneinfo/America/Merida
index b46298e1..ea852da3 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/Metlakatla b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
index 26356078..1e94be3d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla
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 1434ab08..e7fb6f29 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/Miquelon b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
index 06ceaadf..b924b710 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey
index 7dc50577..a8928c8d 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/Montevideo b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
index 0d1e565c..2f357bcf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
index 5091eb5d..33cc6c62 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
index 95ff8a25..f140726f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga
index 37d78301..fc4a03e3 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/Panama b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
index 55b08346..9964b9a3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Panama
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
index b95c7842..bc8a6edf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
index 4d51271a..ac6bb0c7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
index d9590103..287f1439 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
index 16b7f923..a374cb43 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
index 10cb02b8..2e873a5a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
index 61ff6fcb..3a705874 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
index c6d99b3a..d7abb168 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Recife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
index 4365a5c8..0a73b753 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
index 16b7f923..a374cb43 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
index 5df3cf6e..da4c23a5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
index 8080efab..c28f3606 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
index 4e5eba52..4fe36fd4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
index c417ba1d..13ff0838 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
index 477e9395..2adacb2e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
index 2969ebe5..6f802f1c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Thule
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
index bdedd1bd..697cf5bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
index 3718d47d..ac40299f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
index bd6563ec..a71b39c0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
index 83c308ad..616afd9c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
index e1f0b09b..b32e7fd6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
index 60bcef68..6575fdce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
index 7940e6ef..8b2430a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
index 60bcef68..6575fdce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
index 4bb041a2..254af7d1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
index 5696abf5..72830530 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
index c6842af8..15a34c3c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
index b2f9a255..2aea25f8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
index d93201cf..a4b00779 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
index 281b304e..c9e87079 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
index 6a966013..6ed8b7cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
index 78cbcf0e..e2d0f919 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
index 7504052a..06f0a13a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
index 8d9e03c1..73891af1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
index 8d9e03c1..73891af1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
index 317466d1..8b5153e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
index 97fa6c73..f7162edf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
index f5140926..63188b26 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
index 8a090d77..a0de74b9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
index 72496402..c292ac5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
index 82cc49c4..759592a2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
index efb24c27..fb266ede 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
index f7a7d548..f6e20dd3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
index 8624c7ae..3dab0abf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
index e1cfcb8d..0014046d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
index 3baf7528..c4149c05 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan
index 79b9d3c8..e48daa82 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/Chongqing b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
index ce9e00a5..3c0bef20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
index ce9e00a5..3c0bef20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
index 4fc96c89..62c64d85 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
index 776f27da..b11c9284 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
index 4b610b5a..d9104a7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
index 776f27da..b11c9284 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili
index f6ce91a1..30943bbd 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/Dubai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
index 7880d5d7..fc0a589e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
index 694f6e6a..82d85b8c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
index cf54deb8..592b6326 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
index ce9e00a5..3c0bef20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
index 09c876a6..ae82f9b5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
index eab94fe8..e2934e37 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
index 8e5c5813..378a37f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
index 8eb5f647..4cb800a9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
index e8c53c0d..4dcbbb7e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
index 833d4eba..10d4b21b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
index 673d4801..5baa3a8f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
index a4c08297..3002c820 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
index 2d14c999..440ef06b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
index a22cf592..d19b9bd5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
index b9ed49ca..3e80b4e0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
index 337e1d58..ba65c0e8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
index 0342b433..faa14d92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
index 2f810b12..a5d51075 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
index 2f810b12..a5d51075 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
index 2b2f5bfa..72bea64b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
index e1cfcb8d..0014046d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
index 59efd24c..30c6f165 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
index 6d7d47b9..612b01e7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
index 4878622d..c86750cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
index b2f9a255..2aea25f8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
index d801000d..cac65063 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
index d801000d..cac65063 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
index b20cc57e..b4fcac18 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
index ed55442e..556ba866 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila
index 2c9220c9..f4f4b04e 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/Muscat b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
index 7880d5d7..fc0a589e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
index 2576a3b0..d9832761 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
index 95e3c73b..e0ee5fce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
index d805e4f7..b29b7693 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
index e36aec47..ad1f9ca1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
index 72496402..c292ac5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
index 9377d038..12ce24cb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
index dd54989f..7ad7e0b2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
index f5140926..63188b26 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
new file mode 100644
index 00000000..73b9d963
--- /dev/null
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
index 00b27844..c2fe4c14 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
index a00282de..dd77395b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
index b2f9a255..2aea25f8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
index eab94fe8..e2934e37 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
index 9c94900c..485459ce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
index a5d1e970..030d47ce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
index fa1cbd39..73182cf6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
index ce9e00a5..3c0bef20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
index ebc4b0d9..2364b217 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
index f8b7bb21..261a9832 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
index f9cbe672..24c43444 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
index e75bb365..32a9d7d0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
index 09bb06eb..b608d797 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran
index ad9058b4..8cec5ad7 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/Asia/Tel_Aviv b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
index 2d14c999..440ef06b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
index 06d3324d..fe409c7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
index 06d3324d..fe409c7a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
index 28da9c90..670e2ad2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
index ed55442e..556ba866 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
index 82fd4760..2e20cc3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
index 82fd4760..2e20cc3a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
index 0342b433..faa14d92 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
index c0c3767e..9e4a78f6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
index 72496402..c292ac5b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
index 15731abc..8ab253ce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
index 1f86e77f..c815e99b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
index a00282de..dd77395b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
index fff9f3b1..6958d7ed 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
index 409c3b17..250bfe02 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
index 3a5c6dbf..419c660b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
index c6842af8..15a34c3c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
index ac6bd697..10e0fc81 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
index b3311b63..44666086 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
index 65d19ec2..28b32ab2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
index 2fd42a2c..88077f11 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
index 4ed4467f..7636592a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
index 190b0e33..0b1252ab 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
index 26ffd9ac..3021bdb6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
index 874c8650..1ac3fc8f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
index 4ed4467f..7636592a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
index 865801e5..f65a990e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
index cf42d1d8..1cf50298 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
index c49d499c..98ae5570 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
index 92d1215d..02b07ca2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
index 8c6c7dd0..9e04a80e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
index 8ee1a6f5..eab0fb99 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
index 8c6c7dd0..9e04a80e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
index 3f2d3d7f..ba457338 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
index 4ed4467f..7636592a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
index cf42d1d8..1cf50298 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/North
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
index d38b67e2..a876b9e7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
index 26ffd9ac..3021bdb6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
index 190b0e33..0b1252ab 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/South
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
index 4ed4467f..7636592a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
index 92d1215d..02b07ca2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
index 3f2d3d7f..ba457338 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
index d38b67e2..a876b9e7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
index 874c8650..1ac3fc8f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
index 16b7f923..a374cb43 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
index 95ff8a25..f140726f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
index c417ba1d..13ff0838 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
index b10241e6..63d58f80 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/CET b/absl/time/internal/cctz/testdata/zoneinfo/CET
index d585656f..122e9342 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 41c4136f..ca67929f 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/Canada/Central b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
index 3718d47d..ac40299f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
index 8186060a..b69ac451 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Cuba
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Cuba
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/EET b/absl/time/internal/cctz/testdata/zoneinfo/EET
index d2f54c9b..cbdb71dd 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 074a4fc7..21ebc00b 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 087b641d..9bce5007 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/Egypt b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
index 0272fa1b..d3f81962 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Egypt
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Egypt
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Eire b/absl/time/internal/cctz/testdata/zoneinfo/Eire
index 5c5a7a3b..1d994902 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
index 087d1f92..4dab6f90 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
index 6437c684..c749290a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
index 72a912e0..d9699823 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
index 6938a1af..cdeec909 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
index a3155777..fbd2a941 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
index ee776199..ee246ef5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
index 1ea7da29..5a25ff2a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
index dda1a9e1..c0b745f1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
index f4a03855..06e777d5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
index 2d2ccd00..4e0b53a0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
index 826c7700..714b0c56 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
index b125ad2b..78b9daa3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
index dde682d8..a838bebf 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
index 352ec08a..68ff77db 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
index dfa27fec..66af5a42 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
index eef949df..17ba5057 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
index f9363b24..5f3706ce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
index 35add05a..7e9f9c46 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
index 315cae4f..fcef6d9a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
index 7489a153..27973bc8 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
index 560243e8..1efd8412 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
index b2bbe977..1f761844 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
index b979dbbc..952681ed 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
index 365ab1f6..cefc9126 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
index 742082fc..afb093da 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
index abc0b275..9265fb7c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
index a88c4b66..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
index ed064ed4..c3ff07b4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
index 5e069ea5..73a4d013 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
index 7ddd510e..7f6d958f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
index 85036de3..ce8f433e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
index d0d0a08a..9613c981 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
index 4eb7ed0d..4303b903 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
index dfdc6d24..6b94a4f3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
index 5bc1bfeb..5ee23fe0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
index cb2ec067..776be6e4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
index 5c5a7a3b..1d994902 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
index 833d4eba..10d4b21b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
index 982d82a3..f774ffdb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/London
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
index 6c194a5c..c4ca733f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
index ccc9d857..16f6420a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
index 801aead7..453306c0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
index c6842af8..15a34c3c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
index 85036de3..ce8f433e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
index 8495c506..8db477d0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
index 78a131b9..ac4c1634 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
index 78a131b9..ac4c1634 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
index e82dbbc7..432e8315 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
index dcfdd082..0e4d8793 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
index 3a744cc6..b5acca3c 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
index 5bc1bfeb..5ee23fe0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
index 677f0887..66ae8d69 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
index 78a131b9..ac4c1634 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
index 9e2d0c94..696f359d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
index 46ce484f..7abd63fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
index 8f170dd9..d1cfac0e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
index d6bb1561..e33cf671 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
index 32a57223..27de456f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Factory b/absl/time/internal/cctz/testdata/zoneinfo/Factory
index 95bc3a3b..60aa2a0d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Factory
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Factory
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB b/absl/time/internal/cctz/testdata/zoneinfo/GB
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
index a340326e..ac02a814 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT b/absl/time/internal/cctz/testdata/zoneinfo/GMT
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT+0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT-0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/GMT0
+++ b/absl/time/internal/cctz/testdata/zoneinfo/GMT0
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
index 2ee14295..c6347466 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Greenwich
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/HST b/absl/time/internal/cctz/testdata/zoneinfo/HST
index 616c31bc..cccd45eb 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/Hongkong b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
index 8e5c5813..378a37f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Hongkong
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
index ac6bd697..10e0fc81 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Iceland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Iceland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
index f609611c..93d6dda5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
index 6babdeea..d18c3810 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
index 58f80514..f8116e70 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
index 2cb6f3e3..cde4cf7e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
index 49e23e5a..cba7dfe7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
index ffa33658..7c839cfa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
index b23e2cee..17f26169 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
index 6e19601f..9a2918f4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
index 11c6002e..dfe08313 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Iran b/absl/time/internal/cctz/testdata/zoneinfo/Iran
index ad9058b4..8cec5ad7 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/Israel b/absl/time/internal/cctz/testdata/zoneinfo/Israel
index 2d14c999..440ef06b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Israel
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Israel
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
index 162306f8..2a9b7fd5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Jamaica
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
index 54bd71ff..1a7975fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Libya b/absl/time/internal/cctz/testdata/zoneinfo/Libya
index bd885315..07b393bb 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Libya
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Libya
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/MET b/absl/time/internal/cctz/testdata/zoneinfo/MET
index 388dd744..4a826bb1 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 da3e926d..c93a58ee 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 ddca8d19..4506a6e1 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/BajaSur b/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur
index 43ee12d8..e4a78574 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 1434ab08..e7fb6f29 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/NZ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
index 60bcef68..6575fdce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
index abe09cb9..c0041098 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PRC b/absl/time/internal/cctz/testdata/zoneinfo/PRC
index ce9e00a5..3c0bef20 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/PRC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/PRC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT
index d773e28f..99d246ba 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/Pacific/Apia b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
index fd03ff76..dab1f3f6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
index 60bcef68..6575fdce 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
index 6a6c2da2..2892d268 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
index abe09cb9..c0041098 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
index e79bca2d..07c84b71 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
index d650a056..60150175 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
index 80873503..f0b82523 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
index 4fa169f3..e40307f6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
index 61a66953..6bf667d4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
index e6a15447..ea728637 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
index 859b76d9..31f0921e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
index 4e9e36c5..e1fc3daa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
index 908ccc14..7e9d10a1 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
index ffdf8c24..66490d25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
index cf5b3bd3..7cae0cb7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
index b6bd4b08..a584aae5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
index 54bd71ff..1a7975fa 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
index 53f32886..9ef8374d 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
index 5fad0e1b..74d6792b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
index 72707b5e..cb56709a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
index 7e7d920e..acec0429 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
index 1d58fe36..684b010e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
index f630a65d..1f6d610e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
index 99f6bca2..931a1a30 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
index 72707b5e..cb56709a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
index 968f1956..146b3515 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
index 9092e481..ef91b061 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
index d3393a20..c298ddd4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
index d3393a20..c298ddd4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
index f6fd51cb..920ad27e 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
index 9708b870..da6b0fad 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
index ffdf8c24..66490d25 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
index 72707b5e..cb56709a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
index 37e4e883..442b8eb5 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
index e23c0cd2..3db6c750 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
index 35c9e2c6..5553c600 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
index e79bca2d..07c84b71 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
index 837ce1f5..c9e31067 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
index 8be9ac4d..b35344b3 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
index e79bca2d..07c84b71 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Poland b/absl/time/internal/cctz/testdata/zoneinfo/Poland
index d6bb1561..e33cf671 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Poland
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Poland
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROC b/absl/time/internal/cctz/testdata/zoneinfo/ROC
index f9cbe672..24c43444 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/ROK b/absl/time/internal/cctz/testdata/zoneinfo/ROK
index fa1cbd39..73182cf6 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/ROK
+++ b/absl/time/internal/cctz/testdata/zoneinfo/ROK
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
index ebc4b0d9..2364b217 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Singapore
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Singapore
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
index 833d4eba..10d4b21b 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Turkey
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Turkey
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UCT b/absl/time/internal/cctz/testdata/zoneinfo/UCT
index a88c4b66..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UCT
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UCT
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
index 4d51271a..ac6bb0c7 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
index 72707b5e..cb56709a 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
+++ b/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/UTC b/absl/time/internal/cctz/testdata/zoneinfo/UTC
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/UTC
+++ b/absl/time/internal/cctz/testdata/zoneinfo/UTC
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Universal b/absl/time/internal/cctz/testdata/zoneinfo/Universal
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Universal
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Universal
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/WET b/absl/time/internal/cctz/testdata/zoneinfo/WET
index 9b03a17f..c27390b5 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/Zulu b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
index 5583f5b0..91558be0 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Zulu
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Zulu
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
index c2e0f8ea..a4ff61a4 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab
@@ -9,8 +9,8 @@
# All text uses UTF-8 encoding. The columns of the table are as follows:
#
# 1. ISO 3166-1 alpha-2 country code, current as of
-# ISO 3166-1 N905 (2016-11-15). See: Updates on ISO 3166-1
-# http://isotc.iso.org/livelink/livelink/Open/16944257
+# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1
+# https://isotc.iso.org/livelink/livelink/Open/16944257
# 2. The usual English name for the coded region,
# chosen so that alphabetic sorting of subsets produces helpful lists.
# This is not the same as the English name in the ISO 3166 tables.
@@ -166,7 +166,7 @@ ME Montenegro
MF St Martin (French)
MG Madagascar
MH Marshall Islands
-MK Macedonia
+MK North Macedonia
ML Mali
MM Myanmar (Burma)
MN Mongolia
@@ -235,7 +235,7 @@ ST Sao Tome & Principe
SV El Salvador
SX St Maarten (Dutch)
SY Syria
-SZ Swaziland
+SZ Eswatini (Swaziland)
TC Turks & Caicos Is
TD Chad
TF French Southern & Antarctic Lands
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 2729e6e8..822ffa1f 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -211,6 +211,7 @@ KP +3901+12545 Asia/Pyongyang
KR +3733+12658 Asia/Seoul
KZ +4315+07657 Asia/Almaty Kazakhstan (most areas)
KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda
+KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay
KZ +5017+05710 Asia/Aqtobe Aqtöbe/Aktobe
KZ +4431+05016 Asia/Aqtau Mangghystaū/Mankistau
KZ +4707+05156 Asia/Atyrau Atyraū/Atirau/Gur'yev
@@ -288,7 +289,8 @@ RO +4426+02606 Europe/Bucharest
RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade
RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad
RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area
-RU +4457+03406 Europe/Simferopol MSK+00 - Crimea
+# Mention RU and UA alphabetically. See "territorial claims" above.
+RU,UA +4457+03406 Europe/Simferopol MSK+00 - Crimea
RU +5836+04939 Europe/Kirov MSK+00 - Kirov
RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan
RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd
diff --git a/absl/time/internal/get_current_time_chrono.inc b/absl/time/internal/get_current_time_chrono.inc
index ba016e3e..d294b3a6 100644
--- a/absl/time/internal/get_current_time_chrono.inc
+++ b/absl/time/internal/get_current_time_chrono.inc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -16,7 +16,7 @@
#include <cstdint>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
static int64_t GetCurrentTimeNanosFromSystem() {
@@ -27,5 +27,5 @@ static int64_t GetCurrentTimeNanosFromSystem() {
}
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/get_current_time_posix.inc b/absl/time/internal/get_current_time_posix.inc
index 3ff45c4a..0ce2a9a9 100644
--- a/absl/time/internal/get_current_time_posix.inc
+++ b/absl/time/internal/get_current_time_posix.inc
@@ -7,7 +7,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
static int64_t GetCurrentTimeNanosFromSystem() {
@@ -20,5 +20,5 @@ static int64_t GetCurrentTimeNanosFromSystem() {
}
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/test_util.cc b/absl/time/internal/test_util.cc
index 69530e64..2bc449fe 100644
--- a/absl/time/internal/test_util.cc
+++ b/absl/time/internal/test_util.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,7 +24,7 @@
namespace cctz = absl::time_internal::cctz;
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
TimeZone LoadTimeZone(const std::string& name) {
@@ -34,11 +34,11 @@ TimeZone LoadTimeZone(const std::string& name) {
}
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
namespace cctz_extension {
namespace {
@@ -123,5 +123,5 @@ ZoneInfoSourceFactory zone_info_source_factory = TestFactory;
} // namespace cctz_extension
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/internal/test_util.h b/absl/time/internal/test_util.h
index 31ec18e4..1a320cab 100644
--- a/absl/time/internal/test_util.h
+++ b/absl/time/internal/test_util.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -20,14 +20,14 @@
#include "absl/time/time.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace time_internal {
// Loads the named timezone, but dies on any failure.
absl::TimeZone LoadTimeZone(const std::string& name);
} // namespace time_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_INTERNAL_TEST_UTIL_H_
diff --git a/absl/time/time.cc b/absl/time/time.cc
index e60857e2..2c7da3ad 100644
--- a/absl/time/time.cc
+++ b/absl/time/time.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -33,6 +33,10 @@
#include "absl/time/time.h"
+#if defined(_MSC_VER)
+#include <winsock2.h> // for timeval
+#endif
+
#include <cstring>
#include <ctime>
#include <limits>
@@ -41,8 +45,9 @@
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace cctz = absl::time_internal::cctz;
+
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -453,8 +458,7 @@ struct tm ToTM(absl::Time t, absl::TimeZone tz) {
tm.tm_year = static_cast<int>(cs.year() - 1900);
}
- const CivilDay cd(cs);
- switch (GetWeekday(cd)) {
+ switch (GetWeekday(cs)) {
case Weekday::sunday:
tm.tm_wday = 0;
break;
@@ -477,11 +481,11 @@ struct tm ToTM(absl::Time t, absl::TimeZone tz) {
tm.tm_wday = 6;
break;
}
- tm.tm_yday = GetYearDay(cd) - 1;
+ tm.tm_yday = GetYearDay(cs) - 1;
tm.tm_isdst = ci.is_dst ? 1 : 0;
return tm;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/time/time.h b/absl/time/time.h
index 3afec565..1f6500e8 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -58,7 +58,6 @@
// std::string s = absl::FormatTime(
// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
// landing, syd);
-//
#ifndef ABSL_TIME_TIME_H_
#define ABSL_TIME_TIME_H_
@@ -66,7 +65,14 @@
#if !defined(_MSC_VER)
#include <sys/time.h>
#else
-#include <winsock2.h>
+// We don't include `winsock2.h` because it drags in `windows.h` and friends,
+// and they define conflicting macros like OPAQUE, ERROR, and more. This has the
+// potential to break Abseil users.
+//
+// Instead we only forward declare `timeval` and require Windows users include
+// `winsock2.h` themselves. This is both inconsistent and troublesome, but so is
+// including 'windows.h' so we are picking the lesser of two evils here.
+struct timeval;
#endif
#include <chrono> // NOLINT(build/c++11)
#include <cmath>
@@ -77,13 +83,12 @@
#include <type_traits>
#include <utility>
-#include "absl/base/port.h" // Needed for string vs std::string
#include "absl/strings/string_view.h"
#include "absl/time/civil_time.h"
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
class Duration; // Defined below
class Time; // Defined below
@@ -175,6 +180,7 @@ class Duration {
Duration& operator%=(Duration rhs);
// Overloads that forward to either the int64_t or double overloads above.
+ // Integer operands must be representable as int64_t.
template <typename T>
Duration& operator*=(T r) {
int64_t x = r;
@@ -217,6 +223,7 @@ inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; }
inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
// Multiplicative Operators
+// Integer operands must be representable as int64_t.
template <typename T>
Duration operator*(Duration lhs, T rhs) {
return lhs *= rhs;
@@ -371,7 +378,8 @@ constexpr Duration InfiniteDuration();
// Hours()
//
// Factory functions for constructing `Duration` values from an integral number
-// of the unit indicated by the factory function's name.
+// of the unit indicated by the factory function's name. The number must be
+// representable as int64_t.
//
// Note: no "Days()" factory function exists because "a day" is ambiguous.
// Civil days are not always 24 hours long, and a 24-hour duration often does
@@ -571,7 +579,6 @@ std::string UnparseFlag(Duration d);
// The `absl::Time` class represents an instant in time as a count of clock
// ticks of some granularity (resolution) from some starting point (epoch).
//
-//
// `absl::Time` uses a resolution that is high enough to avoid loss in
// precision, and a range that is wide enough to avoid overflow, when
// converting between tick counts in most Google time scales (i.e., resolution
@@ -838,8 +845,8 @@ std::string UnparseFlag(Time t);
//
// See also:
// - https://github.com/google/cctz
-// - http://www.iana.org/time-zones
-// - http://en.wikipedia.org/wiki/Zoneinfo
+// - https://www.iana.org/time-zones
+// - https://en.wikipedia.org/wiki/Zoneinfo
class TimeZone {
public:
explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
@@ -1150,7 +1157,9 @@ TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax);
// // t = 2017-09-26 09:30:00 -0700
//
-// Deprecated. Use `absl::TimeZone::At(CivilSecond).pre`.
+// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the
+// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil
+// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`.
inline Time FromDateTime(int64_t year, int mon, int day, int hour,
int min, int sec, TimeZone tz) {
return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre;
@@ -1221,7 +1230,7 @@ extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
//
// absl::CivilSecond cs(2013, 1, 2, 3, 4, 5);
// absl::Time t = absl::FromCivil(cs, lax);
-// string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
+// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000"
//
// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
@@ -1442,14 +1451,15 @@ T ToChronoDuration(Duration d) {
using Period = typename T::period;
static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
if (time_internal::IsInfiniteDuration(d))
- return d < ZeroDuration() ? T::min() : T::max();
+ return d < ZeroDuration() ? (T::min)() : (T::max)();
const auto v = ToInt64(d, Period{});
- if (v > (std::numeric_limits<Rep>::max)()) return T::max();
- if (v < (std::numeric_limits<Rep>::min)()) return T::min();
+ if (v > (std::numeric_limits<Rep>::max)()) return (T::max)();
+ if (v < (std::numeric_limits<Rep>::min)()) return (T::min)();
return T{v};
}
} // namespace time_internal
+
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::FromInt64(n, std::nano{});
}
@@ -1555,7 +1565,7 @@ constexpr Time FromTimeT(time_t t) {
return time_internal::FromUnixDuration(Seconds(t));
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TIME_TIME_H_
diff --git a/absl/time/time_benchmark.cc b/absl/time/time_benchmark.cc
index 9bbed6f8..99e62799 100644
--- a/absl/time/time_benchmark.cc
+++ b/absl/time/time_benchmark.cc
@@ -3,7 +3,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/time/time_test.cc b/absl/time/time_test.cc
index 4d710709..37af39d9 100644
--- a/absl/time/time_test.cc
+++ b/absl/time/time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -14,6 +14,10 @@
#include "absl/time/time.h"
+#if defined(_MSC_VER)
+#include <winsock2.h> // for timeval
+#endif
+
#include <chrono> // NOLINT(build/c++11)
#include <cstring>
#include <ctime>
@@ -28,7 +32,7 @@
namespace {
-#if GTEST_USES_SIMPLE_RE
+#if defined(GTEST_USES_SIMPLE_RE) && GTEST_USES_SIMPLE_RE
const char kZoneAbbrRE[] = ".*"; // just punt
#else
const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
@@ -108,7 +112,7 @@ TEST(Time, UnixEpoch) {
const auto ci = absl::UTCTimeZone().At(absl::UnixEpoch());
EXPECT_EQ(absl::CivilSecond(1970, 1, 1, 0, 0, 0), ci.cs);
EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
- EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs));
}
TEST(Time, Breakdown) {
@@ -119,14 +123,14 @@ TEST(Time, Breakdown) {
auto ci = tz.At(t);
EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 19, 0, 0, -18000, false);
EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
- EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(ci.cs));
// Just before the epoch.
t -= absl::Nanoseconds(1);
ci = tz.At(t);
EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 18, 59, 59, -18000, false);
EXPECT_EQ(absl::Nanoseconds(999999999), ci.subsecond);
- EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(ci.cs));
// Some time later.
t += absl::Hours(24) * 2735;
@@ -135,7 +139,7 @@ TEST(Time, Breakdown) {
ci = tz.At(t);
EXPECT_CIVIL_INFO(ci, 1977, 6, 28, 14, 30, 15, -14400, true);
EXPECT_EQ(8, ci.subsecond / absl::Nanoseconds(1));
- EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(ci.cs));
}
TEST(Time, AdditiveOperators) {
@@ -975,15 +979,15 @@ TEST(Time, ConversionSaturation) {
EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23,
59, 59, 0, false);
EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond);
- EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(absl::CivilDay(ci.cs)));
- EXPECT_EQ(365, absl::GetYearDay(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs));
+ EXPECT_EQ(365, absl::GetYearDay(ci.cs));
EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At()
ci = utc.At(absl::InfinitePast());
EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
0, 0, false);
EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond);
- EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(absl::CivilDay(ci.cs)));
- EXPECT_EQ(1, absl::GetYearDay(absl::CivilDay(ci.cs)));
+ EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(ci.cs));
+ EXPECT_EQ(1, absl::GetYearDay(ci.cs));
EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At()
// Approach the maximal Time value from below.
diff --git a/absl/time/time_zone_test.cc b/absl/time/time_zone_test.cc
index 43d91904..8f1e74ac 100644
--- a/absl/time/time_zone_test.cc
+++ b/absl/time/time_zone_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index d56fea6e..66ecb044 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -15,11 +15,12 @@
#
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
- "ABSL_TEST_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_EXCEPTIONS_FLAG",
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
+ "ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
@@ -30,6 +31,7 @@ cc_library(
name = "any",
hdrs = ["any.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bad_any_cast",
"//absl/base:config",
@@ -43,6 +45,7 @@ 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",
@@ -56,7 +59,7 @@ cc_library(
"bad_any_cast.h",
],
copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
deps = [
"//absl/base",
@@ -71,7 +74,7 @@ cc_test(
"any_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":any",
"//absl/base",
@@ -89,6 +92,7 @@ cc_test(
"any_test.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":any",
"//absl/base",
@@ -103,7 +107,7 @@ cc_test(
name = "any_exception_safety_test",
srcs = ["any_exception_safety_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":any",
"//absl/base:exception_safety_testing",
@@ -113,8 +117,14 @@ cc_test(
cc_library(
name = "span",
- hdrs = ["span.h"],
+ srcs = [
+ "internal/span.h",
+ ],
+ hdrs = [
+ "span.h",
+ ],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/algorithm",
"//absl/base:core_headers",
@@ -128,7 +138,7 @@ cc_test(
size = "small",
srcs = ["span_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":span",
"//absl/base:config",
@@ -147,6 +157,7 @@ cc_test(
size = "small",
srcs = ["span_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":span",
"//absl/base:config",
@@ -162,11 +173,13 @@ cc_test(
cc_library(
name = "optional",
- srcs = ["optional.cc"],
+ 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/memory",
@@ -180,7 +193,7 @@ cc_library(
srcs = ["bad_optional_access.cc"],
hdrs = ["bad_optional_access.h"],
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base",
"//absl/base:config",
@@ -192,7 +205,7 @@ cc_library(
srcs = ["bad_variant_access.cc"],
hdrs = ["bad_variant_access.h"],
copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base",
"//absl/base:config",
@@ -206,7 +219,7 @@ cc_test(
"optional_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":optional",
"//absl/base",
@@ -223,7 +236,7 @@ cc_test(
"optional_exception_safety_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":optional",
"//absl/base:exception_safety_testing",
@@ -236,6 +249,7 @@ cc_library(
srcs = ["internal/variant.h"],
hdrs = ["variant.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bad_variant_access",
"//absl/base:base_internal",
@@ -251,7 +265,7 @@ cc_test(
size = "small",
srcs = ["variant_test.cc"],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":variant",
"//absl/base:config",
@@ -269,6 +283,7 @@ cc_test(
"variant_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
deps = [
":variant",
@@ -284,7 +299,7 @@ cc_test(
"variant_exception_safety_test.cc",
],
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
- linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS,
+ linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
deps = [
":variant",
"//absl/base:config",
@@ -293,3 +308,27 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "compare",
+ hdrs = ["compare.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ deps = [
+ "//absl/base:core_headers",
+ "//absl/meta:type_traits",
+ ],
+)
+
+cc_test(
+ name = "compare_test",
+ size = "small",
+ srcs = [
+ "compare_test.cc",
+ ],
+ copts = ABSL_TEST_COPTS,
+ deps = [
+ ":compare",
+ "//absl/base",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt
index e8620766..4ce685da 100644
--- a/absl/types/CMakeLists.txt
+++ b/absl/types/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -13,216 +13,336 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-list(APPEND TYPES_PUBLIC_HEADERS
- "any.h"
- "bad_any_cast.h"
- "bad_optional_access.h"
- "optional.h"
- "span.h"
- "variant.h"
+absl_cc_library(
+ NAME
+ any
+ HDRS
+ "any.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::bad_any_cast
+ absl::config
+ absl::core_headers
+ 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
+)
-# any library
-absl_header_library(
- TARGET
- absl_any
- PUBLIC_LIBRARIES
- absl::bad_any_cast
- absl::base
- absl::meta
- absl::utility
- PRIVATE_COMPILE_FLAGS
+absl_cc_library(
+ NAME
+ bad_any_cast_impl
+ SRCS
+ "bad_any_cast.h"
+ "bad_any_cast.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
${ABSL_EXCEPTIONS_FLAG}
- EXPORT_NAME
- any
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
)
-# span library
-absl_header_library(
- TARGET
- absl_span
- PUBLIC_LIBRARIES
- absl::utility
- EXPORT_NAME
- span
+absl_cc_test(
+ NAME
+ any_test
+ SRCS
+ "any_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::any
+ absl::base
+ absl::config
+ absl::exception_testing
+ absl::test_instance_tracker
+ gmock_main
)
+absl_cc_test(
+ NAME
+ any_test_noexceptions
+ SRCS
+ "any_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::any
+ absl::base
+ absl::config
+ absl::exception_testing
+ absl::test_instance_tracker
+ gmock_main
+)
-# bad_any_cast library
-list(APPEND BAD_ANY_CAST_SRC
- "bad_any_cast.cc"
- ${TYPES_PUBLIC_HEADERS}
+absl_cc_test(
+ NAME
+ any_exception_safety_test
+ SRCS
+ "any_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::any
+ absl::exception_safety_testing
+ gmock_main
)
-absl_library(
- TARGET
- absl_bad_any_cast
- SOURCES
- ${BAD_ANY_CAST_SRC}
- PUBLIC_LIBRARIES
- EXPORT_NAME
- bad_any_cast
+absl_cc_library(
+ NAME
+ span
+ HDRS
+ "span.h"
+ SRCS
+ "internal/span.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::algorithm
+ absl::core_headers
+ absl::throw_delegate
+ absl::type_traits
+ PUBLIC
)
+absl_cc_test(
+ NAME
+ span_test
+ SRCS
+ "span_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::span
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::exception_testing
+ absl::fixed_array
+ absl::inlined_vector
+ absl::hash_testing
+ absl::strings
+ gmock_main
+)
-# optional library
-list(APPEND OPTIONAL_SRC
- "optional.cc"
+absl_cc_test(
+ NAME
+ span_test_noexceptions
+ SRCS
+ "span_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::span
+ absl::base
+ absl::config
+ absl::core_headers
+ absl::exception_testing
+ absl::fixed_array
+ absl::inlined_vector
+ absl::hash_testing
+ absl::strings
+ gmock_main
)
-absl_library(
- TARGET
- absl_optional
- SOURCES
- ${OPTIONAL_SRC}
- PUBLIC_LIBRARIES
+absl_cc_library(
+ NAME
+ optional
+ HDRS
+ "optional.h"
+ SRCS
+ "internal/optional.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
absl::bad_optional_access
- absl::base
+ absl::base_internal
+ absl::config
+ absl::core_headers
absl::memory
- absl::meta
+ absl::type_traits
absl::utility
- EXPORT_NAME
- optional
+ PUBLIC
)
-
-set(BAD_OPTIONAL_ACCESS_SRC "bad_optional_access.cc")
-set(BAD_OPTIONAL_ACCESS_LIBRARIES absl::base)
-
-absl_library(
- TARGET
- absl_bad_optional_access
- SOURCES
- ${BAD_OPTIONAL_ACCESS_SRC}
- PUBLIC_LIBRARIES
- ${BAD_OPTIONAL_ACCESS_PUBLIC_LIBRARIES}
- EXPORT_NAME
+absl_cc_library(
+ NAME
bad_optional_access
-)
-
-# variant library
-absl_library(
- TARGET
- absl_variant
- SOURCES
- "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h"
- PUBLIC_LIBRARIES
- absl::base absl::meta absl::utility
- PRIVATE_COMPILE_FLAGS
+ HDRS
+ "bad_optional_access.h"
+ SRCS
+ "bad_optional_access.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
${ABSL_EXCEPTIONS_FLAG}
- EXPORT_NAME
- variant
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ PUBLIC
)
-#
-## TESTS
-#
-
-
-# test any_test
-set(ANY_TEST_SRC "any_test.cc")
-set(ANY_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate absl::any absl::bad_any_cast absl::test_instance_tracker)
-
-absl_test(
- TARGET
- any_test
- SOURCES
- ${ANY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+absl_cc_library(
+ NAME
+ bad_variant_access
+ HDRS
+ "bad_variant_access.h"
+ SRCS
+ "bad_variant_access.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::base
+ absl::config
+ PUBLIC
)
-
-# test any_test_noexceptions
-absl_test(
- TARGET
- any_test_noexceptions
- SOURCES
- ${ANY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_TEST_PUBLIC_LIBRARIES}
-)
-
-# test any_exception_safety_test
-set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
-set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::any
- absl::base
- absl_internal_exception_safety_testing
-)
-
-absl_test(
- TARGET
- any_exception_safety_test
- SOURCES
- ${ANY_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+absl_cc_test(
+ NAME
+ optional_test
+ SRCS
+ "optional_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::optional
+ absl::base
+ absl::config
+ absl::type_traits
+ absl::strings
+ gmock_main
)
-
-# test span_test
-set(SPAN_TEST_SRC "span_test.cc")
-set(SPAN_TEST_PUBLIC_LIBRARIES absl::base absl::strings absl_internal_throw_delegate absl::span absl::test_instance_tracker)
-
-absl_test(
- TARGET
- span_test
- SOURCES
- ${SPAN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPAN_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+absl_cc_test(
+ NAME
+ optional_exception_safety_test
+ SRCS
+ "optional_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::optional
+ absl::exception_safety_testing
+ gmock_main
)
-
-# test span_test_noexceptions
-absl_test(
- TARGET
- span_test_noexceptions
- SOURCES
- ${SPAN_TEST_SRC}
- PUBLIC_LIBRARIES
- ${SPAN_TEST_PUBLIC_LIBRARIES}
+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
)
-
-
-# test optional_test
-set(OPTIONAL_TEST_SRC "optional_test.cc")
-set(OPTIONAL_TEST_PUBLIC_LIBRARIES absl::base absl_internal_throw_delegate absl::optional absl_bad_optional_access)
-
-absl_test(
- TARGET
- optional_test
- SOURCES
- ${OPTIONAL_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OPTIONAL_TEST_PUBLIC_LIBRARIES}
+absl_cc_test(
+ NAME
+ variant_test
+ SRCS
+ "variant_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ ${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::variant
+ absl::config
+ absl::core_headers
+ absl::memory
+ absl::type_traits
+ absl::strings
+ gmock_main
)
+absl_cc_library(
+ NAME
+ compare
+ HDRS
+ "compare.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::core_headers
+ absl::type_traits
+ PUBLIC
+)
-# test optional_exception_safety_test
-set(OPTIONAL_EXCEPTION_SAFETY_TEST_SRC "optional_exception_safety_test.cc")
-set(OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
- absl::optional
- absl_internal_exception_safety_testing
+absl_cc_test(
+ NAME
+ compare_test
+ SRCS
+ "compare_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::compare
+ gmock_main
)
-absl_test(
- TARGET
- optional_exception_safety_test
- SOURCES
- ${OPTIONAL_EXCEPTION_SAFETY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES}
- PRIVATE_COMPILE_FLAGS
+# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
+else()
+absl_cc_test(
+ NAME
+ variant_exception_safety_test
+ SRCS
+ "variant_exception_safety_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
${ABSL_EXCEPTIONS_FLAG}
+ LINKOPTS
+ ${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
+ DEPS
+ absl::variant
+ absl::config
+ absl::exception_safety_testing
+ absl::memory
+ gmock_main
)
+endif()
diff --git a/absl/types/any.h b/absl/types/any.h
index dc3bfcfe..7cae9dd0 100644
--- a/absl/types/any.h
+++ b/absl/types/any.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -58,15 +58,15 @@
#ifdef ABSL_HAVE_STD_ANY
-#include <any>
+#include <any> // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::any;
using std::any_cast;
using std::bad_any_cast;
using std::make_any;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_ANY
@@ -93,7 +93,7 @@ using std::make_any;
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace any_internal {
@@ -533,7 +533,7 @@ T* any_cast(any* operand) noexcept {
: nullptr;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#undef ABSL_ANY_DETAIL_HAS_RTTI
diff --git a/absl/types/any_exception_safety_test.cc b/absl/types/any_exception_safety_test.cc
index f9dd8c48..5d7d8a5c 100644
--- a/absl/types/any_exception_safety_test.cc
+++ b/absl/types/any_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -135,6 +135,7 @@ TEST(AnyExceptionSafety, Assignment) {
EXPECT_TRUE(strong_empty_any_tester.Test(assign_val));
EXPECT_TRUE(strong_empty_any_tester.Test(move));
}
+
// libstdc++ std::any fails this test
#if !defined(ABSL_HAVE_STD_ANY)
TEST(AnyExceptionSafety, Emplace) {
diff --git a/absl/types/any_test.cc b/absl/types/any_test.cc
index 115e78df..87104721 100644
--- a/absl/types/any_test.cc
+++ b/absl/types/any_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -154,6 +154,14 @@ TEST(AnyTest, InPlaceConstruction) {
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,
@@ -162,12 +170,26 @@ TEST(AnyTest, InPlaceConstructionWithCV) {
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);
@@ -175,6 +197,13 @@ TEST(AnyTest, InPlaceConstructionWithArray) {
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},
@@ -184,6 +213,15 @@ TEST(AnyTest, InPlaceConstructionIlist) {
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>(),
@@ -193,11 +231,25 @@ TEST(AnyTest, InPlaceConstructionIlistWithCV) {
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 {};
@@ -501,7 +553,7 @@ TEST(AnyTest, Copy) {
InstanceTracker tracker_raii;
{
- absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123);
+ absl::any o(absl::in_place_type<CopyableOnlyInstance>, 123);
CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o);
absl::any o2(o);
@@ -622,7 +674,7 @@ TEST(AnyTest, ThrowBadAlloc) {
}
{
- absl::any a(absl::in_place_type_t<int>{});
+ 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{}));
@@ -665,7 +717,7 @@ TEST(AnyTest, FailedCopy) {
}
{
- absl::any src(absl::in_place_type_t<BadCopyable>{});
+ absl::any src(absl::in_place_type<BadCopyable>);
ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src});
}
@@ -677,21 +729,21 @@ TEST(AnyTest, FailedCopy) {
{
BadCopyable bad;
- absl::any target(absl::in_place_type_t<BadCopyable>{});
+ 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_t<BadCopyable>{});
+ 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_t<BadCopyable>{});
- absl::any target(absl::in_place_type_t<BadCopyable>{});
+ 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());
}
@@ -707,7 +759,7 @@ TEST(AnyTest, FailedEmplace) {
{
BadCopyable bad;
- absl::any target(absl::in_place_type_t<int>{});
+ absl::any target(absl::in_place_type<int>);
ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad));
#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__)
// libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an
diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc
index 6244d09e..062675df 100644
--- a/absl/types/bad_any_cast.cc
+++ b/absl/types/bad_any_cast.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
bad_any_cast::~bad_any_cast() = default;
@@ -40,7 +40,7 @@ void ThrowBadAnyCast() {
}
} // namespace any_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_ANY
diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h
index 7df9afbb..8a8476ce 100644
--- a/absl/types/bad_any_cast.h
+++ b/absl/types/bad_any_cast.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,15 +30,15 @@
#include <any>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::bad_any_cast;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_ANY
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// bad_any_cast
@@ -67,7 +67,7 @@ namespace any_internal {
[[noreturn]] void ThrowBadAnyCast();
} // namespace any_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_ANY
diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc
index 2dc74d3b..440adac2 100644
--- a/absl/types/bad_optional_access.cc
+++ b/absl/types/bad_optional_access.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -22,7 +22,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
bad_optional_access::~bad_optional_access() = default;
@@ -42,7 +42,7 @@ void throw_bad_optional_access() {
}
} // namespace optional_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h
index 1f56ff64..585c7c77 100644
--- a/absl/types/bad_optional_access.h
+++ b/absl/types/bad_optional_access.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,15 +30,15 @@
#include <optional>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::bad_optional_access;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_OPTIONAL
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// bad_optional_access
@@ -70,7 +70,7 @@ namespace optional_internal {
[[noreturn]] void throw_bad_optional_access();
} // namespace optional_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc
index a646ff53..d60dae9a 100644
--- a/absl/types/bad_variant_access.cc
+++ b/absl/types/bad_variant_access.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -23,7 +23,7 @@
#include "absl/base/internal/raw_logging.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
//////////////////////////
// [variant.bad.access] //
@@ -58,7 +58,7 @@ void Rethrow() {
}
} // namespace variant_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_VARIANT
diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h
index e0490842..8d635b57 100644
--- a/absl/types/bad_variant_access.h
+++ b/absl/types/bad_variant_access.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -30,15 +30,15 @@
#include <variant>
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::bad_variant_access;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_VARIANT
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// bad_variant_access
@@ -74,7 +74,7 @@ namespace variant_internal {
[[noreturn]] void Rethrow();
} // namespace variant_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_HAVE_STD_VARIANT
diff --git a/absl/types/compare.h b/absl/types/compare.h
new file mode 100644
index 00000000..6f371be7
--- /dev/null
+++ b/absl/types/compare.h
@@ -0,0 +1,510 @@
+// 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.
+//
+// -----------------------------------------------------------------------------
+// compare.h
+// -----------------------------------------------------------------------------
+//
+// This header file defines the `absl::weak_equality`, `absl::strong_equality`,
+// `absl::partial_ordering`, `absl::weak_ordering`, and `absl::strong_ordering`
+// types for storing the results of three way comparisons.
+//
+// Example:
+// absl::weak_ordering compare(const std::string& a, const std::string& b);
+//
+// These are C++11 compatible versions of the C++20 corresponding types
+// (`std::weak_equality`, etc.) and are designed to be drop-in replacements
+// for code compliant with C++20.
+
+#ifndef ABSL_TYPES_COMPARE_H_
+#define ABSL_TYPES_COMPARE_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
+#include <type_traits>
+
+#include "absl/base/attributes.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace compare_internal {
+
+using value_type = int8_t;
+
+template <typename T>
+struct Fail {
+ static_assert(sizeof(T) < 0, "Only literal `0` is allowed.");
+};
+
+// We need the NullPtrT template to avoid triggering the modernize-use-nullptr
+// ClangTidy warning in user code.
+template <typename NullPtrT = std::nullptr_t>
+struct OnlyLiteralZero {
+ constexpr OnlyLiteralZero(NullPtrT) noexcept {} // NOLINT
+
+ // Fails compilation when `nullptr` or integral type arguments other than
+ // `int` are passed. This constructor doesn't accept `int` because literal `0`
+ // has type `int`. Literal `0` arguments will be implicitly converted to
+ // `std::nullptr_t` and accepted by the above constructor, while other `int`
+ // arguments will fail to be converted and cause compilation failure.
+ template <
+ typename T,
+ typename = typename std::enable_if<
+ std::is_same<T, std::nullptr_t>::value ||
+ (std::is_integral<T>::value && !std::is_same<T, int>::value)>::type,
+ typename = typename Fail<T>::type>
+ OnlyLiteralZero(T); // NOLINT
+};
+
+enum class eq : value_type {
+ equal = 0,
+ equivalent = equal,
+ nonequal = 1,
+ nonequivalent = nonequal,
+};
+
+enum class ord : value_type { less = -1, greater = 1 };
+
+enum class ncmp : value_type { unordered = -127 };
+
+// These template base classes allow for defining the values of the constants
+// in the header file (for performance) without using inline variables (which
+// aren't available in C++11).
+template <typename T>
+struct weak_equality_base {
+ ABSL_CONST_INIT static const T equivalent;
+ ABSL_CONST_INIT static const T nonequivalent;
+};
+template <typename T>
+const T weak_equality_base<T>::equivalent(eq::equivalent);
+template <typename T>
+const T weak_equality_base<T>::nonequivalent(eq::nonequivalent);
+
+template <typename T>
+struct strong_equality_base {
+ ABSL_CONST_INIT static const T equal;
+ ABSL_CONST_INIT static const T nonequal;
+ ABSL_CONST_INIT static const T equivalent;
+ ABSL_CONST_INIT static const T nonequivalent;
+};
+template <typename T>
+const T strong_equality_base<T>::equal(eq::equal);
+template <typename T>
+const T strong_equality_base<T>::nonequal(eq::nonequal);
+template <typename T>
+const T strong_equality_base<T>::equivalent(eq::equivalent);
+template <typename T>
+const T strong_equality_base<T>::nonequivalent(eq::nonequivalent);
+
+template <typename T>
+struct partial_ordering_base {
+ ABSL_CONST_INIT static const T less;
+ ABSL_CONST_INIT static const T equivalent;
+ ABSL_CONST_INIT static const T greater;
+ ABSL_CONST_INIT static const T unordered;
+};
+template <typename T>
+const T partial_ordering_base<T>::less(ord::less);
+template <typename T>
+const T partial_ordering_base<T>::equivalent(eq::equivalent);
+template <typename T>
+const T partial_ordering_base<T>::greater(ord::greater);
+template <typename T>
+const T partial_ordering_base<T>::unordered(ncmp::unordered);
+
+template <typename T>
+struct weak_ordering_base {
+ ABSL_CONST_INIT static const T less;
+ ABSL_CONST_INIT static const T equivalent;
+ ABSL_CONST_INIT static const T greater;
+};
+template <typename T>
+const T weak_ordering_base<T>::less(ord::less);
+template <typename T>
+const T weak_ordering_base<T>::equivalent(eq::equivalent);
+template <typename T>
+const T weak_ordering_base<T>::greater(ord::greater);
+
+template <typename T>
+struct strong_ordering_base {
+ ABSL_CONST_INIT static const T less;
+ ABSL_CONST_INIT static const T equal;
+ ABSL_CONST_INIT static const T equivalent;
+ ABSL_CONST_INIT static const T greater;
+};
+template <typename T>
+const T strong_ordering_base<T>::less(ord::less);
+template <typename T>
+const T strong_ordering_base<T>::equal(eq::equal);
+template <typename T>
+const T strong_ordering_base<T>::equivalent(eq::equivalent);
+template <typename T>
+const T strong_ordering_base<T>::greater(ord::greater);
+
+} // namespace compare_internal
+
+class weak_equality
+ : public compare_internal::weak_equality_base<weak_equality> {
+ explicit constexpr weak_equality(compare_internal::eq v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ friend struct compare_internal::weak_equality_base<weak_equality>;
+
+ public:
+ // Comparisons
+ friend constexpr bool operator==(
+ weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ == 0;
+ }
+ friend constexpr bool operator!=(
+ weak_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ != 0;
+ }
+ friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+ weak_equality v) noexcept {
+ return 0 == v.value_;
+ }
+ friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+ weak_equality v) noexcept {
+ return 0 != v.value_;
+ }
+
+ private:
+ compare_internal::value_type value_;
+};
+
+class strong_equality
+ : public compare_internal::strong_equality_base<strong_equality> {
+ explicit constexpr strong_equality(compare_internal::eq v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ friend struct compare_internal::strong_equality_base<strong_equality>;
+
+ public:
+ // Conversion
+ constexpr operator weak_equality() const noexcept { // NOLINT
+ return value_ == 0 ? weak_equality::equivalent
+ : weak_equality::nonequivalent;
+ }
+ // Comparisons
+ friend constexpr bool operator==(
+ strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ == 0;
+ }
+ friend constexpr bool operator!=(
+ strong_equality v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ != 0;
+ }
+ friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+ strong_equality v) noexcept {
+ return 0 == v.value_;
+ }
+ friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+ strong_equality v) noexcept {
+ return 0 != v.value_;
+ }
+
+ private:
+ compare_internal::value_type value_;
+};
+
+class partial_ordering
+ : public compare_internal::partial_ordering_base<partial_ordering> {
+ explicit constexpr partial_ordering(compare_internal::eq v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ explicit constexpr partial_ordering(compare_internal::ord v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ explicit constexpr partial_ordering(compare_internal::ncmp v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ friend struct compare_internal::partial_ordering_base<partial_ordering>;
+
+ constexpr bool is_ordered() const noexcept {
+ return value_ !=
+ compare_internal::value_type(compare_internal::ncmp::unordered);
+ }
+
+ public:
+ // Conversion
+ constexpr operator weak_equality() const noexcept { // NOLINT
+ return value_ == 0 ? weak_equality::equivalent
+ : weak_equality::nonequivalent;
+ }
+ // Comparisons
+ friend constexpr bool operator==(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.is_ordered() && v.value_ == 0;
+ }
+ friend constexpr bool operator!=(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return !v.is_ordered() || v.value_ != 0;
+ }
+ friend constexpr bool operator<(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.is_ordered() && v.value_ < 0;
+ }
+ friend constexpr bool operator<=(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.is_ordered() && v.value_ <= 0;
+ }
+ friend constexpr bool operator>(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.is_ordered() && v.value_ > 0;
+ }
+ friend constexpr bool operator>=(
+ partial_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.is_ordered() && v.value_ >= 0;
+ }
+ friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return v.is_ordered() && 0 == v.value_;
+ }
+ friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return !v.is_ordered() || 0 != v.value_;
+ }
+ friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return v.is_ordered() && 0 < v.value_;
+ }
+ friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return v.is_ordered() && 0 <= v.value_;
+ }
+ friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return v.is_ordered() && 0 > v.value_;
+ }
+ friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+ partial_ordering v) noexcept {
+ return v.is_ordered() && 0 >= v.value_;
+ }
+
+ private:
+ compare_internal::value_type value_;
+};
+
+class weak_ordering
+ : public compare_internal::weak_ordering_base<weak_ordering> {
+ explicit constexpr weak_ordering(compare_internal::eq v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ explicit constexpr weak_ordering(compare_internal::ord v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ friend struct compare_internal::weak_ordering_base<weak_ordering>;
+
+ public:
+ // Conversions
+ constexpr operator weak_equality() const noexcept { // NOLINT
+ return value_ == 0 ? weak_equality::equivalent
+ : weak_equality::nonequivalent;
+ }
+ constexpr operator partial_ordering() const noexcept { // NOLINT
+ return value_ == 0 ? partial_ordering::equivalent
+ : (value_ < 0 ? partial_ordering::less
+ : partial_ordering::greater);
+ }
+ // Comparisons
+ friend constexpr bool operator==(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ == 0;
+ }
+ friend constexpr bool operator!=(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ != 0;
+ }
+ friend constexpr bool operator<(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ < 0;
+ }
+ friend constexpr bool operator<=(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ <= 0;
+ }
+ friend constexpr bool operator>(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ > 0;
+ }
+ friend constexpr bool operator>=(
+ weak_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ >= 0;
+ }
+ friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 == v.value_;
+ }
+ friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 != v.value_;
+ }
+ friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 < v.value_;
+ }
+ friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 <= v.value_;
+ }
+ friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 > v.value_;
+ }
+ friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+ weak_ordering v) noexcept {
+ return 0 >= v.value_;
+ }
+
+ private:
+ compare_internal::value_type value_;
+};
+
+class strong_ordering
+ : public compare_internal::strong_ordering_base<strong_ordering> {
+ explicit constexpr strong_ordering(compare_internal::eq v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ explicit constexpr strong_ordering(compare_internal::ord v) noexcept
+ : value_(static_cast<compare_internal::value_type>(v)) {}
+ friend struct compare_internal::strong_ordering_base<strong_ordering>;
+
+ public:
+ // Conversions
+ constexpr operator weak_equality() const noexcept { // NOLINT
+ return value_ == 0 ? weak_equality::equivalent
+ : weak_equality::nonequivalent;
+ }
+ constexpr operator strong_equality() const noexcept { // NOLINT
+ return value_ == 0 ? strong_equality::equal : strong_equality::nonequal;
+ }
+ constexpr operator partial_ordering() const noexcept { // NOLINT
+ return value_ == 0 ? partial_ordering::equivalent
+ : (value_ < 0 ? partial_ordering::less
+ : partial_ordering::greater);
+ }
+ constexpr operator weak_ordering() const noexcept { // NOLINT
+ return value_ == 0
+ ? weak_ordering::equivalent
+ : (value_ < 0 ? weak_ordering::less : weak_ordering::greater);
+ }
+ // Comparisons
+ friend constexpr bool operator==(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ == 0;
+ }
+ friend constexpr bool operator!=(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ != 0;
+ }
+ friend constexpr bool operator<(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ < 0;
+ }
+ friend constexpr bool operator<=(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ <= 0;
+ }
+ friend constexpr bool operator>(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ > 0;
+ }
+ friend constexpr bool operator>=(
+ strong_ordering v, compare_internal::OnlyLiteralZero<>) noexcept {
+ return v.value_ >= 0;
+ }
+ friend constexpr bool operator==(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 == v.value_;
+ }
+ friend constexpr bool operator!=(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 != v.value_;
+ }
+ friend constexpr bool operator<(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 < v.value_;
+ }
+ friend constexpr bool operator<=(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 <= v.value_;
+ }
+ friend constexpr bool operator>(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 > v.value_;
+ }
+ friend constexpr bool operator>=(compare_internal::OnlyLiteralZero<>,
+ strong_ordering v) noexcept {
+ return 0 >= v.value_;
+ }
+
+ private:
+ compare_internal::value_type value_;
+};
+
+namespace compare_internal {
+// We also provide these comparator adapter functions for internal absl use.
+
+// Helper functions to do a boolean comparison of two keys given a boolean
+// or three-way comparator.
+// SFINAE prevents implicit conversions to bool (such as from int).
+template <typename Bool,
+ absl::enable_if_t<std::is_same<bool, Bool>::value, int> = 0>
+constexpr bool compare_result_as_less_than(const Bool r) { return r; }
+constexpr bool compare_result_as_less_than(const absl::weak_ordering r) {
+ return r < 0;
+}
+
+template <typename Compare, typename K, typename LK>
+constexpr bool do_less_than_comparison(const Compare &compare, const K &x,
+ const LK &y) {
+ return compare_result_as_less_than(compare(x, y));
+}
+
+// Helper functions to do a three-way comparison of two keys given a boolean or
+// three-way comparator.
+// SFINAE prevents implicit conversions to int (such as from bool).
+template <typename Int,
+ absl::enable_if_t<std::is_same<int, Int>::value, int> = 0>
+constexpr absl::weak_ordering compare_result_as_ordering(const Int c) {
+ return c < 0 ? absl::weak_ordering::less
+ : c == 0 ? absl::weak_ordering::equivalent
+ : absl::weak_ordering::greater;
+}
+constexpr absl::weak_ordering compare_result_as_ordering(
+ const absl::weak_ordering c) {
+ return c;
+}
+
+template <
+ typename Compare, typename K, typename LK,
+ absl::enable_if_t<!std::is_same<bool, absl::result_of_t<Compare(
+ const K &, const LK &)>>::value,
+ int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
+ const K &x, const LK &y) {
+ return compare_result_as_ordering(compare(x, y));
+}
+template <
+ typename Compare, typename K, typename LK,
+ absl::enable_if_t<std::is_same<bool, absl::result_of_t<Compare(
+ const K &, const LK &)>>::value,
+ int> = 0>
+constexpr absl::weak_ordering do_three_way_comparison(const Compare &compare,
+ const K &x, const LK &y) {
+ return compare(x, y) ? absl::weak_ordering::less
+ : compare(y, x) ? absl::weak_ordering::greater
+ : absl::weak_ordering::equivalent;
+}
+
+} // namespace compare_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_TYPES_COMPARE_H_
diff --git a/absl/types/compare_test.cc b/absl/types/compare_test.cc
new file mode 100644
index 00000000..11b3ad40
--- /dev/null
+++ b/absl/types/compare_test.cc
@@ -0,0 +1,313 @@
+// 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.
+
+#include "absl/types/compare.h"
+
+#include "gtest/gtest.h"
+#include "absl/base/casts.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+namespace {
+
+// This is necessary to avoid a bunch of lint warnings suggesting that we use
+// EXPECT_EQ/etc., which doesn't work in this case because they convert the `0`
+// to an int, which can't be converted to the unspecified zero type.
+bool Identity(bool b) { return b; }
+
+TEST(Compare, WeakEquality) {
+ EXPECT_TRUE(Identity(weak_equality::equivalent == 0));
+ EXPECT_TRUE(Identity(0 == weak_equality::equivalent));
+ EXPECT_TRUE(Identity(weak_equality::nonequivalent != 0));
+ EXPECT_TRUE(Identity(0 != weak_equality::nonequivalent));
+}
+
+TEST(Compare, StrongEquality) {
+ EXPECT_TRUE(Identity(strong_equality::equal == 0));
+ EXPECT_TRUE(Identity(0 == strong_equality::equal));
+ EXPECT_TRUE(Identity(strong_equality::nonequal != 0));
+ EXPECT_TRUE(Identity(0 != strong_equality::nonequal));
+ EXPECT_TRUE(Identity(strong_equality::equivalent == 0));
+ EXPECT_TRUE(Identity(0 == strong_equality::equivalent));
+ EXPECT_TRUE(Identity(strong_equality::nonequivalent != 0));
+ EXPECT_TRUE(Identity(0 != strong_equality::nonequivalent));
+}
+
+TEST(Compare, PartialOrdering) {
+ EXPECT_TRUE(Identity(partial_ordering::less < 0));
+ EXPECT_TRUE(Identity(0 > partial_ordering::less));
+ EXPECT_TRUE(Identity(partial_ordering::less <= 0));
+ EXPECT_TRUE(Identity(0 >= partial_ordering::less));
+ EXPECT_TRUE(Identity(partial_ordering::equivalent == 0));
+ EXPECT_TRUE(Identity(0 == partial_ordering::equivalent));
+ EXPECT_TRUE(Identity(partial_ordering::greater > 0));
+ EXPECT_TRUE(Identity(0 < partial_ordering::greater));
+ EXPECT_TRUE(Identity(partial_ordering::greater >= 0));
+ EXPECT_TRUE(Identity(0 <= partial_ordering::greater));
+ EXPECT_TRUE(Identity(partial_ordering::unordered != 0));
+ EXPECT_TRUE(Identity(0 != partial_ordering::unordered));
+ EXPECT_FALSE(Identity(partial_ordering::unordered < 0));
+ EXPECT_FALSE(Identity(0 < partial_ordering::unordered));
+ EXPECT_FALSE(Identity(partial_ordering::unordered <= 0));
+ EXPECT_FALSE(Identity(0 <= partial_ordering::unordered));
+ EXPECT_FALSE(Identity(partial_ordering::unordered > 0));
+ EXPECT_FALSE(Identity(0 > partial_ordering::unordered));
+ EXPECT_FALSE(Identity(partial_ordering::unordered >= 0));
+ EXPECT_FALSE(Identity(0 >= partial_ordering::unordered));
+}
+
+TEST(Compare, WeakOrdering) {
+ EXPECT_TRUE(Identity(weak_ordering::less < 0));
+ EXPECT_TRUE(Identity(0 > weak_ordering::less));
+ EXPECT_TRUE(Identity(weak_ordering::less <= 0));
+ EXPECT_TRUE(Identity(0 >= weak_ordering::less));
+ EXPECT_TRUE(Identity(weak_ordering::equivalent == 0));
+ EXPECT_TRUE(Identity(0 == weak_ordering::equivalent));
+ EXPECT_TRUE(Identity(weak_ordering::greater > 0));
+ EXPECT_TRUE(Identity(0 < weak_ordering::greater));
+ EXPECT_TRUE(Identity(weak_ordering::greater >= 0));
+ EXPECT_TRUE(Identity(0 <= weak_ordering::greater));
+}
+
+TEST(Compare, StrongOrdering) {
+ EXPECT_TRUE(Identity(strong_ordering::less < 0));
+ EXPECT_TRUE(Identity(0 > strong_ordering::less));
+ EXPECT_TRUE(Identity(strong_ordering::less <= 0));
+ EXPECT_TRUE(Identity(0 >= strong_ordering::less));
+ EXPECT_TRUE(Identity(strong_ordering::equal == 0));
+ EXPECT_TRUE(Identity(0 == strong_ordering::equal));
+ EXPECT_TRUE(Identity(strong_ordering::equivalent == 0));
+ EXPECT_TRUE(Identity(0 == strong_ordering::equivalent));
+ EXPECT_TRUE(Identity(strong_ordering::greater > 0));
+ EXPECT_TRUE(Identity(0 < strong_ordering::greater));
+ EXPECT_TRUE(Identity(strong_ordering::greater >= 0));
+ EXPECT_TRUE(Identity(0 <= strong_ordering::greater));
+}
+
+TEST(Compare, Conversions) {
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_equality::equal) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_equality::nonequal) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_equality::equivalent) == 0));
+ EXPECT_TRUE(Identity(
+ implicit_cast<weak_equality>(strong_equality::nonequivalent) != 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(partial_ordering::less) != 0));
+ EXPECT_TRUE(Identity(
+ implicit_cast<weak_equality>(partial_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(partial_ordering::greater) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(partial_ordering::unordered) != 0));
+
+ EXPECT_TRUE(implicit_cast<weak_equality>(weak_ordering::less) != 0);
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(weak_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(weak_ordering::greater) != 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::less) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::less) < 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::less) <= 0));
+ EXPECT_TRUE(Identity(
+ implicit_cast<partial_ordering>(weak_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::greater) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::greater) > 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(weak_ordering::greater) >= 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_ordering::less) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_ordering::equal) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_equality>(strong_ordering::greater) != 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<strong_equality>(strong_ordering::less) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<strong_equality>(strong_ordering::equal) == 0));
+ EXPECT_TRUE(Identity(
+ implicit_cast<strong_equality>(strong_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<strong_equality>(strong_ordering::greater) != 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::less) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::less) < 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::less) <= 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::equal) == 0));
+ EXPECT_TRUE(Identity(
+ implicit_cast<partial_ordering>(strong_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::greater) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::greater) > 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<partial_ordering>(strong_ordering::greater) >= 0));
+
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::less) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::less) < 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::less) <= 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::equal) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::equivalent) == 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::greater) != 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::greater) > 0));
+ EXPECT_TRUE(
+ Identity(implicit_cast<weak_ordering>(strong_ordering::greater) >= 0));
+}
+
+struct WeakOrderingLess {
+ template <typename T>
+ absl::weak_ordering operator()(const T &a, const T &b) const {
+ return a < b ? absl::weak_ordering::less
+ : a == b ? absl::weak_ordering::equivalent
+ : absl::weak_ordering::greater;
+ }
+};
+
+TEST(CompareResultAsLessThan, SanityTest) {
+ EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(false));
+ EXPECT_TRUE(absl::compare_internal::compare_result_as_less_than(true));
+
+ EXPECT_TRUE(
+ absl::compare_internal::compare_result_as_less_than(weak_ordering::less));
+ EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(
+ weak_ordering::equivalent));
+ EXPECT_FALSE(absl::compare_internal::compare_result_as_less_than(
+ weak_ordering::greater));
+}
+
+TEST(DoLessThanComparison, SanityTest) {
+ std::less<int> less;
+ WeakOrderingLess weak;
+
+ EXPECT_TRUE(absl::compare_internal::do_less_than_comparison(less, -1, 0));
+ EXPECT_TRUE(absl::compare_internal::do_less_than_comparison(weak, -1, 0));
+
+ EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(less, 10, 10));
+ EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(weak, 10, 10));
+
+ EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(less, 10, 5));
+ EXPECT_FALSE(absl::compare_internal::do_less_than_comparison(weak, 10, 5));
+}
+
+TEST(CompareResultAsOrdering, SanityTest) {
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::compare_result_as_ordering(-1) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::compare_result_as_ordering(-1) == 0));
+ EXPECT_FALSE(
+ Identity(absl::compare_internal::compare_result_as_ordering(-1) > 0));
+ EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::less) < 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::less) == 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::less) > 0));
+
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::compare_result_as_ordering(0) < 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::compare_result_as_ordering(0) == 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::compare_result_as_ordering(0) > 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::equivalent) < 0));
+ EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::equivalent) == 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::equivalent) > 0));
+
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::compare_result_as_ordering(1) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::compare_result_as_ordering(1) == 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::compare_result_as_ordering(1) > 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::greater) < 0));
+ EXPECT_FALSE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::greater) == 0));
+ EXPECT_TRUE(Identity(absl::compare_internal::compare_result_as_ordering(
+ weak_ordering::greater) > 0));
+}
+
+TEST(DoThreeWayComparison, SanityTest) {
+ std::less<int> less;
+ WeakOrderingLess weak;
+
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, -1, 0) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, -1, 0) == 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, -1, 0) > 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, -1, 0) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, -1, 0) == 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, -1, 0) > 0));
+
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 10) < 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 10) == 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 10) > 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 10) < 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 10) == 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 10) > 0));
+
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 5) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 5) == 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(less, 10, 5) > 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 5) < 0));
+ EXPECT_FALSE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 5) == 0));
+ EXPECT_TRUE(Identity(
+ absl::compare_internal::do_three_way_comparison(weak, 10, 5) > 0));
+}
+
+} // namespace
+} // inline namespace lts_2019_08_08
+} // namespace absl
diff --git a/absl/types/internal/optional.h b/absl/types/internal/optional.h
new file mode 100644
index 00000000..3c8e7cca
--- /dev/null
+++ b/absl/types/internal/optional.h
@@ -0,0 +1,396 @@
+// 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"
+
+// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+//
+// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
+// __cpp_inheriting_constructors is a predefined macro and a recommended way to
+// check for this language feature, but GCC doesn't support it until 5.0 and
+// Clang doesn't support it until 3.6.
+// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
+// constructor. For example, the following code won't work on MSVC 2015 Update3:
+// struct Base {
+// int t;
+// template <typename T>
+// constexpr Base(T t_) : t(t_) {}
+// };
+// struct Foo : Base {
+// using Base::Base;
+// }
+// constexpr Foo foo(0); // doesn't work on MSVC 2015
+#if defined(__clang__)
+#if __has_feature(cxx_inheriting_constructors)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+#elif (defined(__GNUC__) && \
+ (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
+ (__cpp_inheriting_constructors >= 200802) || \
+ (defined(_MSC_VER) && _MSC_VER >= 1910)
+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
+#endif
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// 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 {
+ dummy_type dummy_;
+ T data_;
+ };
+
+ void destruct() noexcept {
+ if (engaged_) {
+ data_.~T();
+ 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_(absl::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 {
+ dummy_type dummy_;
+ T data_;
+ };
+ 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_(absl::forward<Args>(args)...) {}
+};
+
+template <typename T>
+class optional_data_base : public optional_data_dtor_base<T> {
+ protected:
+ using base = optional_data_dtor_base<T>;
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using base::base;
+#else
+ optional_data_base() = default;
+
+ template <typename... Args>
+ constexpr explicit optional_data_base(in_place_t t, Args&&... args)
+ : base(t, absl::forward<Args>(args)...) {}
+#endif
+
+ 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:
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using optional_data_base<T>::optional_data_base;
+#else
+ optional_data() = default;
+
+ template <typename... Args>
+ constexpr explicit optional_data(in_place_t t, Args&&... args)
+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+};
+
+template <typename T>
+class optional_data<T, false> : public optional_data_base<T> {
+ protected:
+#ifdef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+ using optional_data_base<T>::optional_data_base;
+#else
+ template <typename... Args>
+ constexpr explicit optional_data(in_place_t t, Args&&... args)
+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
+#endif
+
+ 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
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+
+#endif // ABSL_TYPES_INTERNAL_OPTIONAL_H_
diff --git a/absl/types/internal/span.h b/absl/types/internal/span.h
new file mode 100644
index 00000000..873ae160
--- /dev/null
+++ b/absl/types/internal/span.h
@@ -0,0 +1,128 @@
+//
+// Copyright 2019 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#ifndef ABSL_TYPES_INTERNAL_SPAN_H_
+#define ABSL_TYPES_INTERNAL_SPAN_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <string>
+#include <type_traits>
+
+#include "absl/algorithm/algorithm.h"
+#include "absl/base/internal/throw_delegate.h"
+#include "absl/meta/type_traits.h"
+
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+namespace span_internal {
+// A constexpr min function
+constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
+
+// Wrappers for access to container data pointers.
+template <typename C>
+constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
+ -> decltype(c.data()) {
+ return c.data();
+}
+
+// Before C++17, std::string::data returns a const char* in all cases.
+inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
+ int) noexcept {
+ return &s[0];
+}
+
+template <typename C>
+constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
+ -> decltype(GetDataImpl(c, 0)) {
+ return GetDataImpl(c, 0);
+}
+
+// Detection idioms for size() and data().
+template <typename C>
+using HasSize =
+ std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
+
+// We want to enable conversion from vector<T*> to Span<const T* const> but
+// disable conversion from vector<Derived> to Span<Base>. Here we use
+// the fact that U** is convertible to Q* const* if and only if Q is the same
+// type or a more cv-qualified version of U. We also decay the result type of
+// data() to avoid problems with classes which have a member function data()
+// which returns a reference.
+template <typename T, typename C>
+using HasData =
+ std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
+ T* const*>;
+
+// Extracts value type from a Container
+template <typename C>
+struct ElementType {
+ using type = typename absl::remove_reference_t<C>::value_type;
+};
+
+template <typename T, size_t N>
+struct ElementType<T (&)[N]> {
+ using type = T;
+};
+
+template <typename C>
+using ElementT = typename ElementType<C>::type;
+
+template <typename T>
+using EnableIfMutable =
+ 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) {
+ static_assert(std::is_const<T>::value, "");
+ return absl::equal(a.begin(), a.end(), b.begin(), b.end());
+}
+
+template <template <typename> class SpanT, typename T>
+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, "");
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+// The `IsConvertible` classes here are needed because of the
+// `std::is_convertible` bug in libcxx when compiled with GCC. This build
+// configuration is used by Android NDK toolchain. Reference link:
+// https://bugs.llvm.org/show_bug.cgi?id=27538.
+template <typename From, typename To>
+struct IsConvertibleHelper {
+ private:
+ static std::true_type testval(To);
+ static std::false_type testval(...);
+
+ public:
+ using type = decltype(testval(std::declval<From>()));
+};
+
+template <typename From, typename To>
+struct IsConvertible : IsConvertibleHelper<From, To>::type {};
+
+// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
+// older version of libcxx is not supported.
+template <typename From, typename To>
+using EnableIfConvertibleTo =
+ typename std::enable_if<IsConvertible<From, To>::value>::type;
+} // namespace span_internal
+} // inline namespace lts_2019_08_08
+} // namespace absl
+
+#endif // ABSL_TYPES_INTERNAL_SPAN_H_
diff --git a/absl/types/internal/variant.h b/absl/types/internal/variant.h
index 875f88e0..4f29f617 100644
--- a/absl/types/internal/variant.h
+++ b/absl/types/internal/variant.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -15,7 +15,6 @@
// 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_variant_internal_H_
#define ABSL_TYPES_variant_internal_H_
@@ -41,7 +40,7 @@
#if !defined(ABSL_HAVE_STD_VARIANT)
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
template <class... Types>
class variant;
@@ -206,7 +205,7 @@ template <class Op, class... Vs>
using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type;
template <class ReturnType, class FunctionObject, class EndIndices,
- std::size_t... BoundIndices>
+ class BoundIndices>
struct MakeVisitationMatrix;
template <class ReturnType, class FunctionObject, std::size_t... Indices>
@@ -220,7 +219,7 @@ constexpr ReturnType call_with_indices(FunctionObject&& function) {
template <class ReturnType, class FunctionObject, std::size_t... BoundIndices>
struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
- BoundIndices...> {
+ index_sequence<BoundIndices...>> {
using ResultType = ReturnType (*)(FunctionObject&&);
static constexpr ResultType Run() {
return &call_with_indices<ReturnType, FunctionObject,
@@ -228,24 +227,34 @@ struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>,
}
};
+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, std::size_t... BoundIndices>
+ class CurrIndices, class BoundIndices>
struct MakeVisitationMatrixImpl;
-template <class ReturnType, class FunctionObject, std::size_t... EndIndices,
- std::size_t... CurrIndices, std::size_t... BoundIndices>
-struct MakeVisitationMatrixImpl<
- ReturnType, FunctionObject, index_sequence<EndIndices...>,
- index_sequence<CurrIndices...>, BoundIndices...> {
+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,
- index_sequence<EndIndices...>>::ResultType,
+ typename MakeVisitationMatrix<ReturnType, FunctionObject, EndIndices,
+ index_sequence<>>::ResultType,
sizeof...(CurrIndices)>;
static constexpr ResultType Run() {
- return {{MakeVisitationMatrix<ReturnType, FunctionObject,
- index_sequence<EndIndices...>,
- BoundIndices..., CurrIndices>::Run()...}};
+ return {{MakeVisitationMatrix<
+ ReturnType, FunctionObject, EndIndices,
+ AppendToIndexSequenceT<BoundIndices, CurrIndices>>::Run()...}};
}
};
@@ -253,10 +262,11 @@ 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...>,
- BoundIndices...>
- : MakeVisitationMatrixImpl<
- ReturnType, FunctionObject, index_sequence<TailEndIndices...>,
- absl::make_index_sequence<HeadEndIndex>, BoundIndices...> {};
+ index_sequence<BoundIndices...>>
+ : MakeVisitationMatrixImpl<ReturnType, FunctionObject,
+ index_sequence<TailEndIndices...>,
+ absl::make_index_sequence<HeadEndIndex>,
+ index_sequence<BoundIndices...>> {};
struct UnreachableSwitchCase {
template <class Op>
@@ -425,7 +435,8 @@ struct VisitIndicesFallback {
static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) {
return AccessSimpleArray(
MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op,
- index_sequence<(EndIndices + 1)...>>::Run(),
+ index_sequence<(EndIndices + 1)...>,
+ index_sequence<>>::Run(),
(indices + 1)...)(absl::forward<Op>(op));
}
};
@@ -839,8 +850,8 @@ struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> {
// 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&);
- static SizeT<I> Run(H&&);
+ static SizeT<I> Run(const H&, SizeT<I>);
+ static SizeT<I> Run(H&&, SizeT<I>);
};
// The following metafunctions are used in constructor and assignment
@@ -862,7 +873,8 @@ struct ConversionIsPossibleImpl : std::false_type {};
template <class Variant, class T>
struct ConversionIsPossibleImpl<
- Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>>
+ Variant, T,
+ void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>(), {}))>>
: std::true_type {};
template <class Variant, class T>
@@ -870,8 +882,9 @@ struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::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>())) {};
+ 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
@@ -1550,8 +1563,8 @@ struct SwapSameIndex {
variant<Types...>* w;
template <std::size_t I>
void operator()(SizeT<I>) const {
- using std::swap;
- swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w));
+ type_traits_internal::Swap(VariantCoreAccess::Access<I>(*v),
+ VariantCoreAccess::Access<I>(*w));
}
void operator()(SizeT<variant_npos>) const {}
@@ -1606,11 +1619,12 @@ struct VariantHashVisitor {
template <typename Variant, typename... Ts>
struct VariantHashBase<Variant,
absl::enable_if_t<absl::conjunction<
- type_traits_internal::IsHashEnabled<Ts>...>::value>,
+ 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;
}
@@ -1625,7 +1639,7 @@ struct VariantHashBase<Variant,
};
} // namespace variant_internal
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // !defined(ABSL_HAVE_STD_VARIANT)
diff --git a/absl/types/optional.h b/absl/types/optional.h
index 1ca8dec6..6614d7bd 100644
--- a/absl/types/optional.h
+++ b/absl/types/optional.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -35,21 +35,21 @@
#ifndef ABSL_TYPES_OPTIONAL_H_
#define ABSL_TYPES_OPTIONAL_H_
-#include "absl/base/config.h"
+#include "absl/base/config.h" // TODO(calabrese) IWYU removal?
#include "absl/utility/utility.h"
#ifdef ABSL_HAVE_STD_OPTIONAL
-#include <optional>
+#include <optional> // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::bad_optional_access;
using std::optional;
using std::make_optional;
using std::nullopt_t;
using std::nullopt;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_OPTIONAL
@@ -57,45 +57,33 @@ using std::nullopt;
#include <cassert>
#include <functional>
#include <initializer_list>
-#include <new>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
-#include "absl/memory/memory.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"
-// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
+namespace absl {
+inline namespace lts_2019_08_08 {
+
+// nullopt_t
//
-// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015.
-// __cpp_inheriting_constructors is a predefined macro and a recommended way to
-// check for this language feature, but GCC doesn't support it until 5.0 and
-// Clang doesn't support it until 3.6.
-// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template
-// constructor. For example, the following code won't work on MSVC 2015 Update3:
-// struct Base {
-// int t;
-// template <typename T>
-// constexpr Base(T t_) : t(t_) {}
-// };
-// struct Foo : Base {
-// using Base::Base;
-// }
-// constexpr Foo foo(0); // doesn't work on MSVC 2015
-#if defined(__clang__)
-#if __has_feature(cxx_inheriting_constructors)
-#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
-#endif
-#elif (defined(__GNUC__) && \
- (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
- (__cpp_inheriting_constructors >= 200802) || \
- (defined(_MSC_VER) && _MSC_VER >= 1910)
-#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
-#endif
+// 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 {}
+};
-namespace absl {
-inline namespace lts_2018_12_18 {
+// 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
@@ -117,10 +105,6 @@ inline namespace lts_2018_12_18 {
// need the inline variable support in C++17 for external linkage.
// * Throws `absl::bad_optional_access` instead of
// `std::bad_optional_access`.
-// * `optional::swap()` and `absl::swap()` relies on
-// `std::is_(nothrow_)swappable()`, which has been introduced in C++17.
-// As a workaround, we assume `is_swappable()` is always `true`
-// and `is_nothrow_swappable()` is the same as `std::is_trivial()`.
// * `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
@@ -130,366 +114,13 @@ inline namespace lts_2018_12_18 {
// 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;
-
-// nullopt_t
-//
-// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type
-// that does not contain a value.
-struct nullopt_t {
- struct init_t {};
- static init_t init;
-
- // It must not be default-constructible to avoid ambiguity for opt = {}.
- // Note the non-const reference, which is to eliminate ambiguity for code
- // like:
- //
- // struct S { int value; };
- //
- // void Test() {
- // optional<S> opt;
- // opt = {{}};
- // }
- explicit constexpr nullopt_t(init_t& /*unused*/) {}
-};
-
-// nullopt
//
-// A tag constant of type `absl::nullopt_t` used to indicate an empty
-// `absl::optional` in certain functions, such as construction or assignment.
-extern const nullopt_t nullopt;
-
-namespace optional_internal {
-
-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 {
- dummy_type dummy_;
- T data_;
- };
-
- void destruct() noexcept {
- if (engaged_) {
- data_.~T();
- 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_(absl::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 {
- dummy_type dummy_;
- T data_;
- };
- 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_(absl::forward<Args>(args)...) {}
-};
-
-template <typename T>
-class optional_data_base : public optional_data_dtor_base<T> {
- protected:
- using base = optional_data_dtor_base<T>;
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using base::base;
-#else
- optional_data_base() = default;
-
- template <typename... Args>
- constexpr explicit optional_data_base(in_place_t t, Args&&... args)
- : base(t, absl::forward<Args>(args)...) {}
-#endif
-
- 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:
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using optional_data_base<T>::optional_data_base;
-#else
- optional_data() = default;
-
- template <typename... Args>
- constexpr explicit optional_data(in_place_t t, Args&&... args)
- : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
-#endif
-};
-
-template <typename T>
-class optional_data<T, false> : public optional_data_base<T> {
- protected:
-#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using optional_data_base<T>::optional_data_base;
-#else
- template <typename... Args>
- constexpr explicit optional_data(in_place_t t, Args&&... args)
- : optional_data_base<T>(t, absl::forward<Args>(args)...) {}
-#endif
-
- optional_data() = default;
-
- optional_data(const optional_data& rhs) {
- 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) {
- 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>
-constexpr copy_traits get_ctor_copy_traits() {
- return 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>
-constexpr copy_traits get_assign_copy_traits() {
- return 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 {
- if (opt) {
- return std::hash<absl::remove_const_t<T> >()(*opt);
- } else {
- return static_cast<size_t>(0x297814aaad196e6dULL);
- }
- }
-};
-
-} // namespace optional_internal
-
-// -----------------------------------------------------------------------------
-// absl::optional class definition
-// -----------------------------------------------------------------------------
-
template <typename T>
class optional : private optional_internal::optional_data<T>,
private optional_internal::optional_ctor_base<
- optional_internal::get_ctor_copy_traits<T>()>,
+ optional_internal::ctor_copy_traits<T>::traits>,
private optional_internal::optional_assign_base<
- optional_internal::get_assign_copy_traits<T>()> {
+ optional_internal::assign_copy_traits<T>::traits> {
using data_base = optional_internal::optional_data<T>;
public:
@@ -514,10 +145,11 @@ class optional : private optional_internal::optional_data<T>,
// 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.)
- //
- // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE.
- template <typename... Args>
- constexpr explicit optional(in_place_t, Args&&... args)
+ 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(), absl::forward<Args>(args)...) {}
// Constructs a non-empty `optional` direct-initialized value of type `T` from
@@ -753,11 +385,10 @@ class optional : private optional_internal::optional_data<T>,
// Swap, standard semantics
void swap(optional& rhs) noexcept(
std::is_nothrow_move_constructible<T>::value&&
- std::is_trivial<T>::value) {
+ type_traits_internal::IsNothrowSwappable<T>::value) {
if (*this) {
if (rhs) {
- using std::swap;
- swap(**this, *rhs);
+ type_traits_internal::Swap(**this, *rhs);
} else {
rhs.construct(std::move(**this));
this->destruct();
@@ -793,7 +424,9 @@ class optional : private optional_internal::optional_data<T>,
//
// Accesses the underlying `T` value of an `optional`. If the `optional` is
// empty, behavior is undefined.
- constexpr const T& operator*() const & { return reference(); }
+ constexpr const T& operator*() const& {
+ return ABSL_ASSERT(this->engaged_), reference();
+ }
T& operator*() & {
assert(this->engaged_);
return reference();
@@ -869,7 +502,7 @@ class optional : private optional_internal::optional_data<T>,
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 by copy constructible");
+ "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)
@@ -879,7 +512,7 @@ class optional : private optional_internal::optional_data<T>,
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 by copy constructible");
+ "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)
@@ -909,12 +542,10 @@ class optional : private optional_internal::optional_data<T>,
//
// Performs a swap between two `absl::optional` objects, using standard
// semantics.
-//
-// NOTE: we assume `is_swappable()` is always `true`. A compile error will
-// result if this is not the case.
-template <typename T,
- typename std::enable_if<std::is_move_constructible<T>::value,
- bool>::type = false>
+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);
}
@@ -1126,7 +757,7 @@ constexpr auto operator>=(const U& v, const optional<T>& x)
return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace std {
@@ -1138,7 +769,6 @@ struct hash<absl::optional<T> >
} // namespace std
-#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS
#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS
#endif // ABSL_HAVE_STD_OPTIONAL
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc
index 313891f7..056ced42 100644
--- a/absl/types/optional_exception_safety_test.cc
+++ b/absl/types/optional_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -18,7 +18,7 @@
#include "absl/base/internal/exception_safety_testing.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
@@ -280,5 +280,5 @@ TEST(OptionalExceptionSafety, NothrowMoveAssign) {
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc
index fc4f00a4..e6a36eb8 100644
--- a/absl/types/optional_test.cc
+++ b/absl/types/optional_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -157,6 +157,16 @@ struct NonMovable {
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);
@@ -169,15 +179,7 @@ TEST(optionalTest, DefaultConstructor) {
TEST(optionalTest, nulloptConstructor) {
absl::optional<int> empty(absl::nullopt);
EXPECT_FALSE(empty);
-
-#ifdef ABSL_HAVE_STD_OPTIONAL
constexpr absl::optional<int> cempty{absl::nullopt};
-#else
- // Creating a temporary absl::nullopt_t object instead of using absl::nullopt
- // because absl::nullopt cannot be constexpr and have external linkage at the
- // same time.
- constexpr absl::optional<int> cempty{absl::nullopt_t(absl::nullopt_t::init)};
-#endif
static_assert(!cempty.has_value(), "");
EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>,
absl::nullopt_t>::value));
@@ -337,16 +339,18 @@ TEST(optionalTest, InPlaceConstructor) {
static_assert((*opt2).x == ConstexprType::kCtorInitializerList, "");
#endif
- // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...>
- // SFINAE is added to optional::optional(absl::in_place_t, Args&&...).
- // struct I {
- // I(absl::in_place_t);
- // };
+ 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<I>,
- // absl::in_place_t>::value));
- // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const
- // 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&&);
@@ -1476,8 +1480,8 @@ TEST(optionalTest, MoveAssignRegression) {
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_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));
}
@@ -1504,18 +1508,19 @@ TEST(optionalTest, Hash) {
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 defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
- _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
- // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
- // static_assert to catch any user-defined type that doesn't provide a hash
- // specialization. So instantiating std::hash<absl::optional<T>> will result
- // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
+#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
@@ -1623,4 +1628,29 @@ TEST(optionalTest, AssignmentConstraints) {
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
diff --git a/absl/types/span.h b/absl/types/span.h
index 99b6765b..98c6cdc8 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -5,7 +5,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -60,115 +60,18 @@
#include <cstddef>
#include <initializer_list>
#include <iterator>
-#include <string>
#include <type_traits>
#include <utility>
-#include "absl/algorithm/algorithm.h"
#include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h"
-#include "absl/base/port.h"
+#include "absl/base/port.h" // TODO(strel): remove this include
#include "absl/meta/type_traits.h"
+#include "absl/types/internal/span.h"
namespace absl {
-inline namespace lts_2018_12_18 {
-
-template <typename T>
-class Span;
-
-namespace span_internal {
-// A constexpr min function
-constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
-
-// Wrappers for access to container data pointers.
-template <typename C>
-constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
- -> decltype(c.data()) {
- return c.data();
-}
-
-// Before C++17, string::data returns a const char* in all cases.
-inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
- int) noexcept {
- return &s[0];
-}
-
-template <typename C>
-constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
- -> decltype(GetDataImpl(c, 0)) {
- return GetDataImpl(c, 0);
-}
-
-// Detection idioms for size() and data().
-template <typename C>
-using HasSize =
- std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>;
-
-// We want to enable conversion from vector<T*> to Span<const T* const> but
-// disable conversion from vector<Derived> to Span<Base>. Here we use
-// the fact that U** is convertible to Q* const* if and only if Q is the same
-// type or a more cv-qualified version of U. We also decay the result type of
-// data() to avoid problems with classes which have a member function data()
-// which returns a reference.
-template <typename T, typename C>
-using HasData =
- std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*,
- T* const*>;
-
-// Extracts value type from a Container
-template <typename C>
-struct ElementType {
- using type = typename absl::remove_reference_t<C>::value_type;
-};
-
-template <typename T, size_t N>
-struct ElementType<T (&)[N]> {
- using type = T;
-};
-
-template <typename C>
-using ElementT = typename ElementType<C>::type;
-
-template <typename T>
-using EnableIfMutable =
- typename std::enable_if<!std::is_const<T>::value, int>::type;
-
-template <typename T>
-bool EqualImpl(Span<T> a, Span<T> b) {
- static_assert(std::is_const<T>::value, "");
- return absl::equal(a.begin(), a.end(), b.begin(), b.end());
-}
-
-template <typename T>
-bool LessThanImpl(Span<T> a, Span<T> b) {
- static_assert(std::is_const<T>::value, "");
- return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
-}
-
-// The `IsConvertible` classes here are needed because of the
-// `std::is_convertible` bug in libcxx when compiled with GCC. This build
-// configuration is used by Android NDK toolchain. Reference link:
-// https://bugs.llvm.org/show_bug.cgi?id=27538.
-template <typename From, typename To>
-struct IsConvertibleHelper {
- private:
- static std::true_type testval(To);
- static std::false_type testval(...);
-
- public:
- using type = decltype(testval(std::declval<From>()));
-};
-
-template <typename From, typename To>
-struct IsConvertible : IsConvertibleHelper<From, To>::type {};
-
-// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
-// older version of libcxx is not supported.
-template <typename From, typename To>
-using EnableIfConvertibleToSpanConst =
- typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type;
-} // namespace span_internal
+inline namespace lts_2019_08_08 {
//------------------------------------------------------------------------------
// Span
@@ -486,6 +389,40 @@ class Span {
: (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
}
+ // Span::first()
+ //
+ // Returns a `Span` containing first `len` elements. Parameter `len` is of
+ // type `size_type` and thus non-negative. `len` value must be <= size().
+ //
+ // Examples:
+ //
+ // std::vector<int> vec = {10, 11, 12, 13};
+ // absl::MakeSpan(vec).first(1); // {10}
+ // absl::MakeSpan(vec).first(3); // {10, 11, 12}
+ // absl::MakeSpan(vec).first(5); // throws std::out_of_range
+ constexpr Span first(size_type len) const {
+ return (len <= size())
+ ? Span(data(), len)
+ : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+ }
+
+ // Span::last()
+ //
+ // Returns a `Span` containing last `len` elements. Parameter `len` is of
+ // type `size_type` and thus non-negative. `len` value must be <= size().
+ //
+ // Examples:
+ //
+ // std::vector<int> vec = {10, 11, 12, 13};
+ // absl::MakeSpan(vec).last(1); // {13}
+ // absl::MakeSpan(vec).last(3); // {11, 12, 13}
+ // absl::MakeSpan(vec).last(5); // throws std::out_of_range
+ constexpr Span last(size_type len) const {
+ return (len <= size())
+ ? Span(size() - len + data(), len)
+ : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
+ }
+
// Support for absl::Hash.
template <typename H>
friend H AbslHashValue(H h, Span v) {
@@ -518,25 +455,27 @@ const typename Span<T>::size_type Span<T>::npos;
// operator==
template <typename T>
bool operator==(Span<T> a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
+ return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
bool operator==(Span<const T> a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
+ return span_internal::EqualImpl<Span, const T>(a, b);
}
template <typename T>
bool operator==(Span<T> a, Span<const T> b) {
- return span_internal::EqualImpl<const T>(a, b);
+ return span_internal::EqualImpl<Span, const T>(a, b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator==(const U& a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
+ return span_internal::EqualImpl<Span, const T>(a, b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator==(Span<T> a, const U& b) {
- return span_internal::EqualImpl<const T>(a, b);
+ return span_internal::EqualImpl<Span, const T>(a, b);
}
// operator!=
@@ -552,13 +491,15 @@ template <typename T>
bool operator!=(Span<T> a, Span<const T> b) {
return !(a == b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator!=(const U& a, Span<T> b) {
return !(a == b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator!=(Span<T> a, const U& b) {
return !(a == b);
}
@@ -566,25 +507,27 @@ bool operator!=(Span<T> a, const U& b) {
// operator<
template <typename T>
bool operator<(Span<T> a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
+ return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
bool operator<(Span<const T> a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
+ return span_internal::LessThanImpl<Span, const T>(a, b);
}
template <typename T>
bool operator<(Span<T> a, Span<const T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
+ return span_internal::LessThanImpl<Span, const T>(a, b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<(const U& a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
+ return span_internal::LessThanImpl<Span, const T>(a, b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<(Span<T> a, const U& b) {
- return span_internal::LessThanImpl<const T>(a, b);
+ return span_internal::LessThanImpl<Span, const T>(a, b);
}
// operator>
@@ -600,13 +543,15 @@ template <typename T>
bool operator>(Span<T> a, Span<const T> b) {
return b < a;
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>(const U& a, Span<T> b) {
return b < a;
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>(Span<T> a, const U& b) {
return b < a;
}
@@ -624,13 +569,15 @@ template <typename T>
bool operator<=(Span<T> a, Span<const T> b) {
return !(b < a);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<=(const U& a, Span<T> b) {
return !(b < a);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator<=(Span<T> a, const U& b) {
return !(b < a);
}
@@ -648,13 +595,15 @@ template <typename T>
bool operator>=(Span<T> a, Span<const T> b) {
return !(a < b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>=(const U& a, Span<T> b) {
return !(a < b);
}
-template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
+template <
+ typename T, typename U,
+ typename = span_internal::EnableIfConvertibleTo<U, absl::Span<const T>>>
bool operator>=(Span<T> a, const U& b) {
return !(a < b);
}
@@ -759,6 +708,6 @@ template <int&... ExplicitArgumentBarrier, typename T, size_t N>
constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
return Span<const T>(array, N);
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TYPES_SPAN_H_
diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc
index bd739ff2..9269f911 100644
--- a/absl/types/span_test.cc
+++ b/absl/types/span_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -139,8 +139,10 @@ TEST(CharSpan, StringCtor) {
EXPECT_THAT(s_const_abc, SpanIs(abc));
EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value));
- EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value));
- EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value));
+ EXPECT_FALSE(
+ (std::is_constructible<absl::Span<const int>, std::string>::value));
+ EXPECT_TRUE(
+ (std::is_convertible<std::string, absl::Span<const char>>::value));
}
TEST(IntSpan, FromConstPointer) {
@@ -293,6 +295,38 @@ TEST(IntSpan, Subspan) {
#endif
}
+TEST(IntSpan, First) {
+ std::vector<int> empty;
+ EXPECT_THAT(absl::MakeSpan(empty).first(0), SpanIs(empty));
+
+ auto ramp = MakeRamp(10);
+ EXPECT_THAT(absl::MakeSpan(ramp).first(0), SpanIs(ramp.data(), 0));
+ EXPECT_THAT(absl::MakeSpan(ramp).first(10), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).first(3), SpanIs(ramp.data(), 3));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(absl::MakeSpan(ramp).first(11), std::out_of_range);
+#else
+ EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).first(11), "");
+#endif
+}
+
+TEST(IntSpan, Last) {
+ std::vector<int> empty;
+ EXPECT_THAT(absl::MakeSpan(empty).last(0), SpanIs(empty));
+
+ auto ramp = MakeRamp(10);
+ EXPECT_THAT(absl::MakeSpan(ramp).last(0), SpanIs(ramp.data() + 10, 0));
+ EXPECT_THAT(absl::MakeSpan(ramp).last(10), SpanIs(ramp));
+ EXPECT_THAT(absl::MakeSpan(ramp).last(3), SpanIs(ramp.data() + 7, 3));
+
+#ifdef ABSL_HAVE_EXCEPTIONS
+ EXPECT_THROW(absl::MakeSpan(ramp).last(11), std::out_of_range);
+#else
+ EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).last(11), "");
+#endif
+}
+
TEST(IntSpan, MakeSpanPtrLength) {
std::vector<int> empty;
auto s_empty = absl::MakeSpan(empty.data(), empty.size());
@@ -767,6 +801,8 @@ TEST(ConstIntSpan, ConstexprTest) {
ABSL_TEST_CONSTEXPR(span.begin());
ABSL_TEST_CONSTEXPR(span.cbegin());
ABSL_TEST_CONSTEXPR(span.subspan(0, 0));
+ ABSL_TEST_CONSTEXPR(span.first(1));
+ ABSL_TEST_CONSTEXPR(span.last(1));
ABSL_TEST_CONSTEXPR(span[0]);
}
@@ -779,4 +815,19 @@ TEST(Span, SpanSize) {
EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*));
}
+TEST(Span, Hash) {
+ int array[] = {1, 2, 3, 4};
+ int array2[] = {1, 2, 3};
+ using T = absl::Span<const int>;
+ EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(
+ {// Empties
+ T(), T(nullptr, 0), T(array, 0), T(array2, 0),
+ // Different array with same value
+ T(array, 3), T(array2), T({1, 2, 3}),
+ // Same array, but different length
+ T(array, 1), T(array, 2),
+ // Same length, but different array
+ T(array + 1, 2), T(array + 2, 2)}));
+}
+
} // namespace
diff --git a/absl/types/variant.h b/absl/types/variant.h
index 4ae4e00d..1c1962b1 100644
--- a/absl/types/variant.h
+++ b/absl/types/variant.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -47,10 +47,10 @@
#ifdef ABSL_HAVE_STD_VARIANT
-#include <variant>
+#include <variant> // IWYU pragma: export
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
using std::bad_variant_access;
using std::get;
using std::get_if;
@@ -63,7 +63,7 @@ using std::variant_npos;
using std::variant_size;
using std::variant_size_v;
using std::visit;
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#else // ABSL_HAVE_STD_VARIANT
@@ -79,7 +79,7 @@ using std::visit;
#include "absl/types/internal/variant.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// -----------------------------------------------------------------------------
// absl::variant
@@ -132,7 +132,12 @@ class variant;
// 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>
+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);
}
@@ -691,12 +696,12 @@ class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> {
//
// Swaps the values of two variant objects.
//
- // TODO(calabrese)
- // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()`
- // which is introduced in C++17. So we assume `is_swappable()` is always
- // true and `is_nothrow_swappable()` is same as `std::is_trivial()`.
void swap(variant& rhs) noexcept(
- absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) {
+ 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());
}
@@ -793,7 +798,7 @@ operator>=(const variant<Types...>& a, const variant<Types...>& b) {
a.index());
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
namespace std {
@@ -814,7 +819,7 @@ struct hash<absl::variant<T...>>
#endif // ABSL_HAVE_STD_VARIANT
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace variant_internal {
// Helper visitor for converting a variant<Ts...>` into another type (mostly
@@ -850,7 +855,7 @@ To ConvertVariantTo(Variant&& variant) {
std::forward<Variant>(variant));
}
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_TYPES_VARIANT_H_
diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc
index 854f1448..efe02310 100644
--- a/absl/types/variant_benchmark.cc
+++ b/absl/types/variant_benchmark.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -28,7 +28,7 @@
#include "absl/utility/utility.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
template <std::size_t I>
@@ -218,5 +218,5 @@ BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2)
->DenseRange(0, integral_pow(4, 2) - 1);
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
index ff166051..31662545 100644
--- a/absl/types/variant_exception_safety_test.cc
+++ b/absl/types/variant_exception_safety_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -24,11 +24,12 @@
#include "absl/base/config.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 {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
using ::testing::MakeExceptionSafetyTester;
@@ -316,6 +317,12 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
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_HAVE_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
@@ -331,6 +338,8 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
auto copy = rhs;
*lhs = std::move(copy);
}));
+#endif // !(defined(ABSL_HAVE_STD_VARIANT) &&
+ // defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8)
}
}
@@ -510,7 +519,7 @@ TEST(VariantExceptionSafetyTest, Swap) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // !defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
diff --git a/absl/types/variant_test.cc b/absl/types/variant_test.cc
index 59223ea7..ff0f187a 100644
--- a/absl/types/variant_test.cc
+++ b/absl/types/variant_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -67,7 +67,7 @@ struct hash<Hashable> {
struct NonHashable {};
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
namespace {
using ::testing::DoubleEq;
@@ -258,7 +258,7 @@ class NonCopyable {
// each type.
template <typename T>
class VariantTypesTest : public ::testing::Test {};
-TYPED_TEST_CASE(VariantTypesTest, VariantTypes);
+TYPED_TEST_SUITE(VariantTypesTest, VariantTypes);
////////////////////
// [variant.ctor] //
@@ -385,7 +385,7 @@ struct MoveOnly {
TEST(VariantTest, TestMoveConstruct) {
using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>;
- V v(in_place_index_t<1>{}, 10);
+ V v(in_place_index<1>, 10);
V v2 = absl::move(v);
EXPECT_EQ(10, absl::get<1>(v2).value);
}
@@ -461,6 +461,11 @@ TYPED_TEST(VariantTypesTest, TestValueCtor) {
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>>;
@@ -484,14 +489,47 @@ TEST(VariantTest, InPlaceType) {
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", 2);
+ 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>;
+ 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>>;
@@ -519,14 +557,51 @@ TEST(VariantTest, InPlaceIndex) {
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", 2);
+ 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>;
+ 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] //
////////////////////
@@ -560,6 +635,7 @@ TEST(VariantTest, TestDtor) {
}
#ifdef ABSL_HAVE_EXCEPTIONS
+
// See comment in absl/base/config.h
#if defined(ABSL_INTERNAL_MSVC_2017_DBG_MODE)
TEST(VariantTest, DISABLED_TestDtorValuelessByException)
@@ -574,7 +650,7 @@ TEST(VariantTest, TestDtorValuelessByException)
{
using Variant = VariantFactory<IncrementInDtor>::Type;
- Variant v(in_place_index_t<0>(), counter_adjuster);
+ Variant v(in_place_index<0>, counter_adjuster);
EXPECT_EQ(0, counter);
ToValuelessByException(v);
@@ -808,7 +884,7 @@ TEST(VariantTest, TestBackupAssign) {
TEST(VariantTest, TestEmplaceBasic) {
using Variant = variant<int, char>;
- Variant v(absl::in_place_index_t<0>{}, 0);
+ Variant v(absl::in_place_index<0>, 0);
{
char& emplace_result = v.emplace<char>();
@@ -832,9 +908,10 @@ TEST(VariantTest, TestEmplaceBasic) {
}
TEST(VariantTest, TestEmplaceInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
- Var v1(absl::in_place_index_t<0>{}, 555);
+ 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));
@@ -845,7 +922,7 @@ TEST(VariantTest, TestEmplaceInitializerList) {
TEST(VariantTest, TestEmplaceIndex) {
using Variant = variant<int, char>;
- Variant v(absl::in_place_index_t<0>{}, 555);
+ Variant v(absl::in_place_index<0>, 555);
{
char& emplace_result = v.emplace<1>();
@@ -869,9 +946,10 @@ TEST(VariantTest, TestEmplaceIndex) {
}
TEST(VariantTest, TestEmplaceIndexInitializerList) {
- using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
+ using Var =
+ variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>;
- Var v1(absl::in_place_index_t<0>{}, 555);
+ 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));
@@ -920,7 +998,7 @@ TEST(VariantTest, NotValuelessByException) {
TEST(VariantTest, IndexValuelessByException) {
using Var = variant<MoveCanThrow, std::string, double>;
- Var v(absl::in_place_index_t<0>{});
+ Var v(absl::in_place_index<0>);
EXPECT_EQ(0, v.index());
ToValuelessByException(v);
EXPECT_EQ(absl::variant_npos, v.index());
@@ -931,7 +1009,7 @@ TEST(VariantTest, IndexValuelessByException) {
TEST(VariantTest, ValuelessByException) {
using Var = variant<MoveCanThrow, std::string, double>;
- Var v(absl::in_place_index_t<0>{});
+ Var v(absl::in_place_index<0>);
EXPECT_FALSE(v.valueless_by_exception());
ToValuelessByException(v);
EXPECT_TRUE(v.valueless_by_exception());
@@ -962,7 +1040,7 @@ TEST(VariantTest, MemberSwap) {
using V = variant<MoveCanThrow, std::string, int>;
int i = 33;
std::string s = "abc";
- V valueless(in_place_index_t<0>{});
+ V valueless(in_place_index<0>);
ToValuelessByException(valueless);
{
// lhs and rhs holds different alternative
@@ -1123,7 +1201,7 @@ TEST(VariantTest, GetIndex) {
using Var = variant<int, std::string, double, int>;
{
- Var v(absl::in_place_index_t<0>{}, 0);
+ Var v(absl::in_place_index<0>, 0);
using LValueGetType = decltype(absl::get<0>(v));
using RValueGetType = decltype(absl::get<0>(absl::move(v)));
@@ -1183,7 +1261,7 @@ TEST(VariantTest, GetIndex) {
}
{
- Var v(absl::in_place_index_t<0>{}, 0);
+ Var v(absl::in_place_index<0>, 0);
v.emplace<3>(1);
using LValueGetType = decltype(absl::get<3>(v));
@@ -1307,7 +1385,8 @@ TEST(VariantTest, BadGetType) {
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>(const_v));
ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(
absl::get<std::string>(std::move(const_v))); // NOLINT
}
@@ -1329,7 +1408,7 @@ TEST(VariantTest, GetIfIndex) {
using Var = variant<int, std::string, double, int>;
{
- Var v(absl::in_place_index_t<0>{}, 0);
+ Var v(absl::in_place_index<0>, 0);
EXPECT_TRUE(noexcept(absl::get_if<0>(&v)));
{
@@ -1364,7 +1443,8 @@ TEST(VariantTest, GetIfIndex) {
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_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1473,7 +1553,8 @@ TEST(VariantTest, GetIfIndex) {
}
{
auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1485,7 +1566,7 @@ TEST(VariantTest, GetIfIndex) {
}
{
- Var v(absl::in_place_index_t<0>{}, 0);
+ Var v(absl::in_place_index<0>, 0);
v.emplace<3>(1);
EXPECT_TRUE(noexcept(absl::get_if<3>(&v)));
@@ -1526,7 +1607,8 @@ TEST(VariantTest, GetIfIndex) {
}
{
auto* bad_elem = absl::get_if<1>(&const_v);
- EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value));
+ EXPECT_TRUE(
+ (std::is_same<decltype(bad_elem), const std::string*>::value));
EXPECT_EQ(bad_elem, nullptr);
}
{
@@ -1630,8 +1712,8 @@ TEST(VariantTest, OperatorRelational) {
TEST(VariantTest, ValuelessOperatorEquals) {
variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
- valueless(absl::in_place_index_t<0>{}),
- other_valueless(absl::in_place_index_t<0>{});
+ valueless(absl::in_place_index<0>),
+ other_valueless(absl::in_place_index<0>);
ToValuelessByException(valueless);
ToValuelessByException(other_valueless);
@@ -1652,8 +1734,8 @@ TEST(VariantTest, ValuelessOperatorEquals) {
TEST(VariantTest, ValuelessOperatorRelational) {
variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"),
- valueless(absl::in_place_index_t<0>{}),
- other_valueless(absl::in_place_index_t<0>{});
+ valueless(absl::in_place_index<0>),
+ other_valueless(absl::in_place_index<0>);
ToValuelessByException(valueless);
ToValuelessByException(other_valueless);
@@ -1712,8 +1794,8 @@ TEST(VariantTest, VisitSimple) {
EXPECT_EQ("B", piece);
struct StrLen {
- int operator()(const std::string& s) const { return s.size(); }
int operator()(const char* s) const { return strlen(s); }
+ int operator()(const std::string& s) const { return s.size(); }
};
v = "SomeStr";
@@ -1729,9 +1811,13 @@ TEST(VariantTest, VisitRValue) {
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
+ 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{}, absl::move(v)));
@@ -1807,9 +1893,9 @@ TEST(VariantTest, VisitVariadic) {
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));
+ EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")),
+ B(absl::string_view("ABC"))),
+ ::testing::Pair(5, 3));
}
TEST(VariantTest, VisitNoArgs) {
@@ -1978,29 +2064,17 @@ TEST(VariantTest, MonostateHash) {
}
TEST(VariantTest, Hash) {
- static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, "");
- static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value,
+ 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,
"");
- static_assert(
- type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
-
-#if defined(_MSC_VER) || \
- (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
- _LIBCPP_STD_VER > 11) || \
- defined(__APPLE__)
- // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
- // static_assert to catch any user-defined type T that doesn't provide a hash
- // specialization. So instantiating std::hash<variant<T>> will result
- // in a hard error which is not SFINAE friendly.
-#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
-#endif
-#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
- static_assert(
- !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
- static_assert(!type_traits_internal::IsHashEnabled<
- variant<Hashable, NonHashable>>::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
@@ -2008,8 +2082,8 @@ TEST(VariantTest, Hash) {
#if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT))
{
// same value as different alternative
- variant<int, int> v0(in_place_index_t<0>{}, 42);
- variant<int, int> v1(in_place_index_t<1>{}, 42);
+ 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));
}
@@ -2024,11 +2098,10 @@ TEST(VariantTest, Hash) {
EXPECT_GT(hashcodes.size(), 90);
// test const-qualified
+ static_assert(type_traits_internal::IsHashable<variant<const int>>::value,
+ "");
static_assert(
- type_traits_internal::IsHashEnabled<variant<const int>>::value, "");
- static_assert(
- type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
- "");
+ 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));
@@ -2040,7 +2113,8 @@ TEST(VariantTest, Hash) {
// Miscellaneous and deprecated tests //
////////////////////////////////////////
-// Test that a set requiring a basic type conversion works correctly.
+// Test that a set requiring a basic type conversion works correctly
+#if !defined(ABSL_HAVE_STD_VARIANT)
TEST(VariantTest, TestConvertingSet) {
typedef variant<double> Variant;
Variant v(1.0);
@@ -2050,6 +2124,7 @@ TEST(VariantTest, TestConvertingSet) {
ASSERT_TRUE(nullptr != absl::get_if<double>(&v));
EXPECT_DOUBLE_EQ(2, absl::get<double>(v));
}
+#endif // ABSL_HAVE_STD_VARIANT
// Test that a vector of variants behaves reasonably.
TEST(VariantTest, Container) {
@@ -2177,7 +2252,8 @@ TEST(VariantTest, TestImplicitConversion) {
// 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"))));
+ EXPECT_TRUE(
+ absl::holds_alternative<std::string>(PassThrough(std::string("foo"))));
}
struct Convertible2;
@@ -2200,8 +2276,10 @@ struct Convertible2 {
};
TEST(VariantTest, TestRvalueConversion) {
+#if !defined(ABSL_HAVE_STD_VARIANT)
variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0)));
+ 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));
@@ -2231,6 +2309,7 @@ TEST(VariantTest, TestRvalueConversion) {
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+#endif // !ABSL_HAVE_STD_VARIANT
variant<Convertible1, Convertible2> variant3(
ConvertVariantTo<variant<Convertible1, Convertible2>>(
@@ -2243,6 +2322,7 @@ TEST(VariantTest, TestRvalueConversion) {
}
TEST(VariantTest, TestLvalueConversion) {
+#if !defined(ABSL_HAVE_STD_VARIANT)
variant<std::string, int> source1 = 0;
variant<double, std::string> destination(
ConvertVariantTo<variant<double, std::string>>(source1));
@@ -2279,6 +2359,7 @@ TEST(VariantTest, TestLvalueConversion) {
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
EXPECT_EQ(42, absl::get<uint32_t>(variant2));
+#endif
variant<Convertible2, Convertible1> source7((Convertible1()));
variant<Convertible1, Convertible2> variant3(
@@ -2293,7 +2374,8 @@ TEST(VariantTest, TestLvalueConversion) {
TEST(VariantTest, TestMoveConversion) {
using Variant =
variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
- using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)}));
@@ -2301,8 +2383,8 @@ TEST(VariantTest, TestMoveConversion) {
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")));
+ var = ConvertVariantTo<Variant>(
+ OtherVariant(absl::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));
}
@@ -2313,7 +2395,8 @@ TEST(VariantTest, DoesNotMoveFromLvalues) {
// whether moving or copying has occurred.
using Variant =
variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>;
- using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::shared_ptr<int>, std::shared_ptr<std::string>>;
Variant v1(std::make_shared<const int>(0));
@@ -2341,8 +2424,10 @@ TEST(VariantTest, DoesNotMoveFromLvalues) {
}
TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
+#if !defined(ABSL_HAVE_STD_VARIANT)
variant<double, std::string> var(
- ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3)));
+ ConvertVariantTo<variant<double, std::string>>(
+ variant<std::string, int>(3)));
EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0));
var = ConvertVariantTo<variant<double, std::string>>(
@@ -2365,6 +2450,7 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+#endif
variant<Convertible1, Convertible2> variant3(
ConvertVariantTo<variant<Convertible1, Convertible2>>(
@@ -2377,6 +2463,7 @@ TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) {
}
TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
+#if !defined(ABSL_HAVE_STD_VARIANT)
variant<std::string, int> source1 = 3;
variant<double, std::string> destination(
ConvertVariantTo<variant<double, std::string>>(source1));
@@ -2384,7 +2471,8 @@ TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
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")));
+ EXPECT_THAT(absl::get_if<std::string>(&destination),
+ Pointee(std::string("foo")));
variant<int, float> source3(42);
variant<double> singleton(ConvertVariantTo<variant<double>>(source3));
@@ -2407,6 +2495,7 @@ TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
variant<uint32_t> source6(42);
variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6);
EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
+#endif // !ABSL_HAVE_STD_VARIANT
variant<Convertible2, Convertible1> source7((Convertible1()));
variant<Convertible1, Convertible2> variant3(
@@ -2421,15 +2510,16 @@ TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) {
TEST(VariantTest, TestMoveConversionViaConvertVariantTo) {
using Variant =
variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>;
- using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
+ using OtherVariant =
+ variant<std::unique_ptr<int>, std::unique_ptr<std::string>>;
Variant var(
ConvertVariantTo<Variant>(OtherVariant{absl::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")));
+ var = ConvertVariantTo<Variant>(
+ OtherVariant(absl::make_unique<std::string>("foo")));
EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var),
Pointee(Pointee(std::string("foo"))));
}
@@ -2599,7 +2689,7 @@ TEST(VariantTest, MoveCtorBug) {
};
{
using V = absl::variant<TrivialCopyNontrivialMove, int>;
- V v1(absl::in_place_index_t<0>{});
+ 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);
@@ -2607,7 +2697,7 @@ TEST(VariantTest, MoveCtorBug) {
{
// 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_t<1>{});
+ 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);
@@ -2615,5 +2705,5 @@ TEST(VariantTest, MoveCtorBug) {
}
} // namespace
-} // inline namespace lts_2018_12_18
+} // inline namespace lts_2019_08_08
} // namespace absl
diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel
index c01b49bc..d41317e3 100644
--- a/absl/utility/BUILD.bazel
+++ b/absl/utility/BUILD.bazel
@@ -1,6 +1,7 @@
load(
- "//absl:copts.bzl",
+ "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
+ "ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
@@ -12,6 +13,7 @@ cc_library(
name = "utility",
hdrs = ["utility.h"],
copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:base_internal",
"//absl/base:config",
@@ -23,6 +25,7 @@ cc_test(
name = "utility_test",
srcs = ["utility_test.cc"],
copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":utility",
"//absl/base:core_headers",
diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt
index dc3a6319..e1edd19a 100644
--- a/absl/utility/CMakeLists.txt
+++ b/absl/utility/CMakeLists.txt
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# 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,
@@ -14,39 +14,31 @@
# limitations under the License.
#
-
-list(APPEND UTILITY_PUBLIC_HEADERS
- "utility.h"
-)
-
-absl_header_library(
- TARGET
- absl_utility
- PUBLIC_LIBRARIES
- absl::base
- EXPORT_NAME
+absl_cc_library(
+ NAME
utility
+ HDRS
+ "utility.h"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ DEPS
+ absl::base_internal
+ absl::config
+ absl::type_traits
+ PUBLIC
)
-
-#
-## TESTS
-#
-
-# test utility_test
-set(UTILITY_TEST_SRC "utility_test.cc")
-set(UTILITY_TEST_PUBLIC_LIBRARIES
- absl::base
- absl::memory
- absl::strings
- absl::utility
-)
-
-absl_test(
- TARGET
+absl_cc_test(
+ NAME
utility_test
- SOURCES
- ${UTILITY_TEST_SRC}
- PUBLIC_LIBRARIES
- ${UTILITY_TEST_PUBLIC_LIBRARIES}
+ SRCS
+ "utility_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::utility
+ absl::core_headers
+ absl::memory
+ absl::strings
+ gmock_main
)
diff --git a/absl/utility/utility.h b/absl/utility/utility.h
index 66e22dc2..bc9af048 100644
--- a/absl/utility/utility.h
+++ b/absl/utility/utility.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -25,6 +25,7 @@
// * index_sequence_for<Ts...> == std::index_sequence_for<Ts...>
// * 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
@@ -32,10 +33,9 @@
//
// References:
//
-// http://en.cppreference.com/w/cpp/utility/integer_sequence
-// http://en.cppreference.com/w/cpp/utility/apply
+// https://en.cppreference.com/w/cpp/utility/integer_sequence
+// 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_
@@ -51,7 +51,7 @@
#include "absl/meta/type_traits.h"
namespace absl {
-inline namespace lts_2018_12_18 {
+inline namespace lts_2019_08_08 {
// integer_sequence
//
@@ -115,6 +115,20 @@ struct Gen<T, 0> {
using type = integer_sequence<T>;
};
+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
// Compile-time sequences of integers
@@ -164,6 +178,7 @@ ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
#endif // ABSL_HAVE_STD_OPTIONAL
#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT)
+using std::in_place_type;
using std::in_place_type_t;
#else
@@ -173,10 +188,14 @@ using std::in_place_type_t;
// 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>
-struct in_place_type_t {};
+using in_place_type_t = void (*)(utility_internal::InPlaceTypeTag<T>);
+
+template <typename T>
+void in_place_type(utility_internal::InPlaceTypeTag<T>) {}
#endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT
#ifdef ABSL_HAVE_STD_VARIANT
+using std::in_place_index;
using std::in_place_index_t;
#else
@@ -186,7 +205,10 @@ using std::in_place_index_t;
// 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>
-struct in_place_index_t {};
+using in_place_index_t = void (*)(utility_internal::InPlaceIndexTag<I>);
+
+template <size_t I>
+void in_place_index(utility_internal::InPlaceIndexTag<I>) {}
#endif // ABSL_HAVE_STD_VARIANT
// Constexpr move and forward
@@ -235,25 +257,33 @@ auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
//
// Example:
//
-// class Foo{void Bar(int);};
-// void user_function(int, string);
-// void user_function(std::unique_ptr<Foo>);
+// 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, string> tuple1(42, "bar");
-// // Invokes the user function overload on int, string.
-// absl::apply(&user_function, tuple1);
+// std::tuple<int, std::string> tuple1(42, "bar");
+// // Invokes the first user function on int, std::string.
+// absl::apply(&user_function1, tuple1);
//
-// auto foo = absl::make_unique<Foo>();
-// std::tuple<Foo*, int> tuple2(foo.get(), 42);
-// // Invokes the method Bar on foo with one argument 42.
-// absl::apply(&Foo::Bar, foo.get(), 42);
-//
-// std::tuple<std::unique_ptr<Foo>> tuple3(absl::make_unique<Foo>());
+// 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_function, std::move(tuple));
+// 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)
@@ -287,7 +317,34 @@ T exchange(T& obj, U&& new_value) {
return old_value;
}
-} // inline namespace lts_2018_12_18
+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>{});
+}
+
+} // inline namespace lts_2019_08_08
} // namespace absl
#endif // ABSL_UTILITY_UTILITY_H_
diff --git a/absl/utility/utility_test.cc b/absl/utility/utility_test.cc
index 3c447b20..f044ad64 100644
--- a/absl/utility/utility_test.cc
+++ b/absl/utility/utility_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// http://www.apache.org/licenses/LICENSE-2.0
+// 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,
@@ -135,7 +135,7 @@ struct PoorStrCat {
template <typename Tup, size_t... Is>
std::vector<std::string> TupStringVecImpl(const Tup& tup,
- absl::index_sequence<Is...>) {
+ absl::index_sequence<Is...>) {
return {Fmt(std::get<Is>(tup))...};
}
@@ -341,5 +341,36 @@ TEST(ExchangeTest, MoveOnly) {
EXPECT_EQ(1, *b);
}
+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_install_test.sh b/ci/cmake_install_test.sh
new file mode 100755
index 00000000..03eb0432
--- /dev/null
+++ b/ci/cmake_install_test.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# 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.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --tmpfs=/buildfs:exec \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CFLAGS="-Werror" \
+ -e CXXFLAGS="-Werror" \
+ gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
+ /bin/bash CMake/install_test_project/test.sh $@
+
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
new file mode 100755
index 00000000..07af64d0
--- /dev/null
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14 c++17"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190701"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/opt/llvm/clang/bin/clang" \
+ -e BAZEL_COMPILER="llvm" \
+ -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} \
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=${compilation_mode} \
+ --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
+ --copt="-DADDRESS_SANITIZER" \
+ --copt="-DUNDEFINED_BEHAVIOR_SANITIZER" \
+ --copt="-fsanitize=address" \
+ --copt="-fsanitize=float-divide-by-zero" \
+ --copt="-fsanitize=nullability" \
+ --copt="-fsanitize=undefined" \
+ --copt="-fno-sanitize=vptr" \
+ --copt=-Werror \
+ --keep_going \
+ --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_output=errors \
+ --test_tag_filters="-benchmark,-noasan" \
+ ${BAZEL_EXTRA_ARGS:-}
+ done
+done
diff --git a/ci/linux_clang-latest_libcxx_bazel.sh b/ci/linux_clang-latest_libcxx_bazel.sh
new file mode 100755
index 00000000..1197369a
--- /dev/null
+++ b/ci/linux_clang-latest_libcxx_bazel.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14 c++17"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190701"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/opt/llvm/clang/bin/clang" \
+ -e BAZEL_COMPILER="llvm" \
+ -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} \
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=${compilation_mode} \
+ --copt=-Werror \
+ --define="absl=1" \
+ --keep_going \
+ --show_timestamps \
+ --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:-}
+ done
+done
diff --git a/ci/linux_clang-latest_libcxx_tsan_bazel.sh b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
new file mode 100755
index 00000000..04171df8
--- /dev/null
+++ b/ci/linux_clang-latest_libcxx_tsan_bazel.sh
@@ -0,0 +1,83 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14 c++17"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190701"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/opt/llvm/clang/bin/clang" \
+ -e BAZEL_COMPILER="llvm" \
+ -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} \
+ /usr/local/bin/bazel test ... \
+ --build_tag_filters="-notsan" \
+ --compilation_mode=${compilation_mode} \
+ --copt="-DDYNAMIC_ANNOTATIONS_ENABLED=1" \
+ --copt="-DTHREAD_SANITIZER" \
+ --copt="-fsanitize=thread" \
+ --copt=-Werror \
+ --keep_going \
+ --linkopt="-fsanitize=thread" \
+ --show_timestamps \
+ --test_env="TSAN_OPTIONS=report_atomic_races=0" \
+ --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:-}
+ done
+done
diff --git a/ci/linux_clang-latest_libstdcxx_bazel.sh b/ci/linux_clang-latest_libstdcxx_bazel.sh
new file mode 100755
index 00000000..c2217a07
--- /dev/null
+++ b/ci/linux_clang-latest_libstdcxx_bazel.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14 c++17"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_clang-latest:20190701"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/opt/llvm/clang/bin/clang" \
+ -e BAZEL_COMPILER="llvm" \
+ -e BAZEL_CXXOPTS="-std=${std}" \
+ -e CPLUS_INCLUDE_PATH="/usr/include/c++/6" \
+ ${DOCKER_EXTRA_ARGS:-} \
+ ${DOCKER_CONTAINER} \
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=${compilation_mode} \
+ --copt=-Werror \
+ --define="absl=1" \
+ --keep_going \
+ --show_timestamps \
+ --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:-}
+ done
+done
diff --git a/ci/linux_gcc-4.8_libstdcxx_cmake.sh b/ci/linux_gcc-4.8_libstdcxx_cmake.sh
new file mode 100755
index 00000000..4f964e2b
--- /dev/null
+++ b/ci/linux_gcc-4.8_libstdcxx_cmake.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# 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.
+
+# TODO(absl-team): This script isn't fully hermetic because
+# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
+# version of GoogleTest. This means that an upstream change to GoogleTest could
+# break this test. Fix this by allowing this script to pin to a known-good
+# version of GoogleTest.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
+ ABSL_CMAKE_CXX_STANDARDS="11 14"
+fi
+
+if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+ ABSL_CMAKE_BUILD_TYPES="Debug Release"
+fi
+
+for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
+ for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --tmpfs=/buildfs:exec \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CFLAGS="-Werror" \
+ -e CXXFLAGS="-Werror" \
+ gcr.io/google.com/absl-177019/linux_gcc-4.8:20190316 \
+ /bin/bash -c "
+ cd /buildfs && \
+ cmake /abseil-cpp \
+ -DABSL_USE_GOOGLETEST_HEAD=ON \
+ -DABSL_RUN_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DCMAKE_CXX_STANDARD=${std} && \
+ make -j$(nproc) VERBOSE=1 && \
+ ctest -j$(nproc) --output-on-failure"
+ done
+done
diff --git a/ci/linux_gcc-4.9_libstdcxx_bazel.sh b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
new file mode 100755
index 00000000..bdd3e468
--- /dev/null
+++ b/ci/linux_gcc-4.9_libstdcxx_bazel.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20190702"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/usr/bin/gcc-4.9" \
+ -e BAZEL_CXXOPTS="-std=${std}" \
+ ${DOCKER_EXTRA_ARGS:-} \
+ ${DOCKER_CONTAINER} \
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=${compilation_mode} \
+ --copt=-Werror \
+ --define="absl=1" \
+ --keep_going \
+ --show_timestamps \
+ --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:-}
+ done
+done
diff --git a/ci/linux_gcc-latest_libstdcxx_bazel.sh b/ci/linux_gcc-latest_libstdcxx_bazel.sh
new file mode 100755
index 00000000..92933e3a
--- /dev/null
+++ b/ci/linux_gcc-latest_libstdcxx_bazel.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# 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.
+
+# This script that can be invoked to test abseil-cpp in a hermetic environment
+# using a Docker image on Linux. You must have Docker installed to use this
+# script.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${STD:-} ]; then
+ STD="c++11 c++14 c++17"
+fi
+
+if [ -z ${COMPILATION_MODE:-} ]; then
+ COMPILATION_MODE="fastbuild opt"
+fi
+
+readonly DOCKER_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-latest:20190703"
+
+# USE_BAZEL_CACHE=1 only works on Kokoro.
+# Without access to the credentials this won't work.
+if [ ${USE_BAZEL_CACHE:-0} -ne 0 ]; then
+ DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
+ # Bazel doesn't track changes to tools outside of the workspace
+ # (e.g. /usr/bin/gcc), so by appending the docker container to the
+ # remote_http_cache url, we make changes to the container part of
+ # the cache key. Hashing the key is to make it shorter and url-safe.
+ container_key=$(echo ${DOCKER_CONTAINER} | sha256sum | head -c 16)
+ 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
+
+for std in ${STD}; do
+ for compilation_mode in ${COMPILATION_MODE}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with --compilation_mode=${compilation_mode} and --std=${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CC="/usr/local/bin/gcc" \
+ -e BAZEL_CXXOPTS="-std=${std}" \
+ ${DOCKER_EXTRA_ARGS:-} \
+ ${DOCKER_CONTAINER} \
+ /usr/local/bin/bazel test ... \
+ --compilation_mode=${compilation_mode} \
+ --copt=-Werror \
+ --define="absl=1" \
+ --keep_going \
+ --show_timestamps \
+ --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:-}
+ done
+done
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
new file mode 100755
index 00000000..3e831c14
--- /dev/null
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# 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.
+
+# TODO(absl-team): This script isn't fully hermetic because
+# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
+# version of GoogleTest. This means that an upstream change to GoogleTest could
+# break this test. Fix this by allowing this script to pin to a known-good
+# version of GoogleTest.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+if [ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]; then
+ ABSL_CMAKE_CXX_STANDARDS="11 14 17"
+fi
+
+if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+ ABSL_CMAKE_BUILD_TYPES="Debug Release"
+fi
+
+for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
+ for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+ echo "--------------------------------------------------------------------"
+ echo "Testing with CMAKE_BUILD_TYPE=${compilation_mode} and -std=c++${std}"
+
+ time docker run \
+ --volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
+ --workdir=/abseil-cpp \
+ --tmpfs=/buildfs:exec \
+ --cap-add=SYS_PTRACE \
+ --rm \
+ -e CFLAGS="-Werror" \
+ -e CXXFLAGS="-Werror" \
+ gcr.io/google.com/absl-177019/linux_gcc-latest:20190703 \
+ /bin/bash -c "
+ cd /buildfs && \
+ cmake /abseil-cpp \
+ -DABSL_USE_GOOGLETEST_HEAD=ON \
+ -DABSL_RUN_TESTS=ON \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DCMAKE_CXX_STANDARD=${std} && \
+ make -j$(nproc) && \
+ ctest -j$(nproc) --output-on-failure"
+ done
+done
diff --git a/ci/macos_xcode_bazel.sh b/ci/macos_xcode_bazel.sh
new file mode 100755
index 00000000..f0f14280
--- /dev/null
+++ b/ci/macos_xcode_bazel.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# 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.
+
+# This script is invoked on Kokoro to test Abseil on macOS.
+# It is not hermetic and may break when Kokoro is updated.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(realpath $(dirname ${0})/..)"
+fi
+
+# Print the default compiler and Bazel versions.
+echo "---------------"
+gcc -v
+echo "---------------"
+bazel version
+echo "---------------"
+
+cd ${ABSEIL_ROOT}
+
+bazel test ... \
+ --copt=-Werror \
+ --keep_going \
+ --show_timestamps \
+ --test_env="TZDIR=${ABSEIL_ROOT}/absl/time/internal/cctz/testdata/zoneinfo" \
+ --test_output=errors \
+ --test_tag_filters=-benchmark
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
new file mode 100755
index 00000000..75b0f2d1
--- /dev/null
+++ b/ci/macos_xcode_cmake.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 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.
+
+# This script is invoked on Kokoro to test Abseil on macOS.
+# It is not hermetic and may break when Kokoro is updated.
+
+set -euox pipefail
+
+if [ -z ${ABSEIL_ROOT:-} ]; then
+ ABSEIL_ROOT="$(dirname ${0})/.."
+fi
+ABSEIL_ROOT=$(realpath ${ABSEIL_ROOT})
+
+if [ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]; then
+ ABSL_CMAKE_BUILD_TYPES="Debug"
+fi
+
+for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
+ BUILD_DIR=$(mktemp -d ${compilation_mode}.XXXXXXXX)
+ cd ${BUILD_DIR}
+
+ # TODO(absl-team): Enable -Werror once all warnings are fixed.
+ time cmake ${ABSEIL_ROOT} \
+ -GXcode \
+ -DCMAKE_BUILD_TYPE=${compilation_mode} \
+ -DABSL_USE_GOOGLETEST_HEAD=ON \
+ -DABSL_RUN_TESTS=ON
+ time cmake --build .
+ time ctest -C ${compilation_mode} --output-on-failure
+done
diff --git a/conanfile.py b/conanfile.py
new file mode 100644
index 00000000..cd124aae
--- /dev/null
+++ b/conanfile.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Note: Conan is supported on a best-effort basis. Abseil doesn't use Conan
+# internally, so we won't know if it stops working. We may ask community
+# members to help us debug any problems that arise.
+
+from conans import ConanFile, CMake, tools
+from conans.errors import ConanInvalidConfiguration
+from conans.model.version import Version
+
+
+class AbseilConan(ConanFile):
+ name = "abseil"
+ url = "https://github.com/abseil/abseil-cpp"
+ homepage = url
+ author = "Abseil <abseil-io@googlegroups.com>"
+ description = "Abseil Common Libraries (C++) from Google"
+ license = "Apache-2.0"
+ topics = ("conan", "abseil", "abseil-cpp", "google", "common-libraries")
+ exports = ["LICENSE"]
+ exports_sources = ["CMakeLists.txt", "CMake/*", "absl/*"]
+ generators = "cmake"
+ settings = "os", "arch", "compiler", "build_type"
+
+ def configure(self):
+ if self.settings.os == "Windows" and \
+ self.settings.compiler == "Visual Studio" and \
+ Version(self.settings.compiler.version.value) < "14":
+ raise ConanInvalidConfiguration("Abseil does not support MSVC < 14")
+
+ def build(self):
+ tools.replace_in_file("CMakeLists.txt", "project(absl)", "project(absl)\ninclude(conanbuildinfo.cmake)\nconan_basic_setup()")
+ cmake = CMake(self)
+ cmake.definitions["BUILD_TESTING"] = False
+ cmake.configure()
+ cmake.build()
+
+ def package(self):
+ self.copy("LICENSE", dst="licenses")
+ self.copy("*.h", dst="include", src=".")
+ self.copy("*.inc", dst="include", src=".")
+ self.copy("*.a", dst="lib", src=".", keep_path=False)
+ self.copy("*.lib", dst="lib", src=".", keep_path=False)
+
+ def package_info(self):
+ if self.settings.os == "Linux":
+ self.cpp_info.libs = ["-Wl,--start-group"]
+ self.cpp_info.libs.extend(tools.collect_libs(self))
+ if self.settings.os == "Linux":
+ self.cpp_info.libs.extend(["-Wl,--end-group", "pthread"])