mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 20:14:23 +08:00
Creation of LTS branch "lts_2020_02_25"
-0033c9ea91Fix build on FreeBSD/powerpc (#616) by kgotlinux <60880393+kgotlinux@users.noreply.github.com> -0d5ce2797eExport of internal Abseil changes by Abseil Team <absl-team@google.com> -b69c7d880cExport of internal Abseil changes by Abseil Team <absl-team@google.com> -2a5633fc07Merge "Export of internal Abseil changes" by Xiaoyi Zhang <zhangxy@google.com> -f9b3d6e493Add RISCV support to GetProgramCounter() (#621) by Khem Raj <raj.khem@gmail.com> -0232c87f21Add missing ABSL_HAVE_VDSO_SUPPORT conditional (#622) by Sinan Kaya <41809318+franksinankaya@users.noreply.github.com> -3c81410510Export of internal Abseil changes by Abseil Team <absl-team@google.com> -c44657f556Export of internal Abseil changes by Abseil Team <absl-team@google.com> -98eb410c93Export of internal Abseil changes by Abseil Team <absl-team@google.com> -bf78e97730Export of internal Abseil changes by Abseil Team <absl-team@google.com> -d95d156716Export of internal Abseil changes by Abseil Team <absl-team@google.com> -24713a7036Export of internal Abseil changes by Abseil Team <absl-team@google.com> -72382c21feExport of internal Abseil changes by Abseil Team <absl-team@google.com> -08a7e7bf97Export of internal Abseil changes by Abseil Team <absl-team@google.com> -36bcd9599bFix pointer format specifier in documentation (#614) by Andre Nguyen <andre-nguyen@users.noreply.github.com> -0f86336b69Export of internal Abseil changes by Abseil Team <absl-team@google.com> -c512f118ddExport of internal Abseil changes by Abseil Team <absl-team@google.com> -37dd2562ecExport of internal Abseil changes by Abseil Team <absl-team@google.com> -4442770261fix: Add support for more ARM processors detection (#608) by Andre Nguyen <andre-nguyen@users.noreply.github.com> -159bf2bf6dExport of internal Abseil changes by Abseil Team <absl-team@google.com> -a2e6adecc2Use https links. (#586) by nlewycky <nicholas@mxc.ca> -564001ae50Export of internal Abseil changes by Abseil Team <absl-team@google.com> -b3aaac8a37Export of internal Abseil changes by Abseil Team <absl-team@google.com> -63ee2f8877Export of internal Abseil changes by Abseil Team <absl-team@google.com> -a048203a88Export of internal Abseil changes by Abseil Team <absl-team@google.com> -1de0166368Export of internal Abseil changes by Abseil Team <absl-team@google.com> -ad904b6cd3Export of internal Abseil changes by Abseil Team <absl-team@google.com> -2923513914Export of internal Abseil changes by Abseil Team <absl-team@google.com> -bf86cfe165Export of internal Abseil changes by Abseil Team <absl-team@google.com> -12bc53e031Export of internal Abseil changes by Abseil Team <absl-team@google.com> -1e39f8626aExport of internal Abseil changes by Abseil Team <absl-team@google.com> -77f87009a3Export of internal Abseil changes by Abseil Team <absl-team@google.com> -d659fe54b3Export of internal Abseil changes by Abseil Team <absl-team@google.com> -a4b757b5d4Export of internal Abseil changes by Abseil Team <absl-team@google.com> -0514227d25Export of internal Abseil changes by Abseil Team <absl-team@google.com> -7f4fe64af8Export of internal Abseil changes by Abseil Team <absl-team@google.com> -16d9fd58a5Export of internal Abseil changes by Abseil Team <absl-team@google.com> -bcaae6009cExport of internal Abseil changes by Abseil Team <absl-team@google.com> -8ba96a8244Export of internal Abseil changes by Abseil Team <absl-team@google.com> -2103fd9acdExport of internal Abseil changes by Abseil Team <absl-team@google.com> -3df7b52a6aExport of internal Abseil changes by Abseil Team <absl-team@google.com> -fa8c75182fExport of internal Abseil changes by Abseil Team <absl-team@google.com> -85092b4b64Fix Conan builds (#400) by Adrian Ostrowski <adr.ostrowski@gmail.com> -e96ae2203bExport of internal Abseil changes by Abseil Team <absl-team@google.com> -20de2db748Export of internal Abseil changes by Abseil Team <absl-team@google.com> -846e5dbedaExport of internal Abseil changes by Abseil Team <absl-team@google.com> -8207907f4fExport of internal Abseil changes by Abseil Team <absl-team@google.com> -078b89b3c0Export of internal Abseil changes by Abseil Team <absl-team@google.com> -19b021cb3fExport of internal Abseil changes by Abseil Team <absl-team@google.com> -ecc0033b54Always enable proper symbolize implementation on Windows ... by Loo Rong Jie <loorongjie@gmail.com> -2796d500aeExport of internal Abseil changes by Abseil Team <absl-team@google.com> -e4c8d0eb8eExport of internal Abseil changes by Abseil Team <absl-team@google.com> -a15364ce4dExport of internal Abseil changes by Abseil Team <absl-team@google.com> -ab3552a189Export of internal Abseil changes by Abseil Team <absl-team@google.com> -e9f9000c7cFix ABSL_WAITER_MODE detection for mingw (#342) by Joe Sylve <Joe.Sylve@gmail.com> -abea769b55Fix ABSL_HAVE_ALARM check on mingw (#341) by Joe Sylve <Joe.Sylve@gmail.com> -25597bdfc1Export of internal Abseil changes by Abseil Team <absl-team@google.com> -aad33fefaaExport of internal Abseil changes by Abseil Team <absl-team@google.com> -8fe7214fe2Export of internal Abseil changes by Abseil Team <absl-team@google.com> -debac94cfbExport of internal Abseil changes by Abseil Team <absl-team@google.com> -882b3501a3Fix spelling errors (#384) by Sungmann Cho <55860394+chosungmann@users.noreply.github.com> -502efe6d78Export of internal Abseil changes by Abseil Team <absl-team@google.com> -ccdd1d57b6Export of internal Abseil changes by Abseil Team <absl-team@google.com> -ddf8e52a29Export of internal Abseil changes by Abseil Team <absl-team@google.com> -6ec1362810Export of internal Abseil changes by Abseil Team <absl-team@google.com> -ac78ffc3bcExport of internal Abseil changes by Abseil Team <absl-team@google.com> -5374c56e51Export of internal Abseil changes by Abseil Team <absl-team@google.com> -97c1664b4bExport of internal Abseil changes by Abseil Team <absl-team@google.com> -325fd7b042Export of internal Abseil changes by Abseil Team <absl-team@google.com> -83c1d65c90Export of internal Abseil changes by Abseil Team <absl-team@google.com> -eb6b7bd23bExport of internal Abseil changes by Abseil Team <absl-team@google.com> -9ddac555b7Export of internal Abseil changes by Abseil Team <absl-team@google.com> -1948f6f967Export of internal Abseil changes by Abseil Team <absl-team@google.com> -a0d1e098c2Export of internal Abseil changes by Abseil Team <absl-team@google.com> -2d2d7fbc28Export of internal Abseil changes by Abseil Team <absl-team@google.com> -0302d1e5fasupppress unused variable warning for gcc (#372) by Martin <pizzard@users.noreply.github.com> -262d74ba81Export of internal Abseil changes by Abseil Team <absl-team@google.com> -f0afae0d49Export of internal Abseil changes by Abseil Team <absl-team@google.com> -0e7afdcbd2Export of internal Abseil changes by Abseil Team <absl-team@google.com> -9a41ffdd3aExport of internal Abseil changes by Abseil Team <absl-team@google.com> -36910d3d7e[bazel] Add fixes for --incompatible_load_cc_rules_from_b... by Yannic <contact@yannic-bonenberger.com> -aae8143cf9Export of internal Abseil changes by Abseil Team <absl-team@google.com> -d9aa92d7fbExport of internal Abseil changes by Abseil Team <absl-team@google.com> -321ab53030Export of internal Abseil changes by Abseil Team <absl-team@google.com> -4ef574064eExport of internal Abseil changes by Abseil Team <absl-team@google.com> GitOrigin-RevId:0033c9ea91Change-Id: I8a2b70063cb3ab40c6943a6db0fe40cae71ed8d7
This commit is contained in:
504
CMake/AbseilDll.cmake
Normal file
504
CMake/AbseilDll.cmake
Normal file
@@ -0,0 +1,504 @@
|
||||
include(CMakeParseArguments)
|
||||
|
||||
set(ABSL_INTERNAL_DLL_FILES
|
||||
"algorithm/algorithm.h"
|
||||
"algorithm/container.h"
|
||||
"base/attributes.h"
|
||||
"base/call_once.h"
|
||||
"base/casts.h"
|
||||
"base/config.h"
|
||||
"base/const_init.h"
|
||||
"base/dynamic_annotations.cc"
|
||||
"base/dynamic_annotations.h"
|
||||
"base/internal/atomic_hook.h"
|
||||
"base/internal/bits.h"
|
||||
"base/internal/cycleclock.cc"
|
||||
"base/internal/cycleclock.h"
|
||||
"base/internal/direct_mmap.h"
|
||||
"base/internal/endian.h"
|
||||
"base/internal/errno_saver.h"
|
||||
"base/internal/exponential_biased.cc"
|
||||
"base/internal/exponential_biased.h"
|
||||
"base/internal/hide_ptr.h"
|
||||
"base/internal/identity.h"
|
||||
"base/internal/invoke.h"
|
||||
"base/internal/inline_variable.h"
|
||||
"base/internal/low_level_alloc.cc"
|
||||
"base/internal/low_level_alloc.h"
|
||||
"base/internal/low_level_scheduling.h"
|
||||
"base/internal/per_thread_tls.h"
|
||||
"base/internal/periodic_sampler.cc"
|
||||
"base/internal/periodic_sampler.h"
|
||||
"base/internal/pretty_function.h"
|
||||
"base/internal/raw_logging.cc"
|
||||
"base/internal/raw_logging.h"
|
||||
"base/internal/scheduling_mode.h"
|
||||
"base/internal/scoped_set_env.cc"
|
||||
"base/internal/scoped_set_env.h"
|
||||
"base/internal/spinlock.cc"
|
||||
"base/internal/spinlock.h"
|
||||
"base/internal/spinlock_wait.cc"
|
||||
"base/internal/spinlock_wait.h"
|
||||
"base/internal/sysinfo.cc"
|
||||
"base/internal/sysinfo.h"
|
||||
"base/internal/thread_annotations.h"
|
||||
"base/internal/thread_identity.cc"
|
||||
"base/internal/thread_identity.h"
|
||||
"base/internal/throw_delegate.cc"
|
||||
"base/internal/throw_delegate.h"
|
||||
"base/internal/tsan_mutex_interface.h"
|
||||
"base/internal/unaligned_access.h"
|
||||
"base/internal/unscaledcycleclock.cc"
|
||||
"base/internal/unscaledcycleclock.h"
|
||||
"base/log_severity.cc"
|
||||
"base/log_severity.h"
|
||||
"base/macros.h"
|
||||
"base/optimization.h"
|
||||
"base/options.h"
|
||||
"base/policy_checks.h"
|
||||
"base/port.h"
|
||||
"base/thread_annotations.h"
|
||||
"container/btree_map.h"
|
||||
"container/btree_set.h"
|
||||
"container/fixed_array.h"
|
||||
"container/flat_hash_map.h"
|
||||
"container/flat_hash_set.h"
|
||||
"container/inlined_vector.h"
|
||||
"container/internal/btree.h"
|
||||
"container/internal/btree_container.h"
|
||||
"container/internal/common.h"
|
||||
"container/internal/compressed_tuple.h"
|
||||
"container/internal/container_memory.h"
|
||||
"container/internal/counting_allocator.h"
|
||||
"container/internal/hash_function_defaults.h"
|
||||
"container/internal/hash_policy_traits.h"
|
||||
"container/internal/hashtable_debug.h"
|
||||
"container/internal/hashtable_debug_hooks.h"
|
||||
"container/internal/hashtablez_sampler.cc"
|
||||
"container/internal/hashtablez_sampler.h"
|
||||
"container/internal/hashtablez_sampler_force_weak_definition.cc"
|
||||
"container/internal/have_sse.h"
|
||||
"container/internal/inlined_vector.h"
|
||||
"container/internal/layout.h"
|
||||
"container/internal/node_hash_policy.h"
|
||||
"container/internal/raw_hash_map.h"
|
||||
"container/internal/raw_hash_set.cc"
|
||||
"container/internal/raw_hash_set.h"
|
||||
"container/internal/tracked.h"
|
||||
"container/node_hash_map.h"
|
||||
"container/node_hash_set.h"
|
||||
"debugging/failure_signal_handler.cc"
|
||||
"debugging/failure_signal_handler.h"
|
||||
"debugging/leak_check.h"
|
||||
"debugging/leak_check_disable.cc"
|
||||
"debugging/stacktrace.cc"
|
||||
"debugging/stacktrace.h"
|
||||
"debugging/symbolize.cc"
|
||||
"debugging/symbolize.h"
|
||||
"debugging/internal/address_is_readable.cc"
|
||||
"debugging/internal/address_is_readable.h"
|
||||
"debugging/internal/demangle.cc"
|
||||
"debugging/internal/demangle.h"
|
||||
"debugging/internal/elf_mem_image.cc"
|
||||
"debugging/internal/elf_mem_image.h"
|
||||
"debugging/internal/examine_stack.cc"
|
||||
"debugging/internal/examine_stack.h"
|
||||
"debugging/internal/stack_consumption.cc"
|
||||
"debugging/internal/stack_consumption.h"
|
||||
"debugging/internal/stacktrace_config.h"
|
||||
"debugging/internal/symbolize.h"
|
||||
"debugging/internal/vdso_support.cc"
|
||||
"debugging/internal/vdso_support.h"
|
||||
"functional/internal/front_binder.h"
|
||||
"functional/bind_front.h"
|
||||
"functional/function_ref.h"
|
||||
"functional/internal/function_ref.h"
|
||||
"hash/hash.h"
|
||||
"hash/internal/city.h"
|
||||
"hash/internal/city.cc"
|
||||
"hash/internal/hash.h"
|
||||
"hash/internal/hash.cc"
|
||||
"hash/internal/spy_hash_state.h"
|
||||
"memory/memory.h"
|
||||
"meta/type_traits.h"
|
||||
"numeric/int128.cc"
|
||||
"numeric/int128.h"
|
||||
"random/bernoulli_distribution.h"
|
||||
"random/beta_distribution.h"
|
||||
"random/bit_gen_ref.h"
|
||||
"random/discrete_distribution.cc"
|
||||
"random/discrete_distribution.h"
|
||||
"random/distribution_format_traits.h"
|
||||
"random/distributions.h"
|
||||
"random/exponential_distribution.h"
|
||||
"random/gaussian_distribution.cc"
|
||||
"random/gaussian_distribution.h"
|
||||
"random/internal/distributions.h"
|
||||
"random/internal/distribution_caller.h"
|
||||
"random/internal/fast_uniform_bits.h"
|
||||
"random/internal/fastmath.h"
|
||||
"random/internal/gaussian_distribution_gentables.cc"
|
||||
"random/internal/generate_real.h"
|
||||
"random/internal/iostream_state_saver.h"
|
||||
"random/internal/nonsecure_base.h"
|
||||
"random/internal/pcg_engine.h"
|
||||
"random/internal/platform.h"
|
||||
"random/internal/pool_urbg.cc"
|
||||
"random/internal/pool_urbg.h"
|
||||
"random/internal/randen.cc"
|
||||
"random/internal/randen.h"
|
||||
"random/internal/randen_detect.cc"
|
||||
"random/internal/randen_detect.h"
|
||||
"random/internal/randen_engine.h"
|
||||
"random/internal/randen_hwaes.cc"
|
||||
"random/internal/randen_hwaes.h"
|
||||
"random/internal/randen_slow.cc"
|
||||
"random/internal/randen_slow.h"
|
||||
"random/internal/randen_traits.h"
|
||||
"random/internal/salted_seed_seq.h"
|
||||
"random/internal/seed_material.cc"
|
||||
"random/internal/seed_material.h"
|
||||
"random/internal/sequence_urbg.h"
|
||||
"random/internal/traits.h"
|
||||
"random/internal/uniform_helper.h"
|
||||
"random/internal/wide_multiply.h"
|
||||
"random/log_uniform_int_distribution.h"
|
||||
"random/poisson_distribution.h"
|
||||
"random/random.h"
|
||||
"random/seed_gen_exception.cc"
|
||||
"random/seed_gen_exception.h"
|
||||
"random/seed_sequences.cc"
|
||||
"random/seed_sequences.h"
|
||||
"random/uniform_int_distribution.h"
|
||||
"random/uniform_real_distribution.h"
|
||||
"random/zipf_distribution.h"
|
||||
"status/status.h"
|
||||
"status/status.cc"
|
||||
"status/status_payload_printer.h"
|
||||
"status/status_payload_printer.cc"
|
||||
"strings/ascii.cc"
|
||||
"strings/ascii.h"
|
||||
"strings/charconv.cc"
|
||||
"strings/charconv.h"
|
||||
"strings/cord.cc"
|
||||
"strings/cord.h"
|
||||
"strings/escaping.cc"
|
||||
"strings/escaping.h"
|
||||
"strings/internal/cord_internal.h"
|
||||
"strings/internal/charconv_bigint.cc"
|
||||
"strings/internal/charconv_bigint.h"
|
||||
"strings/internal/charconv_parse.cc"
|
||||
"strings/internal/charconv_parse.h"
|
||||
"strings/internal/stl_type_traits.h"
|
||||
"strings/match.cc"
|
||||
"strings/match.h"
|
||||
"strings/numbers.cc"
|
||||
"strings/numbers.h"
|
||||
"strings/str_format.h"
|
||||
"strings/str_cat.cc"
|
||||
"strings/str_cat.h"
|
||||
"strings/str_join.h"
|
||||
"strings/str_replace.cc"
|
||||
"strings/str_replace.h"
|
||||
"strings/str_split.cc"
|
||||
"strings/str_split.h"
|
||||
"strings/string_view.cc"
|
||||
"strings/string_view.h"
|
||||
"strings/strip.h"
|
||||
"strings/substitute.cc"
|
||||
"strings/substitute.h"
|
||||
"strings/internal/char_map.h"
|
||||
"strings/internal/escaping.h"
|
||||
"strings/internal/escaping.cc"
|
||||
"strings/internal/memutil.cc"
|
||||
"strings/internal/memutil.h"
|
||||
"strings/internal/ostringstream.cc"
|
||||
"strings/internal/ostringstream.h"
|
||||
"strings/internal/pow10_helper.cc"
|
||||
"strings/internal/pow10_helper.h"
|
||||
"strings/internal/resize_uninitialized.h"
|
||||
"strings/internal/str_format/arg.cc"
|
||||
"strings/internal/str_format/arg.h"
|
||||
"strings/internal/str_format/bind.cc"
|
||||
"strings/internal/str_format/bind.h"
|
||||
"strings/internal/str_format/checker.h"
|
||||
"strings/internal/str_format/extension.cc"
|
||||
"strings/internal/str_format/extension.h"
|
||||
"strings/internal/str_format/float_conversion.cc"
|
||||
"strings/internal/str_format/float_conversion.h"
|
||||
"strings/internal/str_format/output.cc"
|
||||
"strings/internal/str_format/output.h"
|
||||
"strings/internal/str_format/parser.cc"
|
||||
"strings/internal/str_format/parser.h"
|
||||
"strings/internal/str_join_internal.h"
|
||||
"strings/internal/str_split_internal.h"
|
||||
"strings/internal/utf8.cc"
|
||||
"strings/internal/utf8.h"
|
||||
"synchronization/barrier.cc"
|
||||
"synchronization/barrier.h"
|
||||
"synchronization/blocking_counter.cc"
|
||||
"synchronization/blocking_counter.h"
|
||||
"synchronization/mutex.cc"
|
||||
"synchronization/mutex.h"
|
||||
"synchronization/notification.cc"
|
||||
"synchronization/notification.h"
|
||||
"synchronization/internal/create_thread_identity.cc"
|
||||
"synchronization/internal/create_thread_identity.h"
|
||||
"synchronization/internal/graphcycles.cc"
|
||||
"synchronization/internal/graphcycles.h"
|
||||
"synchronization/internal/kernel_timeout.h"
|
||||
"synchronization/internal/per_thread_sem.cc"
|
||||
"synchronization/internal/per_thread_sem.h"
|
||||
"synchronization/internal/thread_pool.h"
|
||||
"synchronization/internal/waiter.cc"
|
||||
"synchronization/internal/waiter.h"
|
||||
"time/civil_time.cc"
|
||||
"time/civil_time.h"
|
||||
"time/clock.cc"
|
||||
"time/clock.h"
|
||||
"time/duration.cc"
|
||||
"time/format.cc"
|
||||
"time/time.cc"
|
||||
"time/time.h"
|
||||
"time/internal/cctz/include/cctz/civil_time.h"
|
||||
"time/internal/cctz/include/cctz/civil_time_detail.h"
|
||||
"time/internal/cctz/include/cctz/time_zone.h"
|
||||
"time/internal/cctz/include/cctz/zone_info_source.h"
|
||||
"time/internal/cctz/src/civil_time_detail.cc"
|
||||
"time/internal/cctz/src/time_zone_fixed.cc"
|
||||
"time/internal/cctz/src/time_zone_fixed.h"
|
||||
"time/internal/cctz/src/time_zone_format.cc"
|
||||
"time/internal/cctz/src/time_zone_if.cc"
|
||||
"time/internal/cctz/src/time_zone_if.h"
|
||||
"time/internal/cctz/src/time_zone_impl.cc"
|
||||
"time/internal/cctz/src/time_zone_impl.h"
|
||||
"time/internal/cctz/src/time_zone_info.cc"
|
||||
"time/internal/cctz/src/time_zone_info.h"
|
||||
"time/internal/cctz/src/time_zone_libc.cc"
|
||||
"time/internal/cctz/src/time_zone_libc.h"
|
||||
"time/internal/cctz/src/time_zone_lookup.cc"
|
||||
"time/internal/cctz/src/time_zone_posix.cc"
|
||||
"time/internal/cctz/src/time_zone_posix.h"
|
||||
"time/internal/cctz/src/tzfile.h"
|
||||
"time/internal/cctz/src/zone_info_source.cc"
|
||||
"types/any.h"
|
||||
"types/bad_any_cast.cc"
|
||||
"types/bad_any_cast.h"
|
||||
"types/bad_optional_access.cc"
|
||||
"types/bad_optional_access.h"
|
||||
"types/bad_variant_access.cc"
|
||||
"types/bad_variant_access.h"
|
||||
"types/compare.h"
|
||||
"types/internal/conformance_aliases.h"
|
||||
"types/internal/conformance_archetype.h"
|
||||
"types/internal/conformance_profile.h"
|
||||
"types/internal/variant.h"
|
||||
"types/optional.h"
|
||||
"types/internal/optional.h"
|
||||
"types/span.h"
|
||||
"types/internal/span.h"
|
||||
"types/variant.h"
|
||||
"utility/utility.h"
|
||||
)
|
||||
|
||||
set(ABSL_INTERNAL_DLL_TARGETS
|
||||
"stacktrace"
|
||||
"symbolize"
|
||||
"examine_stack"
|
||||
"failure_signal_handler"
|
||||
"debugging_internal"
|
||||
"demangle_internal"
|
||||
"leak_check"
|
||||
"leak_check_disable"
|
||||
"stack_consumption"
|
||||
"debugging"
|
||||
"hash"
|
||||
"spy_hash_state"
|
||||
"city"
|
||||
"memory"
|
||||
"strings"
|
||||
"strings_internal"
|
||||
"cord"
|
||||
"str_format"
|
||||
"str_format_internal"
|
||||
"pow10_helper"
|
||||
"int128"
|
||||
"numeric"
|
||||
"utility"
|
||||
"any"
|
||||
"bad_any_cast"
|
||||
"bad_any_cast_impl"
|
||||
"span"
|
||||
"optional"
|
||||
"bad_optional_access"
|
||||
"bad_variant_access"
|
||||
"variant"
|
||||
"compare"
|
||||
"algorithm"
|
||||
"algorithm_container"
|
||||
"graphcycles_internal"
|
||||
"kernel_timeout_internal"
|
||||
"synchronization"
|
||||
"thread_pool"
|
||||
"bind_front"
|
||||
"function_ref"
|
||||
"atomic_hook"
|
||||
"log_severity"
|
||||
"raw_logging_internal"
|
||||
"spinlock_wait"
|
||||
"config"
|
||||
"dynamic_annotations"
|
||||
"core_headers"
|
||||
"malloc_internal"
|
||||
"base_internal"
|
||||
"base"
|
||||
"throw_delegate"
|
||||
"pretty_function"
|
||||
"endian"
|
||||
"bits"
|
||||
"exponential_biased"
|
||||
"periodic_sampler"
|
||||
"scoped_set_env"
|
||||
"type_traits"
|
||||
"meta"
|
||||
"random_random"
|
||||
"random_bit_gen_ref"
|
||||
"random_distributions"
|
||||
"random_seed_gen_exception"
|
||||
"random_seed_sequences"
|
||||
"random_internal_traits"
|
||||
"random_internal_distribution_caller"
|
||||
"random_internal_distributions"
|
||||
"random_internal_fast_uniform_bits"
|
||||
"random_internal_seed_material"
|
||||
"random_internal_pool_urbg"
|
||||
"random_internal_explicit_seed_seq"
|
||||
"random_internal_sequence_urbg"
|
||||
"random_internal_salted_seed_seq"
|
||||
"random_internal_iostream_state_saver"
|
||||
"random_internal_generate_real"
|
||||
"random_internal_wide_multiply"
|
||||
"random_internal_fastmath"
|
||||
"random_internal_nonsecure_base"
|
||||
"random_internal_pcg_engine"
|
||||
"random_internal_randen_engine"
|
||||
"random_internal_platform"
|
||||
"random_internal_randen"
|
||||
"random_internal_randen_slow"
|
||||
"random_internal_randen_hwaes"
|
||||
"random_internal_randen_hwaes_impl"
|
||||
"random_internal_uniform_helper"
|
||||
"status"
|
||||
"time"
|
||||
"civil_time"
|
||||
"time_zone"
|
||||
"container"
|
||||
"btree"
|
||||
"compressed_tuple"
|
||||
"fixed_array"
|
||||
"inlined_vector_internal"
|
||||
"inlined_vector"
|
||||
"counting_allocator"
|
||||
"flat_hash_map"
|
||||
"flat_hash_set"
|
||||
"node_hash_map"
|
||||
"node_hash_set"
|
||||
"container_memory"
|
||||
"hash_function_defaults"
|
||||
"hash_policy_traits"
|
||||
"hashtablez_sampler"
|
||||
"hashtable_debug"
|
||||
"hashtable_debug_hooks"
|
||||
"have_sse"
|
||||
"node_hash_policy"
|
||||
"raw_hash_map"
|
||||
"container_common"
|
||||
"raw_hash_set"
|
||||
"layout"
|
||||
"tracked"
|
||||
)
|
||||
|
||||
function(absl_internal_dll_contains)
|
||||
cmake_parse_arguments(ABSL_INTERNAL_DLL
|
||||
""
|
||||
"OUTPUT;TARGET"
|
||||
""
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
STRING(REGEX REPLACE "^absl::" "" _target ${ABSL_INTERNAL_DLL_TARGET})
|
||||
|
||||
list(FIND
|
||||
ABSL_INTERNAL_DLL_TARGETS
|
||||
"${_target}"
|
||||
_index)
|
||||
|
||||
if (${_index} GREATER -1)
|
||||
set(${ABSL_INTERNAL_DLL_OUTPUT} 1 PARENT_SCOPE)
|
||||
else()
|
||||
set(${ABSL_INTERNAL_DLL_OUTPUT} 0 PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(absl_internal_dll_targets)
|
||||
cmake_parse_arguments(ABSL_INTERNAL_DLL
|
||||
""
|
||||
"OUTPUT"
|
||||
"DEPS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
set(_deps "")
|
||||
foreach(dep IN LISTS ABSL_INTERNAL_DLL_DEPS)
|
||||
absl_internal_dll_contains(TARGET ${dep} OUTPUT _contains)
|
||||
if (_contains)
|
||||
list(APPEND _deps abseil_dll)
|
||||
else()
|
||||
list(APPEND _deps ${dep})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Because we may have added the DLL multiple times
|
||||
list(REMOVE_DUPLICATES _deps)
|
||||
set(${ABSL_INTERNAL_DLL_OUTPUT} "${_deps}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(absl_make_dll)
|
||||
add_library(
|
||||
abseil_dll
|
||||
SHARED
|
||||
"${ABSL_INTERNAL_DLL_FILES}"
|
||||
)
|
||||
target_link_libraries(
|
||||
abseil_dll
|
||||
PRIVATE
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
)
|
||||
set_property(TARGET abseil_dll PROPERTY LINKER_LANGUAGE "CXX")
|
||||
target_include_directories(
|
||||
abseil_dll
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
target_compile_options(
|
||||
abseil_dll
|
||||
PRIVATE
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
)
|
||||
|
||||
target_compile_definitions(
|
||||
abseil_dll
|
||||
PRIVATE
|
||||
ABSL_BUILD_DLL
|
||||
NOMINMAX
|
||||
INTERFACE
|
||||
${ABSL_CC_LIB_DEFINES}
|
||||
)
|
||||
install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
)
|
||||
endfunction()
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include(AbseilConfigureCopts)
|
||||
include(AbseilDll)
|
||||
include(AbseilInstallDirs)
|
||||
|
||||
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
|
||||
@@ -80,95 +81,173 @@ function(absl_cc_library)
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT ABSL_CC_LIB_TESTONLY OR ABSL_RUN_TESTS)
|
||||
if(ABSL_ENABLE_INSTALL)
|
||||
set(_NAME "${ABSL_CC_LIB_NAME}")
|
||||
else()
|
||||
set(_NAME "absl_${ABSL_CC_LIB_NAME}")
|
||||
endif()
|
||||
if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Check if this is a header-only library
|
||||
# Note that as of February 2019, many popular OS's (for example, Ubuntu
|
||||
# 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't
|
||||
# use list(FILTER...)
|
||||
set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}")
|
||||
foreach(src_file IN LISTS ABSL_CC_SRCS)
|
||||
if(${src_file} MATCHES ".*\\.(h|inc)")
|
||||
list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}")
|
||||
endif()
|
||||
endforeach()
|
||||
if("${ABSL_CC_SRCS}" STREQUAL "")
|
||||
if(ABSL_ENABLE_INSTALL)
|
||||
set(_NAME "${ABSL_CC_LIB_NAME}")
|
||||
else()
|
||||
set(_NAME "absl_${ABSL_CC_LIB_NAME}")
|
||||
endif()
|
||||
|
||||
# Check if this is a header-only library
|
||||
# Note that as of February 2019, many popular OS's (for example, Ubuntu
|
||||
# 16.04 LTS) only come with cmake 3.5 by default. For this reason, we can't
|
||||
# use list(FILTER...)
|
||||
set(ABSL_CC_SRCS "${ABSL_CC_LIB_SRCS}")
|
||||
foreach(src_file IN LISTS ABSL_CC_SRCS)
|
||||
if(${src_file} MATCHES ".*\\.(h|inc)")
|
||||
list(REMOVE_ITEM ABSL_CC_SRCS "${src_file}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if("${ABSL_CC_SRCS}" STREQUAL "")
|
||||
set(ABSL_CC_LIB_IS_INTERFACE 1)
|
||||
else()
|
||||
set(ABSL_CC_LIB_IS_INTERFACE 0)
|
||||
endif()
|
||||
|
||||
# Determine this build target's relationship to the DLL. It's one of four things:
|
||||
# 1. "dll" -- This target is part of the DLL
|
||||
# 2. "dll_dep" -- This target is not part of the DLL, but depends on the DLL.
|
||||
# Note that we assume any target not in the DLL depends on the
|
||||
# DLL. This is not a technical necessity but a convenience
|
||||
# which happens to be true, because nearly every target is
|
||||
# part of the DLL.
|
||||
# 3. "shared" -- This is a shared library, perhaps on a non-windows platform
|
||||
# where DLL doesn't make sense.
|
||||
# 4. "static" -- This target does not depend on the DLL and should be built
|
||||
# statically.
|
||||
if (${ABSL_BUILD_DLL})
|
||||
absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
|
||||
if (${_in_dll})
|
||||
# This target should be replaced by the DLL
|
||||
set(_build_type "dll")
|
||||
set(ABSL_CC_LIB_IS_INTERFACE 1)
|
||||
else()
|
||||
set(ABSL_CC_LIB_IS_INTERFACE 0)
|
||||
# Building a DLL, but this target is not part of the DLL
|
||||
set(_build_type "dll_dep")
|
||||
endif()
|
||||
elseif(BUILD_SHARED_LIBS)
|
||||
set(_build_type "shared")
|
||||
else()
|
||||
set(_build_type "static")
|
||||
endif()
|
||||
|
||||
if(NOT ABSL_CC_LIB_IS_INTERFACE)
|
||||
if(NOT ABSL_CC_LIB_IS_INTERFACE)
|
||||
if(${_build_type} STREQUAL "dll_dep")
|
||||
# This target depends on the DLL. When adding dependencies to this target,
|
||||
# any depended-on-target which is contained inside the DLL is replaced
|
||||
# with a dependency on the DLL.
|
||||
add_library(${_NAME} STATIC "")
|
||||
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
|
||||
target_include_directories(${_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
absl_internal_dll_targets(
|
||||
DEPS ${ABSL_CC_LIB_DEPS}
|
||||
OUTPUT _dll_deps
|
||||
)
|
||||
target_compile_options(${_NAME}
|
||||
PRIVATE ${ABSL_CC_LIB_COPTS})
|
||||
target_link_libraries(${_NAME}
|
||||
PUBLIC ${ABSL_CC_LIB_DEPS}
|
||||
PUBLIC ${_dll_deps}
|
||||
PRIVATE
|
||||
${ABSL_CC_LIB_LINKOPTS}
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
)
|
||||
target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
|
||||
|
||||
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||
if(ABSL_CC_LIB_PUBLIC)
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
|
||||
elseif(ABSL_CC_LIB_TESTONLY)
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
|
||||
if (ABSL_CC_LIB_TESTONLY)
|
||||
set(_gtest_link_define "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||
else()
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
|
||||
set(_gtest_link_define)
|
||||
endif()
|
||||
|
||||
# INTERFACE libraries can't have the CXX_STANDARD property set
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
target_compile_definitions(${_NAME}
|
||||
PUBLIC
|
||||
ABSL_CONSUME_DLL
|
||||
"${_gtest_link_define}"
|
||||
)
|
||||
|
||||
# When being installed, we lose the absl_ prefix. We want to put it back
|
||||
# to have properly named lib files. This is a no-op when we are not being
|
||||
# installed.
|
||||
elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
|
||||
add_library(${_NAME} "")
|
||||
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
|
||||
target_link_libraries(${_NAME}
|
||||
PUBLIC ${ABSL_CC_LIB_DEPS}
|
||||
PRIVATE
|
||||
${ABSL_CC_LIB_LINKOPTS}
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid build type: ${_build_type}")
|
||||
endif()
|
||||
|
||||
# Linker language can be inferred from sources, but in the case of DLLs we
|
||||
# don't have any .cc files so it would be ambiguous. We could set it
|
||||
# explicitly only in the case of DLLs but, because "CXX" is always the
|
||||
# correct linker language for static or for shared libraries, we set it
|
||||
# unconditionally.
|
||||
set_property(TARGET ${_NAME} PROPERTY LINKER_LANGUAGE "CXX")
|
||||
|
||||
target_include_directories(${_NAME}
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_options(${_NAME}
|
||||
PRIVATE ${ABSL_CC_LIB_COPTS})
|
||||
target_compile_definitions(${_NAME} PUBLIC ${ABSL_CC_LIB_DEFINES})
|
||||
|
||||
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||
if(ABSL_CC_LIB_PUBLIC)
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
|
||||
elseif(ABSL_CC_LIB_TESTONLY)
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
|
||||
else()
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
|
||||
endif()
|
||||
|
||||
# INTERFACE libraries can't have the CXX_STANDARD property set
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# When being installed, we lose the absl_ prefix. We want to put it back
|
||||
# to have properly named lib files. This is a no-op when we are not being
|
||||
# installed.
|
||||
if(ABSL_ENABLE_INSTALL)
|
||||
set_target_properties(${_NAME} PROPERTIES
|
||||
OUTPUT_NAME "absl_${_NAME}"
|
||||
)
|
||||
else()
|
||||
# Generating header-only library
|
||||
add_library(${_NAME} INTERFACE)
|
||||
target_include_directories(${_NAME}
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_link_libraries(${_NAME}
|
||||
INTERFACE
|
||||
${ABSL_CC_LIB_DEPS}
|
||||
${ABSL_CC_LIB_LINKOPTS}
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
endif()
|
||||
else()
|
||||
# Generating header-only library
|
||||
add_library(${_NAME} INTERFACE)
|
||||
target_include_directories(${_NAME}
|
||||
INTERFACE
|
||||
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
|
||||
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
|
||||
|
||||
if (${_build_type} STREQUAL "dll")
|
||||
set(ABSL_CC_LIB_DEPS abseil_dll)
|
||||
endif()
|
||||
|
||||
# TODO currently we don't install googletest alongside abseil sources, so
|
||||
# installed abseil can't be tested.
|
||||
if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
|
||||
install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(${_NAME}
|
||||
INTERFACE
|
||||
${ABSL_CC_LIB_DEPS}
|
||||
${ABSL_CC_LIB_LINKOPTS}
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
)
|
||||
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
|
||||
endif()
|
||||
|
||||
# TODO currently we don't install googletest alongside abseil sources, so
|
||||
# installed abseil can't be tested.
|
||||
if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
|
||||
install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
|
||||
RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(absl::${ABSL_CC_LIB_NAME} ALIAS ${_NAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# absl_cc_test()
|
||||
@@ -221,23 +300,42 @@ function(absl_cc_test)
|
||||
)
|
||||
|
||||
set(_NAME "absl_${ABSL_CC_TEST_NAME}")
|
||||
|
||||
add_executable(${_NAME} "")
|
||||
target_sources(${_NAME} PRIVATE ${ABSL_CC_TEST_SRCS})
|
||||
target_include_directories(${_NAME}
|
||||
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS}
|
||||
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
|
||||
)
|
||||
target_compile_definitions(${_NAME}
|
||||
PUBLIC ${ABSL_CC_TEST_DEFINES}
|
||||
)
|
||||
|
||||
if (${ABSL_BUILD_DLL})
|
||||
target_compile_definitions(${_NAME}
|
||||
PUBLIC
|
||||
${ABSL_CC_TEST_DEFINES}
|
||||
ABSL_CONSUME_DLL
|
||||
GTEST_LINKED_AS_SHARED_LIBRARY=1
|
||||
)
|
||||
|
||||
# Replace dependencies on targets inside the DLL with abseil_dll itself.
|
||||
absl_internal_dll_targets(
|
||||
DEPS ${ABSL_CC_TEST_DEPS}
|
||||
OUTPUT ABSL_CC_TEST_DEPS
|
||||
)
|
||||
else()
|
||||
target_compile_definitions(${_NAME}
|
||||
PUBLIC
|
||||
${ABSL_CC_TEST_DEFINES}
|
||||
)
|
||||
endif()
|
||||
target_compile_options(${_NAME}
|
||||
PRIVATE ${ABSL_CC_TEST_COPTS}
|
||||
)
|
||||
|
||||
target_link_libraries(${_NAME}
|
||||
PUBLIC ${ABSL_CC_TEST_DEPS}
|
||||
PRIVATE ${ABSL_CC_TEST_LINKOPTS}
|
||||
)
|
||||
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||
# Add all Abseil targets to a folder in the IDE for organization.
|
||||
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/test)
|
||||
|
||||
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
|
||||
|
||||
@@ -7,6 +7,13 @@ configure_file(
|
||||
${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt
|
||||
)
|
||||
|
||||
set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
set(ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1")
|
||||
endif()
|
||||
|
||||
# Configure and build the downloaded googletest source
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
@@ -22,6 +29,9 @@ if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS ${ABSL_SAVE_CMAKE_CXX_FLAGS})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${ABSL_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker settings on Windows
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
|
||||
@@ -85,13 +85,15 @@ https://github.com/abseil/abseil-cpp/issues/109 for more information.
|
||||
Here's a non-exhaustive list of Abseil CMake public targets:
|
||||
|
||||
```cmake
|
||||
absl::base
|
||||
absl::algorithm
|
||||
absl::base
|
||||
absl::debugging
|
||||
absl::flat_hash_map
|
||||
absl::flags
|
||||
absl::memory
|
||||
absl::meta
|
||||
absl::numeric
|
||||
absl::random
|
||||
absl::strings
|
||||
absl::synchronization
|
||||
absl::time
|
||||
|
||||
@@ -32,6 +32,12 @@ cmake_policy(SET CMP0048 NEW)
|
||||
|
||||
project(absl CXX)
|
||||
|
||||
# Output directory is correct by default for most build setups. However, when
|
||||
# building Abseil as a DLL, it is important to have the DLL in the same
|
||||
# directory as the executable using it. Thus, we put all executables in a single
|
||||
# /bin directory.
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
|
||||
# in the source tree of a project that uses it, install rules are disabled.
|
||||
if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
|
||||
@@ -47,6 +53,7 @@ list(APPEND CMAKE_MODULE_PATH
|
||||
|
||||
include(AbseilInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(AbseilDll)
|
||||
include(AbseilHelpers)
|
||||
|
||||
|
||||
|
||||
@@ -123,10 +123,13 @@ will be expected to conform to the style outlined
|
||||
|
||||
## Running Tests
|
||||
|
||||
Use "bazel test <>" functionality to run the unit tests.
|
||||
If you have [Bazel](https://bazel.build/) installed, use `bazel test
|
||||
--test_tag_filters="-benchmark" ...` to run the unit tests.
|
||||
|
||||
Prerequisites for building and running tests are listed in
|
||||
[README.md](README.md)
|
||||
If you are running the Linux operating system and have
|
||||
[Docker](https://www.docker.com/) installed, you can also run the `linux_*.sh`
|
||||
scripts under the `ci/`(https://github.com/abseil/abseil-cpp/tree/master/ci)
|
||||
directory to test Abseil under a variety of conditions.
|
||||
|
||||
## Abseil Committers
|
||||
|
||||
|
||||
164
FAQ.md
Normal file
164
FAQ.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# Abseil FAQ
|
||||
|
||||
## Is Abseil the right home for my utility library?
|
||||
|
||||
Most often the answer to the question is "no." As both the [About
|
||||
Abseil](https://abseil.io/about/) page and our [contributing
|
||||
guidelines](https://github.com/abseil/abseil-cpp/blob/master/CONTRIBUTING.md#contribution-guidelines)
|
||||
explain, Abseil contains a variety of core C++ library code that is widely used
|
||||
at [Google](https://www.google.com/). As such, Abseil's primary purpose is to be
|
||||
used as a dependency by Google's open source C++ projects. While we do hope that
|
||||
Abseil is also useful to the C++ community at large, this added constraint also
|
||||
means that we are unlikely to accept a contribution of utility code that isn't
|
||||
already widely used by Google.
|
||||
|
||||
## How to I set the C++ dialect used to build Abseil?
|
||||
|
||||
The short answer is that whatever mechanism you choose, you need to make sure
|
||||
that you set this option consistently at the global level for your entire
|
||||
project. If, for example, you want to set the C++ dialect to C++17, with
|
||||
[Bazel](https://bazel/build/) as the build system and `gcc` or `clang` as the
|
||||
compiler, there several ways to do this:
|
||||
* Pass `--cxxopt=-std=c++17` on the command line (for example, `bazel build
|
||||
--cxxopt=-std=c++17 ...`)
|
||||
* Set the environment variable `BAZEL_CXXOPTS` (for example,
|
||||
`BAZEL_CXXOPTS=-std=c++17`)
|
||||
* Add `build --cxxopt=-std=c++17` to your [`.bazelrc`
|
||||
file](https://docs.bazel.build/versions/master/guide.html#bazelrc)
|
||||
|
||||
If you are using CMake as the build system, you'll need to add a line like
|
||||
`set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the
|
||||
[CMake build
|
||||
instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md)
|
||||
for more information.
|
||||
|
||||
For a longer answer to this question and to understand why some other approaches
|
||||
don't work, see the answer to ["What is ABI and why don't you recommend using a
|
||||
pre-compiled version of
|
||||
Abseil?"](#what-is-abi-and-why-dont-you-recommend-using-a-pre-compiled-version-of-abseil)
|
||||
|
||||
## What is ABI and why don't you recommend using a pre-compiled version of Abseil?
|
||||
|
||||
For the purposes of this discussion, you can think of
|
||||
[ABI](https://en.wikipedia.org/wiki/Application_binary_interface) as the
|
||||
compiled representation of the interfaces in code. This is in contrast to
|
||||
[API](https://en.wikipedia.org/wiki/Application_programming_interface), which
|
||||
you can think of as the interfaces as defined by the code itself. [Abseil has a
|
||||
strong promise of API compatibility, but does not make any promise of ABI
|
||||
compatibility](https://abseil.io/about/compatibility). Let's take a look at what
|
||||
this means in practice.
|
||||
|
||||
You might be tempted to do something like this in a
|
||||
[Bazel](https://bazel.build/) `BUILD` file:
|
||||
|
||||
```
|
||||
# DON'T DO THIS!!!
|
||||
cc_library(
|
||||
name = "my_library",
|
||||
srcs = ["my_library.cc"],
|
||||
copts = ["-std=c++17"], # May create a mixed-mode compile!
|
||||
deps = ["@com_google_absl//absl/strings"],
|
||||
)
|
||||
```
|
||||
|
||||
Applying `-std=c++17` to an individual target in your `BUILD` file is going to
|
||||
compile that specific target in C++17 mode, but it isn't going to ensure the
|
||||
Abseil library is built in C++17 mode, since the Abseil library itself is a
|
||||
different build target. If your code includes an Abseil header, then your
|
||||
program may contain conflicting definitions of the same
|
||||
class/function/variable/enum, etc. As a rule, all compile options that affect
|
||||
the ABI of a program need to be applied to the entire build on a global basis.
|
||||
|
||||
C++ has something called the [One Definition
|
||||
Rule](https://en.wikipedia.org/wiki/One_Definition_Rule) (ODR). C++ doesn't
|
||||
allow multiple definitions of the same class/function/variable/enum, etc. ODR
|
||||
violations sometimes result in linker errors, but linkers do not always catch
|
||||
violations. Uncaught ODR violations can result in strange runtime behaviors or
|
||||
crashes that can be hard to debug.
|
||||
|
||||
If you build the Abseil library and your code using different compile options
|
||||
that affect ABI, there is a good chance you will run afoul of the One Definition
|
||||
Rule. Examples of GCC compile options that affect ABI include (but aren't
|
||||
limited to) language dialect (e.g. `-std=`), optimization level (e.g. `-O2`),
|
||||
code generation flags (e.g. `-fexceptions`), and preprocessor defines
|
||||
(e.g. `-DNDEBUG`).
|
||||
|
||||
If you use a pre-compiled version of Abseil, (for example, from your Linux
|
||||
distribution package manager or from something like
|
||||
[vcpkg](https://github.com/microsoft/vcpkg)) you have to be very careful to
|
||||
ensure ABI compatibility across the components of your program. The only way you
|
||||
can be sure your program is going to be correct regarding ABI is to ensure
|
||||
you've used the exact same compile options as were used to build the
|
||||
pre-compiled library. This does not mean that Abseil cannot work as part of a
|
||||
Linux distribution since a knowledgeable binary packager will have ensured that
|
||||
all packages have been built with consistent compile options. This is one of the
|
||||
reasons we warn against - though do not outright reject - using Abseil as a
|
||||
pre-compiled library.
|
||||
|
||||
Another possible way that you might afoul of ABI issues is if you accidentally
|
||||
include two versions of Abseil in your program. Multiple versions of Abseil can
|
||||
end up within the same binary if your program uses the Abseil library and
|
||||
another library also transitively depends on Abseil (resulting in what is
|
||||
sometimes called the diamond dependency problem). In cases such as this you must
|
||||
structure your build so that all libraries use the same version of Abseil.
|
||||
[Abseil's strong promise of API compatibility between
|
||||
releases](https://abseil.io/about/compatibility) means the latest "HEAD" release
|
||||
of Abseil is almost certainly the right choice if you are doing as we recommend
|
||||
and building all of your code from source.
|
||||
|
||||
For these reasons we recommend you avoid pre-compiled code and build the Abseil
|
||||
library yourself in a consistent manner with the rest of your code.
|
||||
|
||||
## What is "live at head" and how do I do it?
|
||||
|
||||
From Abseil's point-of-view, "live at head" means that every Abseil source
|
||||
release (which happens on an almost daily basis) is either API compatible with
|
||||
the previous release, or comes with an automated tool that you can run over code
|
||||
to make it compatible. In practice, the need to use an automated tool is
|
||||
extremely rare. This means that upgrading from one source release to another
|
||||
should be a routine practice that can and should be performed often.
|
||||
|
||||
We recommend you update to the [latest commit in the `master` branch of
|
||||
Abseil](https://github.com/abseil/abseil-cpp/commits/master) as often as
|
||||
possible. Not only will you pick up bug fixes more quickly, but if you have good
|
||||
automated testing, you will catch and be able to fix any [Hyrum's
|
||||
Law](https://www.hyrumslaw.com/) dependency problems on an incremental basis
|
||||
instead of being overwhelmed by them and having difficulty isolating them if you
|
||||
wait longer between updates.
|
||||
|
||||
If you are using the [Bazel](https://bazel.build/) build system and its
|
||||
[external dependencies](https://docs.bazel.build/versions/master/external.html)
|
||||
feature, updating the
|
||||
[`http_archive`](https://docs.bazel.build/versions/master/repo/http.html#http_archive)
|
||||
rule in your
|
||||
[`WORKSPACE`](https://docs.bazel.build/versions/master/be/workspace.html) for
|
||||
`com_google_abseil` to point to the [latest commit in the `master` branch of
|
||||
Abseil](https://github.com/abseil/abseil-cpp/commits/master) is all you need to
|
||||
do. For example, on February 11, 2020, the latest commit to the master branch
|
||||
was `98eb410c93ad059f9bba1bf43f5bb916fc92a5ea`. To update to this commit, you
|
||||
would add the following snippet to your `WORKSPACE` file:
|
||||
|
||||
```
|
||||
http_archive(
|
||||
name = "com_google_absl",
|
||||
urls = ["https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip"], # 2020-02-11T18:50:53Z
|
||||
strip_prefix = "abseil-cpp-98eb410c93ad059f9bba1bf43f5bb916fc92a5ea",
|
||||
sha256 = "aabf6c57e3834f8dc3873a927f37eaf69975d4b28117fc7427dfb1c661542a87",
|
||||
)
|
||||
```
|
||||
|
||||
To get the `sha256` of this URL, run `curl -sL --output -
|
||||
https://github.com/abseil/abseil-cpp/archive/98eb410c93ad059f9bba1bf43f5bb916fc92a5ea.zip
|
||||
| sha256sum -`.
|
||||
|
||||
You can commit the updated `WORKSPACE` file to your source control every time
|
||||
you update, and if you have good automated testing, you might even consider
|
||||
automating this.
|
||||
|
||||
One thing we don't recommend is using GitHub's `master.zip` files (for example
|
||||
[https://github.com/abseil/abseil-cpp/archive/master.zip](https://github.com/abseil/abseil-cpp/archive/master.zip)),
|
||||
which are always the latest commit in the `master` branch, to implement live at
|
||||
head. Since these `master.zip` URLs are not versioned, you will lose build
|
||||
reproducibility. In addition, some build systems, including Bazel, will simply
|
||||
cache this file, which means you won't actually be updating to the latest
|
||||
release until your cache is cleared or invalidated.
|
||||
1
LTS.md
1
LTS.md
@@ -12,3 +12,4 @@ The following lists LTS branches and the dates on which they have been released:
|
||||
|
||||
* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
|
||||
* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
|
||||
* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
|
||||
|
||||
38
WORKSPACE
38
WORKSPACE
@@ -1,17 +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.
|
||||
#
|
||||
|
||||
workspace(name = "com_google_absl")
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
# Bazel toolchains
|
||||
http_archive(
|
||||
name = "bazel_toolchains",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/bc09b995c137df042bb80a395b73d7ce6f26afbe.tar.gz",
|
||||
"https://github.com/bazelbuild/bazel-toolchains/archive/bc09b995c137df042bb80a395b73d7ce6f26afbe.tar.gz",
|
||||
],
|
||||
strip_prefix = "bazel-toolchains-bc09b995c137df042bb80a395b73d7ce6f26afbe",
|
||||
sha256 = "4329663fe6c523425ad4d3c989a8ac026b04e1acedeceb56aa4b190fa7f3973c",
|
||||
)
|
||||
|
||||
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
@@ -27,3 +32,14 @@ http_archive(
|
||||
strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
|
||||
sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
|
||||
)
|
||||
|
||||
# C++ rules for Bazel.
|
||||
http_archive(
|
||||
name = "rules_cc",
|
||||
sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
|
||||
strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
|
||||
"https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -14,12 +14,15 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
load(
|
||||
":compiler_config_setting.bzl",
|
||||
"create_llvm_config",
|
||||
)
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
load(":compiler_config_setting.bzl", "create_llvm_config")
|
||||
|
||||
create_llvm_config(
|
||||
name = "llvm_compiler",
|
||||
visibility = [":__subpackages__"],
|
||||
|
||||
@@ -14,20 +14,24 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
|
||||
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(algorithm)
|
||||
add_subdirectory(container)
|
||||
add_subdirectory(debugging)
|
||||
add_subdirectory(flags)
|
||||
add_subdirectory(functional)
|
||||
add_subdirectory(hash)
|
||||
add_subdirectory(memory)
|
||||
add_subdirectory(meta)
|
||||
add_subdirectory(numeric)
|
||||
add_subdirectory(random)
|
||||
add_subdirectory(status)
|
||||
add_subdirectory(strings)
|
||||
add_subdirectory(synchronization)
|
||||
add_subdirectory(time)
|
||||
add_subdirectory(types)
|
||||
add_subdirectory(utility)
|
||||
|
||||
if (${ABSL_BUILD_DLL})
|
||||
absl_make_dll()
|
||||
endif()
|
||||
|
||||
229
absl/abseil.podspec.gen.py
Executable file
229
absl/abseil.podspec.gen.py
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""This script generates abseil.podspec from all BUILD.bazel files.
|
||||
|
||||
This is expected to run on abseil git repository with Bazel 1.0 on Linux.
|
||||
It recursively analyzes BUILD.bazel files using query command of Bazel to
|
||||
dump its build rules in XML format. From these rules, it constructs podspec
|
||||
structure.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import xml.etree.ElementTree
|
||||
|
||||
# Template of root podspec.
|
||||
SPEC_TEMPLATE = """
|
||||
# This file has been automatically generated from a script.
|
||||
# Please make modifications to `abseil.podspec.gen.py` instead.
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'abseil'
|
||||
s.version = '${version}'
|
||||
s.summary = 'Abseil Common Libraries (C++) from Google'
|
||||
s.homepage = 'https://abseil.io'
|
||||
s.license = 'Apache License, Version 2.0'
|
||||
s.authors = { 'Abseil Team' => 'abseil-io@googlegroups.com' }
|
||||
s.source = {
|
||||
:git => 'https://github.com/abseil/abseil-cpp.git',
|
||||
:tag => '${tag}',
|
||||
}
|
||||
s.module_name = 'absl'
|
||||
s.header_mappings_dir = 'absl'
|
||||
s.header_dir = 'absl'
|
||||
s.libraries = 'c++'
|
||||
s.compiler_flags = '-Wno-everything'
|
||||
s.pod_target_xcconfig = {
|
||||
'USER_HEADER_SEARCH_PATHS' => '$(inherited) "$(PODS_TARGET_SRCROOT)"',
|
||||
'USE_HEADERMAP' => 'NO',
|
||||
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
|
||||
}
|
||||
s.ios.deployment_target = '7.0'
|
||||
s.osx.deployment_target = '10.9'
|
||||
s.tvos.deployment_target = '9.0'
|
||||
s.watchos.deployment_target = '2.0'
|
||||
"""
|
||||
|
||||
# Rule object representing the rule of Bazel BUILD.
|
||||
Rule = collections.namedtuple(
|
||||
"Rule", "type name package srcs hdrs textual_hdrs deps visibility testonly")
|
||||
|
||||
|
||||
def get_elem_value(elem, name):
|
||||
"""Returns the value of XML element with the given name."""
|
||||
for child in elem:
|
||||
if child.attrib.get("name") != name:
|
||||
continue
|
||||
if child.tag == "string":
|
||||
return child.attrib.get("value")
|
||||
if child.tag == "boolean":
|
||||
return child.attrib.get("value") == "true"
|
||||
if child.tag == "list":
|
||||
return [nested_child.attrib.get("value") for nested_child in child]
|
||||
raise "Cannot recognize tag: " + child.tag
|
||||
return None
|
||||
|
||||
|
||||
def normalize_paths(paths):
|
||||
"""Returns the list of normalized path."""
|
||||
# e.g. ["//absl/strings:dir/header.h"] -> ["absl/strings/dir/header.h"]
|
||||
return [path.lstrip("/").replace(":", "/") for path in paths]
|
||||
|
||||
|
||||
def parse_rule(elem, package):
|
||||
"""Returns a rule from bazel XML rule."""
|
||||
return Rule(
|
||||
type=elem.attrib["class"],
|
||||
name=get_elem_value(elem, "name"),
|
||||
package=package,
|
||||
srcs=normalize_paths(get_elem_value(elem, "srcs") or []),
|
||||
hdrs=normalize_paths(get_elem_value(elem, "hdrs") or []),
|
||||
textual_hdrs=normalize_paths(get_elem_value(elem, "textual_hdrs") or []),
|
||||
deps=get_elem_value(elem, "deps") or [],
|
||||
visibility=get_elem_value(elem, "visibility") or [],
|
||||
testonly=get_elem_value(elem, "testonly") or False)
|
||||
|
||||
|
||||
def read_build(package):
|
||||
"""Runs bazel query on given package file and returns all cc rules."""
|
||||
result = subprocess.check_output(
|
||||
["bazel", "query", package + ":all", "--output", "xml"])
|
||||
root = xml.etree.ElementTree.fromstring(result)
|
||||
return [
|
||||
parse_rule(elem, package)
|
||||
for elem in root
|
||||
if elem.tag == "rule" and elem.attrib["class"].startswith("cc_")
|
||||
]
|
||||
|
||||
|
||||
def collect_rules(root_path):
|
||||
"""Collects and returns all rules from root path recursively."""
|
||||
rules = []
|
||||
for cur, _, _ in os.walk(root_path):
|
||||
build_path = os.path.join(cur, "BUILD.bazel")
|
||||
if os.path.exists(build_path):
|
||||
rules.extend(read_build("//" + cur))
|
||||
return rules
|
||||
|
||||
|
||||
def relevant_rule(rule):
|
||||
"""Returns true if a given rule is relevant when generating a podspec."""
|
||||
return (
|
||||
# cc_library only (ignore cc_test, cc_binary)
|
||||
rule.type == "cc_library" and
|
||||
# ignore empty rule
|
||||
(rule.hdrs + rule.textual_hdrs + rule.srcs) and
|
||||
# ignore test-only rule
|
||||
not rule.testonly)
|
||||
|
||||
|
||||
def get_spec_var(depth):
|
||||
"""Returns the name of variable for spec with given depth."""
|
||||
return "s" if depth == 0 else "s{}".format(depth)
|
||||
|
||||
|
||||
def get_spec_name(label):
|
||||
"""Converts the label of bazel rule to the name of podspec."""
|
||||
assert label.startswith("//absl/"), "{} doesn't start with //absl/".format(
|
||||
label)
|
||||
# e.g. //absl/apple/banana -> abseil/apple/banana
|
||||
return "abseil/" + label[7:]
|
||||
|
||||
|
||||
def write_podspec(f, rules, args):
|
||||
"""Writes a podspec from given rules and args."""
|
||||
rule_dir = build_rule_directory(rules)["abseil"]
|
||||
# Write root part with given arguments
|
||||
spec = re.sub(r"\$\{(\w+)\}", lambda x: args[x.group(1)],
|
||||
SPEC_TEMPLATE).lstrip()
|
||||
f.write(spec)
|
||||
# Write all target rules
|
||||
write_podspec_map(f, rule_dir, 0)
|
||||
f.write("end\n")
|
||||
|
||||
|
||||
def build_rule_directory(rules):
|
||||
"""Builds a tree-style rule directory from given rules."""
|
||||
rule_dir = {}
|
||||
for rule in rules:
|
||||
cur = rule_dir
|
||||
for frag in get_spec_name(rule.package).split("/"):
|
||||
cur = cur.setdefault(frag, {})
|
||||
cur[rule.name] = rule
|
||||
return rule_dir
|
||||
|
||||
|
||||
def write_podspec_map(f, cur_map, depth):
|
||||
"""Writes podspec from rule map recursively."""
|
||||
for key, value in sorted(cur_map.items()):
|
||||
indent = " " * (depth + 1)
|
||||
f.write("{indent}{var0}.subspec '{key}' do |{var1}|\n".format(
|
||||
indent=indent,
|
||||
key=key,
|
||||
var0=get_spec_var(depth),
|
||||
var1=get_spec_var(depth + 1)))
|
||||
if isinstance(value, dict):
|
||||
write_podspec_map(f, value, depth + 1)
|
||||
else:
|
||||
write_podspec_rule(f, value, depth + 1)
|
||||
f.write("{indent}end\n".format(indent=indent))
|
||||
|
||||
|
||||
def write_podspec_rule(f, rule, depth):
|
||||
"""Writes podspec from given rule."""
|
||||
indent = " " * (depth + 1)
|
||||
spec_var = get_spec_var(depth)
|
||||
# Puts all files in hdrs, textual_hdrs, and srcs into source_files.
|
||||
# Since CocoaPods treats header_files a bit differently from bazel,
|
||||
# this won't generate a header_files field so that all source_files
|
||||
# are considered as header files.
|
||||
srcs = sorted(set(rule.hdrs + rule.textual_hdrs + rule.srcs))
|
||||
write_indented_list(
|
||||
f, "{indent}{var}.source_files = ".format(indent=indent, var=spec_var),
|
||||
srcs)
|
||||
# Writes dependencies of this rule.
|
||||
for dep in sorted(rule.deps):
|
||||
name = get_spec_name(dep.replace(":", "/"))
|
||||
f.write("{indent}{var}.dependency '{dep}'\n".format(
|
||||
indent=indent, var=spec_var, dep=name))
|
||||
|
||||
|
||||
def write_indented_list(f, leading, values):
|
||||
"""Writes leading values in an indented style."""
|
||||
f.write(leading)
|
||||
f.write((",\n" + " " * len(leading)).join("'{}'".format(v) for v in values))
|
||||
f.write("\n")
|
||||
|
||||
|
||||
def generate(args):
|
||||
"""Generates a podspec file from all BUILD files under absl directory."""
|
||||
rules = filter(relevant_rule, collect_rules("absl"))
|
||||
with open(args.output, "wt") as f:
|
||||
write_podspec(f, rules, vars(args))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generates abseil.podspec from BUILD.bazel")
|
||||
parser.add_argument(
|
||||
"-v", "--version", help="The version of podspec", required=True)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--tag",
|
||||
default=None,
|
||||
help="The name of git tag (default: version)")
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--output",
|
||||
default="abseil.podspec",
|
||||
help="The name of output file (default: abseil.podspec)")
|
||||
args = parser.parse_args()
|
||||
if args.tag is None:
|
||||
args.tag = args.version
|
||||
generate(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -14,6 +14,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
load(
|
||||
"//absl:copts/configure_copts.bzl",
|
||||
"ABSL_DEFAULT_COPTS",
|
||||
@@ -30,6 +31,7 @@ cc_library(
|
||||
hdrs = ["algorithm.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = ["//absl/base:config"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
|
||||
@@ -21,6 +21,8 @@ absl_cc_library(
|
||||
"algorithm.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace algorithm_internal {
|
||||
|
||||
@@ -85,6 +87,8 @@ It RotateImpl(It first, It middle, It last, std::false_type) {
|
||||
|
||||
} // namespace algorithm_internal
|
||||
|
||||
// equal()
|
||||
//
|
||||
// Compares the equality of two ranges specified by pairs of iterators, using
|
||||
// the given predicate, returning true iff for each corresponding iterator i1
|
||||
// and i2 in the first and second range respectively, pred(*i1, *i2) == true
|
||||
@@ -105,8 +109,8 @@ bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||
typename std::iterator_traits<InputIter2>::iterator_category{});
|
||||
}
|
||||
|
||||
// Performs comparison of two ranges specified by pairs of iterators using
|
||||
// operator==.
|
||||
// Overload of equal() that performs comparison of two ranges specified by pairs
|
||||
// of iterators using operator==.
|
||||
template <typename InputIter1, typename InputIter2>
|
||||
bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||
InputIter2 last2) {
|
||||
@@ -114,6 +118,8 @@ bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
|
||||
algorithm_internal::EqualTo{});
|
||||
}
|
||||
|
||||
// linear_search()
|
||||
//
|
||||
// Performs a linear search for `value` using the iterator `first` up to
|
||||
// but not including `last`, returning true if [`first`, `last`) contains an
|
||||
// element equal to `value`.
|
||||
@@ -127,6 +133,8 @@ bool linear_search(InputIterator first, InputIterator last,
|
||||
return std::find(first, last, value) != last;
|
||||
}
|
||||
|
||||
// rotate()
|
||||
//
|
||||
// Performs a left rotation on a range of elements (`first`, `last`) such that
|
||||
// `middle` is now the first element. `rotate()` returns an iterator pointing to
|
||||
// the first element before rotation. This function is exactly the same as
|
||||
@@ -136,7 +144,6 @@ bool linear_search(InputIterator first, InputIterator last,
|
||||
// The complexity of this algorithm is the same as that of `std::rotate`, but if
|
||||
// `ForwardIterator` is not a random-access iterator, then `absl::rotate`
|
||||
// performs an additional pass over the range to construct the return value.
|
||||
|
||||
template <typename ForwardIterator>
|
||||
ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
|
||||
ForwardIterator last) {
|
||||
@@ -146,7 +153,7 @@ ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
|
||||
ForwardIterator>());
|
||||
}
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_ALGORITHM_ALGORITHM_H_
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_algorithm_internal {
|
||||
|
||||
// NOTE: it is important to defer to ADL lookup for building with C++ modules,
|
||||
@@ -113,6 +113,18 @@ template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
struct IsUnorderedContainer<std::unordered_set<Key, Hash, KeyEqual, Allocator>>
|
||||
: std::true_type {};
|
||||
|
||||
// container_algorithm_internal::c_size. It is meant for internal use only.
|
||||
|
||||
template <class C>
|
||||
auto c_size(C& c) -> decltype(c.size()) {
|
||||
return c.size();
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr std::size_t c_size(T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
|
||||
} // namespace container_algorithm_internal
|
||||
|
||||
// PUBLIC API
|
||||
@@ -257,7 +269,8 @@ container_algorithm_internal::ContainerIter<Sequence1> c_find_end(
|
||||
// c_find_first_of()
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::find_first_of()` function to
|
||||
// find the first elements in an ordered set within a container.
|
||||
// find the first element within the container that is also within the options
|
||||
// container.
|
||||
template <typename C1, typename C2>
|
||||
container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container,
|
||||
C2& options) {
|
||||
@@ -366,7 +379,8 @@ c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) {
|
||||
|
||||
template <typename C1, typename C2>
|
||||
bool c_equal(const C1& c1, const C2& c2) {
|
||||
return ((c1.size() == c2.size()) &&
|
||||
return ((container_algorithm_internal::c_size(c1) ==
|
||||
container_algorithm_internal::c_size(c2)) &&
|
||||
std::equal(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2)));
|
||||
@@ -376,7 +390,8 @@ bool c_equal(const C1& c1, const C2& c2) {
|
||||
// the function's test condition.
|
||||
template <typename C1, typename C2, typename BinaryPredicate>
|
||||
bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
|
||||
return ((c1.size() == c2.size()) &&
|
||||
return ((container_algorithm_internal::c_size(c1) ==
|
||||
container_algorithm_internal::c_size(c2)) &&
|
||||
std::equal(container_algorithm_internal::c_begin(c1),
|
||||
container_algorithm_internal::c_end(c1),
|
||||
container_algorithm_internal::c_begin(c2),
|
||||
@@ -1706,7 +1721,7 @@ OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first,
|
||||
output_first, std::forward<BinaryOp>(op));
|
||||
}
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_ALGORITHM_CONTAINER_H_
|
||||
|
||||
@@ -163,23 +163,29 @@ TEST_F(NonMutatingTest, MismatchWithPredicate) {
|
||||
TEST_F(NonMutatingTest, Equal) {
|
||||
EXPECT_TRUE(absl::c_equal(vector_, sequence_));
|
||||
EXPECT_TRUE(absl::c_equal(sequence_, vector_));
|
||||
EXPECT_TRUE(absl::c_equal(sequence_, array_));
|
||||
EXPECT_TRUE(absl::c_equal(array_, vector_));
|
||||
|
||||
// Test that behavior appropriately differs from that of equal().
|
||||
std::vector<int> vector_plus = {1, 2, 3};
|
||||
vector_plus.push_back(4);
|
||||
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_));
|
||||
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus));
|
||||
EXPECT_FALSE(absl::c_equal(array_, vector_plus));
|
||||
}
|
||||
|
||||
TEST_F(NonMutatingTest, EqualWithPredicate) {
|
||||
EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals));
|
||||
EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals));
|
||||
EXPECT_TRUE(absl::c_equal(array_, sequence_, Equals));
|
||||
EXPECT_TRUE(absl::c_equal(vector_, array_, Equals));
|
||||
|
||||
// Test that behavior appropriately differs from that of equal().
|
||||
std::vector<int> vector_plus = {1, 2, 3};
|
||||
vector_plus.push_back(4);
|
||||
EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals));
|
||||
EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals));
|
||||
EXPECT_FALSE(absl::c_equal(vector_plus, array_, Equals));
|
||||
}
|
||||
|
||||
TEST_F(NonMutatingTest, IsPermutation) {
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load(
|
||||
"//absl:copts/configure_copts.bzl",
|
||||
"ABSL_DEFAULT_COPTS",
|
||||
"ABSL_DEFAULT_LINKOPTS",
|
||||
"ABSL_EXCEPTIONS_FLAG",
|
||||
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
|
||||
"ABSL_TEST_COPTS",
|
||||
)
|
||||
|
||||
@@ -35,6 +34,21 @@ cc_library(
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "errno_saver",
|
||||
hdrs = ["internal/errno_saver.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [":config"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
@@ -43,16 +57,27 @@ cc_library(
|
||||
hdrs = ["log_severity.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [":core_headers"],
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "raw_logging_internal",
|
||||
srcs = ["internal/raw_logging.cc"],
|
||||
hdrs = ["internal/raw_logging.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":atomic_hook",
|
||||
":config",
|
||||
":core_headers",
|
||||
":log_severity",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
@@ -64,22 +89,24 @@ cc_library(
|
||||
"internal/spinlock_wait.cc",
|
||||
"internal/spinlock_win32.inc",
|
||||
],
|
||||
hdrs = [
|
||||
"internal/scheduling_mode.h",
|
||||
"internal/spinlock_wait.h",
|
||||
],
|
||||
hdrs = ["internal/spinlock_wait.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl/base:__pkg__",
|
||||
],
|
||||
deps = [":core_headers"],
|
||||
deps = [
|
||||
":base_internal",
|
||||
":core_headers",
|
||||
":errno_saver",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "config",
|
||||
hdrs = [
|
||||
"config.h",
|
||||
"options.h",
|
||||
"policy_checks.h",
|
||||
],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
@@ -130,14 +157,15 @@ cc_library(
|
||||
"//conditions:default": ["-pthread"],
|
||||
}) + ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
"//visibility:public",
|
||||
],
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":config",
|
||||
":core_headers",
|
||||
":dynamic_annotations",
|
||||
":spinlock_wait",
|
||||
":raw_logging_internal",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -156,6 +184,7 @@ cc_library(
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":config",
|
||||
"//absl/meta:type_traits",
|
||||
],
|
||||
)
|
||||
@@ -164,7 +193,6 @@ cc_library(
|
||||
name = "base",
|
||||
srcs = [
|
||||
"internal/cycleclock.cc",
|
||||
"internal/raw_logging.cc",
|
||||
"internal/spinlock.cc",
|
||||
"internal/sysinfo.cc",
|
||||
"internal/thread_identity.cc",
|
||||
@@ -176,7 +204,6 @@ cc_library(
|
||||
"internal/cycleclock.h",
|
||||
"internal/low_level_scheduling.h",
|
||||
"internal/per_thread_tls.h",
|
||||
"internal/raw_logging.h",
|
||||
"internal/spinlock.h",
|
||||
"internal/sysinfo.h",
|
||||
"internal/thread_identity.h",
|
||||
@@ -185,7 +212,9 @@ cc_library(
|
||||
],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = select({
|
||||
"//absl:windows": [],
|
||||
"//absl:windows": [
|
||||
"-DEFAULTLIB:advapi32.lib",
|
||||
],
|
||||
"//conditions:default": ["-pthread"],
|
||||
}) + ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
@@ -195,11 +224,25 @@ cc_library(
|
||||
":core_headers",
|
||||
":dynamic_annotations",
|
||||
":log_severity",
|
||||
":raw_logging_internal",
|
||||
":spinlock_wait",
|
||||
"//absl/meta:type_traits",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "atomic_hook_test_helper",
|
||||
testonly = 1,
|
||||
srcs = ["internal/atomic_hook_test_helper.cc"],
|
||||
hdrs = ["internal/atomic_hook_test_helper.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":atomic_hook",
|
||||
":core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "atomic_hook_test",
|
||||
size = "small",
|
||||
@@ -208,6 +251,7 @@ cc_test(
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":atomic_hook",
|
||||
":atomic_hook_test_helper",
|
||||
":core_headers",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -232,28 +276,41 @@ cc_library(
|
||||
name = "throw_delegate",
|
||||
srcs = ["internal/throw_delegate.cc"],
|
||||
hdrs = ["internal/throw_delegate.h"],
|
||||
copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":base",
|
||||
":config",
|
||||
":raw_logging_internal",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "throw_delegate_test",
|
||||
srcs = ["throw_delegate_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":config",
|
||||
":throw_delegate",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "errno_saver_test",
|
||||
size = "small",
|
||||
srcs = ["internal/errno_saver_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":errno_saver",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "exception_testing",
|
||||
testonly = 1,
|
||||
@@ -281,8 +338,8 @@ cc_library(
|
||||
testonly = 1,
|
||||
srcs = ["internal/exception_safety_testing.cc"],
|
||||
hdrs = ["internal/exception_safety_testing.h"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":config",
|
||||
":pretty_function",
|
||||
@@ -297,8 +354,8 @@ cc_library(
|
||||
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 + ABSL_DEFAULT_LINKOPTS,
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":exception_safety_testing",
|
||||
"//absl/memory",
|
||||
@@ -347,8 +404,8 @@ cc_library(
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":core_headers",
|
||||
":spinlock_wait",
|
||||
"//absl/synchronization",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
@@ -363,8 +420,8 @@ cc_test(
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":core_headers",
|
||||
":spinlock_wait",
|
||||
"//absl/synchronization",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -382,6 +439,7 @@ cc_library(
|
||||
deps = [
|
||||
":base",
|
||||
":base_internal",
|
||||
":raw_logging_internal",
|
||||
"//absl/synchronization",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
@@ -455,7 +513,7 @@ cc_test(
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":base",
|
||||
":raw_logging_internal",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -519,7 +577,10 @@ cc_library(
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [":core_headers"],
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
@@ -534,6 +595,75 @@ cc_test(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "exponential_biased",
|
||||
srcs = ["internal/exponential_biased.cc"],
|
||||
hdrs = ["internal/exponential_biased.h"],
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
":config",
|
||||
":core_headers",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "exponential_biased_test",
|
||||
size = "small",
|
||||
srcs = ["internal/exponential_biased_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":exponential_biased",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "periodic_sampler",
|
||||
srcs = ["internal/periodic_sampler.cc"],
|
||||
hdrs = ["internal/periodic_sampler.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":core_headers",
|
||||
":exponential_biased",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "periodic_sampler_test",
|
||||
size = "small",
|
||||
srcs = ["internal/periodic_sampler_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":core_headers",
|
||||
":periodic_sampler",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "periodic_sampler_benchmark",
|
||||
testonly = 1,
|
||||
srcs = ["internal/periodic_sampler_benchmark.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
tags = ["benchmark"],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":core_headers",
|
||||
":periodic_sampler",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "scoped_set_env",
|
||||
testonly = 1,
|
||||
@@ -543,7 +673,10 @@ cc_library(
|
||||
visibility = [
|
||||
"//absl:__subpackages__",
|
||||
],
|
||||
deps = [":base"],
|
||||
deps = [
|
||||
":config",
|
||||
":raw_logging_internal",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
@@ -565,8 +698,10 @@ cc_test(
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":base",
|
||||
":log_severity",
|
||||
"//absl/flags:flag_internal",
|
||||
"//absl/flags:marshalling",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -14,11 +14,27 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
find_library(LIBRT rt)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
atomic_hook
|
||||
HDRS
|
||||
"internal/atomic_hook.h"
|
||||
DEPS
|
||||
absl::config
|
||||
absl::core_headers
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
errno_saver
|
||||
HDRS
|
||||
"internal/errno_saver.h"
|
||||
DEPS
|
||||
absl::config
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
)
|
||||
@@ -39,6 +55,15 @@ absl_cc_library(
|
||||
absl_cc_library(
|
||||
NAME
|
||||
raw_logging_internal
|
||||
HDRS
|
||||
"internal/raw_logging.h"
|
||||
SRCS
|
||||
"internal/raw_logging.cc"
|
||||
DEPS
|
||||
absl::atomic_hook
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::log_severity
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
)
|
||||
@@ -47,7 +72,6 @@ absl_cc_library(
|
||||
NAME
|
||||
spinlock_wait
|
||||
HDRS
|
||||
"internal/scheduling_mode.h"
|
||||
"internal/spinlock_wait.h"
|
||||
SRCS
|
||||
"internal/spinlock_akaros.inc"
|
||||
@@ -58,7 +82,9 @@ absl_cc_library(
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base_internal
|
||||
absl::core_headers
|
||||
absl::errno_saver
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
@@ -66,6 +92,7 @@ absl_cc_library(
|
||||
config
|
||||
HDRS
|
||||
"config.h"
|
||||
"options.h"
|
||||
"policy_checks.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
@@ -116,10 +143,11 @@ absl_cc_library(
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::base_internal
|
||||
absl::config
|
||||
absl::core_headers
|
||||
absl::dynamic_annotations
|
||||
absl::spinlock_wait
|
||||
absl::raw_logging_internal
|
||||
Threads::Threads
|
||||
)
|
||||
|
||||
@@ -131,9 +159,11 @@ absl_cc_library(
|
||||
"internal/identity.h"
|
||||
"internal/inline_variable.h"
|
||||
"internal/invoke.h"
|
||||
"internal/scheduling_mode.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::type_traits
|
||||
)
|
||||
|
||||
@@ -146,23 +176,23 @@ absl_cc_library(
|
||||
"internal/cycleclock.h"
|
||||
"internal/low_level_scheduling.h"
|
||||
"internal/per_thread_tls.h"
|
||||
"internal/raw_logging.h"
|
||||
"internal/spinlock.h"
|
||||
"internal/sysinfo.h"
|
||||
"internal/thread_identity.h"
|
||||
"internal/tsan_mutex_interface.h"
|
||||
"internal/unscaledcycleclock.h"
|
||||
"log_severity.h"
|
||||
SRCS
|
||||
"internal/cycleclock.cc"
|
||||
"internal/raw_logging.cc"
|
||||
"internal/spinlock.cc"
|
||||
"internal/sysinfo.cc"
|
||||
"internal/thread_identity.cc"
|
||||
"internal/unscaledcycleclock.cc"
|
||||
"log_severity.cc"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
$<$<BOOL:${LIBRT}>:${LIBRT}>
|
||||
$<$<BOOL:${MINGW}>:"advapi32">
|
||||
DEPS
|
||||
absl::atomic_hook
|
||||
absl::base_internal
|
||||
@@ -170,6 +200,7 @@ absl_cc_library(
|
||||
absl::core_headers
|
||||
absl::dynamic_annotations
|
||||
absl::log_severity
|
||||
absl::raw_logging_internal
|
||||
absl::spinlock_wait
|
||||
absl::type_traits
|
||||
Threads::Threads
|
||||
@@ -185,9 +216,9 @@ absl_cc_library(
|
||||
"internal/throw_delegate.cc"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::config
|
||||
absl::raw_logging_internal
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
@@ -221,9 +252,6 @@ absl_cc_library(
|
||||
"internal/exception_safety_testing.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::pretty_function
|
||||
@@ -242,15 +270,25 @@ absl_cc_test(
|
||||
"exception_safety_testing_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::exception_safety_testing
|
||||
absl::memory
|
||||
gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
atomic_hook_test_helper
|
||||
SRCS
|
||||
"internal/atomic_hook_test_helper.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::atomic_hook
|
||||
absl::core_headers
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
atomic_hook_test
|
||||
@@ -259,8 +297,10 @@ absl_cc_test(
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::atomic_hook_test_helper
|
||||
absl::atomic_hook
|
||||
absl::core_headers
|
||||
gmock
|
||||
gtest_main
|
||||
)
|
||||
|
||||
@@ -277,6 +317,19 @@ absl_cc_test(
|
||||
gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
errno_saver_test
|
||||
SRCS
|
||||
"internal/errno_saver_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::errno_saver
|
||||
gmock
|
||||
gtest_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
throw_delegate_test
|
||||
@@ -286,6 +339,7 @@ absl_cc_test(
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::config
|
||||
absl::throw_delegate
|
||||
gtest_main
|
||||
)
|
||||
@@ -329,8 +383,8 @@ absl_cc_library(
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::base_internal
|
||||
absl::core_headers
|
||||
absl::spinlock_wait
|
||||
absl::synchronization
|
||||
gtest
|
||||
TESTONLY
|
||||
@@ -346,8 +400,8 @@ absl_cc_test(
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::base_internal
|
||||
absl::core_headers
|
||||
absl::spinlock_wait
|
||||
absl::synchronization
|
||||
gtest_main
|
||||
)
|
||||
@@ -415,7 +469,7 @@ absl_cc_test(
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gtest_main
|
||||
)
|
||||
@@ -468,6 +522,7 @@ absl_cc_library(
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::core_headers
|
||||
)
|
||||
|
||||
@@ -483,6 +538,60 @@ absl_cc_test(
|
||||
gtest_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
exponential_biased
|
||||
SRCS
|
||||
"internal/exponential_biased.cc"
|
||||
HDRS
|
||||
"internal/exponential_biased.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
absl::core_headers
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
exponential_biased_test
|
||||
SRCS
|
||||
"internal/exponential_biased_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::exponential_biased
|
||||
absl::strings
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
periodic_sampler
|
||||
SRCS
|
||||
"internal/periodic_sampler.cc"
|
||||
HDRS
|
||||
"internal/periodic_sampler.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::core_headers
|
||||
absl::exponential_biased
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
periodic_sampler_test
|
||||
SRCS
|
||||
"internal/periodic_sampler_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::core_headers
|
||||
absl::periodic_sampler
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
scoped_set_env
|
||||
@@ -493,7 +602,8 @@ absl_cc_library(
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::config
|
||||
absl::raw_logging_internal
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
@@ -525,8 +635,10 @@ absl_cc_test(
|
||||
SRCS
|
||||
"log_severity_test.cc"
|
||||
DEPS
|
||||
absl::base
|
||||
absl::flags_internal
|
||||
absl::flags_marshalling
|
||||
absl::log_severity
|
||||
absl::strings
|
||||
gmock
|
||||
gtest_main
|
||||
)
|
||||
|
||||
@@ -157,10 +157,12 @@
|
||||
// Tags a function as weak for the purposes of compilation and linking.
|
||||
// Weak attributes currently do not work properly in LLVM's Windows backend,
|
||||
// so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
|
||||
// for futher information.
|
||||
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
|
||||
// for further information.
|
||||
// The MinGW compiler doesn't complain about the weak attribute until the link
|
||||
// step, presumably because Windows doesn't use ELF binaries.
|
||||
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))) && \
|
||||
!(defined(__llvm__) && defined(_WIN32))
|
||||
!(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
|
||||
#undef ABSL_ATTRIBUTE_WEAK
|
||||
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
||||
@@ -561,7 +563,19 @@
|
||||
|
||||
// ABSL_ATTRIBUTE_PACKED
|
||||
//
|
||||
// Prevents the compiler from padding a structure to natural alignment
|
||||
// Instructs the compiler not to use natural alignment for a tagged data
|
||||
// structure, but instead to reduce its alignment to 1. This attribute can
|
||||
// either be applied to members of a structure or to a structure in its
|
||||
// entirety. Applying this attribute (judiciously) to a structure in its
|
||||
// entirety to optimize the memory footprint of very commonly-used structs is
|
||||
// fine. Do not apply this attribute to a structure in its entirety if the
|
||||
// purpose is to control the offsets of the members in the structure. Instead,
|
||||
// apply this attribute only to structure members that need it.
|
||||
//
|
||||
// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
|
||||
// natural alignment of structure members not annotated is preserved. Aligned
|
||||
// member accesses are faster than non-aligned member accesses even if the
|
||||
// targeted microprocessor supports non-aligned accesses.
|
||||
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
|
||||
#else
|
||||
@@ -599,7 +613,6 @@
|
||||
//
|
||||
// Note that this attribute is redundant if the variable is declared constexpr.
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||
// NOLINTNEXTLINE(whitespace/braces)
|
||||
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
|
||||
#else
|
||||
#define ABSL_CONST_INIT
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "absl/base/macros.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
|
||||
template <int N>
|
||||
@@ -105,5 +105,5 @@ TEST(BitCast, Double) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
class once_flag;
|
||||
|
||||
@@ -143,12 +143,13 @@ enum {
|
||||
};
|
||||
|
||||
template <typename Callable, typename... Args>
|
||||
ABSL_ATTRIBUTE_NOINLINE
|
||||
void CallOnceImpl(std::atomic<uint32_t>* control,
|
||||
base_internal::SchedulingMode scheduling_mode, Callable&& fn,
|
||||
Args&&... args) {
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
uint32_t old_control = control->load(std::memory_order_acquire);
|
||||
uint32_t old_control = control->load(std::memory_order_relaxed);
|
||||
if (old_control != kOnceInit &&
|
||||
old_control != kOnceRunning &&
|
||||
old_control != kOnceWaiter &&
|
||||
@@ -166,14 +167,23 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
|
||||
// Must do this before potentially modifying control word's state.
|
||||
base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode);
|
||||
// Short circuit the simplest case to avoid procedure call overhead.
|
||||
// The base_internal::SpinLockWait() call returns either kOnceInit or
|
||||
// kOnceDone. If it returns kOnceDone, it must have loaded the control word
|
||||
// with std::memory_order_acquire and seen a value of kOnceDone.
|
||||
uint32_t old_control = kOnceInit;
|
||||
if (control->compare_exchange_strong(old_control, kOnceRunning,
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_relaxed) ||
|
||||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
|
||||
scheduling_mode) == kOnceInit) {
|
||||
base_internal::Invoke(std::forward<Callable>(fn),
|
||||
std::forward<Args>(args)...);
|
||||
// The call to SpinLockWake below is an optimization, because the waiter
|
||||
// in SpinLockWait is waiting with a short timeout. The atomic load/store
|
||||
// sequence is slightly faster than an atomic exchange:
|
||||
// old_control = control->exchange(base_internal::kOnceDone,
|
||||
// std::memory_order_release);
|
||||
// We opt for a slightly faster case when there are no waiters, in spite
|
||||
// of longer tail latency when there are waiters.
|
||||
old_control = control->load(std::memory_order_relaxed);
|
||||
control->store(base_internal::kOnceDone, std::memory_order_release);
|
||||
if (old_control == base_internal::kOnceWaiter) {
|
||||
@@ -210,7 +220,7 @@ void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) {
|
||||
}
|
||||
}
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_CALL_ONCE_H_
|
||||
|
||||
@@ -24,18 +24,18 @@
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
|
||||
absl::once_flag once;
|
||||
|
||||
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;
|
||||
int call_once_finished_count GUARDED_BY(counters_mu) = 0;
|
||||
int call_once_return_count GUARDED_BY(counters_mu) = 0;
|
||||
bool done_blocking GUARDED_BY(counters_mu) = false;
|
||||
int running_thread_count ABSL_GUARDED_BY(counters_mu) = 0;
|
||||
int call_once_invoke_count ABSL_GUARDED_BY(counters_mu) = 0;
|
||||
int call_once_finished_count ABSL_GUARDED_BY(counters_mu) = 0;
|
||||
int call_once_return_count ABSL_GUARDED_BY(counters_mu) = 0;
|
||||
bool done_blocking ABSL_GUARDED_BY(counters_mu) = false;
|
||||
|
||||
// Function to be called from absl::call_once. Waits for a notification.
|
||||
void WaitAndIncrement() {
|
||||
@@ -61,7 +61,7 @@ void ThreadBody() {
|
||||
}
|
||||
|
||||
// Returns true if all threads are set up for the test.
|
||||
bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
|
||||
bool ThreadsAreSetup(void*) ABSL_EXCLUSIVE_LOCKS_REQUIRED(counters_mu) {
|
||||
// All ten threads must be running, and WaitAndIncrement should be blocked.
|
||||
return running_thread_count == 10 && call_once_invoke_count == 1;
|
||||
}
|
||||
@@ -103,5 +103,5 @@ TEST(CallOnceTest, ExecutionCount) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace internal_casts {
|
||||
|
||||
@@ -178,7 +178,7 @@ inline Dest bit_cast(const Source& source) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_CASTS_H_
|
||||
|
||||
@@ -63,8 +63,72 @@
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/base/policy_checks.h"
|
||||
|
||||
// Helper macro to convert a CPP variable to a string literal.
|
||||
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
|
||||
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Abseil namespace annotations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
|
||||
//
|
||||
// An annotation placed at the beginning/end of each `namespace absl` scope.
|
||||
// This is used to inject an inline namespace.
|
||||
//
|
||||
// The proper way to write Abseil code in the `absl` namespace is:
|
||||
//
|
||||
// namespace absl {
|
||||
// ABSL_NAMESPACE_BEGIN
|
||||
//
|
||||
// void Foo(); // absl::Foo().
|
||||
//
|
||||
// ABSL_NAMESPACE_END
|
||||
// } // namespace absl
|
||||
//
|
||||
// Users of Abseil should not use these macros, because users of Abseil should
|
||||
// not write `namespace absl {` in their own code for any reason. (Abseil does
|
||||
// not support forward declarations of its own types, nor does it support
|
||||
// user-provided specialization of Abseil templates. Code that violates these
|
||||
// rules may be broken without warning.)
|
||||
#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
|
||||
!defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
|
||||
#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||
|
||||
#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
|
||||
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||
|
||||
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
|
||||
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||
"not be empty.");
|
||||
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
|
||||
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||
"be changed to a new, unique identifier name.");
|
||||
|
||||
#endif
|
||||
|
||||
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||
#define ABSL_NAMESPACE_BEGIN
|
||||
#define ABSL_NAMESPACE_END
|
||||
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||
#define ABSL_NAMESPACE_BEGIN \
|
||||
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
|
||||
#define ABSL_NAMESPACE_END }
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Compiler Feature Checks
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -84,6 +148,12 @@
|
||||
#define ABSL_HAVE_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
#if defined(__is_identifier)
|
||||
#define ABSL_INTERNAL_HAS_KEYWORD(x) !(__is_identifier(x))
|
||||
#else
|
||||
#define ABSL_INTERNAL_HAS_KEYWORD(x) 0
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
|
||||
// We assume __thread is supported on Linux when compiled with Clang or compiled
|
||||
// against libstdc++ with _GLIBCXX_HAVE_TLS defined.
|
||||
@@ -125,13 +195,24 @@
|
||||
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
|
||||
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
|
||||
(!defined(__clang__) && defined(__GNUC__) && \
|
||||
(__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \
|
||||
(__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 4)) && \
|
||||
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
|
||||
(defined(_MSC_VER) && !defined(__NVCC__))
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_SOURCE_LOCATION_CURRENT
|
||||
//
|
||||
// Indicates whether `absl::SourceLocation::current()` will return useful
|
||||
// information in some contexts.
|
||||
#ifndef ABSL_HAVE_SOURCE_LOCATION_CURRENT
|
||||
#if ABSL_INTERNAL_HAS_KEYWORD(__builtin_LINE) && \
|
||||
ABSL_INTERNAL_HAS_KEYWORD(__builtin_FILE)
|
||||
#define ABSL_HAVE_SOURCE_LOCATION_CURRENT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_THREAD_LOCAL
|
||||
//
|
||||
// Checks whether C++11's `thread_local` storage duration specifier is
|
||||
@@ -235,13 +316,19 @@
|
||||
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
|
||||
|
||||
#elif defined(__clang__)
|
||||
// TODO(calabrese)
|
||||
// Switch to using __cpp_exceptions when we no longer support versions < 3.6.
|
||||
// For details on this check, see:
|
||||
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
|
||||
|
||||
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
|
||||
// Clang >= 3.6
|
||||
#if __has_feature(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // __has_feature(cxx_exceptions)
|
||||
#else
|
||||
// Clang < 3.6
|
||||
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
|
||||
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
|
||||
#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
|
||||
|
||||
// Handle remaining special cases and default to exceptions being supported.
|
||||
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
|
||||
@@ -307,7 +394,7 @@
|
||||
|
||||
// ABSL_HAVE_SEMAPHORE_H
|
||||
//
|
||||
// Checks whether the platform supports the <semaphore.h> header and sem_open(3)
|
||||
// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
|
||||
// family of functions as standardized in POSIX.1-2001.
|
||||
//
|
||||
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
|
||||
@@ -334,8 +421,15 @@
|
||||
#define ABSL_HAVE_ALARM 1
|
||||
#elif defined(_MSC_VER)
|
||||
// feature tests for Microsoft's library
|
||||
#elif defined(__MINGW32__)
|
||||
// mingw32 doesn't provide alarm(2):
|
||||
// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
|
||||
// mingw-w64 provides a no-op implementation:
|
||||
// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// emscripten doesn't support signals
|
||||
#elif defined(__Fuchsia__)
|
||||
// Signals don't exist on fuchsia.
|
||||
#elif defined(__native_client__)
|
||||
#else
|
||||
// other standard libraries
|
||||
@@ -461,6 +555,68 @@
|
||||
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_ANY
|
||||
//
|
||||
// Indicates whether absl::any is an alias for std::any.
|
||||
#if !defined(ABSL_OPTION_USE_STD_ANY)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_ANY == 0 || \
|
||||
(ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
|
||||
#undef ABSL_USES_STD_ANY
|
||||
#elif ABSL_OPTION_USE_STD_ANY == 1 || \
|
||||
(ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
|
||||
#define ABSL_USES_STD_ANY 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_OPTIONAL
|
||||
//
|
||||
// Indicates whether absl::optional is an alias for std::optional.
|
||||
#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
|
||||
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
|
||||
#undef ABSL_USES_STD_OPTIONAL
|
||||
#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
|
||||
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
|
||||
#define ABSL_USES_STD_OPTIONAL 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_VARIANT
|
||||
//
|
||||
// Indicates whether absl::variant is an alias for std::variant.
|
||||
#if !defined(ABSL_OPTION_USE_STD_VARIANT)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
|
||||
(ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
|
||||
#undef ABSL_USES_STD_VARIANT
|
||||
#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
|
||||
(ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
|
||||
#define ABSL_USES_STD_VARIANT 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_STRING_VIEW
|
||||
//
|
||||
// Indicates whether absl::string_view is an alias for std::string_view.
|
||||
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
|
||||
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||
!defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||
#undef ABSL_USES_STD_STRING_VIEW
|
||||
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
|
||||
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||
defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||
#define ABSL_USES_STD_STRING_VIEW 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
|
||||
// SEH exception from emplace for variant<SomeStruct> when constructing the
|
||||
// struct can throw. This defeats some of variant_test and
|
||||
@@ -469,4 +625,47 @@
|
||||
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_MANGLED_NS
|
||||
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
|
||||
//
|
||||
// Internal macros for building up mangled names in our internal fork of CCTZ.
|
||||
// This implementation detail is only needed and provided for the MSVC build.
|
||||
//
|
||||
// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
|
||||
// the mangled spelling of the `absl` namespace, and
|
||||
// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
|
||||
// the proper count to skip past the CCTZ fork namespace names. (This number
|
||||
// is one larger when there is an inline namespace name to skip.)
|
||||
#if defined(_MSC_VER)
|
||||
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||
#define ABSL_INTERNAL_MANGLED_NS "absl"
|
||||
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
|
||||
#else
|
||||
#define ABSL_INTERNAL_MANGLED_NS \
|
||||
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
|
||||
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef ABSL_INTERNAL_HAS_KEYWORD
|
||||
|
||||
// ABSL_DLL
|
||||
//
|
||||
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
|
||||
// so we can annotate symbols appropriately as being exported. When used in
|
||||
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
|
||||
// that consumers know the symbol is defined inside the DLL. In all other cases,
|
||||
// the macro expands to nothing.
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(ABSL_BUILD_DLL)
|
||||
#define ABSL_DLL __declspec(dllexport)
|
||||
#elif defined(ABSL_CONSUME_DLL)
|
||||
#define ABSL_DLL __declspec(dllimport)
|
||||
#else
|
||||
#define ABSL_DLL
|
||||
#endif
|
||||
#else
|
||||
#define ABSL_DLL
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
#endif // ABSL_BASE_CONFIG_H_
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#ifndef ABSL_BASE_CONST_INIT_H_
|
||||
#define ABSL_BASE_CONST_INIT_H_
|
||||
|
||||
#include "absl/base/config.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
|
||||
@@ -62,13 +64,13 @@
|
||||
// or thread_local storage duration.
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
enum ConstInitType {
|
||||
kConstInit,
|
||||
};
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_CONST_INIT_H_
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "absl/base/internal/exception_safety_testing.h"
|
||||
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
@@ -326,17 +328,15 @@ TEST(ThrowingValueTest, NonThrowingDelete) {
|
||||
UnsetCountdown();
|
||||
}
|
||||
|
||||
using Storage =
|
||||
absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
|
||||
|
||||
TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
|
||||
constexpr int kArrayLen = 2;
|
||||
// We intentionally create extra space to store the tag allocated by placement
|
||||
// new[].
|
||||
constexpr int kStorageLen = 4;
|
||||
|
||||
Storage buf;
|
||||
Storage array_buf[kStorageLen];
|
||||
alignas(ThrowingValue<>) unsigned char buf[sizeof(ThrowingValue<>)];
|
||||
alignas(ThrowingValue<>) unsigned char
|
||||
array_buf[sizeof(ThrowingValue<>[kStorageLen])];
|
||||
auto* placed = new (&buf) ThrowingValue<>(1);
|
||||
auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen];
|
||||
|
||||
@@ -900,12 +900,12 @@ TEST(ConstructorTrackerTest, CreatedAfter) {
|
||||
}
|
||||
|
||||
TEST(ConstructorTrackerTest, NotDestroyedAfter) {
|
||||
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
|
||||
alignas(Tracked) unsigned char storage[sizeof(Tracked)];
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
{
|
||||
exceptions_internal::ConstructorTracker ct(
|
||||
exceptions_internal::countdown);
|
||||
new (&storage) Tracked;
|
||||
new (&storage) Tracked();
|
||||
},
|
||||
"not destroyed");
|
||||
}
|
||||
@@ -922,11 +922,11 @@ TEST(ConstructorTrackerTest, DestroyedTwice) {
|
||||
|
||||
TEST(ConstructorTrackerTest, ConstructedTwice) {
|
||||
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
|
||||
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
|
||||
alignas(Tracked) unsigned char storage[sizeof(Tracked)];
|
||||
EXPECT_NONFATAL_FAILURE(
|
||||
{
|
||||
new (&storage) Tracked;
|
||||
new (&storage) Tracked;
|
||||
new (&storage) Tracked();
|
||||
new (&storage) Tracked();
|
||||
reinterpret_cast<Tracked*>(&storage)->~Tracked();
|
||||
},
|
||||
"re-constructed");
|
||||
@@ -952,3 +952,5 @@ TEST(ThrowingAllocatorTraitsTest, Assignablility) {
|
||||
} // namespace
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace inline_variable_testing_internal {
|
||||
namespace {
|
||||
|
||||
@@ -60,5 +60,5 @@ TEST(InlineVariableTest, FunPtrType) {
|
||||
|
||||
} // namespace
|
||||
} // namespace inline_variable_testing_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "absl/base/internal/inline_variable_testing.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "absl/base/internal/inline_variable_testing.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
@@ -21,29 +20,51 @@
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _MSC_FULL_VER
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
|
||||
#else
|
||||
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
|
||||
#else
|
||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
template <typename T>
|
||||
class AtomicHook;
|
||||
|
||||
// AtomicHook is a helper class, templatized on a raw function pointer type, for
|
||||
// implementing Abseil customization hooks. It is a callable object that
|
||||
// dispatches to the registered hook.
|
||||
// To workaround AtomicHook not being constant-initializable on some platforms,
|
||||
// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
|
||||
// instead of `ABSL_CONST_INIT`.
|
||||
#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
|
||||
#else
|
||||
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
#endif
|
||||
|
||||
// `AtomicHook` is a helper class, templatized on a raw function pointer type,
|
||||
// for implementing Abseil customization hooks. It is a callable object that
|
||||
// dispatches to the registered hook. Objects of type `AtomicHook` must have
|
||||
// static or thread storage duration.
|
||||
//
|
||||
// A default constructed object performs a no-op (and returns a default
|
||||
// constructed object) if no hook has been registered.
|
||||
//
|
||||
// Hooks can be pre-registered via constant initialization, for example,
|
||||
// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
|
||||
// and then changed at runtime via a call to Store().
|
||||
// Hooks can be pre-registered via constant initialization, for example:
|
||||
//
|
||||
// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
|
||||
// my_hook(DefaultAction);
|
||||
//
|
||||
// and then changed at runtime via a call to `Store()`.
|
||||
//
|
||||
// Reads and writes guarantee memory_order_acquire/memory_order_release
|
||||
// semantics.
|
||||
@@ -58,12 +79,23 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
||||
|
||||
// Constructs an object that by default dispatches to/returns the
|
||||
// pre-registered default_fn when no hook has been registered at runtime.
|
||||
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||
#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: hook_(default_fn), default_fn_(default_fn) {}
|
||||
#else
|
||||
#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: hook_(kUninitialized), default_fn_(default_fn) {}
|
||||
#else
|
||||
// As of January 2020, on all known versions of MSVC this constructor runs in
|
||||
// the global constructor sequence. If `Store()` is called by a dynamic
|
||||
// initializer, we want to preserve the value, even if this constructor runs
|
||||
// after the call to `Store()`. If not, `hook_` will be
|
||||
// zero-initialized by the linker and we have no need to set it.
|
||||
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: /* hook_(deliberately omitted), */ default_fn_(default_fn) {
|
||||
static_assert(kUninitialized == 0, "here we rely on zero-initialization");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stores the provided function pointer as the value for this hook.
|
||||
@@ -159,9 +191,10 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
||||
};
|
||||
|
||||
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||
#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
|
||||
@@ -14,16 +14,22 @@
|
||||
|
||||
#include "absl/base/internal/atomic_hook.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/internal/atomic_hook_test_helper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using ::testing::Eq;
|
||||
|
||||
int value = 0;
|
||||
void TestHook(int x) { value = x; }
|
||||
|
||||
TEST(AtomicHookTest, NoDefaultFunction) {
|
||||
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
void (*)(int)>
|
||||
hook;
|
||||
value = 0;
|
||||
|
||||
// Test the default DummyFunction.
|
||||
@@ -49,8 +55,9 @@ TEST(AtomicHookTest, NoDefaultFunction) {
|
||||
|
||||
TEST(AtomicHookTest, WithDefaultFunction) {
|
||||
// Set the default value to TestHook at compile-time.
|
||||
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
|
||||
TestHook);
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
void (*)(int)>
|
||||
hook(TestHook);
|
||||
value = 0;
|
||||
|
||||
// Test the default value is TestHook.
|
||||
@@ -67,4 +74,24 @@ TEST(AtomicHookTest, WithDefaultFunction) {
|
||||
EXPECT_EQ(value, 2);
|
||||
}
|
||||
|
||||
ABSL_CONST_INIT int override_func_calls = 0;
|
||||
void OverrideFunc() { override_func_calls++; }
|
||||
static struct OverrideInstaller {
|
||||
OverrideInstaller() { absl::atomic_hook_internal::func.Store(OverrideFunc); }
|
||||
} override_installer;
|
||||
|
||||
TEST(AtomicHookTest, DynamicInitFromAnotherTU) {
|
||||
// MSVC 14.2 doesn't do constexpr static init correctly; in particular it
|
||||
// tends to sequence static init (i.e. defaults) of `AtomicHook` objects
|
||||
// after their dynamic init (i.e. overrides), overwriting whatever value was
|
||||
// written during dynamic init. This regression test validates the fix.
|
||||
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
|
||||
EXPECT_THAT(absl::atomic_hook_internal::default_func_calls, Eq(0));
|
||||
EXPECT_THAT(override_func_calls, Eq(0));
|
||||
absl::atomic_hook_internal::func();
|
||||
EXPECT_THAT(absl::atomic_hook_internal::default_func_calls, Eq(0));
|
||||
EXPECT_THAT(override_func_calls, Eq(1));
|
||||
EXPECT_THAT(absl::atomic_hook_internal::func.Load(), Eq(OverrideFunc));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -12,19 +12,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include "absl/base/internal/atomic_hook_test_helper.h"
|
||||
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/internal/atomic_hook.h"
|
||||
|
||||
// This program is used in integration tests.
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace atomic_hook_internal {
|
||||
|
||||
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;
|
||||
}
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<VoidF>
|
||||
func(DefaultFunc);
|
||||
ABSL_CONST_INIT int default_func_calls = 0;
|
||||
void DefaultFunc() { default_func_calls++; }
|
||||
void RegisterFunc(VoidF f) { func.Store(f); }
|
||||
|
||||
} // namespace atomic_hook_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
@@ -12,19 +12,23 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#ifndef ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||
#define ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/base/internal/atomic_hook.h"
|
||||
|
||||
// This program is used in integration tests.
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace atomic_hook_internal {
|
||||
|
||||
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;
|
||||
}
|
||||
using VoidF = void (*)();
|
||||
extern absl::base_internal::AtomicHook<VoidF> func;
|
||||
extern int default_func_calls;
|
||||
void DefaultFunc();
|
||||
void RegisterFunc(VoidF func);
|
||||
|
||||
} // namespace atomic_hook_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_ATOMIC_HOOK_TEST_HELPER_H_
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// Clang on Windows has __builtin_clzll; otherwise we need to use the
|
||||
// windows intrinsic functions.
|
||||
#if defined(_MSC_VER)
|
||||
@@ -46,15 +48,27 @@
|
||||
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
|
||||
int zeroes = 60;
|
||||
if (n >> 32) zeroes -= 32, n >>= 32;
|
||||
if (n >> 16) zeroes -= 16, n >>= 16;
|
||||
if (n >> 8) zeroes -= 8, n >>= 8;
|
||||
if (n >> 4) zeroes -= 4, n >>= 4;
|
||||
if (n >> 32) {
|
||||
zeroes -= 32;
|
||||
n >>= 32;
|
||||
}
|
||||
if (n >> 16) {
|
||||
zeroes -= 16;
|
||||
n >>= 16;
|
||||
}
|
||||
if (n >> 8) {
|
||||
zeroes -= 8;
|
||||
n >>= 8;
|
||||
}
|
||||
if (n >> 4) {
|
||||
zeroes -= 4;
|
||||
n >>= 4;
|
||||
}
|
||||
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
|
||||
}
|
||||
|
||||
@@ -96,9 +110,18 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
|
||||
|
||||
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
|
||||
int zeroes = 28;
|
||||
if (n >> 16) zeroes -= 16, n >>= 16;
|
||||
if (n >> 8) zeroes -= 8, n >>= 8;
|
||||
if (n >> 4) zeroes -= 4, n >>= 4;
|
||||
if (n >> 16) {
|
||||
zeroes -= 16;
|
||||
n >>= 16;
|
||||
}
|
||||
if (n >> 8) {
|
||||
zeroes -= 8;
|
||||
n >>= 8;
|
||||
}
|
||||
if (n >> 4) {
|
||||
zeroes -= 4;
|
||||
n >>= 4;
|
||||
}
|
||||
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
|
||||
}
|
||||
|
||||
@@ -189,7 +212,7 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
|
||||
#undef ABSL_BASE_INTERNAL_FORCEINLINE
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_BITS_H_
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "absl/base/internal/unscaledcycleclock.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
#if ABSL_USE_UNSCALED_CYCLECLOCK
|
||||
@@ -103,5 +103,5 @@ double CycleClock::Frequency() {
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -44,8 +44,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -86,7 +88,7 @@ class CycleClockSource {
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_
|
||||
|
||||
@@ -62,7 +62,7 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
|
||||
#endif // __BIONIC__
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // 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_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
// The following guarantees declaration of the byte swap functions
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h> // NOLINT(build/include)
|
||||
#elif defined(__APPLE__)
|
||||
// macOS / Darwin features
|
||||
#include <libkern/OSByteOrder.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#elif defined(__GLIBC__)
|
||||
@@ -34,7 +31,7 @@
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// 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.
|
||||
@@ -64,11 +61,6 @@ inline uint16_t gbswap_16(uint16_t host_int) {
|
||||
return _byteswap_ushort(host_int);
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
|
||||
inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
|
||||
inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
|
||||
|
||||
#else
|
||||
inline uint64_t gbswap_64(uint64_t host_int) {
|
||||
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
|
||||
@@ -114,7 +106,7 @@ inline uint16_t gbswap_16(uint16_t host_int) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // intrinics available
|
||||
#endif // intrinsics available
|
||||
|
||||
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||
|
||||
@@ -268,7 +260,7 @@ inline void Store64(void *p, uint64_t v) {
|
||||
|
||||
} // namespace big_endian
|
||||
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
|
||||
const uint64_t kInitialNumber{0x0123456789abcdef};
|
||||
@@ -261,5 +261,5 @@ TEST(EndianessTest, big_endian) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
43
absl/base/internal/errno_saver.h
Normal file
43
absl/base/internal/errno_saver.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||
#define ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// `ErrnoSaver` captures the value of `errno` upon construction and restores it
|
||||
// upon deletion. It is used in low-level code and must be super fast. Do not
|
||||
// add instrumentation, even in debug modes.
|
||||
class ErrnoSaver {
|
||||
public:
|
||||
ErrnoSaver() : saved_errno_(errno) {}
|
||||
~ErrnoSaver() { errno = saved_errno_; }
|
||||
int operator()() const { return saved_errno_; }
|
||||
|
||||
private:
|
||||
const int saved_errno_;
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ERRNO_SAVER_H_
|
||||
44
absl/base/internal/errno_saver_test.cc
Normal file
44
absl/base/internal/errno_saver_test.cc
Normal file
@@ -0,0 +1,44 @@
|
||||
// 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/internal/errno_saver.h"
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
using ::testing::Eq;
|
||||
|
||||
struct ErrnoPrinter {
|
||||
int no;
|
||||
};
|
||||
std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) {
|
||||
return os << strerror(ep.no) << " [" << ep.no << "]";
|
||||
}
|
||||
bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; }
|
||||
|
||||
TEST(ErrnoSaverTest, Works) {
|
||||
errno = EDOM;
|
||||
{
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM}));
|
||||
errno = ERANGE;
|
||||
EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{ERANGE}));
|
||||
EXPECT_THAT(ErrnoPrinter{errno_saver()}, Eq(ErrnoPrinter{EDOM}));
|
||||
}
|
||||
EXPECT_THAT(ErrnoPrinter{errno}, Eq(ErrnoPrinter{EDOM}));
|
||||
}
|
||||
} // namespace
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "absl/base/internal/exception_safety_testing.h"
|
||||
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
@@ -73,3 +75,5 @@ std::string GetSpecString(AllocSpec spec) {
|
||||
} // namespace exceptions_internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
|
||||
#define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -27,7 +31,6 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/pretty_function.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
@@ -1093,4 +1096,6 @@ class ExceptionSafetyTestBuilder {
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
|
||||
|
||||
93
absl/base/internal/exponential_biased.cc
Normal file
93
absl/base/internal/exponential_biased.cc
Normal file
@@ -0,0 +1,93 @@
|
||||
// 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/exponential_biased.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// The algorithm generates a random number between 0 and 1 and applies 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 ExponentialBiased::GetSkipCount(int64_t mean) {
|
||||
if (ABSL_PREDICT_FALSE(!initialized_)) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
uint64_t rng = NextRandom(rng_);
|
||||
rng_ = 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.)
|
||||
// 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 >> (kPrngNumBits - 26)) + 1.0;
|
||||
// Put the computed p-value through the CDF of a geometric.
|
||||
double interval = bias_ + (std::log2(q) - 26) * (-std::log(2.0) * mean);
|
||||
// Very large values of interval overflow int64_t. To avoid that, we will
|
||||
// cheat and clamp any huge values to (int64_t max)/2. This is a potential
|
||||
// source of bias, but the mean would need to be such a large value that it's
|
||||
// not likely to come up. For example, with a mean of 1e18, the probability of
|
||||
// hitting this condition is about 1/1000. For a mean of 1e17, standard
|
||||
// calculators claim that this event won't happen.
|
||||
if (interval > static_cast<double>(std::numeric_limits<int64_t>::max() / 2)) {
|
||||
// Assume huge values are bias neutral, retain bias for next call.
|
||||
return std::numeric_limits<int64_t>::max() / 2;
|
||||
}
|
||||
double value = std::round(interval);
|
||||
bias_ = interval - value;
|
||||
return value;
|
||||
}
|
||||
|
||||
int64_t ExponentialBiased::GetStride(int64_t mean) {
|
||||
return GetSkipCount(mean - 1) + 1;
|
||||
}
|
||||
|
||||
void ExponentialBiased::Initialize() {
|
||||
// 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>(this) +
|
||||
global_rand.fetch_add(1, std::memory_order_relaxed);
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
r = NextRandom(r);
|
||||
}
|
||||
rng_ = r;
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
130
absl/base/internal/exponential_biased.h
Normal file
130
absl/base/internal/exponential_biased.h
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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_EXPONENTIAL_BIASED_H_
|
||||
#define ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// ExponentialBiased provides a small and fast random number generator for a
|
||||
// rounded exponential distribution. This generator manages very little state,
|
||||
// and imposes no synchronization overhead. This makes it useful in specialized
|
||||
// scenarios requiring minimum overhead, such as stride based periodic sampling.
|
||||
//
|
||||
// ExponentialBiased provides two closely related functions, GetSkipCount() and
|
||||
// GetStride(), both returning a rounded integer defining a number of events
|
||||
// required before some event with a given mean probability occurs.
|
||||
//
|
||||
// The distribution is useful to generate a random wait time or some periodic
|
||||
// event with a given mean probability. For example, if an action is supposed to
|
||||
// happen on average once every 'N' events, then we can get a random 'stride'
|
||||
// counting down how long before the event to happen. For example, if we'd want
|
||||
// to sample one in every 1000 'Frobber' calls, our code could look like this:
|
||||
//
|
||||
// Frobber::Frobber() {
|
||||
// stride_ = exponential_biased_.GetStride(1000);
|
||||
// }
|
||||
//
|
||||
// void Frobber::Frob(int arg) {
|
||||
// if (--stride == 0) {
|
||||
// SampleFrob(arg);
|
||||
// stride_ = exponential_biased_.GetStride(1000);
|
||||
// }
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The rounding of the return value creates a bias, especially for smaller means
|
||||
// where the distribution of the fraction is not evenly distributed. We correct
|
||||
// this bias by tracking the fraction we rounded up or down on each iteration,
|
||||
// effectively tracking the distance between the cumulative value, and the
|
||||
// rounded cumulative value. For example, given a mean of 2:
|
||||
//
|
||||
// raw = 1.63076, cumulative = 1.63076, rounded = 2, bias = -0.36923
|
||||
// raw = 0.14624, cumulative = 1.77701, rounded = 2, bias = 0.14624
|
||||
// raw = 4.93194, cumulative = 6.70895, rounded = 7, bias = -0.06805
|
||||
// raw = 0.24206, cumulative = 6.95101, rounded = 7, bias = 0.24206
|
||||
// etc...
|
||||
//
|
||||
// Adjusting with rounding bias is relatively trivial:
|
||||
//
|
||||
// double value = bias_ + exponential_distribution(mean)();
|
||||
// double rounded_value = std::round(value);
|
||||
// bias_ = value - rounded_value;
|
||||
// return rounded_value;
|
||||
//
|
||||
// This class is thread-compatible.
|
||||
class ExponentialBiased {
|
||||
public:
|
||||
// The number of bits set by NextRandom.
|
||||
static constexpr int kPrngNumBits = 48;
|
||||
|
||||
// `GetSkipCount()` returns the number of events to skip before some chosen
|
||||
// event happens. For example, randomly tossing a coin, we will on average
|
||||
// throw heads once before we get tails. We can simulate random coin tosses
|
||||
// using GetSkipCount() as:
|
||||
//
|
||||
// ExponentialBiased eb;
|
||||
// for (...) {
|
||||
// int number_of_heads_before_tail = eb.GetSkipCount(1);
|
||||
// for (int flips = 0; flips < number_of_heads_before_tail; ++flips) {
|
||||
// printf("head...");
|
||||
// }
|
||||
// printf("tail\n");
|
||||
// }
|
||||
//
|
||||
int64_t GetSkipCount(int64_t mean);
|
||||
|
||||
// GetStride() returns the number of events required for a specific event to
|
||||
// happen. See the class comments for a usage example. `GetStride()` is
|
||||
// equivalent to `GetSkipCount(mean - 1) + 1`. When to use `GetStride()` or
|
||||
// `GetSkipCount()` depends mostly on what best fits the use case.
|
||||
int64_t GetStride(int64_t mean);
|
||||
|
||||
// Computes a random number in the range [0, 1<<(kPrngNumBits+1) - 1]
|
||||
//
|
||||
// This is public to enable testing.
|
||||
static uint64_t NextRandom(uint64_t rnd);
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
|
||||
uint64_t rng_{0};
|
||||
double bias_{0};
|
||||
bool initialized_{false};
|
||||
};
|
||||
|
||||
// Returns the next prng value.
|
||||
// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48
|
||||
// This is the lrand64 generator.
|
||||
inline uint64_t ExponentialBiased::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 =
|
||||
~((~static_cast<uint64_t>(0)) << prng_mod_power);
|
||||
return (prng_mult * rnd + prng_add) & prng_mod_mask;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
|
||||
199
absl/base/internal/exponential_biased_test.cc
Normal file
199
absl/base/internal/exponential_biased_test.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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/exponential_biased.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
using ::testing::Ge;
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
MATCHER_P2(IsBetween, a, b,
|
||||
absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a,
|
||||
" and ", b)) {
|
||||
return a <= arg && arg <= b;
|
||||
}
|
||||
|
||||
// Tests of the quality of the random numbers generated
|
||||
// This uses the Anderson Darling test for uniformity.
|
||||
// See "Evaluating the Anderson-Darling Distribution" by Marsaglia
|
||||
// for details.
|
||||
|
||||
// Short cut version of ADinf(z), z>0 (from Marsaglia)
|
||||
// This returns the p-value for Anderson Darling statistic in
|
||||
// the limit as n-> infinity. For finite n, apply the error fix below.
|
||||
double AndersonDarlingInf(double z) {
|
||||
if (z < 2) {
|
||||
return exp(-1.2337141 / z) / sqrt(z) *
|
||||
(2.00012 +
|
||||
(0.247105 -
|
||||
(0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) *
|
||||
z) *
|
||||
z);
|
||||
}
|
||||
return exp(
|
||||
-exp(1.0776 -
|
||||
(2.30695 -
|
||||
(0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) *
|
||||
z));
|
||||
}
|
||||
|
||||
// Corrects the approximation error in AndersonDarlingInf for small values of n
|
||||
// Add this to AndersonDarlingInf to get a better approximation
|
||||
// (from Marsaglia)
|
||||
double AndersonDarlingErrFix(int n, double x) {
|
||||
if (x > 0.8) {
|
||||
return (-130.2137 +
|
||||
(745.2337 -
|
||||
(1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) *
|
||||
x) /
|
||||
n;
|
||||
}
|
||||
double cutoff = 0.01265 + 0.1757 / n;
|
||||
if (x < cutoff) {
|
||||
double t = x / cutoff;
|
||||
t = sqrt(t) * (1 - t) * (49 * t - 102);
|
||||
return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
|
||||
} else {
|
||||
double t = (x - cutoff) / (0.8 - cutoff);
|
||||
t = -0.00022633 +
|
||||
(6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) *
|
||||
t;
|
||||
return t * (0.04213 + 0.01365 / n) / n;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the AndersonDarling p-value given n and the value of the statistic
|
||||
double AndersonDarlingPValue(int n, double z) {
|
||||
double ad = AndersonDarlingInf(z);
|
||||
double errfix = AndersonDarlingErrFix(n, ad);
|
||||
return ad + errfix;
|
||||
}
|
||||
|
||||
double AndersonDarlingStatistic(const std::vector<double>& random_sample) {
|
||||
int n = random_sample.size();
|
||||
double ad_sum = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
ad_sum += (2 * i + 1) *
|
||||
std::log(random_sample[i] * (1 - random_sample[n - 1 - i]));
|
||||
}
|
||||
double ad_statistic = -n - 1 / static_cast<double>(n) * ad_sum;
|
||||
return ad_statistic;
|
||||
}
|
||||
|
||||
// Tests if the array of doubles is uniformly distributed.
|
||||
// Returns the p-value of the Anderson Darling Statistic
|
||||
// for the given set of sorted random doubles
|
||||
// See "Evaluating the Anderson-Darling Distribution" by
|
||||
// Marsaglia and Marsaglia for details.
|
||||
double AndersonDarlingTest(const std::vector<double>& random_sample) {
|
||||
double ad_statistic = AndersonDarlingStatistic(random_sample);
|
||||
double p = AndersonDarlingPValue(random_sample.size(), ad_statistic);
|
||||
return p;
|
||||
}
|
||||
|
||||
TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) {
|
||||
ExponentialBiased eb;
|
||||
for (int runs = 0; runs < 10; ++runs) {
|
||||
for (int flips = eb.GetSkipCount(1); flips > 0; --flips) {
|
||||
printf("head...");
|
||||
}
|
||||
printf("tail\n");
|
||||
}
|
||||
int heads = 0;
|
||||
for (int i = 0; i < 10000000; i += 1 + eb.GetSkipCount(1)) {
|
||||
++heads;
|
||||
}
|
||||
printf("Heads = %d (%f%%)\n", heads, 100.0 * heads / 10000000);
|
||||
}
|
||||
|
||||
TEST(ExponentialBiasedTest, SampleDemoWithStride) {
|
||||
ExponentialBiased eb;
|
||||
int stride = eb.GetStride(10);
|
||||
int samples = 0;
|
||||
for (int i = 0; i < 10000000; ++i) {
|
||||
if (--stride == 0) {
|
||||
++samples;
|
||||
stride = eb.GetStride(10);
|
||||
}
|
||||
}
|
||||
printf("Samples = %d (%f%%)\n", samples, 100.0 * samples / 10000000);
|
||||
}
|
||||
|
||||
|
||||
// Testing that NextRandom generates uniform random numbers. Applies the
|
||||
// Anderson-Darling test for uniformity
|
||||
TEST(ExponentialBiasedTest, TestNextRandom) {
|
||||
for (auto n : std::vector<int>({
|
||||
10, // Check short-range correlation
|
||||
100, 1000,
|
||||
10000 // Make sure there's no systemic error
|
||||
})) {
|
||||
uint64_t x = 1;
|
||||
// This assumes that the prng returns 48 bit numbers
|
||||
uint64_t max_prng_value = static_cast<uint64_t>(1) << 48;
|
||||
// Initialize.
|
||||
for (int i = 1; i <= 20; i++) {
|
||||
x = ExponentialBiased::NextRandom(x);
|
||||
}
|
||||
std::vector<uint64_t> int_random_sample(n);
|
||||
// Collect samples
|
||||
for (int i = 0; i < n; i++) {
|
||||
int_random_sample[i] = x;
|
||||
x = ExponentialBiased::NextRandom(x);
|
||||
}
|
||||
// First sort them...
|
||||
std::sort(int_random_sample.begin(), int_random_sample.end());
|
||||
std::vector<double> random_sample(n);
|
||||
// Convert them to uniform randoms (in the range [0,1])
|
||||
for (int i = 0; i < n; i++) {
|
||||
random_sample[i] =
|
||||
static_cast<double>(int_random_sample[i]) / max_prng_value;
|
||||
}
|
||||
// Now compute the Anderson-Darling statistic
|
||||
double ad_pvalue = AndersonDarlingTest(random_sample);
|
||||
EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001)
|
||||
<< "prng is not uniform: n = " << n << " p = " << ad_pvalue;
|
||||
}
|
||||
}
|
||||
|
||||
// The generator needs to be available as a thread_local and as a static
|
||||
// variable.
|
||||
TEST(ExponentialBiasedTest, InitializationModes) {
|
||||
ABSL_CONST_INIT static ExponentialBiased eb_static;
|
||||
EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
|
||||
|
||||
#if ABSL_HAVE_THREAD_LOCAL
|
||||
thread_local ExponentialBiased eb_thread;
|
||||
EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
|
||||
#endif
|
||||
|
||||
ExponentialBiased eb_stack;
|
||||
EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0));
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
@@ -17,8 +17,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Arbitrary value with high bits set. Xor'ing with it is unlikely
|
||||
@@ -43,7 +45,7 @@ inline T* UnhidePtr(uintptr_t hidden) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
#define ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
@@ -29,7 +31,7 @@ template <typename T>
|
||||
using identity_t = typename identity<T>::type;
|
||||
|
||||
} // namespace internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "absl/base/internal/inline_variable.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// top of this file for the API documentation.
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// The five classes below each implement one of the clauses from the definition
|
||||
@@ -181,7 +181,7 @@ InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_INVOKE_H_
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
#endif // __APPLE__
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// A first-fit allocator with amortized logarithmic free() time.
|
||||
@@ -204,32 +204,33 @@ struct LowLevelAlloc::Arena {
|
||||
|
||||
base_internal::SpinLock mu;
|
||||
// Head of free list, sorted by address
|
||||
AllocList freelist GUARDED_BY(mu);
|
||||
AllocList freelist ABSL_GUARDED_BY(mu);
|
||||
// Count of allocated blocks
|
||||
int32_t allocation_count GUARDED_BY(mu);
|
||||
int32_t allocation_count ABSL_GUARDED_BY(mu);
|
||||
// flags passed to NewArena
|
||||
const uint32_t flags;
|
||||
// Result of sysconf(_SC_PAGESIZE)
|
||||
const size_t pagesize;
|
||||
// Lowest power of two >= max(16, sizeof(AllocList))
|
||||
const size_t roundup;
|
||||
const size_t round_up;
|
||||
// Smallest allocation block size
|
||||
const size_t min_size;
|
||||
// PRNG state
|
||||
uint32_t random GUARDED_BY(mu);
|
||||
uint32_t random ABSL_GUARDED_BY(mu);
|
||||
};
|
||||
|
||||
namespace {
|
||||
using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena),
|
||||
alignof(LowLevelAlloc::Arena)>::type;
|
||||
|
||||
// Static storage space for the lazily-constructed, default global arena
|
||||
// instances. We require this space because the whole point of LowLevelAlloc
|
||||
// is to avoid relying on malloc/new.
|
||||
ArenaStorage default_arena_storage;
|
||||
ArenaStorage unhooked_arena_storage;
|
||||
alignas(LowLevelAlloc::Arena) unsigned char default_arena_storage[sizeof(
|
||||
LowLevelAlloc::Arena)];
|
||||
alignas(LowLevelAlloc::Arena) unsigned char unhooked_arena_storage[sizeof(
|
||||
LowLevelAlloc::Arena)];
|
||||
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||
ArenaStorage unhooked_async_sig_safe_arena_storage;
|
||||
alignas(
|
||||
LowLevelAlloc::Arena) unsigned char unhooked_async_sig_safe_arena_storage
|
||||
[sizeof(LowLevelAlloc::Arena)];
|
||||
#endif
|
||||
|
||||
// We must use LowLevelCallOnce here to construct the global arenas, rather than
|
||||
@@ -276,10 +277,10 @@ static const uintptr_t kMagicAllocated = 0x4c833e95U;
|
||||
static const uintptr_t kMagicUnallocated = ~kMagicAllocated;
|
||||
|
||||
namespace {
|
||||
class SCOPED_LOCKABLE ArenaLock {
|
||||
class ABSL_SCOPED_LOCKABLE ArenaLock {
|
||||
public:
|
||||
explicit ArenaLock(LowLevelAlloc::Arena *arena)
|
||||
EXCLUSIVE_LOCK_FUNCTION(arena->mu)
|
||||
ABSL_EXCLUSIVE_LOCK_FUNCTION(arena->mu)
|
||||
: arena_(arena) {
|
||||
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||
if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) {
|
||||
@@ -291,7 +292,7 @@ class SCOPED_LOCKABLE ArenaLock {
|
||||
arena_->mu.Lock();
|
||||
}
|
||||
~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); }
|
||||
void Leave() UNLOCK_FUNCTION() {
|
||||
void Leave() ABSL_UNLOCK_FUNCTION() {
|
||||
arena_->mu.Unlock();
|
||||
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||
if (mask_valid_) {
|
||||
@@ -337,11 +338,11 @@ size_t GetPageSize() {
|
||||
|
||||
size_t RoundedUpBlockSize() {
|
||||
// Round up block sizes to a power of two close to the header size.
|
||||
size_t roundup = 16;
|
||||
while (roundup < sizeof(AllocList::Header)) {
|
||||
roundup += roundup;
|
||||
size_t round_up = 16;
|
||||
while (round_up < sizeof(AllocList::Header)) {
|
||||
round_up += round_up;
|
||||
}
|
||||
return roundup;
|
||||
return round_up;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -351,8 +352,8 @@ LowLevelAlloc::Arena::Arena(uint32_t flags_value)
|
||||
allocation_count(0),
|
||||
flags(flags_value),
|
||||
pagesize(GetPageSize()),
|
||||
roundup(RoundedUpBlockSize()),
|
||||
min_size(2 * roundup),
|
||||
round_up(RoundedUpBlockSize()),
|
||||
min_size(2 * round_up),
|
||||
random(0) {
|
||||
freelist.header.size = 0;
|
||||
freelist.header.magic =
|
||||
@@ -448,7 +449,7 @@ static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) {
|
||||
// that the freelist is in the correct order, that it
|
||||
// consists of regions marked "unallocated", and that no two regions
|
||||
// are adjacent in memory (they should have been coalesced).
|
||||
// L < arena->mu
|
||||
// L >= arena->mu
|
||||
static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) {
|
||||
ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()");
|
||||
AllocList *next = prev->next[i];
|
||||
@@ -509,8 +510,6 @@ void LowLevelAlloc::Free(void *v) {
|
||||
if (v != nullptr) {
|
||||
AllocList *f = reinterpret_cast<AllocList *>(
|
||||
reinterpret_cast<char *>(v) - sizeof (f->header));
|
||||
ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header),
|
||||
"bad magic number in Free()");
|
||||
LowLevelAlloc::Arena *arena = f->header.arena;
|
||||
ArenaLock section(arena);
|
||||
AddToFreelist(v, arena);
|
||||
@@ -529,7 +528,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
|
||||
ArenaLock section(arena);
|
||||
// round up with header
|
||||
size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)),
|
||||
arena->roundup);
|
||||
arena->round_up);
|
||||
for (;;) { // loop until we find a suitable region
|
||||
// find the minimum levels that a block of this size must have
|
||||
int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1;
|
||||
@@ -615,7 +614,7 @@ void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_LOW_LEVEL_ALLOC_MISSING
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class LowLevelAlloc {
|
||||
@@ -120,7 +120,7 @@ class LowLevelAlloc {
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <utility>
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
@@ -150,7 +150,7 @@ static struct BeforeMain {
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -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_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class SchedulingHelper; // To allow use of SchedulingGuard.
|
||||
@@ -101,7 +101,7 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
|
||||
53
absl/base/internal/periodic_sampler.cc
Normal file
53
absl/base/internal/periodic_sampler.cc
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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/periodic_sampler.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "absl/base/internal/exponential_biased.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept {
|
||||
return rng_.GetStride(period);
|
||||
}
|
||||
|
||||
bool PeriodicSamplerBase::SubtleConfirmSample() noexcept {
|
||||
int current_period = period();
|
||||
|
||||
// Deal with period case 0 (always off) and 1 (always on)
|
||||
if (ABSL_PREDICT_FALSE(current_period < 2)) {
|
||||
stride_ = 0;
|
||||
return current_period == 1;
|
||||
}
|
||||
|
||||
// Check if this is the first call to Sample()
|
||||
if (ABSL_PREDICT_FALSE(stride_ == 1)) {
|
||||
stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
|
||||
if (static_cast<int64_t>(stride_) < -1) {
|
||||
++stride_;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stride_ = static_cast<uint64_t>(-GetExponentialBiased(current_period));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
211
absl/base/internal/periodic_sampler.h
Normal file
211
absl/base/internal/periodic_sampler.h
Normal file
@@ -0,0 +1,211 @@
|
||||
// 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_PERIODIC_SAMPLER_H_
|
||||
#define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "absl/base/internal/exponential_biased.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// PeriodicSamplerBase provides the basic period sampler implementation.
|
||||
//
|
||||
// This is the base class for the templated PeriodicSampler class, which holds
|
||||
// a global std::atomic value identified by a user defined tag, such that
|
||||
// each specific PeriodSampler implementation holds its own global period.
|
||||
//
|
||||
// PeriodicSamplerBase is thread-compatible except where stated otherwise.
|
||||
class PeriodicSamplerBase {
|
||||
public:
|
||||
// PeriodicSamplerBase is trivial / copyable / movable / destructible.
|
||||
PeriodicSamplerBase() = default;
|
||||
PeriodicSamplerBase(PeriodicSamplerBase&&) = default;
|
||||
PeriodicSamplerBase(const PeriodicSamplerBase&) = default;
|
||||
|
||||
// Returns true roughly once every `period` calls. This is established by a
|
||||
// randomly picked `stride` that is counted down on each call to `Sample`.
|
||||
// This stride is picked such that the probability of `Sample()` returning
|
||||
// true is 1 in `period`.
|
||||
inline bool Sample() noexcept;
|
||||
|
||||
// The below methods are intended for optimized use cases where the
|
||||
// size of the inlined fast path code is highly important. Applications
|
||||
// should use the `Sample()` method unless they have proof that their
|
||||
// specific use case requires the optimizations offered by these methods.
|
||||
//
|
||||
// An example of such a use case is SwissTable sampling. All sampling checks
|
||||
// are in inlined SwissTable methods, and the number of call sites is huge.
|
||||
// In this case, the inlined code size added to each translation unit calling
|
||||
// SwissTable methods is non-trivial.
|
||||
//
|
||||
// The `SubtleMaybeSample()` function spuriously returns true even if the
|
||||
// function should not be sampled, applications MUST match each call to
|
||||
// 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call,
|
||||
// and use the result of the latter as the sampling decision.
|
||||
// In other words: the code should logically be equivalent to:
|
||||
//
|
||||
// if (SubtleMaybeSample() && SubtleConfirmSample()) {
|
||||
// // Sample this call
|
||||
// }
|
||||
//
|
||||
// In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can
|
||||
// be placed out of line, for example, the typical use case looks as follows:
|
||||
//
|
||||
// // --- frobber.h -----------
|
||||
// void FrobberSampled();
|
||||
//
|
||||
// inline void FrobberImpl() {
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// inline void Frobber() {
|
||||
// if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) {
|
||||
// FrobberSampled();
|
||||
// } else {
|
||||
// FrobberImpl();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // --- frobber.cc -----------
|
||||
// void FrobberSampled() {
|
||||
// if (!sampler.SubtleConfirmSample())) {
|
||||
// // Spurious false positive
|
||||
// FrobberImpl();
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // Sampled execution
|
||||
// // ...
|
||||
// }
|
||||
inline bool SubtleMaybeSample() noexcept;
|
||||
bool SubtleConfirmSample() noexcept;
|
||||
|
||||
protected:
|
||||
// We explicitly don't use a virtual destructor as this class is never
|
||||
// virtually destroyed, and it keeps the class trivial, which avoids TLS
|
||||
// prologue and epilogue code for our TLS instances.
|
||||
~PeriodicSamplerBase() = default;
|
||||
|
||||
// Returns the next stride for our sampler.
|
||||
// This function is virtual for testing purposes only.
|
||||
virtual int64_t GetExponentialBiased(int period) noexcept;
|
||||
|
||||
private:
|
||||
// Returns the current period of this sampler. Thread-safe.
|
||||
virtual int period() const noexcept = 0;
|
||||
|
||||
// Keep and decrement stride_ as an unsigned integer, but compare the value
|
||||
// to zero casted as a signed int. clang and msvc do not create optimum code
|
||||
// if we use signed for the combined decrement and sign comparison.
|
||||
//
|
||||
// Below 3 alternative options, all compiles generate the best code
|
||||
// using the unsigned increment <---> signed int comparison option.
|
||||
//
|
||||
// Option 1:
|
||||
// int64_t stride_;
|
||||
// if (ABSL_PREDICT_TRUE(++stride_ < 0)) { ... }
|
||||
//
|
||||
// GCC x64 (OK) : https://gcc.godbolt.org/z/R5MzzA
|
||||
// GCC ppc (OK) : https://gcc.godbolt.org/z/z7NZAt
|
||||
// Clang x64 (BAD): https://gcc.godbolt.org/z/t4gPsd
|
||||
// ICC x64 (OK) : https://gcc.godbolt.org/z/rE6s8W
|
||||
// MSVC x64 (OK) : https://gcc.godbolt.org/z/ARMXqS
|
||||
//
|
||||
// Option 2:
|
||||
// int64_t stride_ = 0;
|
||||
// if (ABSL_PREDICT_TRUE(--stride_ >= 0)) { ... }
|
||||
//
|
||||
// GCC x64 (OK) : https://gcc.godbolt.org/z/jSQxYK
|
||||
// GCC ppc (OK) : https://gcc.godbolt.org/z/VJdYaA
|
||||
// Clang x64 (BAD): https://gcc.godbolt.org/z/Xm4NjX
|
||||
// ICC x64 (OK) : https://gcc.godbolt.org/z/4snaFd
|
||||
// MSVC x64 (BAD): https://gcc.godbolt.org/z/BgnEKE
|
||||
//
|
||||
// Option 3:
|
||||
// uint64_t stride_;
|
||||
// if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) { ... }
|
||||
//
|
||||
// GCC x64 (OK) : https://gcc.godbolt.org/z/bFbfPy
|
||||
// GCC ppc (OK) : https://gcc.godbolt.org/z/S9KkUE
|
||||
// Clang x64 (OK) : https://gcc.godbolt.org/z/UYzRb4
|
||||
// ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD
|
||||
// MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5
|
||||
uint64_t stride_ = 0;
|
||||
ExponentialBiased rng_;
|
||||
};
|
||||
|
||||
inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept {
|
||||
// See comments on `stride_` for the unsigned increment / signed compare.
|
||||
if (ABSL_PREDICT_TRUE(static_cast<int64_t>(++stride_) < 0)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PeriodicSamplerBase::Sample() noexcept {
|
||||
return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample()
|
||||
: false;
|
||||
}
|
||||
|
||||
// PeriodicSampler is a concreted periodic sampler implementation.
|
||||
// The user provided Tag identifies the implementation, and is required to
|
||||
// isolate the global state of this instance from other instances.
|
||||
//
|
||||
// Typical use case:
|
||||
//
|
||||
// struct HashTablezTag {};
|
||||
// thread_local PeriodicSampler sampler;
|
||||
//
|
||||
// void HashTableSamplingLogic(...) {
|
||||
// if (sampler.Sample()) {
|
||||
// HashTableSlowSamplePath(...);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
template <typename Tag, int default_period = 0>
|
||||
class PeriodicSampler final : public PeriodicSamplerBase {
|
||||
public:
|
||||
~PeriodicSampler() = default;
|
||||
|
||||
int period() const noexcept final {
|
||||
return period_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Sets the global period for this sampler. Thread-safe.
|
||||
// Setting a period of 0 disables the sampler, i.e., every call to Sample()
|
||||
// will return false. Setting a period of 1 puts the sampler in 'always on'
|
||||
// mode, i.e., every call to Sample() returns true.
|
||||
static void SetGlobalPeriod(int period) {
|
||||
period_.store(period, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::atomic<int> period_;
|
||||
};
|
||||
|
||||
template <typename Tag, int default_period>
|
||||
std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period);
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
|
||||
79
absl/base/internal/periodic_sampler_benchmark.cc
Normal file
79
absl/base/internal/periodic_sampler_benchmark.cc
Normal file
@@ -0,0 +1,79 @@
|
||||
// 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 "benchmark/benchmark.h"
|
||||
#include "absl/base/internal/periodic_sampler.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
template <typename Sampler>
|
||||
void BM_Sample(Sampler* sampler, benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(sampler);
|
||||
benchmark::DoNotOptimize(sampler->Sample());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Sampler>
|
||||
void BM_SampleMinunumInlined(Sampler* sampler, benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
benchmark::DoNotOptimize(sampler);
|
||||
if (ABSL_PREDICT_FALSE(sampler->SubtleMaybeSample())) {
|
||||
benchmark::DoNotOptimize(sampler->SubtleConfirmSample());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BM_PeriodicSampler_TinySample(benchmark::State& state) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 10> sampler;
|
||||
BM_Sample(&sampler, state);
|
||||
}
|
||||
BENCHMARK(BM_PeriodicSampler_TinySample);
|
||||
|
||||
void BM_PeriodicSampler_ShortSample(benchmark::State& state) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 1024> sampler;
|
||||
BM_Sample(&sampler, state);
|
||||
}
|
||||
BENCHMARK(BM_PeriodicSampler_ShortSample);
|
||||
|
||||
void BM_PeriodicSampler_LongSample(benchmark::State& state) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 1024 * 1024> sampler;
|
||||
BM_Sample(&sampler, state);
|
||||
}
|
||||
BENCHMARK(BM_PeriodicSampler_LongSample);
|
||||
|
||||
void BM_PeriodicSampler_LongSampleMinunumInlined(benchmark::State& state) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 1024 * 1024> sampler;
|
||||
BM_SampleMinunumInlined(&sampler, state);
|
||||
}
|
||||
BENCHMARK(BM_PeriodicSampler_LongSampleMinunumInlined);
|
||||
|
||||
void BM_PeriodicSampler_Disabled(benchmark::State& state) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 0> sampler;
|
||||
BM_Sample(&sampler, state);
|
||||
}
|
||||
BENCHMARK(BM_PeriodicSampler_Disabled);
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
177
absl/base/internal/periodic_sampler_test.cc
Normal file
177
absl/base/internal/periodic_sampler_test.cc
Normal file
@@ -0,0 +1,177 @@
|
||||
// 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/periodic_sampler.h"
|
||||
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/macros.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
using testing::Eq;
|
||||
using testing::Return;
|
||||
using testing::StrictMock;
|
||||
|
||||
class MockPeriodicSampler : public PeriodicSamplerBase {
|
||||
public:
|
||||
virtual ~MockPeriodicSampler() = default;
|
||||
|
||||
MOCK_METHOD(int, period, (), (const, noexcept));
|
||||
MOCK_METHOD(int64_t, GetExponentialBiased, (int), (noexcept));
|
||||
};
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, Sample) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(16));
|
||||
EXPECT_CALL(sampler, GetExponentialBiased(16))
|
||||
.WillOnce(Return(2))
|
||||
.WillOnce(Return(3))
|
||||
.WillOnce(Return(4));
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, ImmediatelySample) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
|
||||
EXPECT_CALL(sampler, GetExponentialBiased(16))
|
||||
.WillOnce(Return(1))
|
||||
.WillOnce(Return(2))
|
||||
.WillOnce(Return(3));
|
||||
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, Disabled) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(0));
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, AlwaysOn) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(1));
|
||||
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, Disable) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).WillOnce(Return(16));
|
||||
EXPECT_CALL(sampler, GetExponentialBiased(16)).WillOnce(Return(3));
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(0));
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerBaseTest, Enable) {
|
||||
StrictMock<MockPeriodicSampler> sampler;
|
||||
|
||||
EXPECT_CALL(sampler, period()).WillOnce(Return(0));
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
|
||||
EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
|
||||
EXPECT_CALL(sampler, GetExponentialBiased(16))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(3));
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_TRUE(sampler.Sample());
|
||||
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
EXPECT_FALSE(sampler.Sample());
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerTest, ConstructConstInit) {
|
||||
struct Tag {};
|
||||
ABSL_CONST_INIT static PeriodicSampler<Tag> sampler;
|
||||
(void)sampler;
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerTest, DefaultPeriod0) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag> sampler;
|
||||
EXPECT_THAT(sampler.period(), Eq(0));
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerTest, DefaultPeriod) {
|
||||
struct Tag {};
|
||||
PeriodicSampler<Tag, 100> sampler;
|
||||
EXPECT_THAT(sampler.period(), Eq(100));
|
||||
}
|
||||
|
||||
TEST(PeriodicSamplerTest, SetGlobalPeriod) {
|
||||
struct Tag1 {};
|
||||
struct Tag2 {};
|
||||
PeriodicSampler<Tag1, 25> sampler1;
|
||||
PeriodicSampler<Tag2, 50> sampler2;
|
||||
|
||||
EXPECT_THAT(sampler1.period(), Eq(25));
|
||||
EXPECT_THAT(sampler2.period(), Eq(50));
|
||||
|
||||
std::thread thread([] {
|
||||
PeriodicSampler<Tag1, 25> sampler1;
|
||||
PeriodicSampler<Tag2, 50> sampler2;
|
||||
EXPECT_THAT(sampler1.period(), Eq(25));
|
||||
EXPECT_THAT(sampler2.period(), Eq(50));
|
||||
sampler1.SetGlobalPeriod(10);
|
||||
sampler2.SetGlobalPeriod(20);
|
||||
});
|
||||
thread.join();
|
||||
|
||||
EXPECT_THAT(sampler1.period(), Eq(10));
|
||||
EXPECT_THAT(sampler2.period(), Eq(20));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
@@ -37,9 +37,9 @@
|
||||
// this, consider moving both to config.h instead.
|
||||
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||
defined(__Fuchsia__) || defined(__native_client__) || \
|
||||
defined(__EMSCRIPTEN__)
|
||||
#include <unistd.h>
|
||||
defined(__EMSCRIPTEN__) || defined(__ASYLO__)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define ABSL_HAVE_POSIX_WRITE 1
|
||||
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
|
||||
@@ -71,10 +71,12 @@
|
||||
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
|
||||
// whitelisted set of platforms for which we expect not to be able to raw log.
|
||||
|
||||
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::LogPrefixHook> log_prefix_hook;
|
||||
ABSL_CONST_INIT static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::AbortHook> abort_hook;
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::LogPrefixHook>
|
||||
log_prefix_hook;
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
|
||||
absl::raw_logging_internal::AbortHook>
|
||||
abort_hook;
|
||||
|
||||
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
static const char kTruncated[] = " ... (message truncated)\n";
|
||||
@@ -182,7 +184,7 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
|
||||
} // namespace
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace raw_logging_internal {
|
||||
void SafeWriteToStderr(const char *s, size_t len) {
|
||||
#if defined(ABSL_HAVE_SYSCALL_WRITE)
|
||||
@@ -225,13 +227,14 @@ bool RawLoggingFullySupported() {
|
||||
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
|
||||
}
|
||||
|
||||
ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction>
|
||||
internal_log_function(DefaultInternalLog);
|
||||
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
absl::base_internal::AtomicHook<InternalLogFunction>
|
||||
internal_log_function(DefaultInternalLog);
|
||||
|
||||
void RegisterInternalLogFunction(InternalLogFunction func) {
|
||||
internal_log_function.Store(func);
|
||||
}
|
||||
|
||||
} // namespace raw_logging_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -22,9 +22,11 @@
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/atomic_hook.h"
|
||||
#include "absl/base/log_severity.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
// This is similar to LOG(severity) << format..., but
|
||||
@@ -70,14 +72,10 @@
|
||||
//
|
||||
// The API is a subset of the above: each macro only takes two arguments. Use
|
||||
// StrCat if you need to build a richer message.
|
||||
#define ABSL_INTERNAL_LOG(severity, message) \
|
||||
do { \
|
||||
constexpr const char* absl_raw_logging_internal_basename = \
|
||||
::absl::raw_logging_internal::Basename(__FILE__, \
|
||||
sizeof(__FILE__) - 1); \
|
||||
::absl::raw_logging_internal::internal_log_function( \
|
||||
ABSL_RAW_LOGGING_INTERNAL_##severity, \
|
||||
absl_raw_logging_internal_basename, __LINE__, message); \
|
||||
#define ABSL_INTERNAL_LOG(severity, message) \
|
||||
do { \
|
||||
::absl::raw_logging_internal::internal_log_function( \
|
||||
ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, message); \
|
||||
} while (0)
|
||||
|
||||
#define ABSL_INTERNAL_CHECK(condition, message) \
|
||||
@@ -97,7 +95,7 @@
|
||||
::absl::NormalizeLogSeverity(severity)
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace raw_logging_internal {
|
||||
|
||||
// Helper function to implement ABSL_RAW_LOG
|
||||
@@ -158,7 +156,7 @@ using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
|
||||
//
|
||||
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
|
||||
// was located.
|
||||
// The null-terminated logged message lives in the buffer between 'buf_start'
|
||||
// The NUL-terminated logged message lives in the buffer between 'buf_start'
|
||||
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
|
||||
// buffer (as written by the LogPrefixHook.)
|
||||
using AbortHook = void (*)(const char* file, int line, const char* buf_start,
|
||||
@@ -172,12 +170,14 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity,
|
||||
const char* file, int line,
|
||||
const std::string& message);
|
||||
|
||||
extern base_internal::AtomicHook<InternalLogFunction> internal_log_function;
|
||||
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES extern base_internal::AtomicHook<
|
||||
InternalLogFunction>
|
||||
internal_log_function;
|
||||
|
||||
void RegisterInternalLogFunction(InternalLogFunction func);
|
||||
|
||||
} // namespace raw_logging_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Used to describe how a thread may be scheduled. Typically associated with
|
||||
@@ -50,7 +52,7 @@ enum SchedulingMode {
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
namespace {
|
||||
@@ -77,5 +77,5 @@ ScopedSetEnv::~ScopedSetEnv() {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class ScopedSetEnv {
|
||||
@@ -37,7 +39,7 @@ class ScopedSetEnv {
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SCOPED_SET_ENV_H_
|
||||
|
||||
@@ -54,11 +54,11 @@
|
||||
// holder to acquire the lock. There may be outstanding waiter(s).
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
|
||||
int64_t wait_cycles)>
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static base_internal::AtomicHook<void (*)(
|
||||
const void *lock, int64_t wait_cycles)>
|
||||
submit_profile_data;
|
||||
|
||||
void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
|
||||
@@ -229,5 +229,5 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -46,10 +46,10 @@
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class LOCKABLE SpinLock {
|
||||
class ABSL_LOCKABLE SpinLock {
|
||||
public:
|
||||
SpinLock() : lockword_(kSpinLockCooperative) {
|
||||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||
@@ -80,7 +80,7 @@ class LOCKABLE SpinLock {
|
||||
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
|
||||
|
||||
// Acquire this SpinLock.
|
||||
inline void Lock() EXCLUSIVE_LOCK_FUNCTION() {
|
||||
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
|
||||
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
|
||||
if (!TryLockImpl()) {
|
||||
SlowLock();
|
||||
@@ -92,7 +92,7 @@ class LOCKABLE SpinLock {
|
||||
// acquisition was successful. If the lock was not acquired, false is
|
||||
// returned. If this SpinLock is free at the time of the call, TryLock
|
||||
// will return true with high probability.
|
||||
inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
|
||||
bool res = TryLockImpl();
|
||||
ABSL_TSAN_MUTEX_POST_LOCK(
|
||||
@@ -102,7 +102,7 @@ class LOCKABLE SpinLock {
|
||||
}
|
||||
|
||||
// Release this SpinLock, which must be held by the calling thread.
|
||||
inline void Unlock() UNLOCK_FUNCTION() {
|
||||
inline void Unlock() ABSL_UNLOCK_FUNCTION() {
|
||||
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
|
||||
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
|
||||
lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
|
||||
@@ -180,13 +180,13 @@ class LOCKABLE SpinLock {
|
||||
|
||||
// Corresponding locker object that arranges to acquire a spinlock for
|
||||
// the duration of a C++ scope.
|
||||
class SCOPED_LOCKABLE SpinLockHolder {
|
||||
class ABSL_SCOPED_LOCKABLE SpinLockHolder {
|
||||
public:
|
||||
inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l)
|
||||
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
|
||||
: lock_(l) {
|
||||
l->Lock();
|
||||
}
|
||||
inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); }
|
||||
inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
|
||||
|
||||
SpinLockHolder(const SpinLockHolder&) = delete;
|
||||
SpinLockHolder& operator=(const SpinLockHolder&) = delete;
|
||||
@@ -226,11 +226,10 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
|
||||
}
|
||||
}
|
||||
|
||||
if (lockword_.compare_exchange_strong(
|
||||
if (!lockword_.compare_exchange_strong(
|
||||
lock_value,
|
||||
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
|
||||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||||
} else {
|
||||
base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
|
||||
}
|
||||
|
||||
@@ -238,7 +237,7 @@ inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/internal/errno_saver.h"
|
||||
|
||||
// The SpinLock lockword is `std::atomic<uint32_t>`. Here we assert that
|
||||
// `std::atomic<uint32_t>` is bitwise equivalent of the `int` expected
|
||||
@@ -51,12 +51,11 @@ extern "C" {
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
||||
std::atomic<uint32_t> *w, uint32_t value, int loop,
|
||||
absl::base_internal::SchedulingMode) {
|
||||
int save_errno = errno;
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
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,
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
// This file is a Posix-specific part of spinlock_wait.cc
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <cerrno>
|
||||
|
||||
#include "absl/base/internal/errno_saver.h"
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
@@ -27,7 +28,7 @@ extern "C" {
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
||||
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
|
||||
absl::base_internal::SchedulingMode /* mode */) {
|
||||
int save_errno = errno;
|
||||
absl::base_internal::ErrnoSaver errno_saver;
|
||||
if (loop == 0) {
|
||||
} else if (loop == 1) {
|
||||
sched_yield();
|
||||
@@ -37,7 +38,6 @@ ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
|
||||
tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop);
|
||||
nanosleep(&tm, nullptr);
|
||||
}
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// See spinlock_wait.h for spec.
|
||||
@@ -77,5 +77,5 @@ int SpinLockSuggestedDelayNS(int loop) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// In some build configurations we pass --detect-odr-violations to the
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "absl/base/attributes.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlwapi.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
@@ -56,13 +55,9 @@
|
||||
#include "absl/base/internal/unscaledcycleclock.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
static once_flag init_system_info_once;
|
||||
static int num_cpus = 0;
|
||||
static double nominal_cpu_frequency = 1.0; // 0.0 might be dangerous.
|
||||
|
||||
static int GetNumCPUs() {
|
||||
#if defined(__myriad2__)
|
||||
return 1;
|
||||
@@ -77,14 +72,23 @@ static int GetNumCPUs() {
|
||||
#if defined(_WIN32)
|
||||
|
||||
static double GetNominalCPUFrequency() {
|
||||
DWORD data;
|
||||
DWORD data_size = sizeof(data);
|
||||
#pragma comment(lib, "shlwapi.lib") // For SHGetValue().
|
||||
if (SUCCEEDED(
|
||||
SHGetValueA(HKEY_LOCAL_MACHINE,
|
||||
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
|
||||
"~MHz", nullptr, &data, &data_size))) {
|
||||
return data * 1e6; // Value is MHz.
|
||||
#pragma comment(lib, "advapi32.lib") // For Reg* functions.
|
||||
HKEY key;
|
||||
// Use the Reg* functions rather than the SH functions because shlwapi.dll
|
||||
// pulls in gdi32.dll which makes process destruction much more costly.
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0,
|
||||
KEY_READ, &key) == ERROR_SUCCESS) {
|
||||
DWORD type = 0;
|
||||
DWORD data = 0;
|
||||
DWORD data_size = sizeof(data);
|
||||
auto result = RegQueryValueExA(key, "~MHz", 0, &type,
|
||||
reinterpret_cast<LPBYTE>(&data), &data_size);
|
||||
RegCloseKey(key);
|
||||
if (result == ERROR_SUCCESS && type == REG_DWORD &&
|
||||
data_size == sizeof(data)) {
|
||||
return data * 1e6; // Value is MHz.
|
||||
}
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
@@ -257,28 +261,34 @@ static double GetNominalCPUFrequency() {
|
||||
|
||||
#endif
|
||||
|
||||
// InitializeSystemInfo() may be called before main() and before
|
||||
// malloc is properly initialized, therefore this must not allocate
|
||||
// memory.
|
||||
static void InitializeSystemInfo() {
|
||||
num_cpus = GetNumCPUs();
|
||||
nominal_cpu_frequency = GetNominalCPUFrequency();
|
||||
}
|
||||
ABSL_CONST_INIT static once_flag init_num_cpus_once;
|
||||
ABSL_CONST_INIT static int num_cpus = 0;
|
||||
|
||||
// NumCPUs() may be called before main() and before malloc is properly
|
||||
// initialized, therefore this must not allocate memory.
|
||||
int NumCPUs() {
|
||||
base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
|
||||
base_internal::LowLevelCallOnce(
|
||||
&init_num_cpus_once, []() { num_cpus = GetNumCPUs(); });
|
||||
return num_cpus;
|
||||
}
|
||||
|
||||
// A default frequency of 0.0 might be dangerous if it is used in division.
|
||||
ABSL_CONST_INIT static once_flag init_nominal_cpu_frequency_once;
|
||||
ABSL_CONST_INIT static double nominal_cpu_frequency = 1.0;
|
||||
|
||||
// NominalCPUFrequency() may be called before main() and before malloc is
|
||||
// properly initialized, therefore this must not allocate memory.
|
||||
double NominalCPUFrequency() {
|
||||
base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo);
|
||||
base_internal::LowLevelCallOnce(
|
||||
&init_nominal_cpu_frequency_once,
|
||||
[]() { nominal_cpu_frequency = GetNominalCPUFrequency(); });
|
||||
return nominal_cpu_frequency;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
pid_t GetTID() {
|
||||
return GetCurrentThreadId();
|
||||
return pid_t{GetCurrentThreadId()};
|
||||
}
|
||||
|
||||
#elif defined(__linux__)
|
||||
@@ -402,5 +412,5 @@ pid_t GetTID() {
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <intsafe.h>
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Nominal core processor cycles per second of each processor. This is _not_
|
||||
@@ -52,14 +52,15 @@ int NumCPUs();
|
||||
// On Linux, you may send a signal to the resulting ID with kill(). However,
|
||||
// it is recommended for portability that you use pthread_kill() instead.
|
||||
#ifdef _WIN32
|
||||
// On Windows, process id and thread id are of the same type according to
|
||||
// the return types of GetProcessId() and GetThreadId() are both DWORD.
|
||||
using pid_t = DWORD;
|
||||
// On Windows, process id and thread id are of the same type according to the
|
||||
// return types of GetProcessId() and GetThreadId() are both DWORD, an unsigned
|
||||
// 32-bit type.
|
||||
using pid_t = uint32_t;
|
||||
#endif
|
||||
pid_t GetTID();
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SYSINFO_H_
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
@@ -59,8 +59,8 @@ TEST(SysinfoTest, GetTID) {
|
||||
#endif
|
||||
// Test that TIDs are unique to each thread.
|
||||
// Uses a few loops to exercise implementations that reallocate IDs.
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
constexpr int kNumThreads = 64;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
constexpr int kNumThreads = 10;
|
||||
Barrier all_threads_done(kNumThreads);
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
@@ -96,5 +96,5 @@ TEST(SysinfoTest, LinuxGetTID) {
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
@@ -56,7 +56,12 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
|
||||
#ifdef __GNUC__
|
||||
__attribute__((visibility("protected")))
|
||||
#endif // __GNUC__
|
||||
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
|
||||
#if ABSL_PER_THREAD_TLS
|
||||
// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
|
||||
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
|
||||
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||
thread_local ThreadIdentity* thread_identity_ptr = nullptr;
|
||||
#endif // ABSL_PER_THREAD_TLS
|
||||
#endif // TLS or CPP11
|
||||
|
||||
void SetCurrentThreadIdentity(
|
||||
@@ -70,8 +75,8 @@ void SetCurrentThreadIdentity(
|
||||
absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey,
|
||||
reclaimer);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// Emscripten PThread implementation does not support signals.
|
||||
#if defined(__EMSCRIPTEN__) || defined(__MINGW32__)
|
||||
// Emscripten and MinGW pthread implementations does not support signals.
|
||||
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
|
||||
// for more information.
|
||||
pthread_setspecific(thread_identity_pthread_key,
|
||||
@@ -90,7 +95,7 @@ void SetCurrentThreadIdentity(
|
||||
pthread_setspecific(thread_identity_pthread_key,
|
||||
reinterpret_cast<void*>(identity));
|
||||
pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr);
|
||||
#endif // !__EMSCRIPTEN__
|
||||
#endif // !__EMSCRIPTEN__ && !__MINGW32__
|
||||
|
||||
#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||
// NOTE: Not async-safe. But can be open-coded.
|
||||
@@ -108,6 +113,18 @@ void SetCurrentThreadIdentity(
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
|
||||
// Please see the comment on `CurrentThreadIdentityIfPresent` in
|
||||
// thread_identity.h. Because DLLs cannot expose thread_local variables in
|
||||
// headers, we opt for the correct-but-slower option of placing the definition
|
||||
// of this function only in a translation unit inside DLL.
|
||||
#if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL)
|
||||
ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void ClearCurrentThreadIdentity() {
|
||||
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
@@ -131,5 +148,5 @@ ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -30,10 +30,11 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
struct SynchLocksHeld;
|
||||
struct SynchWaitParams;
|
||||
@@ -209,7 +210,7 @@ void ClearCurrentThreadIdentity();
|
||||
#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set
|
||||
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
|
||||
#elif defined(_WIN32)
|
||||
#elif defined(_WIN32) && !defined(__MINGW32__)
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
|
||||
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
|
||||
@@ -225,11 +226,26 @@ void ClearCurrentThreadIdentity();
|
||||
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
|
||||
extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr;
|
||||
#if ABSL_PER_THREAD_TLS
|
||||
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
|
||||
thread_identity_ptr;
|
||||
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
|
||||
#else
|
||||
#error Thread-local storage not detected on this platform
|
||||
#endif
|
||||
|
||||
// thread_local variables cannot be in headers exposed by DLLs. However, it is
|
||||
// important for performance reasons in general that
|
||||
// `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a
|
||||
// DLL boundary so, with DLLs, we opt to have the function not be inlined. Note
|
||||
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
|
||||
// this entire inline definition when compiling as a DLL.
|
||||
#if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL)
|
||||
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||
return thread_identity_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif ABSL_THREAD_IDENTITY_MODE != \
|
||||
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||
@@ -237,7 +253,7 @@ inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
@@ -124,5 +124,5 @@ TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -19,8 +19,10 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Helper functions that allow throwing exceptions consistently from anywhere.
|
||||
@@ -67,7 +69,7 @@ namespace base_internal {
|
||||
// [[noreturn]] void ThrowStdBadArrayNewLength();
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// unaligned APIs
|
||||
|
||||
@@ -56,7 +58,7 @@ void __sanitizer_unaligned_store64(void *p, uint64_t v);
|
||||
} // extern "C"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
inline uint16_t UnalignedLoad16(const void *p) {
|
||||
@@ -84,7 +86,7 @@ inline void UnalignedStore64(void *p, uint64_t v) {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
|
||||
@@ -104,7 +106,7 @@ inline void UnalignedStore64(void *p, uint64_t v) {
|
||||
#else
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
inline uint16_t UnalignedLoad16(const void *p) {
|
||||
@@ -132,7 +134,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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
|
||||
|
||||
@@ -21,13 +21,18 @@
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__) || defined(__ppc__)
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/platform/ppc.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "absl/base/internal/sysinfo.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
#if defined(__i386__)
|
||||
@@ -57,11 +62,43 @@ double UnscaledCycleClock::Frequency() {
|
||||
#elif defined(__powerpc__) || defined(__ppc__)
|
||||
|
||||
int64_t UnscaledCycleClock::Now() {
|
||||
#ifdef __GLIBC__
|
||||
return __ppc_get_timebase();
|
||||
#else
|
||||
#ifdef __powerpc64__
|
||||
int64_t tbr;
|
||||
asm volatile("mfspr %0, 268" : "=r"(tbr));
|
||||
return tbr;
|
||||
#else
|
||||
int32_t tbu, tbl, tmp;
|
||||
asm volatile(
|
||||
"0:\n"
|
||||
"mftbu %[hi32]\n"
|
||||
"mftb %[lo32]\n"
|
||||
"mftbu %[tmp]\n"
|
||||
"cmpw %[tmp],%[hi32]\n"
|
||||
"bne 0b\n"
|
||||
: [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));
|
||||
return (static_cast<int64_t>(tbu) << 32) | tbl;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
double UnscaledCycleClock::Frequency() {
|
||||
#ifdef __GLIBC__
|
||||
return __ppc_get_timebase_freq();
|
||||
#elif defined(__FreeBSD__)
|
||||
static once_flag init_timebase_frequency_once;
|
||||
static double timebase_frequency = 0.0;
|
||||
base_internal::LowLevelCallOnce(&init_timebase_frequency_once, [&]() {
|
||||
size_t length = sizeof(timebase_frequency);
|
||||
sysctlbyname("kern.timecounter.tc.timebase.frequency", &timebase_frequency,
|
||||
&length, nullptr, 0);
|
||||
});
|
||||
return timebase_frequency;
|
||||
#else
|
||||
#error Must implement UnscaledCycleClock::Frequency()
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
@@ -97,7 +134,7 @@ double UnscaledCycleClock::Frequency() {
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
class UnscaledCycleClockWrapperForGetCurrentTime;
|
||||
} // namespace time_internal
|
||||
@@ -116,7 +116,7 @@ class UnscaledCycleClock {
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
namespace {
|
||||
|
||||
@@ -219,5 +219,5 @@ TEST(InvokeTest, SfinaeFriendly) {
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#include <ostream>
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -19,13 +19,53 @@
|
||||
#include <ostream>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// Four severity levels are defined. Logging APIs should terminate the program
|
||||
// absl::LogSeverity
|
||||
//
|
||||
// Four severity levels are defined. Logging APIs should terminate the program
|
||||
// when a message is logged at severity `kFatal`; the other levels have no
|
||||
// special semantics.
|
||||
//
|
||||
// Values other than the four defined levels (e.g. produced by `static_cast`)
|
||||
// are valid, but their semantics when passed to a function, macro, or flag
|
||||
// depend on the function, macro, or flag. The usual behavior is to normalize
|
||||
// such values to a defined severity level, however in some cases values other
|
||||
// than the defined levels are useful for comparison.
|
||||
//
|
||||
// Exmaple:
|
||||
//
|
||||
// // Effectively disables all logging:
|
||||
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
|
||||
//
|
||||
// Abseil flags may be defined with type `LogSeverity`. Dependency layering
|
||||
// constraints require that the `AbslParseFlag()` overload be declared and
|
||||
// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
|
||||
// overload is defined there as well for consistency.
|
||||
//
|
||||
// absl::LogSeverity Flag String Representation
|
||||
//
|
||||
// An `absl::LogSeverity` has a string representation used for parsing
|
||||
// command-line flags based on the enumerator name (e.g. `kFatal`) or
|
||||
// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
|
||||
// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
|
||||
// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
|
||||
//
|
||||
// Additionally, the parser accepts arbitrary integers (as if the type were
|
||||
// `int`).
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// --my_log_level=kInfo
|
||||
// --my_log_level=INFO
|
||||
// --my_log_level=info
|
||||
// --my_log_level=0
|
||||
//
|
||||
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
|
||||
// the standard levels and a base-ten integer otherwise.
|
||||
enum class LogSeverity : int {
|
||||
kInfo = 0,
|
||||
kWarning = 1,
|
||||
@@ -33,6 +73,8 @@ enum class LogSeverity : int {
|
||||
kFatal = 3,
|
||||
};
|
||||
|
||||
// LogSeverities()
|
||||
//
|
||||
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
|
||||
// least to most severe.
|
||||
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
|
||||
@@ -40,8 +82,10 @@ constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
|
||||
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
|
||||
}
|
||||
|
||||
// LogSeverityName()
|
||||
//
|
||||
// Returns the all-caps string representation (e.g. "INFO") of the specified
|
||||
// severity level if it is one of the normal levels and "UNKNOWN" otherwise.
|
||||
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
|
||||
constexpr const char* LogSeverityName(absl::LogSeverity s) {
|
||||
return s == absl::LogSeverity::kInfo
|
||||
? "INFO"
|
||||
@@ -52,6 +96,8 @@ constexpr const char* LogSeverityName(absl::LogSeverity s) {
|
||||
: s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN";
|
||||
}
|
||||
|
||||
// NormalizeLogSeverity()
|
||||
//
|
||||
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
|
||||
// normalize to `kError` (**NOT** `kFatal`).
|
||||
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
|
||||
@@ -60,14 +106,16 @@ constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
|
||||
: s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s;
|
||||
}
|
||||
constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
|
||||
return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
|
||||
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
|
||||
}
|
||||
|
||||
// operator<<
|
||||
//
|
||||
// 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
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
|
||||
|
||||
@@ -14,14 +14,26 @@
|
||||
|
||||
#include "absl/base/log_severity.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <ios>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/flags/internal/flag.h"
|
||||
#include "absl/flags/marshalling.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
||||
namespace {
|
||||
using testing::Eq;
|
||||
using ::testing::Eq;
|
||||
using ::testing::IsFalse;
|
||||
using ::testing::IsTrue;
|
||||
using ::testing::TestWithParam;
|
||||
using ::testing::Values;
|
||||
|
||||
std::string StreamHelper(absl::LogSeverity value) {
|
||||
std::ostringstream stream;
|
||||
@@ -40,4 +52,153 @@ TEST(StreamTest, Works) {
|
||||
Eq("absl::LogSeverity(4)"));
|
||||
}
|
||||
|
||||
static_assert(
|
||||
absl::flags_internal::IsAtomicFlagTypeTrait<absl::LogSeverity>::value,
|
||||
"Flags of type absl::LogSeverity ought to be lock-free.");
|
||||
|
||||
using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Instantiation, ParseFlagFromOutOfRangeIntegerTest,
|
||||
Values(static_cast<int64_t>(std::numeric_limits<int>::min()) - 1,
|
||||
static_cast<int64_t>(std::numeric_limits<int>::max()) + 1));
|
||||
TEST_P(ParseFlagFromOutOfRangeIntegerTest, ReturnsError) {
|
||||
const std::string to_parse = absl::StrCat(GetParam());
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
EXPECT_THAT(absl::ParseFlag(to_parse, &value, &error), IsFalse()) << value;
|
||||
}
|
||||
|
||||
using ParseFlagFromAlmostOutOfRangeIntegerTest = TestWithParam<int>;
|
||||
INSTANTIATE_TEST_SUITE_P(Instantiation,
|
||||
ParseFlagFromAlmostOutOfRangeIntegerTest,
|
||||
Values(std::numeric_limits<int>::min(),
|
||||
std::numeric_limits<int>::max()));
|
||||
TEST_P(ParseFlagFromAlmostOutOfRangeIntegerTest, YieldsExpectedValue) {
|
||||
const auto expected = static_cast<absl::LogSeverity>(GetParam());
|
||||
const std::string to_parse = absl::StrCat(GetParam());
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
ASSERT_THAT(absl::ParseFlag(to_parse, &value, &error), IsTrue()) << error;
|
||||
EXPECT_THAT(value, Eq(expected));
|
||||
}
|
||||
|
||||
using ParseFlagFromIntegerMatchingEnumeratorTest =
|
||||
TestWithParam<std::tuple<absl::string_view, absl::LogSeverity>>;
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Instantiation, ParseFlagFromIntegerMatchingEnumeratorTest,
|
||||
Values(std::make_tuple("0", absl::LogSeverity::kInfo),
|
||||
std::make_tuple(" 0", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("-0", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("+0", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("00", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("0 ", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("0x0", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("1", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("+1", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("2", absl::LogSeverity::kError),
|
||||
std::make_tuple("3", absl::LogSeverity::kFatal)));
|
||||
TEST_P(ParseFlagFromIntegerMatchingEnumeratorTest, YieldsExpectedValue) {
|
||||
const absl::string_view to_parse = std::get<0>(GetParam());
|
||||
const absl::LogSeverity expected = std::get<1>(GetParam());
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
ASSERT_THAT(absl::ParseFlag(to_parse, &value, &error), IsTrue()) << error;
|
||||
EXPECT_THAT(value, Eq(expected));
|
||||
}
|
||||
|
||||
using ParseFlagFromOtherIntegerTest =
|
||||
TestWithParam<std::tuple<absl::string_view, int>>;
|
||||
INSTANTIATE_TEST_SUITE_P(Instantiation, ParseFlagFromOtherIntegerTest,
|
||||
Values(std::make_tuple("-1", -1),
|
||||
std::make_tuple("4", 4),
|
||||
std::make_tuple("010", 10),
|
||||
std::make_tuple("0x10", 16)));
|
||||
TEST_P(ParseFlagFromOtherIntegerTest, YieldsExpectedValue) {
|
||||
const absl::string_view to_parse = std::get<0>(GetParam());
|
||||
const auto expected = static_cast<absl::LogSeverity>(std::get<1>(GetParam()));
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
ASSERT_THAT(absl::ParseFlag(to_parse, &value, &error), IsTrue()) << error;
|
||||
EXPECT_THAT(value, Eq(expected));
|
||||
}
|
||||
|
||||
using ParseFlagFromEnumeratorTest =
|
||||
TestWithParam<std::tuple<absl::string_view, absl::LogSeverity>>;
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Instantiation, ParseFlagFromEnumeratorTest,
|
||||
Values(std::make_tuple("INFO", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("info", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("kInfo", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("iNfO", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("kInFo", absl::LogSeverity::kInfo),
|
||||
std::make_tuple("WARNING", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("warning", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("kWarning", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("WaRnInG", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("KwArNiNg", absl::LogSeverity::kWarning),
|
||||
std::make_tuple("ERROR", absl::LogSeverity::kError),
|
||||
std::make_tuple("error", absl::LogSeverity::kError),
|
||||
std::make_tuple("kError", absl::LogSeverity::kError),
|
||||
std::make_tuple("eRrOr", absl::LogSeverity::kError),
|
||||
std::make_tuple("kErRoR", absl::LogSeverity::kError),
|
||||
std::make_tuple("FATAL", absl::LogSeverity::kFatal),
|
||||
std::make_tuple("fatal", absl::LogSeverity::kFatal),
|
||||
std::make_tuple("kFatal", absl::LogSeverity::kFatal),
|
||||
std::make_tuple("FaTaL", absl::LogSeverity::kFatal),
|
||||
std::make_tuple("KfAtAl", absl::LogSeverity::kFatal)));
|
||||
TEST_P(ParseFlagFromEnumeratorTest, YieldsExpectedValue) {
|
||||
const absl::string_view to_parse = std::get<0>(GetParam());
|
||||
const absl::LogSeverity expected = std::get<1>(GetParam());
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
ASSERT_THAT(absl::ParseFlag(to_parse, &value, &error), IsTrue()) << error;
|
||||
EXPECT_THAT(value, Eq(expected));
|
||||
}
|
||||
|
||||
using ParseFlagFromGarbageTest = TestWithParam<absl::string_view>;
|
||||
INSTANTIATE_TEST_SUITE_P(Instantiation, ParseFlagFromGarbageTest,
|
||||
Values("", "\0", " ", "garbage", "kkinfo", "I"));
|
||||
TEST_P(ParseFlagFromGarbageTest, ReturnsError) {
|
||||
const absl::string_view to_parse = GetParam();
|
||||
absl::LogSeverity value;
|
||||
std::string error;
|
||||
EXPECT_THAT(absl::ParseFlag(to_parse, &value, &error), IsFalse()) << value;
|
||||
}
|
||||
|
||||
using UnparseFlagToEnumeratorTest =
|
||||
TestWithParam<std::tuple<absl::LogSeverity, absl::string_view>>;
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Instantiation, UnparseFlagToEnumeratorTest,
|
||||
Values(std::make_tuple(absl::LogSeverity::kInfo, "INFO"),
|
||||
std::make_tuple(absl::LogSeverity::kWarning, "WARNING"),
|
||||
std::make_tuple(absl::LogSeverity::kError, "ERROR"),
|
||||
std::make_tuple(absl::LogSeverity::kFatal, "FATAL")));
|
||||
TEST_P(UnparseFlagToEnumeratorTest, ReturnsExpectedValueAndRoundTrips) {
|
||||
const absl::LogSeverity to_unparse = std::get<0>(GetParam());
|
||||
const absl::string_view expected = std::get<1>(GetParam());
|
||||
const std::string stringified_value = absl::UnparseFlag(to_unparse);
|
||||
EXPECT_THAT(stringified_value, Eq(expected));
|
||||
absl::LogSeverity reparsed_value;
|
||||
std::string error;
|
||||
EXPECT_THAT(absl::ParseFlag(stringified_value, &reparsed_value, &error),
|
||||
IsTrue());
|
||||
EXPECT_THAT(reparsed_value, Eq(to_unparse));
|
||||
}
|
||||
|
||||
using UnparseFlagToOtherIntegerTest = TestWithParam<int>;
|
||||
INSTANTIATE_TEST_SUITE_P(Instantiation, UnparseFlagToOtherIntegerTest,
|
||||
Values(std::numeric_limits<int>::min(), -1, 4,
|
||||
std::numeric_limits<int>::max()));
|
||||
TEST_P(UnparseFlagToOtherIntegerTest, ReturnsExpectedValueAndRoundTrips) {
|
||||
const absl::LogSeverity to_unparse =
|
||||
static_cast<absl::LogSeverity>(GetParam());
|
||||
const std::string expected = absl::StrCat(GetParam());
|
||||
const std::string stringified_value = absl::UnparseFlag(to_unparse);
|
||||
EXPECT_THAT(stringified_value, Eq(expected));
|
||||
absl::LogSeverity reparsed_value;
|
||||
std::string error;
|
||||
EXPECT_THAT(absl::ParseFlag(stringified_value, &reparsed_value, &error),
|
||||
IsTrue());
|
||||
EXPECT_THAT(reparsed_value, Eq(to_unparse));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
@@ -43,14 +44,14 @@
|
||||
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// kLinkerInitialized
|
||||
@@ -74,13 +75,13 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
||||
// // Invocation
|
||||
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
enum LinkerInitialized {
|
||||
kLinkerInitialized = 0,
|
||||
};
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// ABSL_FALLTHROUGH_INTENDED
|
||||
@@ -111,7 +112,7 @@ enum LinkerInitialized {
|
||||
// when performing switch labels fall-through diagnostic
|
||||
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
|
||||
// for details:
|
||||
// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
||||
//
|
||||
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
|
||||
// has no effect on diagnostics. In any case this macro has no effect on runtime
|
||||
@@ -141,10 +142,15 @@ enum LinkerInitialized {
|
||||
// declarations. The macro argument is used as a custom diagnostic message (e.g.
|
||||
// suggestion of a better alternative).
|
||||
//
|
||||
// Example:
|
||||
// Examples:
|
||||
//
|
||||
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
|
||||
// ABSL_DEPRECATED("Use Baz instead") void Bar() {...}
|
||||
//
|
||||
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
|
||||
//
|
||||
// template <typename T>
|
||||
// ABSL_DEPRECATED("Use DoThat() instead")
|
||||
// void DoThis();
|
||||
//
|
||||
// Every usage of a deprecated entity will trigger a warning when compiled with
|
||||
// clang's `-Wdeprecated-declarations` option. This option is turned off by
|
||||
@@ -162,7 +168,7 @@ enum LinkerInitialized {
|
||||
// Used on a function overload to trap bad calls: any call that matches the
|
||||
// overload will cause a compile-time error. This macro uses a clang-specific
|
||||
// "enable_if" attribute, as described at
|
||||
// http://clang.llvm.org/docs/AttributeReference.html#enable-if
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#enable-if
|
||||
//
|
||||
// Overloads which use this macro should be bracketed by
|
||||
// `#ifdef ABSL_BAD_CALL_IF`.
|
||||
@@ -175,12 +181,9 @@ enum LinkerInitialized {
|
||||
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
|
||||
// "'c' must have the value of an unsigned char or EOF");
|
||||
// #endif // ABSL_BAD_CALL_IF
|
||||
|
||||
#if defined(__clang__)
|
||||
# if __has_attribute(enable_if)
|
||||
# define ABSL_BAD_CALL_IF(expr, msg) \
|
||||
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
|
||||
# endif
|
||||
#if ABSL_HAVE_ATTRIBUTE(enable_if)
|
||||
#define ABSL_BAD_CALL_IF(expr, msg) \
|
||||
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
|
||||
#endif
|
||||
|
||||
// ABSL_ASSERT()
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
||||
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
|
||||
#else
|
||||
#define ABSL_PREDICT_FALSE(x) (x)
|
||||
#define ABSL_PREDICT_TRUE(x) (x)
|
||||
|
||||
211
absl/base/options.h
Normal file
211
absl/base/options.h
Normal file
@@ -0,0 +1,211 @@
|
||||
#ifndef ABSL_BASE_OPTIONS_H_
|
||||
#define ABSL_BASE_OPTIONS_H_
|
||||
|
||||
// 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: options.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This file contains Abseil configuration options for setting specific
|
||||
// implementations instead of letting Abseil determine which implementation to
|
||||
// use at compile-time. Setting these options may be useful for package or build
|
||||
// managers who wish to guarantee ABI stability within binary builds (which are
|
||||
// otherwise difficult to enforce).
|
||||
//
|
||||
// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
|
||||
// maintainers of package managers who wish to package Abseil read and
|
||||
// understand this file! ***
|
||||
//
|
||||
// Abseil contains a number of possible configuration endpoints, based on
|
||||
// parameters such as the detected platform, language version, or command-line
|
||||
// flags used to invoke the underlying binary. As is the case with all
|
||||
// libraries, binaries which contain Abseil code must ensure that separate
|
||||
// packages use the same compiled copy of Abseil to avoid a diamond dependency
|
||||
// problem, which can occur if two packages built with different Abseil
|
||||
// configuration settings are linked together. Diamond dependency problems in
|
||||
// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
|
||||
// linker errors), or undefined behavior (resulting in crashes).
|
||||
//
|
||||
// Diamond dependency problems can be avoided if all packages utilize the same
|
||||
// exact version of Abseil. Building from source code with the same compilation
|
||||
// parameters is the easiest way to avoid such dependency problems. However, for
|
||||
// package managers who cannot control such compilation parameters, we are
|
||||
// providing the file to allow you to inject ABI (Application Binary Interface)
|
||||
// stability across builds. Settings options in this file will neither change
|
||||
// API nor ABI, providing a stable copy of Abseil between packages.
|
||||
//
|
||||
// Care must be taken to keep options within these configurations isolated
|
||||
// from any other dynamic settings, such as command-line flags which could alter
|
||||
// these options. This file is provided specifically to help build and package
|
||||
// managers provide a stable copy of Abseil within their libraries and binaries;
|
||||
// other developers should not have need to alter the contents of this file.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Usage
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// For any particular package release, set the appropriate definitions within
|
||||
// this file to whatever value makes the most sense for your package(s). Note
|
||||
// that, by default, most of these options, at the moment, affect the
|
||||
// implementation of types; future options may affect other implementation
|
||||
// details.
|
||||
//
|
||||
// NOTE: the defaults within this file all assume that Abseil can select the
|
||||
// proper Abseil implementation at compile-time, which will not be sufficient
|
||||
// to guarantee ABI stability to package managers.
|
||||
|
||||
// Include a standard library header to allow configuration based on the
|
||||
// standard library in use.
|
||||
#ifdef __cplusplus
|
||||
#include <ciso646>
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type Compatibility Options
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// ABSL_OPTION_USE_STD_ANY
|
||||
//
|
||||
// This option controls whether absl::any is implemented as an alias to
|
||||
// std::any, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::any. This requires that all code
|
||||
// using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::any is available. This option is
|
||||
// useful when you are building your entire program, including all of its
|
||||
// dependencies, from source. It should not be used otherwise -- for example,
|
||||
// if you are distributing Abseil in a binary package manager -- since in
|
||||
// mode 2, absl::any will name a different type, with a different mangled name
|
||||
// and binary layout, depending on the compiler flags passed by the end user.
|
||||
// For more info, see https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_ANY 2
|
||||
|
||||
|
||||
// ABSL_OPTION_USE_STD_OPTIONAL
|
||||
//
|
||||
// This option controls whether absl::optional is implemented as an alias to
|
||||
// std::optional, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::optional. This requires that all
|
||||
// code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::optional is available. This option
|
||||
// is useful when you are building your program from source. It should not be
|
||||
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||
// package manager -- since in mode 2, absl::optional will name a different
|
||||
// type, with a different mangled name and binary layout, depending on the
|
||||
// compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::optional is a typedef of std::optional, use the feature macro
|
||||
// ABSL_USES_STD_OPTIONAL.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_OPTIONAL 2
|
||||
|
||||
|
||||
// ABSL_OPTION_USE_STD_STRING_VIEW
|
||||
//
|
||||
// This option controls whether absl::string_view is implemented as an alias to
|
||||
// std::string_view, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::string_view. This requires that
|
||||
// all code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::string_view is available. This
|
||||
// option is useful when you are building your program from source. It should
|
||||
// not be used otherwise -- for example, if you are distributing Abseil in a
|
||||
// binary package manager -- since in mode 2, absl::string_view will name a
|
||||
// different type, with a different mangled name and binary layout, depending on
|
||||
// the compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::string_view is a typedef of std::string_view, use the feature macro
|
||||
// ABSL_USES_STD_STRING_VIEW.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_STRING_VIEW 2
|
||||
|
||||
// ABSL_OPTION_USE_STD_VARIANT
|
||||
//
|
||||
// This option controls whether absl::variant is implemented as an alias to
|
||||
// std::variant, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::variant. This requires that all
|
||||
// code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::variant is available. This option
|
||||
// is useful when you are building your program from source. It should not be
|
||||
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||
// package manager -- since in mode 2, absl::variant will name a different
|
||||
// type, with a different mangled name and binary layout, depending on the
|
||||
// compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::variant is a typedef of std::variant, use the feature macro
|
||||
// ABSL_USES_STD_VARIANT.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_VARIANT 2
|
||||
|
||||
|
||||
// ABSL_OPTION_USE_INLINE_NAMESPACE
|
||||
// ABSL_OPTION_INLINE_NAMESPACE_NAME
|
||||
//
|
||||
// These options controls whether all entities in the absl namespace are
|
||||
// contained within an inner inline namespace. This does not affect the
|
||||
// user-visible API of Abseil, but it changes the mangled names of all symbols.
|
||||
//
|
||||
// This can be useful as a version tag if you are distributing Abseil in
|
||||
// precompiled form. This will prevent a binary library build of Abseil with
|
||||
// one inline namespace being used with headers configured with a different
|
||||
// inline namespace name. Binary packagers are reminded that Abseil does not
|
||||
// guarantee any ABI stability in Abseil, so any update of Abseil or
|
||||
// configuration change in such a binary package should be combined with a
|
||||
// new, unique value for the inline namespace name.
|
||||
//
|
||||
// A value of 0 means not to use inline namespaces.
|
||||
//
|
||||
// A value of 1 means to use an inline namespace with the given name inside
|
||||
// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
|
||||
// be changed to a new, unique identifier name. In particular "head" is not
|
||||
// allowed.
|
||||
|
||||
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
|
||||
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_02_25
|
||||
|
||||
#endif // ABSL_BASE_OPTIONS_H_
|
||||
@@ -82,16 +82,6 @@
|
||||
// Standard Library Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// We have chosen glibc 2.12 as the minimum as it was tagged for release
|
||||
// in May, 2010 and includes some functionality used in Google software
|
||||
// (for instance pthread_setname_np):
|
||||
// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
|
||||
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
|
||||
#if !__GLIBC_PREREQ(2, 12)
|
||||
#error "Minimum required version of glibc is 2.12."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_STLPORT_VERSION)
|
||||
#error "STLPort is not supported."
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,7 @@ constexpr int32_t kNumThreads = 10;
|
||||
constexpr int32_t kIters = 1000;
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// This is defined outside of anonymous namespace so that it can be
|
||||
@@ -267,5 +267,5 @@ TEST(SpinLockWithThreads, DoesNotDeadlock) {
|
||||
|
||||
} // namespace
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
// TODO(mbonadei): Remove after the backward compatibility period.
|
||||
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
|
||||
|
||||
@@ -256,7 +257,7 @@
|
||||
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Takes a reference to a guarded data member, and returns an unguarded
|
||||
@@ -273,7 +274,7 @@ inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
} // inline namespace lts_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <new>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
@@ -38,31 +39,43 @@ constexpr const char* what_arg = "The quick brown fox jumps over the lazy dog";
|
||||
|
||||
template <typename E>
|
||||
void ExpectThrowChar(void (*f)(const char*)) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
try {
|
||||
f(what_arg);
|
||||
FAIL() << "Didn't throw";
|
||||
} catch (const E& e) {
|
||||
EXPECT_STREQ(e.what(), what_arg);
|
||||
}
|
||||
#else
|
||||
EXPECT_DEATH_IF_SUPPORTED(f(what_arg), what_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ExpectThrowString(void (*f)(const std::string&)) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
try {
|
||||
f(what_arg);
|
||||
FAIL() << "Didn't throw";
|
||||
} catch (const E& e) {
|
||||
EXPECT_STREQ(e.what(), what_arg);
|
||||
}
|
||||
#else
|
||||
EXPECT_DEATH_IF_SUPPORTED(f(what_arg), what_arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ExpectThrowNoWhat(void (*f)()) {
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
try {
|
||||
f();
|
||||
FAIL() << "Didn't throw";
|
||||
} catch (const E& e) {
|
||||
}
|
||||
#else
|
||||
EXPECT_DEATH_IF_SUPPORTED(f(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(ThrowHelper, Test) {
|
||||
|
||||
@@ -14,12 +14,11 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
load(
|
||||
"//absl:copts/configure_copts.bzl",
|
||||
"ABSL_DEFAULT_COPTS",
|
||||
"ABSL_DEFAULT_LINKOPTS",
|
||||
"ABSL_EXCEPTIONS_FLAG",
|
||||
"ABSL_EXCEPTIONS_FLAG_LINKOPTS",
|
||||
"ABSL_TEST_COPTS",
|
||||
)
|
||||
|
||||
@@ -71,20 +70,6 @@ cc_library(
|
||||
cc_test(
|
||||
name = "fixed_array_test",
|
||||
srcs = ["fixed_array_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":fixed_array",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/hash:hash_testing",
|
||||
"//absl/memory",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "fixed_array_test_noexceptions",
|
||||
srcs = ["fixed_array_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
@@ -99,10 +84,11 @@ cc_test(
|
||||
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 + ABSL_DEFAULT_LINKOPTS,
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":fixed_array",
|
||||
"//absl/base:config",
|
||||
"//absl/base:exception_safety_testing",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -155,39 +141,21 @@ cc_library(
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = ["//visibility:private"],
|
||||
deps = ["//absl/base:config"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "inlined_vector_test",
|
||||
srcs = ["inlined_vector_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
linkopts = ABSL_EXCEPTIONS_FLAG_LINKOPTS + ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":counting_allocator",
|
||||
":inlined_vector",
|
||||
":test_instance_tracker",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/hash:hash_testing",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
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",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exception_testing",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/hash:hash_testing",
|
||||
"//absl/memory",
|
||||
"//absl/strings",
|
||||
@@ -203,8 +171,8 @@ cc_test(
|
||||
tags = ["benchmark"],
|
||||
deps = [
|
||||
":inlined_vector",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/strings",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
@@ -213,9 +181,10 @@ cc_test(
|
||||
cc_test(
|
||||
name = "inlined_vector_exception_safety_test",
|
||||
srcs = ["inlined_vector_exception_safety_test.cc"],
|
||||
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||
copts = ABSL_TEST_COPTS,
|
||||
deps = [
|
||||
":inlined_vector",
|
||||
"//absl/base:config",
|
||||
"//absl/base:exception_safety_testing",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -447,6 +416,7 @@ cc_library(
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":hash_policy_testing",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
],
|
||||
@@ -509,6 +479,9 @@ cc_library(
|
||||
hdrs = ["internal/hashtable_debug_hooks.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
@@ -524,6 +497,7 @@ cc_library(
|
||||
":have_sse",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:exponential_biased",
|
||||
"//absl/debugging:stacktrace",
|
||||
"//absl/memory",
|
||||
"//absl/synchronization",
|
||||
@@ -551,6 +525,7 @@ cc_library(
|
||||
hdrs = ["internal/node_hash_policy.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = ["//absl/base:config"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
@@ -635,6 +610,7 @@ cc_test(
|
||||
":raw_hash_set",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/strings",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -678,8 +654,8 @@ cc_test(
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":layout",
|
||||
"//absl/base",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/types:span",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
@@ -691,6 +667,9 @@ cc_library(
|
||||
hdrs = ["internal/tracked.h"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
@@ -825,3 +804,99 @@ cc_test(
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "btree",
|
||||
srcs = [
|
||||
"internal/btree.h",
|
||||
"internal/btree_container.h",
|
||||
],
|
||||
hdrs = [
|
||||
"btree_map.h",
|
||||
"btree_set.h",
|
||||
],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":common",
|
||||
":compressed_tuple",
|
||||
":container_memory",
|
||||
":layout",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:throw_delegate",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
"//absl/types:compare",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "btree_test_common",
|
||||
testonly = 1,
|
||||
hdrs = ["btree_test.h"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":btree",
|
||||
":flat_hash_set",
|
||||
"//absl/strings",
|
||||
"//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "btree_test",
|
||||
size = "large",
|
||||
srcs = [
|
||||
"btree_test.cc",
|
||||
],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
shard_count = 10,
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":btree",
|
||||
":btree_test_common",
|
||||
":counting_allocator",
|
||||
":test_instance_tracker",
|
||||
"//absl/base:core_headers",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/flags:flag",
|
||||
"//absl/hash:hash_testing",
|
||||
"//absl/memory",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/strings",
|
||||
"//absl/types:compare",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "btree_benchmark",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"btree_benchmark.cc",
|
||||
],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
tags = ["benchmark"],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
":btree",
|
||||
":btree_test_common",
|
||||
":flat_hash_map",
|
||||
":flat_hash_set",
|
||||
":hashtable_debug",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/flags:flag",
|
||||
"//absl/hash",
|
||||
"//absl/memory",
|
||||
"//absl/strings:str_format",
|
||||
"//absl/time",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -23,6 +23,73 @@ absl_cc_library(
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
btree
|
||||
HDRS
|
||||
"btree_map.h"
|
||||
"btree_set.h"
|
||||
"internal/btree.h"
|
||||
"internal/btree_container.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
DEPS
|
||||
absl::container_common
|
||||
absl::compare
|
||||
absl::compressed_tuple
|
||||
absl::container_memory
|
||||
absl::core_headers
|
||||
absl::layout
|
||||
absl::memory
|
||||
absl::strings
|
||||
absl::throw_delegate
|
||||
absl::type_traits
|
||||
absl::utility
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
btree_test_common
|
||||
hdrs
|
||||
"btree_test.h"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
DEPS
|
||||
absl::btree
|
||||
absl::flat_hash_set
|
||||
absl::strings
|
||||
absl::time
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
btree_test
|
||||
SRCS
|
||||
"btree_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
LINKOPTS
|
||||
${ABSL_DEFAULT_LINKOPTS}
|
||||
DEPS
|
||||
absl::btree
|
||||
absl::btree_test_common
|
||||
absl::compare
|
||||
absl::core_headers
|
||||
absl::counting_allocator
|
||||
absl::flags
|
||||
absl::hash_testing
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
absl::test_instance_tracker
|
||||
absl::type_traits
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_library(
|
||||
NAME
|
||||
compressed_tuple
|
||||
@@ -74,24 +141,6 @@ absl_cc_test(
|
||||
fixed_array_test
|
||||
SRCS
|
||||
"fixed_array_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::fixed_array
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
absl::memory
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
fixed_array_test_noexceptions
|
||||
SRCS
|
||||
"fixed_array_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
@@ -109,11 +158,9 @@ absl_cc_test(
|
||||
"fixed_array_exception_safety_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::fixed_array
|
||||
absl::config
|
||||
absl::exception_safety_testing
|
||||
gmock_main
|
||||
)
|
||||
@@ -157,6 +204,8 @@ absl_cc_library(
|
||||
"internal/counting_allocator.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
@@ -166,37 +215,15 @@ absl_cc_test(
|
||||
"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
|
||||
absl::core_headers
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
absl::memory
|
||||
absl::strings
|
||||
gmock_main
|
||||
)
|
||||
|
||||
absl_cc_test(
|
||||
NAME
|
||||
inlined_vector_test_noexceptions
|
||||
SRCS
|
||||
"inlined_vector_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::inlined_vector
|
||||
absl::test_instance_tracker
|
||||
absl::base
|
||||
absl::core_headers
|
||||
absl::exception_testing
|
||||
absl::hash_testing
|
||||
absl::memory
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gmock_main
|
||||
)
|
||||
@@ -208,11 +235,9 @@ absl_cc_test(
|
||||
"inlined_vector_exception_safety_test.cc"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
${ABSL_EXCEPTIONS_FLAG}
|
||||
LINKOPTS
|
||||
${ABSL_EXCEPTIONS_FLAG_LINKOPTS}
|
||||
DEPS
|
||||
absl::inlined_vector
|
||||
absl::config
|
||||
absl::exception_safety_testing
|
||||
gmock_main
|
||||
)
|
||||
@@ -448,6 +473,7 @@ absl_cc_library(
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::hash_policy_testing
|
||||
absl::memory
|
||||
absl::meta
|
||||
absl::strings
|
||||
TESTONLY
|
||||
@@ -514,6 +540,7 @@ absl_cc_library(
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::base
|
||||
absl::exponential_biased
|
||||
absl::have_sse
|
||||
absl::synchronization
|
||||
)
|
||||
@@ -549,6 +576,8 @@ absl_cc_library(
|
||||
"internal/hashtable_debug_hooks.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
@@ -568,6 +597,8 @@ absl_cc_library(
|
||||
"internal/node_hash_policy.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
@@ -602,7 +633,7 @@ absl_cc_library(
|
||||
NAME
|
||||
container_common
|
||||
HDRS
|
||||
"internal/commom.h"
|
||||
"internal/common.h"
|
||||
COPTS
|
||||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
@@ -653,6 +684,7 @@ absl_cc_test(
|
||||
absl::raw_hash_set
|
||||
absl::base
|
||||
absl::core_headers
|
||||
absl::raw_logging_internal
|
||||
absl::strings
|
||||
gmock_main
|
||||
)
|
||||
@@ -696,8 +728,8 @@ absl_cc_test(
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::layout
|
||||
absl::base
|
||||
absl::core_headers
|
||||
absl::raw_logging_internal
|
||||
absl::span
|
||||
gmock_main
|
||||
)
|
||||
@@ -709,6 +741,8 @@ absl_cc_library(
|
||||
"internal/tracked.h"
|
||||
COPTS
|
||||
${ABSL_TEST_COPTS}
|
||||
DEPS
|
||||
absl::config
|
||||
TESTONLY
|
||||
)
|
||||
|
||||
|
||||
707
absl/container/btree_benchmark.cc
Normal file
707
absl/container/btree_benchmark.cc
Normal file
@@ -0,0 +1,707 @@
|
||||
// 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 <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/btree_set.h"
|
||||
#include "absl/container/btree_test.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/container/internal/hashtable_debug.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/hash/hash.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
namespace {
|
||||
|
||||
constexpr size_t kBenchmarkValues = 1 << 20;
|
||||
|
||||
// How many times we add and remove sub-batches in one batch of *AddRem
|
||||
// benchmarks.
|
||||
constexpr size_t kAddRemBatchSize = 1 << 2;
|
||||
|
||||
// Generates n values in the range [0, 4 * n].
|
||||
template <typename V>
|
||||
std::vector<V> GenerateValues(int n) {
|
||||
constexpr int kSeed = 23;
|
||||
return GenerateValuesWithSeed<V>(n, 4 * n, kSeed);
|
||||
}
|
||||
|
||||
// Benchmark insertion of values into a container.
|
||||
template <typename T>
|
||||
void BM_InsertImpl(benchmark::State& state, bool sorted) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
if (sorted) {
|
||||
std::sort(values.begin(), values.end());
|
||||
}
|
||||
T container(values.begin(), values.end());
|
||||
|
||||
// Remove and re-insert 10% of the keys per batch.
|
||||
const int batch_size = (kBenchmarkValues + 9) / 10;
|
||||
while (state.KeepRunningBatch(batch_size)) {
|
||||
state.PauseTiming();
|
||||
const auto i = static_cast<int>(state.iterations());
|
||||
|
||||
for (int j = i; j < i + batch_size; j++) {
|
||||
int x = j % kBenchmarkValues;
|
||||
container.erase(key_of_value(values[x]));
|
||||
}
|
||||
|
||||
state.ResumeTiming();
|
||||
|
||||
for (int j = i; j < i + batch_size; j++) {
|
||||
int x = j % kBenchmarkValues;
|
||||
container.insert(values[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BM_Insert(benchmark::State& state) {
|
||||
BM_InsertImpl<T>(state, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BM_InsertSorted(benchmark::State& state) {
|
||||
BM_InsertImpl<T>(state, true);
|
||||
}
|
||||
|
||||
// container::insert sometimes returns a pair<iterator, bool> and sometimes
|
||||
// returns an iterator (for multi- containers).
|
||||
template <typename Iter>
|
||||
Iter GetIterFromInsert(const std::pair<Iter, bool>& pair) {
|
||||
return pair.first;
|
||||
}
|
||||
template <typename Iter>
|
||||
Iter GetIterFromInsert(const Iter iter) {
|
||||
return iter;
|
||||
}
|
||||
|
||||
// Benchmark insertion of values into a container at the end.
|
||||
template <typename T>
|
||||
void BM_InsertEnd(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
T container;
|
||||
const int kSize = 10000;
|
||||
for (int i = 0; i < kSize; ++i) {
|
||||
container.insert(Generator<V>(kSize)(i));
|
||||
}
|
||||
V v = Generator<V>(kSize)(kSize - 1);
|
||||
typename T::key_type k = key_of_value(v);
|
||||
|
||||
auto it = container.find(k);
|
||||
while (state.KeepRunning()) {
|
||||
// Repeatedly removing then adding v.
|
||||
container.erase(it);
|
||||
it = GetIterFromInsert(container.insert(v));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BM_LookupImpl(benchmark::State& state, bool sorted) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
if (sorted) {
|
||||
std::sort(values.begin(), values.end());
|
||||
}
|
||||
T container(values.begin(), values.end());
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
int idx = state.iterations() % kBenchmarkValues;
|
||||
benchmark::DoNotOptimize(container.find(key_of_value(values[idx])));
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark lookup of values in a container.
|
||||
template <typename T>
|
||||
void BM_Lookup(benchmark::State& state) {
|
||||
BM_LookupImpl<T>(state, false);
|
||||
}
|
||||
|
||||
// Benchmark lookup of values in a full container, meaning that values
|
||||
// are inserted in-order to take advantage of biased insertion, which
|
||||
// yields a full tree.
|
||||
template <typename T>
|
||||
void BM_FullLookup(benchmark::State& state) {
|
||||
BM_LookupImpl<T>(state, true);
|
||||
}
|
||||
|
||||
// Benchmark deletion of values from a container.
|
||||
template <typename T>
|
||||
void BM_Delete(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
T container(values.begin(), values.end());
|
||||
|
||||
// Remove and re-insert 10% of the keys per batch.
|
||||
const int batch_size = (kBenchmarkValues + 9) / 10;
|
||||
while (state.KeepRunningBatch(batch_size)) {
|
||||
const int i = state.iterations();
|
||||
|
||||
for (int j = i; j < i + batch_size; j++) {
|
||||
int x = j % kBenchmarkValues;
|
||||
container.erase(key_of_value(values[x]));
|
||||
}
|
||||
|
||||
state.PauseTiming();
|
||||
for (int j = i; j < i + batch_size; j++) {
|
||||
int x = j % kBenchmarkValues;
|
||||
container.insert(values[x]);
|
||||
}
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark deletion of multiple values from a container.
|
||||
template <typename T>
|
||||
void BM_DeleteRange(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
T container(values.begin(), values.end());
|
||||
|
||||
// Remove and re-insert 10% of the keys per batch.
|
||||
const int batch_size = (kBenchmarkValues + 9) / 10;
|
||||
while (state.KeepRunningBatch(batch_size)) {
|
||||
const int i = state.iterations();
|
||||
|
||||
const int start_index = i % kBenchmarkValues;
|
||||
|
||||
state.PauseTiming();
|
||||
{
|
||||
std::vector<V> removed;
|
||||
removed.reserve(batch_size);
|
||||
auto itr = container.find(key_of_value(values[start_index]));
|
||||
auto start = itr;
|
||||
for (int j = 0; j < batch_size; j++) {
|
||||
if (itr == container.end()) {
|
||||
state.ResumeTiming();
|
||||
container.erase(start, itr);
|
||||
state.PauseTiming();
|
||||
itr = container.begin();
|
||||
start = itr;
|
||||
}
|
||||
removed.push_back(*itr++);
|
||||
}
|
||||
|
||||
state.ResumeTiming();
|
||||
container.erase(start, itr);
|
||||
state.PauseTiming();
|
||||
|
||||
container.insert(removed.begin(), removed.end());
|
||||
}
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark steady-state insert (into first half of range) and remove (from
|
||||
// second half of range), treating the container approximately like a queue with
|
||||
// log-time access for all elements. This benchmark does not test the case where
|
||||
// insertion and removal happen in the same region of the tree. This benchmark
|
||||
// counts two value constructors.
|
||||
template <typename T>
|
||||
void BM_QueueAddRem(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
|
||||
|
||||
T container;
|
||||
|
||||
const size_t half = kBenchmarkValues / 2;
|
||||
std::vector<int> remove_keys(half);
|
||||
std::vector<int> add_keys(half);
|
||||
|
||||
// We want to do the exact same work repeatedly, and the benchmark can end
|
||||
// after a different number of iterations depending on the speed of the
|
||||
// individual run so we use a large batch size here and ensure that we do
|
||||
// deterministic work every batch.
|
||||
while (state.KeepRunningBatch(half * kAddRemBatchSize)) {
|
||||
state.PauseTiming();
|
||||
|
||||
container.clear();
|
||||
|
||||
for (size_t i = 0; i < half; ++i) {
|
||||
remove_keys[i] = i;
|
||||
add_keys[i] = i;
|
||||
}
|
||||
constexpr int kSeed = 5;
|
||||
std::mt19937_64 rand(kSeed);
|
||||
std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||
std::shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||
|
||||
// Note needs lazy generation of values.
|
||||
Generator<V> g(kBenchmarkValues * kAddRemBatchSize);
|
||||
|
||||
for (size_t i = 0; i < half; ++i) {
|
||||
container.insert(g(add_keys[i]));
|
||||
container.insert(g(half + remove_keys[i]));
|
||||
}
|
||||
|
||||
// There are three parts each of size "half":
|
||||
// 1 is being deleted from [offset - half, offset)
|
||||
// 2 is standing [offset, offset + half)
|
||||
// 3 is being inserted into [offset + half, offset + 2 * half)
|
||||
size_t offset = 0;
|
||||
|
||||
for (size_t i = 0; i < kAddRemBatchSize; ++i) {
|
||||
std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||
std::shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||
offset += half;
|
||||
|
||||
state.ResumeTiming();
|
||||
for (size_t idx = 0; idx < half; ++idx) {
|
||||
container.erase(key_of_value(g(offset - half + remove_keys[idx])));
|
||||
container.insert(g(offset + half + add_keys[idx]));
|
||||
}
|
||||
state.PauseTiming();
|
||||
}
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
// Mixed insertion and deletion in the same range using pre-constructed values.
|
||||
template <typename T>
|
||||
void BM_MixedAddRem(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||
|
||||
ABSL_RAW_CHECK(kBenchmarkValues % 2 == 0, "for performance");
|
||||
|
||||
T container;
|
||||
|
||||
// Create two random shuffles
|
||||
std::vector<int> remove_keys(kBenchmarkValues);
|
||||
std::vector<int> add_keys(kBenchmarkValues);
|
||||
|
||||
// We want to do the exact same work repeatedly, and the benchmark can end
|
||||
// after a different number of iterations depending on the speed of the
|
||||
// individual run so we use a large batch size here and ensure that we do
|
||||
// deterministic work every batch.
|
||||
while (state.KeepRunningBatch(kBenchmarkValues * kAddRemBatchSize)) {
|
||||
state.PauseTiming();
|
||||
|
||||
container.clear();
|
||||
|
||||
constexpr int kSeed = 7;
|
||||
std::mt19937_64 rand(kSeed);
|
||||
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues * 2);
|
||||
|
||||
// Insert the first half of the values (already in random order)
|
||||
container.insert(values.begin(), values.begin() + kBenchmarkValues);
|
||||
|
||||
// Insert the first half of the values (already in random order)
|
||||
for (size_t i = 0; i < kBenchmarkValues; ++i) {
|
||||
// remove_keys and add_keys will be swapped before each round,
|
||||
// therefore fill add_keys here w/ the keys being inserted, so
|
||||
// they'll be the first to be removed.
|
||||
remove_keys[i] = i + kBenchmarkValues;
|
||||
add_keys[i] = i;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kAddRemBatchSize; ++i) {
|
||||
remove_keys.swap(add_keys);
|
||||
std::shuffle(remove_keys.begin(), remove_keys.end(), rand);
|
||||
std::shuffle(add_keys.begin(), add_keys.end(), rand);
|
||||
|
||||
state.ResumeTiming();
|
||||
for (size_t idx = 0; idx < kBenchmarkValues; ++idx) {
|
||||
container.erase(key_of_value(values[remove_keys[idx]]));
|
||||
container.insert(values[add_keys[idx]]);
|
||||
}
|
||||
state.PauseTiming();
|
||||
}
|
||||
state.ResumeTiming();
|
||||
}
|
||||
}
|
||||
|
||||
// Insertion at end, removal from the beginning. This benchmark
|
||||
// counts two value constructors.
|
||||
// TODO(ezb): we could add a GenerateNext version of generator that could reduce
|
||||
// noise for string-like types.
|
||||
template <typename T>
|
||||
void BM_Fifo(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
|
||||
T container;
|
||||
// Need lazy generation of values as state.max_iterations is large.
|
||||
Generator<V> g(kBenchmarkValues + state.max_iterations);
|
||||
|
||||
for (int i = 0; i < kBenchmarkValues; i++) {
|
||||
container.insert(g(i));
|
||||
}
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
container.erase(container.begin());
|
||||
container.insert(container.end(), g(state.iterations() + kBenchmarkValues));
|
||||
}
|
||||
}
|
||||
|
||||
// Iteration (forward) through the tree
|
||||
template <typename T>
|
||||
void BM_FwdIter(benchmark::State& state) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
using R = typename T::value_type const*;
|
||||
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
T container(values.begin(), values.end());
|
||||
|
||||
auto iter = container.end();
|
||||
|
||||
R r = nullptr;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
if (iter == container.end()) iter = container.begin();
|
||||
r = &(*iter);
|
||||
++iter;
|
||||
}
|
||||
|
||||
benchmark::DoNotOptimize(r);
|
||||
}
|
||||
|
||||
// Benchmark random range-construction of a container.
|
||||
template <typename T>
|
||||
void BM_RangeConstructionImpl(benchmark::State& state, bool sorted) {
|
||||
using V = typename remove_pair_const<typename T::value_type>::type;
|
||||
|
||||
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
|
||||
if (sorted) {
|
||||
std::sort(values.begin(), values.end());
|
||||
}
|
||||
{
|
||||
T container(values.begin(), values.end());
|
||||
}
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
T container(values.begin(), values.end());
|
||||
benchmark::DoNotOptimize(container);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BM_InsertRangeRandom(benchmark::State& state) {
|
||||
BM_RangeConstructionImpl<T>(state, false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BM_InsertRangeSorted(benchmark::State& state) {
|
||||
BM_RangeConstructionImpl<T>(state, true);
|
||||
}
|
||||
|
||||
#define STL_ORDERED_TYPES(value) \
|
||||
using stl_set_##value = std::set<value>; \
|
||||
using stl_map_##value = std::map<value, intptr_t>; \
|
||||
using stl_multiset_##value = std::multiset<value>; \
|
||||
using stl_multimap_##value = std::multimap<value, intptr_t>
|
||||
|
||||
using StdString = std::string;
|
||||
STL_ORDERED_TYPES(int32_t);
|
||||
STL_ORDERED_TYPES(int64_t);
|
||||
STL_ORDERED_TYPES(StdString);
|
||||
STL_ORDERED_TYPES(Time);
|
||||
|
||||
#define STL_UNORDERED_TYPES(value) \
|
||||
using stl_unordered_set_##value = std::unordered_set<value>; \
|
||||
using stl_unordered_map_##value = std::unordered_map<value, intptr_t>; \
|
||||
using flat_hash_set_##value = flat_hash_set<value>; \
|
||||
using flat_hash_map_##value = flat_hash_map<value, intptr_t>; \
|
||||
using stl_unordered_multiset_##value = std::unordered_multiset<value>; \
|
||||
using stl_unordered_multimap_##value = \
|
||||
std::unordered_multimap<value, intptr_t>
|
||||
|
||||
#define STL_UNORDERED_TYPES_CUSTOM_HASH(value, hash) \
|
||||
using stl_unordered_set_##value = std::unordered_set<value, hash>; \
|
||||
using stl_unordered_map_##value = std::unordered_map<value, intptr_t, hash>; \
|
||||
using flat_hash_set_##value = flat_hash_set<value, hash>; \
|
||||
using flat_hash_map_##value = flat_hash_map<value, intptr_t, hash>; \
|
||||
using stl_unordered_multiset_##value = std::unordered_multiset<value, hash>; \
|
||||
using stl_unordered_multimap_##value = \
|
||||
std::unordered_multimap<value, intptr_t, hash>
|
||||
|
||||
STL_UNORDERED_TYPES(int32_t);
|
||||
STL_UNORDERED_TYPES(int64_t);
|
||||
STL_UNORDERED_TYPES(StdString);
|
||||
STL_UNORDERED_TYPES_CUSTOM_HASH(Time, absl::Hash<absl::Time>);
|
||||
|
||||
#define BTREE_TYPES(value) \
|
||||
using btree_256_set_##value = \
|
||||
btree_set<value, std::less<value>, std::allocator<value>>; \
|
||||
using btree_256_map_##value = \
|
||||
btree_map<value, intptr_t, std::less<value>, \
|
||||
std::allocator<std::pair<const value, intptr_t>>>; \
|
||||
using btree_256_multiset_##value = \
|
||||
btree_multiset<value, std::less<value>, std::allocator<value>>; \
|
||||
using btree_256_multimap_##value = \
|
||||
btree_multimap<value, intptr_t, std::less<value>, \
|
||||
std::allocator<std::pair<const value, intptr_t>>>
|
||||
|
||||
BTREE_TYPES(int32_t);
|
||||
BTREE_TYPES(int64_t);
|
||||
BTREE_TYPES(StdString);
|
||||
BTREE_TYPES(Time);
|
||||
|
||||
#define MY_BENCHMARK4(type, func) \
|
||||
void BM_##type##_##func(benchmark::State& state) { BM_##func<type>(state); } \
|
||||
BENCHMARK(BM_##type##_##func)
|
||||
|
||||
#define MY_BENCHMARK3(type) \
|
||||
MY_BENCHMARK4(type, Insert); \
|
||||
MY_BENCHMARK4(type, InsertSorted); \
|
||||
MY_BENCHMARK4(type, InsertEnd); \
|
||||
MY_BENCHMARK4(type, Lookup); \
|
||||
MY_BENCHMARK4(type, FullLookup); \
|
||||
MY_BENCHMARK4(type, Delete); \
|
||||
MY_BENCHMARK4(type, DeleteRange); \
|
||||
MY_BENCHMARK4(type, QueueAddRem); \
|
||||
MY_BENCHMARK4(type, MixedAddRem); \
|
||||
MY_BENCHMARK4(type, Fifo); \
|
||||
MY_BENCHMARK4(type, FwdIter); \
|
||||
MY_BENCHMARK4(type, InsertRangeRandom); \
|
||||
MY_BENCHMARK4(type, InsertRangeSorted)
|
||||
|
||||
#define MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type) \
|
||||
MY_BENCHMARK3(stl_##type); \
|
||||
MY_BENCHMARK3(stl_unordered_##type); \
|
||||
MY_BENCHMARK3(btree_256_##type)
|
||||
|
||||
#define MY_BENCHMARK2(type) \
|
||||
MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type); \
|
||||
MY_BENCHMARK3(flat_hash_##type)
|
||||
|
||||
// Define MULTI_TESTING to see benchmarks for multi-containers also.
|
||||
//
|
||||
// You can use --copt=-DMULTI_TESTING.
|
||||
#ifdef MULTI_TESTING
|
||||
#define MY_BENCHMARK(type) \
|
||||
MY_BENCHMARK2(set_##type); \
|
||||
MY_BENCHMARK2(map_##type); \
|
||||
MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multiset_##type); \
|
||||
MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(multimap_##type)
|
||||
#else
|
||||
#define MY_BENCHMARK(type) \
|
||||
MY_BENCHMARK2(set_##type); \
|
||||
MY_BENCHMARK2(map_##type)
|
||||
#endif
|
||||
|
||||
MY_BENCHMARK(int32_t);
|
||||
MY_BENCHMARK(int64_t);
|
||||
MY_BENCHMARK(StdString);
|
||||
MY_BENCHMARK(Time);
|
||||
|
||||
// Define a type whose size and cost of moving are independently customizable.
|
||||
// When sizeof(value_type) increases, we expect btree to no longer have as much
|
||||
// cache-locality advantage over STL. When cost of moving increases, we expect
|
||||
// btree to actually do more work than STL because it has to move values around
|
||||
// and STL doesn't have to.
|
||||
template <int Size, int Copies>
|
||||
struct BigType {
|
||||
BigType() : BigType(0) {}
|
||||
explicit BigType(int x) { std::iota(values.begin(), values.end(), x); }
|
||||
|
||||
void Copy(const BigType& x) {
|
||||
for (int i = 0; i < Size && i < Copies; ++i) values[i] = x.values[i];
|
||||
// If Copies > Size, do extra copies.
|
||||
for (int i = Size, idx = 0; i < Copies; ++i) {
|
||||
int64_t tmp = x.values[idx];
|
||||
benchmark::DoNotOptimize(tmp);
|
||||
idx = idx + 1 == Size ? 0 : idx + 1;
|
||||
}
|
||||
}
|
||||
|
||||
BigType(const BigType& x) { Copy(x); }
|
||||
BigType& operator=(const BigType& x) {
|
||||
Copy(x);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Compare only the first Copies elements if Copies is less than Size.
|
||||
bool operator<(const BigType& other) const {
|
||||
return std::lexicographical_compare(
|
||||
values.begin(), values.begin() + std::min(Size, Copies),
|
||||
other.values.begin(), other.values.begin() + std::min(Size, Copies));
|
||||
}
|
||||
bool operator==(const BigType& other) const {
|
||||
return std::equal(values.begin(), values.begin() + std::min(Size, Copies),
|
||||
other.values.begin());
|
||||
}
|
||||
|
||||
// Support absl::Hash.
|
||||
template <typename State>
|
||||
friend State AbslHashValue(State h, const BigType& b) {
|
||||
for (int i = 0; i < Size && i < Copies; ++i)
|
||||
h = State::combine(std::move(h), b.values[i]);
|
||||
return h;
|
||||
}
|
||||
|
||||
std::array<int64_t, Size> values;
|
||||
};
|
||||
|
||||
#define BIG_TYPE_BENCHMARKS(SIZE, COPIES) \
|
||||
using stl_set_size##SIZE##copies##COPIES = std::set<BigType<SIZE, COPIES>>; \
|
||||
using stl_map_size##SIZE##copies##COPIES = \
|
||||
std::map<BigType<SIZE, COPIES>, intptr_t>; \
|
||||
using stl_multiset_size##SIZE##copies##COPIES = \
|
||||
std::multiset<BigType<SIZE, COPIES>>; \
|
||||
using stl_multimap_size##SIZE##copies##COPIES = \
|
||||
std::multimap<BigType<SIZE, COPIES>, intptr_t>; \
|
||||
using stl_unordered_set_size##SIZE##copies##COPIES = \
|
||||
std::unordered_set<BigType<SIZE, COPIES>, \
|
||||
absl::Hash<BigType<SIZE, COPIES>>>; \
|
||||
using stl_unordered_map_size##SIZE##copies##COPIES = \
|
||||
std::unordered_map<BigType<SIZE, COPIES>, intptr_t, \
|
||||
absl::Hash<BigType<SIZE, COPIES>>>; \
|
||||
using flat_hash_set_size##SIZE##copies##COPIES = \
|
||||
flat_hash_set<BigType<SIZE, COPIES>>; \
|
||||
using flat_hash_map_size##SIZE##copies##COPIES = \
|
||||
flat_hash_map<BigType<SIZE, COPIES>, intptr_t>; \
|
||||
using stl_unordered_multiset_size##SIZE##copies##COPIES = \
|
||||
std::unordered_multiset<BigType<SIZE, COPIES>, \
|
||||
absl::Hash<BigType<SIZE, COPIES>>>; \
|
||||
using stl_unordered_multimap_size##SIZE##copies##COPIES = \
|
||||
std::unordered_multimap<BigType<SIZE, COPIES>, intptr_t, \
|
||||
absl::Hash<BigType<SIZE, COPIES>>>; \
|
||||
using btree_256_set_size##SIZE##copies##COPIES = \
|
||||
btree_set<BigType<SIZE, COPIES>>; \
|
||||
using btree_256_map_size##SIZE##copies##COPIES = \
|
||||
btree_map<BigType<SIZE, COPIES>, intptr_t>; \
|
||||
using btree_256_multiset_size##SIZE##copies##COPIES = \
|
||||
btree_multiset<BigType<SIZE, COPIES>>; \
|
||||
using btree_256_multimap_size##SIZE##copies##COPIES = \
|
||||
btree_multimap<BigType<SIZE, COPIES>, intptr_t>; \
|
||||
MY_BENCHMARK(size##SIZE##copies##COPIES)
|
||||
|
||||
// Define BIG_TYPE_TESTING to see benchmarks for more big types.
|
||||
//
|
||||
// You can use --copt=-DBIG_TYPE_TESTING.
|
||||
#ifndef NODESIZE_TESTING
|
||||
#ifdef BIG_TYPE_TESTING
|
||||
BIG_TYPE_BENCHMARKS(1, 4);
|
||||
BIG_TYPE_BENCHMARKS(4, 1);
|
||||
BIG_TYPE_BENCHMARKS(4, 4);
|
||||
BIG_TYPE_BENCHMARKS(1, 8);
|
||||
BIG_TYPE_BENCHMARKS(8, 1);
|
||||
BIG_TYPE_BENCHMARKS(8, 8);
|
||||
BIG_TYPE_BENCHMARKS(1, 16);
|
||||
BIG_TYPE_BENCHMARKS(16, 1);
|
||||
BIG_TYPE_BENCHMARKS(16, 16);
|
||||
BIG_TYPE_BENCHMARKS(1, 32);
|
||||
BIG_TYPE_BENCHMARKS(32, 1);
|
||||
BIG_TYPE_BENCHMARKS(32, 32);
|
||||
#else
|
||||
BIG_TYPE_BENCHMARKS(32, 32);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Benchmark using unique_ptrs to large value types. In order to be able to use
|
||||
// the same benchmark code as the other types, use a type that holds a
|
||||
// unique_ptr and has a copy constructor.
|
||||
template <int Size>
|
||||
struct BigTypePtr {
|
||||
BigTypePtr() : BigTypePtr(0) {}
|
||||
explicit BigTypePtr(int x) {
|
||||
ptr = absl::make_unique<BigType<Size, Size>>(x);
|
||||
}
|
||||
BigTypePtr(const BigTypePtr& x) {
|
||||
ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr);
|
||||
}
|
||||
BigTypePtr(BigTypePtr&& x) noexcept = default;
|
||||
BigTypePtr& operator=(const BigTypePtr& x) {
|
||||
ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr);
|
||||
}
|
||||
BigTypePtr& operator=(BigTypePtr&& x) noexcept = default;
|
||||
|
||||
bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; }
|
||||
bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; }
|
||||
|
||||
std::unique_ptr<BigType<Size, Size>> ptr;
|
||||
};
|
||||
|
||||
template <int Size>
|
||||
double ContainerInfo(const btree_set<BigTypePtr<Size>>& b) {
|
||||
const double bytes_used =
|
||||
b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
|
||||
const double bytes_per_value = bytes_used / b.size();
|
||||
BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
|
||||
return bytes_per_value;
|
||||
}
|
||||
template <int Size>
|
||||
double ContainerInfo(const btree_map<int, BigTypePtr<Size>>& b) {
|
||||
const double bytes_used =
|
||||
b.bytes_used() + b.size() * sizeof(BigType<Size, Size>);
|
||||
const double bytes_per_value = bytes_used / b.size();
|
||||
BtreeContainerInfoLog(b, bytes_used, bytes_per_value);
|
||||
return bytes_per_value;
|
||||
}
|
||||
|
||||
#define BIG_TYPE_PTR_BENCHMARKS(SIZE) \
|
||||
using stl_set_size##SIZE##copies##SIZE##ptr = std::set<BigType<SIZE, SIZE>>; \
|
||||
using stl_map_size##SIZE##copies##SIZE##ptr = \
|
||||
std::map<int, BigType<SIZE, SIZE>>; \
|
||||
using stl_unordered_set_size##SIZE##copies##SIZE##ptr = \
|
||||
std::unordered_set<BigType<SIZE, SIZE>, \
|
||||
absl::Hash<BigType<SIZE, SIZE>>>; \
|
||||
using stl_unordered_map_size##SIZE##copies##SIZE##ptr = \
|
||||
std::unordered_map<int, BigType<SIZE, SIZE>>; \
|
||||
using flat_hash_set_size##SIZE##copies##SIZE##ptr = \
|
||||
flat_hash_set<BigType<SIZE, SIZE>>; \
|
||||
using flat_hash_map_size##SIZE##copies##SIZE##ptr = \
|
||||
flat_hash_map<int, BigTypePtr<SIZE>>; \
|
||||
using btree_256_set_size##SIZE##copies##SIZE##ptr = \
|
||||
btree_set<BigTypePtr<SIZE>>; \
|
||||
using btree_256_map_size##SIZE##copies##SIZE##ptr = \
|
||||
btree_map<int, BigTypePtr<SIZE>>; \
|
||||
MY_BENCHMARK3(stl_set_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(stl_unordered_set_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(flat_hash_set_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(btree_256_set_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(stl_map_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(stl_unordered_map_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(flat_hash_map_size##SIZE##copies##SIZE##ptr); \
|
||||
MY_BENCHMARK3(btree_256_map_size##SIZE##copies##SIZE##ptr)
|
||||
|
||||
BIG_TYPE_PTR_BENCHMARKS(32);
|
||||
|
||||
} // namespace
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
759
absl/container/btree_map.h
Normal file
759
absl/container/btree_map.h
Normal file
@@ -0,0 +1,759 @@
|
||||
// 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: btree_map.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines B-tree maps: sorted associative containers mapping
|
||||
// keys to values.
|
||||
//
|
||||
// * `absl::btree_map<>`
|
||||
// * `absl::btree_multimap<>`
|
||||
//
|
||||
// These B-tree types are similar to the corresponding types in the STL
|
||||
// (`std::map` and `std::multimap`) and generally conform to the STL interfaces
|
||||
// of those types. However, because they are implemented using B-trees, they
|
||||
// are more efficient in most situations.
|
||||
//
|
||||
// Unlike `std::map` and `std::multimap`, which are commonly implemented using
|
||||
// red-black tree nodes, B-tree maps use more generic B-tree nodes able to hold
|
||||
// multiple values per node. Holding multiple values per node often makes
|
||||
// B-tree maps perform better than their `std::map` counterparts, because
|
||||
// multiple entries can be checked within the same cache hit.
|
||||
//
|
||||
// However, these types should not be considered drop-in replacements for
|
||||
// `std::map` and `std::multimap` as there are some API differences, which are
|
||||
// noted in this header file.
|
||||
//
|
||||
// Importantly, insertions and deletions may invalidate outstanding iterators,
|
||||
// pointers, and references to elements. Such invalidations are typically only
|
||||
// an issue if insertion and deletion operations are interleaved with the use of
|
||||
// more than one iterator, pointer, or reference simultaneously. For this
|
||||
// reason, `insert()` and `erase()` return a valid iterator at the current
|
||||
// position.
|
||||
|
||||
#ifndef ABSL_CONTAINER_BTREE_MAP_H_
|
||||
#define ABSL_CONTAINER_BTREE_MAP_H_
|
||||
|
||||
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// absl::btree_map<>
|
||||
//
|
||||
// An `absl::btree_map<K, V>` is an ordered associative container of
|
||||
// unique keys and associated values designed to be a more efficient replacement
|
||||
// for `std::map` (in most cases).
|
||||
//
|
||||
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||
// `std::less<K>`.
|
||||
//
|
||||
// An `absl::btree_map<K, V>` uses a default allocator of
|
||||
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
|
||||
// nodes, and construct and destruct values within those nodes. You may
|
||||
// instead specify a custom allocator `A` (which in turn requires specifying a
|
||||
// custom comparator `C`) as in `absl::btree_map<K, V, C, A>`.
|
||||
//
|
||||
template <typename Key, typename Value, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||
class btree_map
|
||||
: public container_internal::btree_map_container<
|
||||
container_internal::btree<container_internal::map_params<
|
||||
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||
/*Multi=*/false>>> {
|
||||
using Base = typename btree_map::btree_map_container;
|
||||
|
||||
public:
|
||||
// Constructors and Assignment Operators
|
||||
//
|
||||
// A `btree_map` supports the same overload set as `std::map`
|
||||
// for construction and assignment:
|
||||
//
|
||||
// * Default constructor
|
||||
//
|
||||
// absl::btree_map<int, std::string> map1;
|
||||
//
|
||||
// * Initializer List constructor
|
||||
//
|
||||
// absl::btree_map<int, std::string> map2 =
|
||||
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||
//
|
||||
// * Copy constructor
|
||||
//
|
||||
// absl::btree_map<int, std::string> map3(map2);
|
||||
//
|
||||
// * Copy assignment operator
|
||||
//
|
||||
// absl::btree_map<int, std::string> map4;
|
||||
// map4 = map3;
|
||||
//
|
||||
// * Move constructor
|
||||
//
|
||||
// // Move is guaranteed efficient
|
||||
// absl::btree_map<int, std::string> map5(std::move(map4));
|
||||
//
|
||||
// * Move assignment operator
|
||||
//
|
||||
// // May be efficient if allocators are compatible
|
||||
// absl::btree_map<int, std::string> map6;
|
||||
// map6 = std::move(map5);
|
||||
//
|
||||
// * Range constructor
|
||||
//
|
||||
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||
// absl::btree_map<int, std::string> map7(v.begin(), v.end());
|
||||
btree_map() {}
|
||||
using Base::Base;
|
||||
|
||||
// btree_map::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the `btree_map`.
|
||||
using Base::begin;
|
||||
|
||||
// btree_map::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the `btree_map`.
|
||||
using Base::cbegin;
|
||||
|
||||
// btree_map::end()
|
||||
//
|
||||
// Returns an iterator to the end of the `btree_map`.
|
||||
using Base::end;
|
||||
|
||||
// btree_map::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the `btree_map`.
|
||||
using Base::cend;
|
||||
|
||||
// btree_map::empty()
|
||||
//
|
||||
// Returns whether or not the `btree_map` is empty.
|
||||
using Base::empty;
|
||||
|
||||
// btree_map::max_size()
|
||||
//
|
||||
// Returns the largest theoretical possible number of elements within a
|
||||
// `btree_map` under current memory constraints. This value can be thought
|
||||
// of as the largest value of `std::distance(begin(), end())` for a
|
||||
// `btree_map<Key, T>`.
|
||||
using Base::max_size;
|
||||
|
||||
// btree_map::size()
|
||||
//
|
||||
// Returns the number of elements currently within the `btree_map`.
|
||||
using Base::size;
|
||||
|
||||
// btree_map::clear()
|
||||
//
|
||||
// Removes all elements from the `btree_map`. Invalidates any references,
|
||||
// pointers, or iterators referring to contained elements.
|
||||
using Base::clear;
|
||||
|
||||
// btree_map::erase()
|
||||
//
|
||||
// Erases elements within the `btree_map`. If an erase occurs, any references,
|
||||
// pointers, or iterators are invalidated.
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// iterator erase(iterator position):
|
||||
// iterator erase(const_iterator position):
|
||||
//
|
||||
// Erases the element at `position` of the `btree_map`, returning
|
||||
// the iterator pointing to the element after the one that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// iterator erase(const_iterator first, const_iterator last):
|
||||
//
|
||||
// Erases the elements in the open interval [`first`, `last`), returning
|
||||
// the iterator pointing to the element after the interval that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// template <typename K> size_type erase(const K& key):
|
||||
//
|
||||
// Erases the element with the matching key, if it exists, returning the
|
||||
// number of elements erased.
|
||||
using Base::erase;
|
||||
|
||||
// btree_map::insert()
|
||||
//
|
||||
// Inserts an element of the specified value into the `btree_map`,
|
||||
// returning an iterator pointing to the newly inserted element, provided that
|
||||
// an element with the given key does not already exist. If an insertion
|
||||
// occurs, any references, pointers, or iterators are invalidated.
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(const value_type& value):
|
||||
//
|
||||
// Inserts a value into the `btree_map`. Returns a pair consisting of an
|
||||
// iterator to the inserted element (or to the element that prevented the
|
||||
// insertion) and a bool denoting whether the insertion took place.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(value_type&& value):
|
||||
//
|
||||
// Inserts a moveable value into the `btree_map`. Returns a pair
|
||||
// consisting of an iterator to the inserted element (or to the element that
|
||||
// prevented the insertion) and a bool denoting whether the insertion took
|
||||
// place.
|
||||
//
|
||||
// iterator insert(const_iterator hint, const value_type& value):
|
||||
// iterator insert(const_iterator hint, value_type&& value):
|
||||
//
|
||||
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search. Returns an iterator to the
|
||||
// inserted element, or to the existing element that prevented the
|
||||
// insertion.
|
||||
//
|
||||
// void insert(InputIterator first, InputIterator last):
|
||||
//
|
||||
// Inserts a range of values [`first`, `last`).
|
||||
//
|
||||
// void insert(std::initializer_list<init_type> ilist):
|
||||
//
|
||||
// Inserts the elements within the initializer list `ilist`.
|
||||
using Base::insert;
|
||||
|
||||
// btree_map::insert_or_assign()
|
||||
//
|
||||
// Inserts an element of the specified value into the `btree_map` provided
|
||||
// that a value with the given key does not already exist, or replaces the
|
||||
// corresponding mapped type with the forwarded `obj` argument if a key for
|
||||
// that value already exists, returning an iterator pointing to the newly
|
||||
// inserted element. Overloads are listed below.
|
||||
//
|
||||
// pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj):
|
||||
// pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj):
|
||||
//
|
||||
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||
// `btree_map`. If the returned bool is true, insertion took place, and if
|
||||
// it's false, assignment took place.
|
||||
//
|
||||
// iterator insert_or_assign(const_iterator hint,
|
||||
// const key_type& k, M&& obj):
|
||||
// iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj):
|
||||
//
|
||||
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||
// `btree_map` using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search.
|
||||
using Base::insert_or_assign;
|
||||
|
||||
// btree_map::emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_map`, provided that no element with the given key
|
||||
// already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||
// copyable or moveable.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace;
|
||||
|
||||
// btree_map::emplace_hint()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_map`, using the position of `hint` as a non-binding
|
||||
// suggestion for where to begin the insertion search, and only inserts
|
||||
// provided that no element with the given key already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||
// copyable or moveable.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace_hint;
|
||||
|
||||
// btree_map::try_emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_map`, provided that no element with the given key
|
||||
// already exists. Unlike `emplace()`, if an element with the given key
|
||||
// already exists, we guarantee that no element is constructed.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
//
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
|
||||
// std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
|
||||
//
|
||||
// Inserts (via copy or move) the element of the specified key into the
|
||||
// `btree_map`.
|
||||
//
|
||||
// iterator try_emplace(const_iterator hint,
|
||||
// const key_type& k, Args&&... args):
|
||||
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
|
||||
//
|
||||
// Inserts (via copy or move) the element of the specified key into the
|
||||
// `btree_map` using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search.
|
||||
using Base::try_emplace;
|
||||
|
||||
// btree_map::extract()
|
||||
//
|
||||
// Extracts the indicated element, erasing it in the process, and returns it
|
||||
// as a C++17-compatible node handle. Overloads are listed below.
|
||||
//
|
||||
// node_type extract(const_iterator position):
|
||||
//
|
||||
// Extracts the element at the indicated position and returns a node handle
|
||||
// owning that extracted data.
|
||||
//
|
||||
// template <typename K> node_type extract(const K& x):
|
||||
//
|
||||
// Extracts the element with the key matching the passed key value and
|
||||
// returns a node handle owning that extracted data. If the `btree_map`
|
||||
// does not contain an element with a matching key, this function returns an
|
||||
// empty node handle.
|
||||
//
|
||||
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||
// move-only type that owns and provides access to the elements in associative
|
||||
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||
// It does NOT refer to the data layout of the underlying btree.
|
||||
using Base::extract;
|
||||
|
||||
// btree_map::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` btree_map into this
|
||||
// `btree_map`. If the destination `btree_map` already contains an
|
||||
// element with an equivalent key, that element is not extracted.
|
||||
using Base::merge;
|
||||
|
||||
// btree_map::swap(btree_map& other)
|
||||
//
|
||||
// Exchanges the contents of this `btree_map` with those of the `other`
|
||||
// btree_map, avoiding invocation of any move, copy, or swap operations on
|
||||
// individual elements.
|
||||
//
|
||||
// All iterators and references on the `btree_map` remain valid, excepting
|
||||
// for the past-the-end iterator, which is invalidated.
|
||||
using Base::swap;
|
||||
|
||||
// btree_map::at()
|
||||
//
|
||||
// Returns a reference to the mapped value of the element with key equivalent
|
||||
// to the passed key.
|
||||
using Base::at;
|
||||
|
||||
// btree_map::contains()
|
||||
//
|
||||
// template <typename K> bool contains(const K& key) const:
|
||||
//
|
||||
// Determines whether an element comparing equal to the given `key` exists
|
||||
// within the `btree_map`, returning `true` if so or `false` otherwise.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_map::count()
|
||||
//
|
||||
// template <typename K> size_type count(const K& key) const:
|
||||
//
|
||||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_map`. Note that this function will return either `1` or `0`
|
||||
// since duplicate elements are not allowed within a `btree_map`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_map::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// iterators, containing all elements with the passed key in the
|
||||
// `btree_map`.
|
||||
using Base::equal_range;
|
||||
|
||||
// btree_map::find()
|
||||
//
|
||||
// template <typename K> iterator find(const K& key):
|
||||
// template <typename K> const_iterator find(const K& key) const:
|
||||
//
|
||||
// Finds an element with the passed `key` within the `btree_map`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::find;
|
||||
|
||||
// btree_map::operator[]()
|
||||
//
|
||||
// Returns a reference to the value mapped to the passed key within the
|
||||
// `btree_map`, performing an `insert()` if the key does not already
|
||||
// exist.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated. Otherwise iterators are not affected and references are not
|
||||
// invalidated. Overloads are listed below.
|
||||
//
|
||||
// T& operator[](key_type&& key):
|
||||
// T& operator[](const key_type& key):
|
||||
//
|
||||
// Inserts a value_type object constructed in-place if the element with the
|
||||
// given key does not exist.
|
||||
using Base::operator[];
|
||||
|
||||
// btree_map::get_allocator()
|
||||
//
|
||||
// Returns the allocator function associated with this `btree_map`.
|
||||
using Base::get_allocator;
|
||||
|
||||
// btree_map::key_comp();
|
||||
//
|
||||
// Returns the key comparator associated with this `btree_map`.
|
||||
using Base::key_comp;
|
||||
|
||||
// btree_map::value_comp();
|
||||
//
|
||||
// Returns the value comparator associated with this `btree_map`.
|
||||
using Base::value_comp;
|
||||
};
|
||||
|
||||
// absl::swap(absl::btree_map<>, absl::btree_map<>)
|
||||
//
|
||||
// Swaps the contents of two `absl::btree_map` containers.
|
||||
template <typename K, typename V, typename C, typename A>
|
||||
void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) {
|
||||
return x.swap(y);
|
||||
}
|
||||
|
||||
// absl::erase_if(absl::btree_map<>, Pred)
|
||||
//
|
||||
// Erases all elements that satisfy the predicate pred from the container.
|
||||
template <typename K, typename V, typename C, typename A, typename Pred>
|
||||
void erase_if(btree_map<K, V, C, A> &map, Pred pred) {
|
||||
for (auto it = map.begin(); it != map.end();) {
|
||||
if (pred(*it)) {
|
||||
it = map.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// absl::btree_multimap
|
||||
//
|
||||
// An `absl::btree_multimap<K, V>` is an ordered associative container of
|
||||
// keys and associated values designed to be a more efficient replacement for
|
||||
// `std::multimap` (in most cases). Unlike `absl::btree_map`, a B-tree multimap
|
||||
// allows multiple elements with equivalent keys.
|
||||
//
|
||||
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||
// `std::less<K>`.
|
||||
//
|
||||
// An `absl::btree_multimap<K, V>` uses a default allocator of
|
||||
// `std::allocator<std::pair<const K, V>>` to allocate (and deallocate)
|
||||
// nodes, and construct and destruct values within those nodes. You may
|
||||
// instead specify a custom allocator `A` (which in turn requires specifying a
|
||||
// custom comparator `C`) as in `absl::btree_multimap<K, V, C, A>`.
|
||||
//
|
||||
template <typename Key, typename Value, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||
class btree_multimap
|
||||
: public container_internal::btree_multimap_container<
|
||||
container_internal::btree<container_internal::map_params<
|
||||
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||
/*Multi=*/true>>> {
|
||||
using Base = typename btree_multimap::btree_multimap_container;
|
||||
|
||||
public:
|
||||
// Constructors and Assignment Operators
|
||||
//
|
||||
// A `btree_multimap` supports the same overload set as `std::multimap`
|
||||
// for construction and assignment:
|
||||
//
|
||||
// * Default constructor
|
||||
//
|
||||
// absl::btree_multimap<int, std::string> map1;
|
||||
//
|
||||
// * Initializer List constructor
|
||||
//
|
||||
// absl::btree_multimap<int, std::string> map2 =
|
||||
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||
//
|
||||
// * Copy constructor
|
||||
//
|
||||
// absl::btree_multimap<int, std::string> map3(map2);
|
||||
//
|
||||
// * Copy assignment operator
|
||||
//
|
||||
// absl::btree_multimap<int, std::string> map4;
|
||||
// map4 = map3;
|
||||
//
|
||||
// * Move constructor
|
||||
//
|
||||
// // Move is guaranteed efficient
|
||||
// absl::btree_multimap<int, std::string> map5(std::move(map4));
|
||||
//
|
||||
// * Move assignment operator
|
||||
//
|
||||
// // May be efficient if allocators are compatible
|
||||
// absl::btree_multimap<int, std::string> map6;
|
||||
// map6 = std::move(map5);
|
||||
//
|
||||
// * Range constructor
|
||||
//
|
||||
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||
// absl::btree_multimap<int, std::string> map7(v.begin(), v.end());
|
||||
btree_multimap() {}
|
||||
using Base::Base;
|
||||
|
||||
// btree_multimap::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the `btree_multimap`.
|
||||
using Base::begin;
|
||||
|
||||
// btree_multimap::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the `btree_multimap`.
|
||||
using Base::cbegin;
|
||||
|
||||
// btree_multimap::end()
|
||||
//
|
||||
// Returns an iterator to the end of the `btree_multimap`.
|
||||
using Base::end;
|
||||
|
||||
// btree_multimap::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the `btree_multimap`.
|
||||
using Base::cend;
|
||||
|
||||
// btree_multimap::empty()
|
||||
//
|
||||
// Returns whether or not the `btree_multimap` is empty.
|
||||
using Base::empty;
|
||||
|
||||
// btree_multimap::max_size()
|
||||
//
|
||||
// Returns the largest theoretical possible number of elements within a
|
||||
// `btree_multimap` under current memory constraints. This value can be
|
||||
// thought of as the largest value of `std::distance(begin(), end())` for a
|
||||
// `btree_multimap<Key, T>`.
|
||||
using Base::max_size;
|
||||
|
||||
// btree_multimap::size()
|
||||
//
|
||||
// Returns the number of elements currently within the `btree_multimap`.
|
||||
using Base::size;
|
||||
|
||||
// btree_multimap::clear()
|
||||
//
|
||||
// Removes all elements from the `btree_multimap`. Invalidates any references,
|
||||
// pointers, or iterators referring to contained elements.
|
||||
using Base::clear;
|
||||
|
||||
// btree_multimap::erase()
|
||||
//
|
||||
// Erases elements within the `btree_multimap`. If an erase occurs, any
|
||||
// references, pointers, or iterators are invalidated.
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// iterator erase(iterator position):
|
||||
// iterator erase(const_iterator position):
|
||||
//
|
||||
// Erases the element at `position` of the `btree_multimap`, returning
|
||||
// the iterator pointing to the element after the one that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// iterator erase(const_iterator first, const_iterator last):
|
||||
//
|
||||
// Erases the elements in the open interval [`first`, `last`), returning
|
||||
// the iterator pointing to the element after the interval that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// template <typename K> size_type erase(const K& key):
|
||||
//
|
||||
// Erases the elements matching the key, if any exist, returning the
|
||||
// number of elements erased.
|
||||
using Base::erase;
|
||||
|
||||
// btree_multimap::insert()
|
||||
//
|
||||
// Inserts an element of the specified value into the `btree_multimap`,
|
||||
// returning an iterator pointing to the newly inserted element.
|
||||
// Any references, pointers, or iterators are invalidated. Overloads are
|
||||
// listed below.
|
||||
//
|
||||
// iterator insert(const value_type& value):
|
||||
//
|
||||
// Inserts a value into the `btree_multimap`, returning an iterator to the
|
||||
// inserted element.
|
||||
//
|
||||
// iterator insert(value_type&& value):
|
||||
//
|
||||
// Inserts a moveable value into the `btree_multimap`, returning an iterator
|
||||
// to the inserted element.
|
||||
//
|
||||
// iterator insert(const_iterator hint, const value_type& value):
|
||||
// iterator insert(const_iterator hint, value_type&& value):
|
||||
//
|
||||
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search. Returns an iterator to the
|
||||
// inserted element.
|
||||
//
|
||||
// void insert(InputIterator first, InputIterator last):
|
||||
//
|
||||
// Inserts a range of values [`first`, `last`).
|
||||
//
|
||||
// void insert(std::initializer_list<init_type> ilist):
|
||||
//
|
||||
// Inserts the elements within the initializer list `ilist`.
|
||||
using Base::insert;
|
||||
|
||||
// btree_multimap::emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_multimap`. Any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace;
|
||||
|
||||
// btree_multimap::emplace_hint()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_multimap`, using the position of `hint` as a non-binding
|
||||
// suggestion for where to begin the insertion search.
|
||||
//
|
||||
// Any references, pointers, or iterators are invalidated.
|
||||
using Base::emplace_hint;
|
||||
|
||||
// btree_multimap::extract()
|
||||
//
|
||||
// Extracts the indicated element, erasing it in the process, and returns it
|
||||
// as a C++17-compatible node handle. Overloads are listed below.
|
||||
//
|
||||
// node_type extract(const_iterator position):
|
||||
//
|
||||
// Extracts the element at the indicated position and returns a node handle
|
||||
// owning that extracted data.
|
||||
//
|
||||
// template <typename K> node_type extract(const K& x):
|
||||
//
|
||||
// Extracts the element with the key matching the passed key value and
|
||||
// returns a node handle owning that extracted data. If the `btree_multimap`
|
||||
// does not contain an element with a matching key, this function returns an
|
||||
// empty node handle.
|
||||
//
|
||||
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||
// move-only type that owns and provides access to the elements in associative
|
||||
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||
// It does NOT refer to the data layout of the underlying btree.
|
||||
using Base::extract;
|
||||
|
||||
// btree_multimap::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` btree_multimap into this
|
||||
// `btree_multimap`. If the destination `btree_multimap` already contains an
|
||||
// element with an equivalent key, that element is not extracted.
|
||||
using Base::merge;
|
||||
|
||||
// btree_multimap::swap(btree_multimap& other)
|
||||
//
|
||||
// Exchanges the contents of this `btree_multimap` with those of the `other`
|
||||
// btree_multimap, avoiding invocation of any move, copy, or swap operations
|
||||
// on individual elements.
|
||||
//
|
||||
// All iterators and references on the `btree_multimap` remain valid,
|
||||
// excepting for the past-the-end iterator, which is invalidated.
|
||||
using Base::swap;
|
||||
|
||||
// btree_multimap::contains()
|
||||
//
|
||||
// template <typename K> bool contains(const K& key) const:
|
||||
//
|
||||
// Determines whether an element comparing equal to the given `key` exists
|
||||
// within the `btree_multimap`, returning `true` if so or `false` otherwise.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_multimap::count()
|
||||
//
|
||||
// template <typename K> size_type count(const K& key) const:
|
||||
//
|
||||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_multimap`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_multimap::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// iterators, containing all elements with the passed key in the
|
||||
// `btree_multimap`.
|
||||
using Base::equal_range;
|
||||
|
||||
// btree_multimap::find()
|
||||
//
|
||||
// template <typename K> iterator find(const K& key):
|
||||
// template <typename K> const_iterator find(const K& key) const:
|
||||
//
|
||||
// Finds an element with the passed `key` within the `btree_multimap`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the map is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::find;
|
||||
|
||||
// btree_multimap::get_allocator()
|
||||
//
|
||||
// Returns the allocator function associated with this `btree_multimap`.
|
||||
using Base::get_allocator;
|
||||
|
||||
// btree_multimap::key_comp();
|
||||
//
|
||||
// Returns the key comparator associated with this `btree_multimap`.
|
||||
using Base::key_comp;
|
||||
|
||||
// btree_multimap::value_comp();
|
||||
//
|
||||
// Returns the value comparator associated with this `btree_multimap`.
|
||||
using Base::value_comp;
|
||||
};
|
||||
|
||||
// absl::swap(absl::btree_multimap<>, absl::btree_multimap<>)
|
||||
//
|
||||
// Swaps the contents of two `absl::btree_multimap` containers.
|
||||
template <typename K, typename V, typename C, typename A>
|
||||
void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) {
|
||||
return x.swap(y);
|
||||
}
|
||||
|
||||
// absl::erase_if(absl::btree_multimap<>, Pred)
|
||||
//
|
||||
// Erases all elements that satisfy the predicate pred from the container.
|
||||
template <typename K, typename V, typename C, typename A, typename Pred>
|
||||
void erase_if(btree_multimap<K, V, C, A> &map, Pred pred) {
|
||||
for (auto it = map.begin(); it != map.end();) {
|
||||
if (pred(*it)) {
|
||||
it = map.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_BTREE_MAP_H_
|
||||
683
absl/container/btree_set.h
Normal file
683
absl/container/btree_set.h
Normal file
@@ -0,0 +1,683 @@
|
||||
// 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: btree_set.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines B-tree sets: sorted associative containers of
|
||||
// values.
|
||||
//
|
||||
// * `absl::btree_set<>`
|
||||
// * `absl::btree_multiset<>`
|
||||
//
|
||||
// These B-tree types are similar to the corresponding types in the STL
|
||||
// (`std::set` and `std::multiset`) and generally conform to the STL interfaces
|
||||
// of those types. However, because they are implemented using B-trees, they
|
||||
// are more efficient in most situations.
|
||||
//
|
||||
// Unlike `std::set` and `std::multiset`, which are commonly implemented using
|
||||
// red-black tree nodes, B-tree sets use more generic B-tree nodes able to hold
|
||||
// multiple values per node. Holding multiple values per node often makes
|
||||
// B-tree sets perform better than their `std::set` counterparts, because
|
||||
// multiple entries can be checked within the same cache hit.
|
||||
//
|
||||
// However, these types should not be considered drop-in replacements for
|
||||
// `std::set` and `std::multiset` as there are some API differences, which are
|
||||
// noted in this header file.
|
||||
//
|
||||
// Importantly, insertions and deletions may invalidate outstanding iterators,
|
||||
// pointers, and references to elements. Such invalidations are typically only
|
||||
// an issue if insertion and deletion operations are interleaved with the use of
|
||||
// more than one iterator, pointer, or reference simultaneously. For this
|
||||
// reason, `insert()` and `erase()` return a valid iterator at the current
|
||||
// position.
|
||||
|
||||
#ifndef ABSL_CONTAINER_BTREE_SET_H_
|
||||
#define ABSL_CONTAINER_BTREE_SET_H_
|
||||
|
||||
#include "absl/container/internal/btree.h" // IWYU pragma: export
|
||||
#include "absl/container/internal/btree_container.h" // IWYU pragma: export
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// absl::btree_set<>
|
||||
//
|
||||
// An `absl::btree_set<K>` is an ordered associative container of unique key
|
||||
// values designed to be a more efficient replacement for `std::set` (in most
|
||||
// cases).
|
||||
//
|
||||
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||
// `std::less<K>`.
|
||||
//
|
||||
// An `absl::btree_set<K>` uses a default allocator of `std::allocator<K>` to
|
||||
// allocate (and deallocate) nodes, and construct and destruct values within
|
||||
// those nodes. You may instead specify a custom allocator `A` (which in turn
|
||||
// requires specifying a custom comparator `C`) as in
|
||||
// `absl::btree_set<K, C, A>`.
|
||||
//
|
||||
template <typename Key, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<Key>>
|
||||
class btree_set
|
||||
: public container_internal::btree_set_container<
|
||||
container_internal::btree<container_internal::set_params<
|
||||
Key, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||
/*Multi=*/false>>> {
|
||||
using Base = typename btree_set::btree_set_container;
|
||||
|
||||
public:
|
||||
// Constructors and Assignment Operators
|
||||
//
|
||||
// A `btree_set` supports the same overload set as `std::set`
|
||||
// for construction and assignment:
|
||||
//
|
||||
// * Default constructor
|
||||
//
|
||||
// absl::btree_set<std::string> set1;
|
||||
//
|
||||
// * Initializer List constructor
|
||||
//
|
||||
// absl::btree_set<std::string> set2 =
|
||||
// {{"huey"}, {"dewey"}, {"louie"},};
|
||||
//
|
||||
// * Copy constructor
|
||||
//
|
||||
// absl::btree_set<std::string> set3(set2);
|
||||
//
|
||||
// * Copy assignment operator
|
||||
//
|
||||
// absl::btree_set<std::string> set4;
|
||||
// set4 = set3;
|
||||
//
|
||||
// * Move constructor
|
||||
//
|
||||
// // Move is guaranteed efficient
|
||||
// absl::btree_set<std::string> set5(std::move(set4));
|
||||
//
|
||||
// * Move assignment operator
|
||||
//
|
||||
// // May be efficient if allocators are compatible
|
||||
// absl::btree_set<std::string> set6;
|
||||
// set6 = std::move(set5);
|
||||
//
|
||||
// * Range constructor
|
||||
//
|
||||
// std::vector<std::string> v = {"a", "b"};
|
||||
// absl::btree_set<std::string> set7(v.begin(), v.end());
|
||||
btree_set() {}
|
||||
using Base::Base;
|
||||
|
||||
// btree_set::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the `btree_set`.
|
||||
using Base::begin;
|
||||
|
||||
// btree_set::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the `btree_set`.
|
||||
using Base::cbegin;
|
||||
|
||||
// btree_set::end()
|
||||
//
|
||||
// Returns an iterator to the end of the `btree_set`.
|
||||
using Base::end;
|
||||
|
||||
// btree_set::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the `btree_set`.
|
||||
using Base::cend;
|
||||
|
||||
// btree_set::empty()
|
||||
//
|
||||
// Returns whether or not the `btree_set` is empty.
|
||||
using Base::empty;
|
||||
|
||||
// btree_set::max_size()
|
||||
//
|
||||
// Returns the largest theoretical possible number of elements within a
|
||||
// `btree_set` under current memory constraints. This value can be thought
|
||||
// of as the largest value of `std::distance(begin(), end())` for a
|
||||
// `btree_set<Key>`.
|
||||
using Base::max_size;
|
||||
|
||||
// btree_set::size()
|
||||
//
|
||||
// Returns the number of elements currently within the `btree_set`.
|
||||
using Base::size;
|
||||
|
||||
// btree_set::clear()
|
||||
//
|
||||
// Removes all elements from the `btree_set`. Invalidates any references,
|
||||
// pointers, or iterators referring to contained elements.
|
||||
using Base::clear;
|
||||
|
||||
// btree_set::erase()
|
||||
//
|
||||
// Erases elements within the `btree_set`. Overloads are listed below.
|
||||
//
|
||||
// iterator erase(iterator position):
|
||||
// iterator erase(const_iterator position):
|
||||
//
|
||||
// Erases the element at `position` of the `btree_set`, returning
|
||||
// the iterator pointing to the element after the one that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// iterator erase(const_iterator first, const_iterator last):
|
||||
//
|
||||
// Erases the elements in the open interval [`first`, `last`), returning
|
||||
// the iterator pointing to the element after the interval that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// template <typename K> size_type erase(const K& key):
|
||||
//
|
||||
// Erases the element with the matching key, if it exists, returning the
|
||||
// number of elements erased.
|
||||
using Base::erase;
|
||||
|
||||
// btree_set::insert()
|
||||
//
|
||||
// Inserts an element of the specified value into the `btree_set`,
|
||||
// returning an iterator pointing to the newly inserted element, provided that
|
||||
// an element with the given key does not already exist. If an insertion
|
||||
// occurs, any references, pointers, or iterators are invalidated.
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(const value_type& value):
|
||||
//
|
||||
// Inserts a value into the `btree_set`. Returns a pair consisting of an
|
||||
// iterator to the inserted element (or to the element that prevented the
|
||||
// insertion) and a bool denoting whether the insertion took place.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(value_type&& value):
|
||||
//
|
||||
// Inserts a moveable value into the `btree_set`. Returns a pair
|
||||
// consisting of an iterator to the inserted element (or to the element that
|
||||
// prevented the insertion) and a bool denoting whether the insertion took
|
||||
// place.
|
||||
//
|
||||
// iterator insert(const_iterator hint, const value_type& value):
|
||||
// iterator insert(const_iterator hint, value_type&& value):
|
||||
//
|
||||
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search. Returns an iterator to the
|
||||
// inserted element, or to the existing element that prevented the
|
||||
// insertion.
|
||||
//
|
||||
// void insert(InputIterator first, InputIterator last):
|
||||
//
|
||||
// Inserts a range of values [`first`, `last`).
|
||||
//
|
||||
// void insert(std::initializer_list<init_type> ilist):
|
||||
//
|
||||
// Inserts the elements within the initializer list `ilist`.
|
||||
using Base::insert;
|
||||
|
||||
// btree_set::emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_set`, provided that no element with the given key
|
||||
// already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace;
|
||||
|
||||
// btree_set::emplace_hint()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_set`, using the position of `hint` as a non-binding
|
||||
// suggestion for where to begin the insertion search, and only inserts
|
||||
// provided that no element with the given key already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately.
|
||||
//
|
||||
// If an insertion occurs, any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace_hint;
|
||||
|
||||
// btree_set::extract()
|
||||
//
|
||||
// Extracts the indicated element, erasing it in the process, and returns it
|
||||
// as a C++17-compatible node handle. Overloads are listed below.
|
||||
//
|
||||
// node_type extract(const_iterator position):
|
||||
//
|
||||
// Extracts the element at the indicated position and returns a node handle
|
||||
// owning that extracted data.
|
||||
//
|
||||
// template <typename K> node_type extract(const K& x):
|
||||
//
|
||||
// Extracts the element with the key matching the passed key value and
|
||||
// returns a node handle owning that extracted data. If the `btree_set`
|
||||
// does not contain an element with a matching key, this function returns an
|
||||
// empty node handle.
|
||||
//
|
||||
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||
// move-only type that owns and provides access to the elements in associative
|
||||
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||
// It does NOT refer to the data layout of the underlying btree.
|
||||
using Base::extract;
|
||||
|
||||
// btree_set::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` btree_set into this
|
||||
// `btree_set`. If the destination `btree_set` already contains an
|
||||
// element with an equivalent key, that element is not extracted.
|
||||
using Base::merge;
|
||||
|
||||
// btree_set::swap(btree_set& other)
|
||||
//
|
||||
// Exchanges the contents of this `btree_set` with those of the `other`
|
||||
// btree_set, avoiding invocation of any move, copy, or swap operations on
|
||||
// individual elements.
|
||||
//
|
||||
// All iterators and references on the `btree_set` remain valid, excepting
|
||||
// for the past-the-end iterator, which is invalidated.
|
||||
using Base::swap;
|
||||
|
||||
// btree_set::contains()
|
||||
//
|
||||
// template <typename K> bool contains(const K& key) const:
|
||||
//
|
||||
// Determines whether an element comparing equal to the given `key` exists
|
||||
// within the `btree_set`, returning `true` if so or `false` otherwise.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_set::count()
|
||||
//
|
||||
// template <typename K> size_type count(const K& key) const:
|
||||
//
|
||||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_set`. Note that this function will return either `1` or `0`
|
||||
// since duplicate elements are not allowed within a `btree_set`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_set::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// iterators, containing all elements with the passed key in the
|
||||
// `btree_set`.
|
||||
using Base::equal_range;
|
||||
|
||||
// btree_set::find()
|
||||
//
|
||||
// template <typename K> iterator find(const K& key):
|
||||
// template <typename K> const_iterator find(const K& key) const:
|
||||
//
|
||||
// Finds an element with the passed `key` within the `btree_set`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::find;
|
||||
|
||||
// btree_set::get_allocator()
|
||||
//
|
||||
// Returns the allocator function associated with this `btree_set`.
|
||||
using Base::get_allocator;
|
||||
|
||||
// btree_set::key_comp();
|
||||
//
|
||||
// Returns the key comparator associated with this `btree_set`.
|
||||
using Base::key_comp;
|
||||
|
||||
// btree_set::value_comp();
|
||||
//
|
||||
// Returns the value comparator associated with this `btree_set`. The keys to
|
||||
// sort the elements are the values themselves, therefore `value_comp` and its
|
||||
// sibling member function `key_comp` are equivalent.
|
||||
using Base::value_comp;
|
||||
};
|
||||
|
||||
// absl::swap(absl::btree_set<>, absl::btree_set<>)
|
||||
//
|
||||
// Swaps the contents of two `absl::btree_set` containers.
|
||||
template <typename K, typename C, typename A>
|
||||
void swap(btree_set<K, C, A> &x, btree_set<K, C, A> &y) {
|
||||
return x.swap(y);
|
||||
}
|
||||
|
||||
// absl::erase_if(absl::btree_set<>, Pred)
|
||||
//
|
||||
// Erases all elements that satisfy the predicate pred from the container.
|
||||
template <typename K, typename C, typename A, typename Pred>
|
||||
void erase_if(btree_set<K, C, A> &set, Pred pred) {
|
||||
for (auto it = set.begin(); it != set.end();) {
|
||||
if (pred(*it)) {
|
||||
it = set.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// absl::btree_multiset<>
|
||||
//
|
||||
// An `absl::btree_multiset<K>` is an ordered associative container of
|
||||
// keys and associated values designed to be a more efficient replacement
|
||||
// for `std::multiset` (in most cases). Unlike `absl::btree_set`, a B-tree
|
||||
// multiset allows equivalent elements.
|
||||
//
|
||||
// Keys are sorted using an (optional) comparison function, which defaults to
|
||||
// `std::less<K>`.
|
||||
//
|
||||
// An `absl::btree_multiset<K>` uses a default allocator of `std::allocator<K>`
|
||||
// to allocate (and deallocate) nodes, and construct and destruct values within
|
||||
// those nodes. You may instead specify a custom allocator `A` (which in turn
|
||||
// requires specifying a custom comparator `C`) as in
|
||||
// `absl::btree_multiset<K, C, A>`.
|
||||
//
|
||||
template <typename Key, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<Key>>
|
||||
class btree_multiset
|
||||
: public container_internal::btree_multiset_container<
|
||||
container_internal::btree<container_internal::set_params<
|
||||
Key, Compare, Alloc, /*TargetNodeSize=*/256,
|
||||
/*Multi=*/true>>> {
|
||||
using Base = typename btree_multiset::btree_multiset_container;
|
||||
|
||||
public:
|
||||
// Constructors and Assignment Operators
|
||||
//
|
||||
// A `btree_multiset` supports the same overload set as `std::set`
|
||||
// for construction and assignment:
|
||||
//
|
||||
// * Default constructor
|
||||
//
|
||||
// absl::btree_multiset<std::string> set1;
|
||||
//
|
||||
// * Initializer List constructor
|
||||
//
|
||||
// absl::btree_multiset<std::string> set2 =
|
||||
// {{"huey"}, {"dewey"}, {"louie"},};
|
||||
//
|
||||
// * Copy constructor
|
||||
//
|
||||
// absl::btree_multiset<std::string> set3(set2);
|
||||
//
|
||||
// * Copy assignment operator
|
||||
//
|
||||
// absl::btree_multiset<std::string> set4;
|
||||
// set4 = set3;
|
||||
//
|
||||
// * Move constructor
|
||||
//
|
||||
// // Move is guaranteed efficient
|
||||
// absl::btree_multiset<std::string> set5(std::move(set4));
|
||||
//
|
||||
// * Move assignment operator
|
||||
//
|
||||
// // May be efficient if allocators are compatible
|
||||
// absl::btree_multiset<std::string> set6;
|
||||
// set6 = std::move(set5);
|
||||
//
|
||||
// * Range constructor
|
||||
//
|
||||
// std::vector<std::string> v = {"a", "b"};
|
||||
// absl::btree_multiset<std::string> set7(v.begin(), v.end());
|
||||
btree_multiset() {}
|
||||
using Base::Base;
|
||||
|
||||
// btree_multiset::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the `btree_multiset`.
|
||||
using Base::begin;
|
||||
|
||||
// btree_multiset::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the `btree_multiset`.
|
||||
using Base::cbegin;
|
||||
|
||||
// btree_multiset::end()
|
||||
//
|
||||
// Returns an iterator to the end of the `btree_multiset`.
|
||||
using Base::end;
|
||||
|
||||
// btree_multiset::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the `btree_multiset`.
|
||||
using Base::cend;
|
||||
|
||||
// btree_multiset::empty()
|
||||
//
|
||||
// Returns whether or not the `btree_multiset` is empty.
|
||||
using Base::empty;
|
||||
|
||||
// btree_multiset::max_size()
|
||||
//
|
||||
// Returns the largest theoretical possible number of elements within a
|
||||
// `btree_multiset` under current memory constraints. This value can be
|
||||
// thought of as the largest value of `std::distance(begin(), end())` for a
|
||||
// `btree_multiset<Key>`.
|
||||
using Base::max_size;
|
||||
|
||||
// btree_multiset::size()
|
||||
//
|
||||
// Returns the number of elements currently within the `btree_multiset`.
|
||||
using Base::size;
|
||||
|
||||
// btree_multiset::clear()
|
||||
//
|
||||
// Removes all elements from the `btree_multiset`. Invalidates any references,
|
||||
// pointers, or iterators referring to contained elements.
|
||||
using Base::clear;
|
||||
|
||||
// btree_multiset::erase()
|
||||
//
|
||||
// Erases elements within the `btree_multiset`. Overloads are listed below.
|
||||
//
|
||||
// iterator erase(iterator position):
|
||||
// iterator erase(const_iterator position):
|
||||
//
|
||||
// Erases the element at `position` of the `btree_multiset`, returning
|
||||
// the iterator pointing to the element after the one that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// iterator erase(const_iterator first, const_iterator last):
|
||||
//
|
||||
// Erases the elements in the open interval [`first`, `last`), returning
|
||||
// the iterator pointing to the element after the interval that was erased
|
||||
// (or end() if none exists).
|
||||
//
|
||||
// template <typename K> size_type erase(const K& key):
|
||||
//
|
||||
// Erases the elements matching the key, if any exist, returning the
|
||||
// number of elements erased.
|
||||
using Base::erase;
|
||||
|
||||
// btree_multiset::insert()
|
||||
//
|
||||
// Inserts an element of the specified value into the `btree_multiset`,
|
||||
// returning an iterator pointing to the newly inserted element.
|
||||
// Any references, pointers, or iterators are invalidated. Overloads are
|
||||
// listed below.
|
||||
//
|
||||
// iterator insert(const value_type& value):
|
||||
//
|
||||
// Inserts a value into the `btree_multiset`, returning an iterator to the
|
||||
// inserted element.
|
||||
//
|
||||
// iterator insert(value_type&& value):
|
||||
//
|
||||
// Inserts a moveable value into the `btree_multiset`, returning an iterator
|
||||
// to the inserted element.
|
||||
//
|
||||
// iterator insert(const_iterator hint, const value_type& value):
|
||||
// iterator insert(const_iterator hint, value_type&& value):
|
||||
//
|
||||
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search. Returns an iterator to the
|
||||
// inserted element.
|
||||
//
|
||||
// void insert(InputIterator first, InputIterator last):
|
||||
//
|
||||
// Inserts a range of values [`first`, `last`).
|
||||
//
|
||||
// void insert(std::initializer_list<init_type> ilist):
|
||||
//
|
||||
// Inserts the elements within the initializer list `ilist`.
|
||||
using Base::insert;
|
||||
|
||||
// btree_multiset::emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_multiset`. Any references, pointers, or iterators are
|
||||
// invalidated.
|
||||
using Base::emplace;
|
||||
|
||||
// btree_multiset::emplace_hint()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `btree_multiset`, using the position of `hint` as a non-binding
|
||||
// suggestion for where to begin the insertion search.
|
||||
//
|
||||
// Any references, pointers, or iterators are invalidated.
|
||||
using Base::emplace_hint;
|
||||
|
||||
// btree_multiset::extract()
|
||||
//
|
||||
// Extracts the indicated element, erasing it in the process, and returns it
|
||||
// as a C++17-compatible node handle. Overloads are listed below.
|
||||
//
|
||||
// node_type extract(const_iterator position):
|
||||
//
|
||||
// Extracts the element at the indicated position and returns a node handle
|
||||
// owning that extracted data.
|
||||
//
|
||||
// template <typename K> node_type extract(const K& x):
|
||||
//
|
||||
// Extracts the element with the key matching the passed key value and
|
||||
// returns a node handle owning that extracted data. If the `btree_multiset`
|
||||
// does not contain an element with a matching key, this function returns an
|
||||
// empty node handle.
|
||||
//
|
||||
// NOTE: In this context, `node_type` refers to the C++17 concept of a
|
||||
// move-only type that owns and provides access to the elements in associative
|
||||
// containers (https://en.cppreference.com/w/cpp/container/node_handle).
|
||||
// It does NOT refer to the data layout of the underlying btree.
|
||||
using Base::extract;
|
||||
|
||||
// btree_multiset::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` btree_multiset into this
|
||||
// `btree_multiset`. If the destination `btree_multiset` already contains an
|
||||
// element with an equivalent key, that element is not extracted.
|
||||
using Base::merge;
|
||||
|
||||
// btree_multiset::swap(btree_multiset& other)
|
||||
//
|
||||
// Exchanges the contents of this `btree_multiset` with those of the `other`
|
||||
// btree_multiset, avoiding invocation of any move, copy, or swap operations
|
||||
// on individual elements.
|
||||
//
|
||||
// All iterators and references on the `btree_multiset` remain valid,
|
||||
// excepting for the past-the-end iterator, which is invalidated.
|
||||
using Base::swap;
|
||||
|
||||
// btree_multiset::contains()
|
||||
//
|
||||
// template <typename K> bool contains(const K& key) const:
|
||||
//
|
||||
// Determines whether an element comparing equal to the given `key` exists
|
||||
// within the `btree_multiset`, returning `true` if so or `false` otherwise.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::contains;
|
||||
|
||||
// btree_multiset::count()
|
||||
//
|
||||
// template <typename K> size_type count(const K& key) const:
|
||||
//
|
||||
// Returns the number of elements comparing equal to the given `key` within
|
||||
// the `btree_multiset`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::count;
|
||||
|
||||
// btree_multiset::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// iterators, containing all elements with the passed key in the
|
||||
// `btree_multiset`.
|
||||
using Base::equal_range;
|
||||
|
||||
// btree_multiset::find()
|
||||
//
|
||||
// template <typename K> iterator find(const K& key):
|
||||
// template <typename K> const_iterator find(const K& key) const:
|
||||
//
|
||||
// Finds an element with the passed `key` within the `btree_multiset`.
|
||||
//
|
||||
// Supports heterogeneous lookup, provided that the set is provided a
|
||||
// compatible heterogeneous comparator.
|
||||
using Base::find;
|
||||
|
||||
// btree_multiset::get_allocator()
|
||||
//
|
||||
// Returns the allocator function associated with this `btree_multiset`.
|
||||
using Base::get_allocator;
|
||||
|
||||
// btree_multiset::key_comp();
|
||||
//
|
||||
// Returns the key comparator associated with this `btree_multiset`.
|
||||
using Base::key_comp;
|
||||
|
||||
// btree_multiset::value_comp();
|
||||
//
|
||||
// Returns the value comparator associated with this `btree_multiset`. The
|
||||
// keys to sort the elements are the values themselves, therefore `value_comp`
|
||||
// and its sibling member function `key_comp` are equivalent.
|
||||
using Base::value_comp;
|
||||
};
|
||||
|
||||
// absl::swap(absl::btree_multiset<>, absl::btree_multiset<>)
|
||||
//
|
||||
// Swaps the contents of two `absl::btree_multiset` containers.
|
||||
template <typename K, typename C, typename A>
|
||||
void swap(btree_multiset<K, C, A> &x, btree_multiset<K, C, A> &y) {
|
||||
return x.swap(y);
|
||||
}
|
||||
|
||||
// absl::erase_if(absl::btree_multiset<>, Pred)
|
||||
//
|
||||
// Erases all elements that satisfy the predicate pred from the container.
|
||||
template <typename K, typename C, typename A, typename Pred>
|
||||
void erase_if(btree_multiset<K, C, A> &set, Pred pred) {
|
||||
for (auto it = set.begin(); it != set.end();) {
|
||||
if (pred(*it)) {
|
||||
it = set.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_BTREE_SET_H_
|
||||
2404
absl/container/btree_test.cc
Normal file
2404
absl/container/btree_test.cc
Normal file
File diff suppressed because it is too large
Load Diff
155
absl/container/btree_test.h
Normal file
155
absl/container/btree_test.h
Normal file
@@ -0,0 +1,155 @@
|
||||
// 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_BTREE_TEST_H_
|
||||
#define ABSL_CONTAINER_BTREE_TEST_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/btree_map.h"
|
||||
#include "absl/container/btree_set.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
// Like remove_const but propagates the removal through std::pair.
|
||||
template <typename T>
|
||||
struct remove_pair_const {
|
||||
using type = typename std::remove_const<T>::type;
|
||||
};
|
||||
template <typename T, typename U>
|
||||
struct remove_pair_const<std::pair<T, U> > {
|
||||
using type = std::pair<typename remove_pair_const<T>::type,
|
||||
typename remove_pair_const<U>::type>;
|
||||
};
|
||||
|
||||
// Utility class to provide an accessor for a key given a value. The default
|
||||
// behavior is to treat the value as a pair and return the first element.
|
||||
template <typename K, typename V>
|
||||
struct KeyOfValue {
|
||||
struct type {
|
||||
const K& operator()(const V& p) const { return p.first; }
|
||||
};
|
||||
};
|
||||
|
||||
// Partial specialization of KeyOfValue class for when the key and value are
|
||||
// the same type such as in set<> and btree_set<>.
|
||||
template <typename K>
|
||||
struct KeyOfValue<K, K> {
|
||||
struct type {
|
||||
const K& operator()(const K& k) const { return k; }
|
||||
};
|
||||
};
|
||||
|
||||
inline char* GenerateDigits(char buf[16], unsigned val, unsigned maxval) {
|
||||
assert(val <= maxval);
|
||||
constexpr unsigned kBase = 64; // avoid integer division.
|
||||
unsigned p = 15;
|
||||
buf[p--] = 0;
|
||||
while (maxval > 0) {
|
||||
buf[p--] = ' ' + (val % kBase);
|
||||
val /= kBase;
|
||||
maxval /= kBase;
|
||||
}
|
||||
return buf + p + 1;
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
struct Generator {
|
||||
int maxval;
|
||||
explicit Generator(int m) : maxval(m) {}
|
||||
K operator()(int i) const {
|
||||
assert(i <= maxval);
|
||||
return K(i);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Generator<absl::Time> {
|
||||
int maxval;
|
||||
explicit Generator(int m) : maxval(m) {}
|
||||
absl::Time operator()(int i) const { return absl::FromUnixMillis(i); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Generator<std::string> {
|
||||
int maxval;
|
||||
explicit Generator(int m) : maxval(m) {}
|
||||
std::string operator()(int i) const {
|
||||
char buf[16];
|
||||
return GenerateDigits(buf, i, maxval);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
struct Generator<std::pair<T, U> > {
|
||||
Generator<typename remove_pair_const<T>::type> tgen;
|
||||
Generator<typename remove_pair_const<U>::type> ugen;
|
||||
|
||||
explicit Generator(int m) : tgen(m), ugen(m) {}
|
||||
std::pair<T, U> operator()(int i) const {
|
||||
return std::make_pair(tgen(i), ugen(i));
|
||||
}
|
||||
};
|
||||
|
||||
// Generate n values for our tests and benchmarks. Value range is [0, maxval].
|
||||
inline std::vector<int> GenerateNumbersWithSeed(int n, int maxval, int seed) {
|
||||
// NOTE: Some tests rely on generated numbers not changing between test runs.
|
||||
// We use std::minstd_rand0 because it is well-defined, but don't use
|
||||
// std::uniform_int_distribution because platforms use different algorithms.
|
||||
std::minstd_rand0 rng(seed);
|
||||
|
||||
std::vector<int> values;
|
||||
absl::flat_hash_set<int> unique_values;
|
||||
if (values.size() < n) {
|
||||
for (int i = values.size(); i < n; i++) {
|
||||
int value;
|
||||
do {
|
||||
value = static_cast<int>(rng()) % (maxval + 1);
|
||||
} while (!unique_values.insert(value).second);
|
||||
|
||||
values.push_back(value);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Generates n values in the range [0, maxval].
|
||||
template <typename V>
|
||||
std::vector<V> GenerateValuesWithSeed(int n, int maxval, int seed) {
|
||||
const std::vector<int> nums = GenerateNumbersWithSeed(n, maxval, seed);
|
||||
Generator<V> gen(maxval);
|
||||
std::vector<V> vec;
|
||||
|
||||
vec.reserve(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
vec.push_back(gen(nums[i]));
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_BTREE_TEST_H_
|
||||
@@ -31,7 +31,6 @@
|
||||
#define ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
@@ -51,7 +50,7 @@
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
namespace absl {
|
||||
inline namespace lts_2019_08_08 {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
|
||||
|
||||
@@ -387,8 +386,7 @@ class FixedArray {
|
||||
// error: call to int __builtin___sprintf_chk(etc...)
|
||||
// will always overflow destination buffer [-Werror]
|
||||
//
|
||||
template <typename OuterT = value_type,
|
||||
typename InnerT = absl::remove_extent_t<OuterT>,
|
||||
template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
|
||||
size_t InnerN = std::extent<OuterT>::value>
|
||||
struct StorageElementWrapper {
|
||||
InnerT array[InnerN];
|
||||
@@ -397,8 +395,6 @@ class FixedArray {
|
||||
using StorageElement =
|
||||
absl::conditional_t<std::is_array<value_type>::value,
|
||||
StorageElementWrapper<value_type>, value_type>;
|
||||
using StorageElementBuffer =
|
||||
absl::aligned_storage_t<sizeof(StorageElement), alignof(StorageElement)>;
|
||||
|
||||
static pointer AsValueType(pointer ptr) { return ptr; }
|
||||
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
|
||||
@@ -408,25 +404,25 @@ class FixedArray {
|
||||
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
|
||||
static_assert(alignof(StorageElement) == alignof(value_type), "");
|
||||
|
||||
struct NonEmptyInlinedStorage {
|
||||
StorageElement* data() {
|
||||
return reinterpret_cast<StorageElement*>(inlined_storage_.data());
|
||||
}
|
||||
class NonEmptyInlinedStorage {
|
||||
public:
|
||||
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
|
||||
void AnnotateConstruct(size_type n);
|
||||
void AnnotateDestruct(size_type n);
|
||||
|
||||
#ifdef ADDRESS_SANITIZER
|
||||
void* RedzoneBegin() { return &redzone_begin_; }
|
||||
void* RedzoneEnd() { return &redzone_end_ + 1; }
|
||||
#endif // ADDRESS_SANITIZER
|
||||
|
||||
void AnnotateConstruct(size_type);
|
||||
void AnnotateDestruct(size_type);
|
||||
|
||||
private:
|
||||
ADDRESS_SANITIZER_REDZONE(redzone_begin_);
|
||||
std::array<StorageElementBuffer, inline_elements> inlined_storage_;
|
||||
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
|
||||
ADDRESS_SANITIZER_REDZONE(redzone_end_);
|
||||
};
|
||||
|
||||
struct EmptyInlinedStorage {
|
||||
class EmptyInlinedStorage {
|
||||
public:
|
||||
StorageElement* data() { return nullptr; }
|
||||
void AnnotateConstruct(size_type) {}
|
||||
void AnnotateDestruct(size_type) {}
|
||||
@@ -460,9 +456,7 @@ class FixedArray {
|
||||
size_type size() const { return size_alloc_.template get<0>(); }
|
||||
StorageElement* begin() const { return data_; }
|
||||
StorageElement* end() const { return begin() + size(); }
|
||||
allocator_type& alloc() {
|
||||
return size_alloc_.template get<1>();
|
||||
}
|
||||
allocator_type& alloc() { return size_alloc_.template get<1>(); }
|
||||
|
||||
private:
|
||||
static bool UsingInlinedStorage(size_type n) {
|
||||
@@ -515,7 +509,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_2019_08_08
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user