summaryrefslogtreecommitdiff
path: root/absl
diff options
context:
space:
mode:
Diffstat (limited to 'absl')
-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
1040 files changed, 46891 insertions, 6466 deletions
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