master
captainfffsama 2 years ago
parent fa1c832514
commit 61dd9043e1
  1. 41
      abseil-cpp/.github/ISSUE_TEMPLATE/00-bug_report.md
  2. 7
      abseil-cpp/.github/ISSUE_TEMPLATE/90-question.md
  3. 1
      abseil-cpp/.github/ISSUE_TEMPLATE/config.yml
  4. 15
      abseil-cpp/.gitignore
  5. 75
      abseil-cpp/CMake/AbseilDll.cmake
  6. 134
      abseil-cpp/CMake/AbseilHelpers.cmake
  7. 20
      abseil-cpp/CMake/AbseilInstallDirs.cmake
  8. 30
      abseil-cpp/CMake/Googletest/CMakeLists.txt.in
  9. 101
      abseil-cpp/CMake/README.md
  10. 4
      abseil-cpp/CMake/install_test_project/CMakeLists.txt
  11. 9
      abseil-cpp/CMake/install_test_project/simple.cc
  12. 164
      abseil-cpp/CMake/install_test_project/test.sh
  13. 97
      abseil-cpp/CMakeLists.txt
  14. 5
      abseil-cpp/FAQ.md
  15. 16
      abseil-cpp/LTS.md
  16. 42
      abseil-cpp/README.md
  17. 45
      abseil-cpp/WORKSPACE
  18. 83
      abseil-cpp/absl/BUILD.bazel
  19. 2
      abseil-cpp/absl/CMakeLists.txt
  20. 4
      abseil-cpp/absl/abseil.podspec.gen.py
  21. 2
      abseil-cpp/absl/algorithm/BUILD.bazel
  22. 5
      abseil-cpp/absl/algorithm/CMakeLists.txt
  23. 9
      abseil-cpp/absl/algorithm/algorithm_test.cc
  24. 200
      abseil-cpp/absl/algorithm/container.h
  25. 145
      abseil-cpp/absl/base/BUILD.bazel
  26. 176
      abseil-cpp/absl/base/CMakeLists.txt
  27. 190
      abseil-cpp/absl/base/attributes.h
  28. 11
      abseil-cpp/absl/base/call_once.h
  29. 129
      abseil-cpp/absl/base/casts.h
  30. 359
      abseil-cpp/absl/base/config.h
  31. 61
      abseil-cpp/absl/base/dynamic_annotations.h
  32. 3
      abseil-cpp/absl/base/exception_safety_testing_test.cc
  33. 219
      abseil-cpp/absl/base/internal/bits.h
  34. 97
      abseil-cpp/absl/base/internal/bits_test.cc
  35. 54
      abseil-cpp/absl/base/internal/cycleclock.cc
  36. 69
      abseil-cpp/absl/base/internal/cycleclock.h
  37. 11
      abseil-cpp/absl/base/internal/direct_mmap.h
  38. 140
      abseil-cpp/absl/base/internal/endian.h
  39. 26
      abseil-cpp/absl/base/internal/exception_safety_testing.h
  40. 8
      abseil-cpp/absl/base/internal/exponential_biased.cc
  41. 12
      abseil-cpp/absl/base/internal/exponential_biased.h
  42. 10
      abseil-cpp/absl/base/internal/exponential_biased_test.cc
  43. 2
      abseil-cpp/absl/base/internal/fast_type_id.h
  44. 54
      abseil-cpp/absl/base/internal/invoke.h
  45. 30
      abseil-cpp/absl/base/internal/low_level_alloc_test.cc
  46. 5
      abseil-cpp/absl/base/internal/low_level_scheduling.h
  47. 8
      abseil-cpp/absl/base/internal/periodic_sampler.cc
  48. 14
      abseil-cpp/absl/base/internal/periodic_sampler.h
  49. 6
      abseil-cpp/absl/base/internal/periodic_sampler_benchmark.cc
  50. 6
      abseil-cpp/absl/base/internal/periodic_sampler_test.cc
  51. 138
      abseil-cpp/absl/base/internal/prefetch.h
  52. 43
      abseil-cpp/absl/base/internal/prefetch_test.cc
  53. 101
      abseil-cpp/absl/base/internal/raw_logging.cc
  54. 45
      abseil-cpp/absl/base/internal/raw_logging.h
  55. 16
      abseil-cpp/absl/base/internal/spinlock.cc
  56. 31
      abseil-cpp/absl/base/internal/spinlock.h
  57. 4
      abseil-cpp/absl/base/internal/spinlock_akaros.inc
  58. 13
      abseil-cpp/absl/base/internal/spinlock_linux.inc
  59. 4
      abseil-cpp/absl/base/internal/spinlock_posix.inc
  60. 24
      abseil-cpp/absl/base/internal/spinlock_wait.h
  61. 10
      abseil-cpp/absl/base/internal/spinlock_win32.inc
  62. 2
      abseil-cpp/absl/base/internal/strerror.cc
  63. 6
      abseil-cpp/absl/base/internal/strerror_test.cc
  64. 70
      abseil-cpp/absl/base/internal/sysinfo.cc
  65. 12
      abseil-cpp/absl/base/internal/sysinfo_test.cc
  66. 18
      abseil-cpp/absl/base/internal/thread_identity.cc
  67. 110
      abseil-cpp/absl/base/internal/thread_identity.h
  68. 118
      abseil-cpp/absl/base/internal/throw_delegate.cc
  69. 76
      abseil-cpp/absl/base/internal/unaligned_access.h
  70. 33
      abseil-cpp/absl/base/internal/unscaledcycleclock.cc
  71. 21
      abseil-cpp/absl/base/internal/unscaledcycleclock.h
  72. 102
      abseil-cpp/absl/base/invoke_test.cc
  73. 28
      abseil-cpp/absl/base/log_severity.cc
  74. 59
      abseil-cpp/absl/base/log_severity.h
  75. 49
      abseil-cpp/absl/base/log_severity_test.cc
  76. 11
      abseil-cpp/absl/base/macros.h
  77. 47
      abseil-cpp/absl/base/optimization.h
  78. 2
      abseil-cpp/absl/base/options.h
  79. 1
      abseil-cpp/absl/base/port.h
  80. 1
      abseil-cpp/absl/base/spinlock_test_common.cc
  81. 6
      abseil-cpp/absl/base/thread_annotations.h
  82. 65
      abseil-cpp/absl/cleanup/BUILD.bazel
  83. 56
      abseil-cpp/absl/cleanup/CMakeLists.txt
  84. 140
      abseil-cpp/absl/cleanup/cleanup.h
  85. 311
      abseil-cpp/absl/cleanup/cleanup_test.cc
  86. 100
      abseil-cpp/absl/cleanup/internal/cleanup.h
  87. 38
      abseil-cpp/absl/compiler_config_setting.bzl
  88. 146
      abseil-cpp/absl/container/BUILD.bazel
  89. 147
      abseil-cpp/absl/container/CMakeLists.txt
  90. 100
      abseil-cpp/absl/container/btree_benchmark.cc
  91. 160
      abseil-cpp/absl/container/btree_map.h
  92. 178
      abseil-cpp/absl/container/btree_set.h
  93. 832
      abseil-cpp/absl/container/btree_test.cc
  94. 11
      abseil-cpp/absl/container/fixed_array.h
  95. 15
      abseil-cpp/absl/container/flat_hash_map.h
  96. 41
      abseil-cpp/absl/container/flat_hash_map_test.cc
  97. 26
      abseil-cpp/absl/container/flat_hash_set.h
  98. 10
      abseil-cpp/absl/container/flat_hash_set_test.cc
  99. 225
      abseil-cpp/absl/container/inlined_vector.h
  100. 22
      abseil-cpp/absl/container/inlined_vector_benchmark.cc
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,41 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
Include a clear and concise description of what the problem is, including what
you expected to happen, and what actually happened.
**Steps to reproduce the bug**
It's important that we are able to reproduce the problem that you are
experiencing. Please provide all code and relevant steps to reproduce the
problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links
to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the
problem are also helpful.
**What version of Abseil are you using?**
**What operating system and version are you using**
If you are using a Linux distribution please include the name and version of the
distribution as well.
**What compiler and version are you using?**
Please include the output of `gcc -v` or `clang -v`, or the equivalent for your
compiler.
**What build system are you using?**
Please include the output of `bazel --version` or `cmake --version`, or the
equivalent for your build system.
**Additional context**
Add any other context about the problem here.

@ -0,0 +1,7 @@
---
name: Question
about: Have a question? Ask us anything! :-)
title: ''
labels: 'question'
assignees: ''
---

@ -0,0 +1 @@
blank_issues_enables: true

@ -0,0 +1,15 @@
# Ignore all bazel-* symlinks.
/bazel-*
# Ignore Bazel verbose explanations
--verbose_explanations
# Ignore CMake usual build directory
build
# Ignore Vim files
*.swp
# Ignore QtCreator Project file
CMakeLists.txt.user
# Ignore VS Code files
.vscode/*
# Ignore generated python artifacts
*.pyc
copts/__pycache__/

@ -1,5 +1,4 @@
include(CMakeParseArguments) include(CMakeParseArguments)
include(GNUInstallDirs)
set(ABSL_INTERNAL_DLL_FILES set(ABSL_INTERNAL_DLL_FILES
"algorithm/algorithm.h" "algorithm/algorithm.h"
@ -11,12 +10,15 @@ set(ABSL_INTERNAL_DLL_FILES
"base/const_init.h" "base/const_init.h"
"base/dynamic_annotations.h" "base/dynamic_annotations.h"
"base/internal/atomic_hook.h" "base/internal/atomic_hook.h"
"base/internal/bits.h"
"base/internal/cycleclock.cc" "base/internal/cycleclock.cc"
"base/internal/cycleclock.h" "base/internal/cycleclock.h"
"base/internal/direct_mmap.h" "base/internal/direct_mmap.h"
"base/internal/dynamic_annotations.h" "base/internal/dynamic_annotations.h"
"base/internal/endian.h" "base/internal/endian.h"
"base/internal/errno_saver.h" "base/internal/errno_saver.h"
"base/internal/exponential_biased.cc"
"base/internal/exponential_biased.h"
"base/internal/fast_type_id.h" "base/internal/fast_type_id.h"
"base/internal/hide_ptr.h" "base/internal/hide_ptr.h"
"base/internal/identity.h" "base/internal/identity.h"
@ -26,7 +28,8 @@ set(ABSL_INTERNAL_DLL_FILES
"base/internal/low_level_alloc.h" "base/internal/low_level_alloc.h"
"base/internal/low_level_scheduling.h" "base/internal/low_level_scheduling.h"
"base/internal/per_thread_tls.h" "base/internal/per_thread_tls.h"
"base/internal/prefetch.h" "base/internal/periodic_sampler.cc"
"base/internal/periodic_sampler.h"
"base/internal/pretty_function.h" "base/internal/pretty_function.h"
"base/internal/raw_logging.cc" "base/internal/raw_logging.cc"
"base/internal/raw_logging.h" "base/internal/raw_logging.h"
@ -58,8 +61,6 @@ set(ABSL_INTERNAL_DLL_FILES
"base/policy_checks.h" "base/policy_checks.h"
"base/port.h" "base/port.h"
"base/thread_annotations.h" "base/thread_annotations.h"
"cleanup/cleanup.h"
"cleanup/internal/cleanup.h"
"container/btree_map.h" "container/btree_map.h"
"container/btree_set.h" "container/btree_set.h"
"container/fixed_array.h" "container/fixed_array.h"
@ -79,9 +80,10 @@ set(ABSL_INTERNAL_DLL_FILES
"container/internal/hashtablez_sampler.cc" "container/internal/hashtablez_sampler.cc"
"container/internal/hashtablez_sampler.h" "container/internal/hashtablez_sampler.h"
"container/internal/hashtablez_sampler_force_weak_definition.cc" "container/internal/hashtablez_sampler_force_weak_definition.cc"
"container/internal/have_sse.h"
"container/internal/inlined_vector.h" "container/internal/inlined_vector.h"
"container/internal/layout.h" "container/internal/layout.h"
"container/internal/node_slot_policy.h" "container/internal/node_hash_policy.h"
"container/internal/raw_hash_map.h" "container/internal/raw_hash_map.h"
"container/internal/raw_hash_set.cc" "container/internal/raw_hash_set.cc"
"container/internal/raw_hash_set.h" "container/internal/raw_hash_set.h"
@ -91,6 +93,7 @@ set(ABSL_INTERNAL_DLL_FILES
"debugging/failure_signal_handler.cc" "debugging/failure_signal_handler.cc"
"debugging/failure_signal_handler.h" "debugging/failure_signal_handler.h"
"debugging/leak_check.h" "debugging/leak_check.h"
"debugging/leak_check_disable.cc"
"debugging/stacktrace.cc" "debugging/stacktrace.cc"
"debugging/stacktrace.h" "debugging/stacktrace.h"
"debugging/symbolize.cc" "debugging/symbolize.cc"
@ -109,11 +112,9 @@ set(ABSL_INTERNAL_DLL_FILES
"debugging/internal/symbolize.h" "debugging/internal/symbolize.h"
"debugging/internal/vdso_support.cc" "debugging/internal/vdso_support.cc"
"debugging/internal/vdso_support.h" "debugging/internal/vdso_support.h"
"functional/any_invocable.h"
"functional/internal/front_binder.h" "functional/internal/front_binder.h"
"functional/bind_front.h" "functional/bind_front.h"
"functional/function_ref.h" "functional/function_ref.h"
"functional/internal/any_invocable.h"
"functional/internal/function_ref.h" "functional/internal/function_ref.h"
"hash/hash.h" "hash/hash.h"
"hash/internal/city.h" "hash/internal/city.h"
@ -121,20 +122,10 @@ set(ABSL_INTERNAL_DLL_FILES
"hash/internal/hash.h" "hash/internal/hash.h"
"hash/internal/hash.cc" "hash/internal/hash.cc"
"hash/internal/spy_hash_state.h" "hash/internal/spy_hash_state.h"
"hash/internal/low_level_hash.h"
"hash/internal/low_level_hash.cc"
"memory/memory.h" "memory/memory.h"
"meta/type_traits.h" "meta/type_traits.h"
"numeric/bits.h"
"numeric/int128.cc" "numeric/int128.cc"
"numeric/int128.h" "numeric/int128.h"
"numeric/internal/bits.h"
"numeric/internal/representation.h"
"profiling/internal/exponential_biased.cc"
"profiling/internal/exponential_biased.h"
"profiling/internal/periodic_sampler.cc"
"profiling/internal/periodic_sampler.h"
"profiling/internal/sample_recorder.h"
"random/bernoulli_distribution.h" "random/bernoulli_distribution.h"
"random/beta_distribution.h" "random/beta_distribution.h"
"random/bit_gen_ref.h" "random/bit_gen_ref.h"
@ -197,46 +188,14 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/charconv.h" "strings/charconv.h"
"strings/cord.cc" "strings/cord.cc"
"strings/cord.h" "strings/cord.h"
"strings/cord_analysis.cc"
"strings/cord_analysis.h"
"strings/cord_buffer.cc"
"strings/cord_buffer.h"
"strings/escaping.cc" "strings/escaping.cc"
"strings/escaping.h" "strings/escaping.h"
"strings/internal/cord_internal.h"
"strings/internal/charconv_bigint.cc" "strings/internal/charconv_bigint.cc"
"strings/internal/charconv_bigint.h" "strings/internal/charconv_bigint.h"
"strings/internal/charconv_parse.cc" "strings/internal/charconv_parse.cc"
"strings/internal/charconv_parse.h" "strings/internal/charconv_parse.h"
"strings/internal/cord_data_edge.h"
"strings/internal/cord_internal.cc"
"strings/internal/cord_internal.h"
"strings/internal/cord_rep_btree.cc"
"strings/internal/cord_rep_btree.h"
"strings/internal/cord_rep_btree_navigator.cc"
"strings/internal/cord_rep_btree_navigator.h"
"strings/internal/cord_rep_btree_reader.cc"
"strings/internal/cord_rep_btree_reader.h"
"strings/internal/cord_rep_crc.cc"
"strings/internal/cord_rep_crc.h"
"strings/internal/cord_rep_consume.h"
"strings/internal/cord_rep_consume.cc"
"strings/internal/cord_rep_flat.h"
"strings/internal/cord_rep_ring.cc"
"strings/internal/cord_rep_ring.h"
"strings/internal/cord_rep_ring_reader.h"
"strings/internal/cordz_functions.cc"
"strings/internal/cordz_functions.h"
"strings/internal/cordz_handle.cc"
"strings/internal/cordz_handle.h"
"strings/internal/cordz_info.cc"
"strings/internal/cordz_info.h"
"strings/internal/cordz_sample_token.cc"
"strings/internal/cordz_sample_token.h"
"strings/internal/cordz_statistics.h"
"strings/internal/cordz_update_scope.h"
"strings/internal/cordz_update_tracker.h"
"strings/internal/stl_type_traits.h" "strings/internal/stl_type_traits.h"
"strings/internal/string_constant.h"
"strings/match.cc" "strings/match.cc"
"strings/match.h" "strings/match.h"
"strings/numbers.cc" "strings/numbers.cc"
@ -291,7 +250,6 @@ set(ABSL_INTERNAL_DLL_FILES
"synchronization/notification.h" "synchronization/notification.h"
"synchronization/internal/create_thread_identity.cc" "synchronization/internal/create_thread_identity.cc"
"synchronization/internal/create_thread_identity.h" "synchronization/internal/create_thread_identity.h"
"synchronization/internal/futex.h"
"synchronization/internal/graphcycles.cc" "synchronization/internal/graphcycles.cc"
"synchronization/internal/graphcycles.h" "synchronization/internal/graphcycles.h"
"synchronization/internal/kernel_timeout.h" "synchronization/internal/kernel_timeout.h"
@ -349,7 +307,6 @@ set(ABSL_INTERNAL_DLL_FILES
"types/internal/span.h" "types/internal/span.h"
"types/variant.h" "types/variant.h"
"utility/utility.h" "utility/utility.h"
"debugging/leak_check.cc"
) )
set(ABSL_INTERNAL_DLL_TARGETS set(ABSL_INTERNAL_DLL_TARGETS
@ -360,6 +317,7 @@ set(ABSL_INTERNAL_DLL_TARGETS
"debugging_internal" "debugging_internal"
"demangle_internal" "demangle_internal"
"leak_check" "leak_check"
"leak_check_disable"
"stack_consumption" "stack_consumption"
"debugging" "debugging"
"hash" "hash"
@ -390,7 +348,6 @@ set(ABSL_INTERNAL_DLL_TARGETS
"kernel_timeout_internal" "kernel_timeout_internal"
"synchronization" "synchronization"
"thread_pool" "thread_pool"
"any_invocable"
"bind_front" "bind_front"
"function_ref" "function_ref"
"atomic_hook" "atomic_hook"
@ -460,13 +417,13 @@ set(ABSL_INTERNAL_DLL_TARGETS
"hashtablez_sampler" "hashtablez_sampler"
"hashtable_debug" "hashtable_debug"
"hashtable_debug_hooks" "hashtable_debug_hooks"
"node_slot_policy" "have_sse"
"node_hash_policy"
"raw_hash_map" "raw_hash_map"
"container_common" "container_common"
"raw_hash_set" "raw_hash_set"
"layout" "layout"
"tracked" "tracked"
"sample_recorder"
) )
function(absl_internal_dll_contains) function(absl_internal_dll_contains)
@ -530,7 +487,7 @@ function(absl_make_dll)
abseil_dll abseil_dll
PUBLIC PUBLIC
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
) )
target_compile_options( target_compile_options(
@ -548,8 +505,8 @@ function(absl_make_dll)
${ABSL_CC_LIB_DEFINES} ${ABSL_CC_LIB_DEFINES}
) )
install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets install(TARGETS abseil_dll EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
) )
endfunction() endfunction()

@ -17,6 +17,7 @@
include(CMakeParseArguments) include(CMakeParseArguments)
include(AbseilConfigureCopts) include(AbseilConfigureCopts)
include(AbseilDll) include(AbseilDll)
include(AbseilInstallDirs)
# The IDE folder for Abseil that will be used if Abseil is included in a CMake # The IDE folder for Abseil that will be used if Abseil is included in a CMake
# project that sets # project that sets
@ -40,8 +41,7 @@ endif()
# LINKOPTS: List of link options # LINKOPTS: List of link options
# PUBLIC: Add this so that this library will be exported under absl:: # PUBLIC: Add this so that this library will be exported under absl::
# Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal. # Also in IDE, target will appear in Abseil folder while non PUBLIC will be in Abseil/internal.
# TESTONLY: When added, this target will only be built if both # TESTONLY: When added, this target will only be built if user passes -DABSL_RUN_TESTS=ON to CMake.
# BUILD_TESTING=ON and ABSL_BUILD_TESTING=ON.
# #
# Note: # Note:
# By default, absl_cc_library will always create a library named absl_${NAME}, # By default, absl_cc_library will always create a library named absl_${NAME},
@ -83,8 +83,7 @@ function(absl_cc_library)
${ARGN} ${ARGN}
) )
if(NOT ABSL_CC_LIB_PUBLIC AND ABSL_CC_LIB_TESTONLY AND if(ABSL_CC_LIB_TESTONLY AND NOT ABSL_RUN_TESTS)
NOT (BUILD_TESTING AND ABSL_BUILD_TESTING))
return() return()
endif() endif()
@ -105,7 +104,7 @@ function(absl_cc_library)
endif() endif()
endforeach() endforeach()
if(ABSL_CC_SRCS STREQUAL "") if("${ABSL_CC_SRCS}" STREQUAL "")
set(ABSL_CC_LIB_IS_INTERFACE 1) set(ABSL_CC_LIB_IS_INTERFACE 1)
else() else()
set(ABSL_CC_LIB_IS_INTERFACE 0) set(ABSL_CC_LIB_IS_INTERFACE 0)
@ -123,11 +122,7 @@ function(absl_cc_library)
# 4. "static" -- This target does not depend on the DLL and should be built # 4. "static" -- This target does not depend on the DLL and should be built
# statically. # statically.
if (${ABSL_BUILD_DLL}) if (${ABSL_BUILD_DLL})
if(ABSL_ENABLE_INSTALL) absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
absl_internal_dll_contains(TARGET ${_NAME} OUTPUT _in_dll)
else()
absl_internal_dll_contains(TARGET ${ABSL_CC_LIB_NAME} OUTPUT _in_dll)
endif()
if (${_in_dll}) if (${_in_dll})
# This target should be replaced by the DLL # This target should be replaced by the DLL
set(_build_type "dll") set(_build_type "dll")
@ -142,55 +137,8 @@ function(absl_cc_library)
set(_build_type "static") set(_build_type "static")
endif() endif()
# Generate a pkg-config file for every library:
if((_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
AND ABSL_ENABLE_INSTALL)
if(NOT ABSL_CC_LIB_TESTONLY)
if(absl_VERSION)
set(PC_VERSION "${absl_VERSION}")
else()
set(PC_VERSION "head")
endif()
foreach(dep ${ABSL_CC_LIB_DEPS})
if(${dep} MATCHES "^absl::(.*)")
# Join deps with commas.
if(PC_DEPS)
set(PC_DEPS "${PC_DEPS},")
endif()
set(PC_DEPS "${PC_DEPS} absl_${CMAKE_MATCH_1} = ${PC_VERSION}")
endif()
endforeach()
foreach(cflag ${ABSL_CC_LIB_COPTS})
if(${cflag} MATCHES "^(-Wno|/wd)")
# These flags are needed to suppress warnings that might fire in our headers.
set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
elseif(${cflag} MATCHES "^(-W|/w[1234eo])")
# Don't impose our warnings on others.
else()
set(PC_CFLAGS "${PC_CFLAGS} ${cflag}")
endif()
endforeach()
string(REPLACE ";" " " PC_LINKOPTS "${ABSL_CC_LIB_LINKOPTS}")
FILE(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc" CONTENT "\
prefix=${CMAKE_INSTALL_PREFIX}\n\
exec_prefix=\${prefix}\n\
libdir=${CMAKE_INSTALL_FULL_LIBDIR}\n\
includedir=${CMAKE_INSTALL_FULL_INCLUDEDIR}\n\
\n\
Name: absl_${_NAME}\n\
Description: Abseil ${_NAME} library\n\
URL: https://abseil.io/\n\
Version: ${PC_VERSION}\n\
Requires:${PC_DEPS}\n\
Libs: -L\${libdir} ${PC_LINKOPTS} $<$<NOT:$<BOOL:${ABSL_CC_LIB_IS_INTERFACE}>>:-labsl_${_NAME}>\n\
Cflags: -I\${includedir}${PC_CFLAGS}\n")
INSTALL(FILES "${CMAKE_BINARY_DIR}/lib/pkgconfig/absl_${_NAME}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
endif()
endif()
if(NOT ABSL_CC_LIB_IS_INTERFACE) if(NOT ABSL_CC_LIB_IS_INTERFACE)
if(_build_type STREQUAL "dll_dep") if(${_build_type} STREQUAL "dll_dep")
# This target depends on the DLL. When adding dependencies to this target, # This target depends on the DLL. When adding dependencies to this target,
# any depended-on-target which is contained inside the DLL is replaced # any depended-on-target which is contained inside the DLL is replaced
# with a dependency on the DLL. # with a dependency on the DLL.
@ -219,7 +167,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
"${_gtest_link_define}" "${_gtest_link_define}"
) )
elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared") elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared")
add_library(${_NAME} "") add_library(${_NAME} "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
target_link_libraries(${_NAME} target_link_libraries(${_NAME}
@ -242,7 +190,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
target_include_directories(${_NAME} target_include_directories(${_NAME}
PUBLIC PUBLIC
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
) )
target_compile_options(${_NAME} target_compile_options(${_NAME}
PRIVATE ${ABSL_CC_LIB_COPTS}) PRIVATE ${ABSL_CC_LIB_COPTS})
@ -257,23 +205,9 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal) set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}/internal)
endif() endif()
if(ABSL_PROPAGATE_CXX_STD) # INTERFACE libraries can't have the CXX_STANDARD property set
# Abseil libraries require C++11 as the current minimum standard. set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
# Top-level application CMake projects should ensure a consistent C++ set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} PUBLIC cxx_std_11)
else()
# Note: This is legacy (before CMake 3.8) behavior. Setting the
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
# that is the default value anyway.
#
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
# "decaying" to an older standard if the requested one isn't available).
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
endif()
# When being installed, we lose the absl_ prefix. We want to put it back # 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 # to have properly named lib files. This is a no-op when we are not being
@ -281,7 +215,6 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
if(ABSL_ENABLE_INSTALL) if(ABSL_ENABLE_INSTALL)
set_target_properties(${_NAME} PROPERTIES set_target_properties(${_NAME} PROPERTIES
OUTPUT_NAME "absl_${_NAME}" OUTPUT_NAME "absl_${_NAME}"
SOVERSION "2206.0.0"
) )
endif() endif()
else() else()
@ -290,10 +223,10 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
target_include_directories(${_NAME} target_include_directories(${_NAME}
INTERFACE INTERFACE
"$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>" "$<BUILD_INTERFACE:${ABSL_COMMON_INCLUDE_DIRS}>"
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
) )
if (_build_type STREQUAL "dll") if (${_build_type} STREQUAL "dll")
set(ABSL_CC_LIB_DEPS abseil_dll) set(ABSL_CC_LIB_DEPS abseil_dll)
endif() endif()
@ -304,25 +237,15 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
${ABSL_DEFAULT_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS}
) )
target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES}) target_compile_definitions(${_NAME} INTERFACE ${ABSL_CC_LIB_DEFINES})
if(ABSL_PROPAGATE_CXX_STD)
# Abseil libraries require C++11 as the current minimum standard.
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} INTERFACE cxx_std_11)
# (INTERFACE libraries can't have the CXX_STANDARD property set, so there
# is no legacy behavior else case).
endif()
endif() endif()
# TODO currently we don't install googletest alongside abseil sources, so # TODO currently we don't install googletest alongside abseil sources, so
# installed abseil can't be tested. # installed abseil can't be tested.
if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL) if(NOT ABSL_CC_LIB_TESTONLY AND ABSL_ENABLE_INSTALL)
install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${ABSL_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${ABSL_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${ABSL_INSTALL_LIBDIR}
) )
endif() endif()
@ -363,11 +286,11 @@ endfunction()
# "awesome_test.cc" # "awesome_test.cc"
# DEPS # DEPS
# absl::awesome # absl::awesome
# GTest::gmock # gmock
# GTest::gtest_main # gtest_main
# ) # )
function(absl_cc_test) function(absl_cc_test)
if(NOT (BUILD_TESTING AND ABSL_BUILD_TESTING)) if(NOT ABSL_RUN_TESTS)
return() return()
endif() endif()
@ -417,23 +340,8 @@ function(absl_cc_test)
# Add all Abseil targets to 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 FOLDER ${ABSL_IDE_FOLDER}/test)
if(ABSL_PROPAGATE_CXX_STD) set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
# Abseil libraries require C++11 as the current minimum standard. set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
# Top-level application CMake projects should ensure a consistent C++
# standard for all compiled sources by setting CMAKE_CXX_STANDARD.
target_compile_features(${_NAME} PUBLIC cxx_std_11)
else()
# Note: This is legacy (before CMake 3.8) behavior. Setting the
# target-level CXX_STANDARD property to ABSL_CXX_STANDARD (which is
# initialized by CMAKE_CXX_STANDARD) should have no real effect, since
# that is the default value anyway.
#
# CXX_STANDARD_REQUIRED does guard against the top-level CMake project
# not having enabled CMAKE_CXX_STANDARD_REQUIRED (which prevents
# "decaying" to an older standard if the requested one isn't available).
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD ${ABSL_CXX_STANDARD})
set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
endif()
add_test(NAME ${_NAME} COMMAND ${_NAME}) add_test(NAME ${_NAME} COMMAND ${_NAME})
endfunction() endfunction()

@ -0,0 +1,20 @@
include(GNUInstallDirs)
# absl_VERSION is only set if we are an LTS release being installed, in which
# case it may be into a system directory and so we need to make subdirectories
# for each installed version of Abseil. This mechanism is implemented in
# Abseil's internal Copybara (https://github.com/google/copybara) workflows and
# isn't visible in the CMake buildsystem itself.
if(absl_VERSION)
set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
else()
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
endif()

@ -3,12 +3,24 @@ cmake_minimum_required(VERSION 2.8.2)
project(googletest-external NONE) project(googletest-external NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(googletest if(${ABSL_USE_GOOGLETEST_HEAD})
URL "${absl_gtest_download_url}" # May be empty ExternalProject_Add(googletest
SOURCE_DIR "${absl_gtest_src_dir}" GIT_REPOSITORY https://github.com/google/googletest.git
BINARY_DIR "${absl_gtest_build_dir}" GIT_TAG master
CONFIGURE_COMMAND "" SOURCE_DIR "${absl_gtest_src_dir}"
BUILD_COMMAND "" BINARY_DIR "${absl_gtest_build_dir}"
INSTALL_COMMAND "" CONFIGURE_COMMAND ""
TEST_COMMAND "" BUILD_COMMAND ""
) INSTALL_COMMAND ""
TEST_COMMAND ""
)
else()
ExternalProject_Add(googletest
SOURCE_DIR "${absl_gtest_src_dir}"
BINARY_DIR "${absl_gtest_build_dir}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
endif()

@ -20,10 +20,8 @@ googletest framework
### Step-by-Step Instructions ### Step-by-Step Instructions
1. If you want to build the Abseil tests, integrate the Abseil dependency 1. If you want to build the Abseil tests, integrate the Abseil dependency
[Google Test](https://github.com/google/googletest) into your CMake [Google Test](https://github.com/google/googletest) into your CMake project. To disable Abseil tests, you have to pass
project. To disable Abseil tests, you have to pass either `-DBUILD_TESTING=OFF` when configuring your project with CMake.
`-DBUILD_TESTING=OFF` or `-DABSL_BUILD_TESTING=OFF` when configuring your
project with CMake.
2. Download Abseil and copy it into a subdirectory in your CMake project or add 2. Download Abseil and copy it into a subdirectory in your CMake project or add
Abseil as a [git submodule](https://git-scm.com/docs/git-submodule) in your Abseil as a [git submodule](https://git-scm.com/docs/git-submodule) in your
@ -36,16 +34,15 @@ to include Abseil directly in your CMake project.
4. Add the **absl::** target you wish to use to the 4. Add the **absl::** target you wish to use to the
[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) [`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)
section of your executable or of your library.<br> section of your executable or of your library.<br>
Here is a short CMakeLists.txt example of an application project using Abseil. Here is a short CMakeLists.txt example of a project file using Abseil.
```cmake ```cmake
cmake_minimum_required(VERSION 3.8.2) cmake_minimum_required(VERSION 3.5)
project(my_app_project) project(my_project)
# Pick the C++ standard to compile with. # Pick the C++ standard to compile with.
# Abseil currently supports C++11, C++14, and C++17. # Abseil currently supports C++11, C++14, and C++17.
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(abseil-cpp) add_subdirectory(abseil-cpp)
@ -53,48 +50,9 @@ add_executable(my_exe source.cpp)
target_link_libraries(my_exe absl::base absl::synchronization absl::strings) target_link_libraries(my_exe absl::base absl::synchronization absl::strings)
``` ```
Note that if you are developing a library designed for use by other clients, you
should instead leave `CMAKE_CXX_STANDARD` unset (or only set if being built as
the current top-level CMake project) and configure the minimum required C++
standard at the target level. If you require a later minimum C++ standard than
Abseil does, it's a good idea to also enforce that `CMAKE_CXX_STANDARD` (which
will control Abseil library targets) is set to at least that minimum. For
example:
```cmake
cmake_minimum_required(VERSION 3.8.2)
project(my_lib_project)
# Leave C++ standard up to the root application, so set it only if this is the
# current top-level CMake project.
if(CMAKE_SOURCE_DIR STREQUAL my_lib_project_SOURCE_DIR)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
add_subdirectory(abseil-cpp)
add_library(my_lib source.cpp)
target_link_libraries(my_lib absl::base absl::synchronization absl::strings)
# Enforce that my_lib requires C++17. Important to document for clients that they
# must set CMAKE_CXX_STANDARD to 17 or higher for proper Abseil ABI compatibility
# (since otherwise, Abseil library targets could be compiled with a lower C++
# standard than my_lib).
target_compile_features(my_lib PUBLIC cxx_std_17)
if(CMAKE_CXX_STANDARD LESS 17)
message(FATAL_ERROR
"my_lib_project requires CMAKE_CXX_STANDARD >= 17 (got: ${CMAKE_CXX_STANDARD})")
endif()
```
Then the top-level application project that uses your library is responsible for
setting a consistent `CMAKE_CXX_STANDARD` that is sufficiently high.
### Running Abseil Tests with CMake ### Running Abseil Tests with CMake
Use the `-DABSL_BUILD_TESTING=ON` flag to run Abseil tests. Note that Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run.
BUILD_TESTING must also be on (the default).
You will need to provide Abseil with a Googletest dependency. There are two You will need to provide Abseil with a Googletest dependency. There are two
options for how to do this: options for how to do this:
@ -112,7 +70,7 @@ For example, to run just the Abseil tests, you could use this script:
cd path/to/abseil-cpp cd path/to/abseil-cpp
mkdir build mkdir build
cd build cd build
cmake -DABSL_BUILD_TESTING=ON -DABSL_USE_GOOGLETEST_HEAD=ON .. cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
make -j make -j
ctest ctest
``` ```
@ -141,48 +99,3 @@ absl::synchronization
absl::time absl::time
absl::utility absl::utility
``` ```
## Traditional CMake Set-Up
For larger projects, it may make sense to use the traditional CMake set-up where you build and install projects separately.
First, you'd need to build and install Google Test:
```
cmake -S /source/googletest -B /build/googletest -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/installation/dir -DBUILD_GMOCK=ON
cmake --build /build/googletest --target install
```
Then you need to configure and build Abseil. Make sure you enable `ABSL_USE_EXTERNAL_GOOGLETEST` and `ABSL_FIND_GOOGLETEST`. You also need to enable `ABSL_ENABLE_INSTALL` so that you can install Abseil itself.
```
cmake -S /source/abseil-cpp -B /build/abseil-cpp -DCMAKE_PREFIX_PATH=/installation/dir -DCMAKE_INSTALL_PREFIX=/installation/dir -DABSL_ENABLE_INSTALL=ON -DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON
cmake --build /temporary/build/abseil-cpp
```
(`CMAKE_PREFIX_PATH` is where you already have Google Test installed; `CMAKE_INSTALL_PREFIX` is where you want to have Abseil installed; they can be different.)
Run the tests:
```
ctest --test-dir /temporary/build/abseil-cpp
```
And finally install:
```
cmake --build /temporary/build/abseil-cpp --target install
```
# CMake Option Synposis
## Enable Standard CMake Installation
`-DABSL_ENABLE_INSTALL=ON`
## Google Test Options
`-DABSL_BUILD_TESTING=ON` must be set to enable testing
- Have Abseil download and build Google Test for you: `-DABSL_USE_EXTERNAL_GOOGLETEST=OFF` (default)
- Download and build latest Google Test: `-DABSL_USE_GOOGLETEST_HEAD=ON`
- Download specific Google Test version (ZIP archive): `-DABSL_GOOGLETEST_DOWNLOAD_URL=https://.../version.zip`
- Use Google Test from specific local directory: `-DABSL_LOCAL_GOOGLETEST_DIR=/path/to/googletest`
- Use Google Test included elsewhere in your project: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON`
- Use standard CMake `find_package(CTest)` to find installed Google Test: `-DABSL_USE_EXTERNAL_GOOGLETEST=ON -DABSL_FIND_GOOGLETEST=ON`

@ -18,8 +18,10 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project(absl_cmake_testing CXX) project(absl_cmake_testing CXX)
set(CMAKE_CXX_STANDARD 11)
add_executable(simple simple.cc) add_executable(simple simple.cc)
find_package(absl REQUIRED) find_package(absl REQUIRED)
target_link_libraries(simple absl::strings absl::config) target_link_libraries(simple absl::strings)

@ -14,17 +14,8 @@
// limitations under the License. // limitations under the License.
#include <iostream> #include <iostream>
#include "absl/base/config.h"
#include "absl/strings/substitute.h" #include "absl/strings/substitute.h"
#if !defined(ABSL_LTS_RELEASE_VERSION) || ABSL_LTS_RELEASE_VERSION != 99998877
#error ABSL_LTS_RELEASE_VERSION is not set correctly.
#endif
#if !defined(ABSL_LTS_RELEASE_PATCH_LEVEL) || ABSL_LTS_RELEASE_PATCH_LEVEL != 0
#error ABSL_LTS_RELEASE_PATCH_LEVEL is not set correctly.
#endif
int main(int argc, char** argv) { int main(int argc, char** argv) {
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]); std::cout << absl::Substitute("Arg $0: $1\n", i, argv[i]);

@ -13,60 +13,70 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
# Unit and integration tests for Abseil LTS CMake installation # "Unit" and integration tests for Absl CMake installation
# TODO(absl-team): This script isn't fully hermetic because
# -DABSL_USE_GOOGLETEST_HEAD=ON means that this script isn't pinned to a fixed
# version of GoogleTest. This means that an upstream change to GoogleTest could
# break this test. Fix this by allowing this script to pin to a known-good
# version of GoogleTest.
# Fail on any error. Treat unset variables an error. Print commands as executed. # Fail on any error. Treat unset variables an error. Print commands as executed.
set -euox pipefail set -euox pipefail
install_absl() {
pushd "${absl_build_dir}"
if [[ "${#}" -eq 1 ]]; then
cmake -DCMAKE_INSTALL_PREFIX="${1}" "${absl_dir}"
else
cmake "${absl_dir}"
fi
cmake --build . --target install -- -j
popd
}
uninstall_absl() {
xargs rm < "${absl_build_dir}"/install_manifest.txt
rm -rf "${absl_build_dir}"
mkdir -p "${absl_build_dir}"
}
lts_install=""
while getopts ":l" lts; do
case "${lts}" in
l )
lts_install="true"
;;
esac
done
absl_dir=/abseil-cpp absl_dir=/abseil-cpp
absl_build_dir=/buildfs absl_build_dir=/buildfs/absl-build
googletest_builddir=/googletest_builddir
project_dir="${absl_dir}"/CMake/install_test_project project_dir="${absl_dir}"/CMake/install_test_project
project_build_dir=/buildfs/project-build project_build_dir=/buildfs/project-build
build_shared_libs="OFF" mkdir -p "${absl_build_dir}"
if [ "${LINK_TYPE:-}" = "DYNAMIC" ]; then mkdir -p "${project_build_dir}"
build_shared_libs="ON"
fi
# Build and install GoogleTest
mkdir "${googletest_builddir}"
pushd "${googletest_builddir}"
curl -L "${ABSL_GOOGLETEST_DOWNLOAD_URL}" --output "${ABSL_GOOGLETEST_COMMIT}".zip
unzip "${ABSL_GOOGLETEST_COMMIT}".zip
pushd "googletest-${ABSL_GOOGLETEST_COMMIT}"
mkdir build
pushd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS="${build_shared_libs}" ..
make -j $(nproc)
make install
ldconfig
popd
popd
popd
# Run the LTS transformations if [[ "${lts_install}" ]]; then
./create_lts.py 99998877 install_dir="/usr/local"
else
# Build and install Abseil install_dir="${project_build_dir}"/install
pushd "${absl_build_dir}" fi
cmake "${absl_dir}" \ mkdir -p "${install_dir}"
-DABSL_USE_EXTERNAL_GOOGLETEST=ON \
-DABSL_FIND_GOOGLETEST=ON \
-DCMAKE_BUILD_TYPE=Release \
-DABSL_BUILD_TESTING=ON \
-DBUILD_SHARED_LIBS="${build_shared_libs}"
make -j $(nproc)
ctest -j $(nproc) --output-on-failure
make install
ldconfig
popd
# Test the project against the installed Abseil # Test build, install, and link against installed abseil
mkdir -p "${project_build_dir}"
pushd "${project_build_dir}" pushd "${project_build_dir}"
cmake "${project_dir}" if [[ "${lts_install}" ]]; then
install_absl
cmake "${project_dir}"
else
install_absl "${install_dir}"
cmake "${project_dir}" -DCMAKE_PREFIX_PATH="${install_dir}"
fi
cmake --build . --target simple cmake --build . --target simple
output="$(${project_build_dir}/simple "printme" 2>&1)" output="$(${project_build_dir}/simple "printme" 2>&1)"
@ -78,35 +88,57 @@ fi
popd popd
if ! grep absl::strings "/usr/local/lib/cmake/absl/abslTargets.cmake"; then # Test that we haven't accidentally made absl::abslblah
cat "/usr/local/lib/cmake/absl/abslTargets.cmake" pushd "${install_dir}"
echo "CMake targets named incorrectly"
exit 1
fi
pushd "${HOME}"
cat > hello-abseil.cc << EOF
#include <cstdlib>
#include "absl/strings/str_format.h"
int main(int argc, char **argv) { # Starting in CMake 3.12 the default install dir is lib$bit_width
absl::PrintF("Hello Abseil!\n"); if [[ -d lib64 ]]; then
return EXIT_SUCCESS; libdir="lib64"
} elif [[ -d lib ]]; then
EOF libdir="lib"
else
echo "ls *, */*, */*/*:"
ls *
ls */*
ls */*/*
echo "unknown lib dir"
fi
if [ "${LINK_TYPE:-}" != "DYNAMIC" ]; then if [[ "${lts_install}" ]]; then
pc_args=($(pkg-config --cflags --libs --static absl_str_format)) # LTS versions append the date of the release to the subdir.
g++ -static -o hello-abseil hello-abseil.cc "${pc_args[@]}" # 9999/99/99 is the dummy date used in the local_lts workflow.
absl_subdir="absl_99999999"
else else
pc_args=($(pkg-config --cflags --libs absl_str_format)) absl_subdir="absl"
g++ -o hello-abseil hello-abseil.cc "${pc_args[@]}"
fi fi
hello="$(./hello-abseil)"
[[ "${hello}" == "Hello Abseil!" ]]
if ! grep absl::strings "${libdir}/cmake/${absl_subdir}/abslTargets.cmake"; then
cat "${libdir}"/cmake/absl/abslTargets.cmake
echo "CMake targets named incorrectly"
exit 1
fi
uninstall_absl
popd popd
if [[ ! "${lts_install}" ]]; then
# Test that we warn if installed without a prefix or a system prefix
output="$(install_absl 2>&1)"
if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
echo "Install without prefix didn't warn as expected. Output:"
echo "${output}"
exit 1
fi
uninstall_absl
output="$(install_absl /usr 2>&1)"
if [[ "${output}" != *"Please set CMAKE_INSTALL_PREFIX"* ]]; then
echo "Install with /usr didn't warn as expected. Output:"
echo "${output}"
exit 1
fi
uninstall_absl
fi
echo "Install test complete!" echo "Install test complete!"
exit 0 exit 0

@ -41,13 +41,7 @@ if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW) cmake_policy(SET CMP0077 NEW)
endif (POLICY CMP0077) endif (POLICY CMP0077)
# Allow the user to specify the MSVC runtime project(absl CXX)
if (POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif (POLICY CMP0091)
project(absl LANGUAGES CXX VERSION 20220623)
include(CTest)
# Output directory is correct by default for most build setups. However, when # 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 # building Abseil as a DLL, it is important to have the DLL in the same
@ -57,26 +51,19 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # 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. # in the source tree of a project that uses it, install rules are disabled.
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
option(ABSL_ENABLE_INSTALL "Enable install rule" OFF) option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
else() else()
option(ABSL_ENABLE_INSTALL "Enable install rule" ON) option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
endif() endif()
option(ABSL_PROPAGATE_CXX_STD
"Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil"
OFF) # TODO: Default to ON for CMake 3.8 and greater.
if((${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.8) AND (NOT ABSL_PROPAGATE_CXX_STD))
message(WARNING "A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON for CMake 3.8 and up. We recommend enabling this option to ensure your project still builds correctly.")
endif()
list(APPEND CMAKE_MODULE_PATH list(APPEND CMAKE_MODULE_PATH
${CMAKE_CURRENT_LIST_DIR}/CMake ${CMAKE_CURRENT_LIST_DIR}/CMake
${CMAKE_CURRENT_LIST_DIR}/absl/copts ${CMAKE_CURRENT_LIST_DIR}/absl/copts
) )
include(AbseilInstallDirs)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
include(AbseilDll) include(AbseilDll)
include(AbseilHelpers) include(AbseilHelpers)
@ -105,57 +92,28 @@ endif()
## pthread ## pthread
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
include(CMakeDependentOption)
option(ABSL_BUILD_TESTING
"If ON, Abseil will build all of Abseil's own tests." OFF)
option(ABSL_USE_EXTERNAL_GOOGLETEST option(ABSL_USE_EXTERNAL_GOOGLETEST
"If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subdirectory." OFF) "If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
cmake_dependent_option(ABSL_FIND_GOOGLETEST
"If ON, Abseil will use find_package(GTest) rather than assuming that GoogleTest is already provided by the including project."
ON
"ABSL_USE_EXTERNAL_GOOGLETEST"
OFF)
option(ABSL_USE_GOOGLETEST_HEAD option(ABSL_USE_GOOGLETEST_HEAD
"If ON, abseil will download HEAD from GoogleTest at config time." OFF) "If ON, abseil will download HEAD from googletest at config time." OFF)
set(ABSL_GOOGLETEST_DOWNLOAD_URL "" CACHE STRING "If set, download GoogleTest from this URL")
set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
"If ABSL_USE_GOOGLETEST_HEAD is OFF and ABSL_GOOGLETEST_URL is not set, specifies the directory of a local GoogleTest checkout." "If ABSL_USE_GOOGLETEST_HEAD is OFF, specifies the directory of a local googletest checkout."
) )
if(BUILD_TESTING AND ABSL_BUILD_TESTING) option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
if(${ABSL_RUN_TESTS})
# enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
# on the command line
include(CTest)
## check targets ## check targets
if (ABSL_USE_EXTERNAL_GOOGLETEST) if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
if (ABSL_FIND_GOOGLETEST)
find_package(GTest REQUIRED)
elseif(NOT TARGET GTest::gtest)
if(TARGET gtest)
# When Google Test is included directly rather than through find_package, the aliases are missing.
add_library(GTest::gtest ALIAS gtest)
add_library(GTest::gtest_main ALIAS gtest_main)
add_library(GTest::gmock ALIAS gmock)
add_library(GTest::gmock_main ALIAS gmock_main)
else()
message(FATAL_ERROR "ABSL_USE_EXTERNAL_GOOGLETEST is ON and ABSL_FIND_GOOGLETEST is OFF, which means that the top-level project must build the Google Test project. However, the target gtest was not found.")
endif()
endif()
else()
set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
if(ABSL_USE_GOOGLETEST_HEAD AND ABSL_GOOGLETEST_DOWNLOAD_URL) if(${ABSL_USE_GOOGLETEST_HEAD})
message(FATAL_ERROR "Do not set both ABSL_USE_GOOGLETEST_HEAD and ABSL_GOOGLETEST_DOWNLOAD_URL")
endif()
if(ABSL_USE_GOOGLETEST_HEAD)
set(absl_gtest_download_url "https://github.com/google/googletest/archive/main.zip")
elseif(ABSL_GOOGLETEST_DOWNLOAD_URL)
set(absl_gtest_download_url ${ABSL_GOOGLETEST_DOWNLOAD_URL})
endif()
if(absl_gtest_download_url)
set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src) set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
else() else()
set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR}) set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
@ -163,30 +121,35 @@ if(BUILD_TESTING AND ABSL_BUILD_TESTING)
include(CMake/Googletest/DownloadGTest.cmake) include(CMake/Googletest/DownloadGTest.cmake)
endif() endif()
check_target(GTest::gtest) check_target(gtest)
check_target(GTest::gtest_main) check_target(gtest_main)
check_target(GTest::gmock) check_target(gmock)
check_target(GTest::gmock_main)
list(APPEND ABSL_TEST_COMMON_LIBRARIES
gtest_main
gtest
gmock
${CMAKE_THREAD_LIBS_INIT}
)
endif() endif()
add_subdirectory(absl) add_subdirectory(absl)
if(ABSL_ENABLE_INSTALL) if(ABSL_ENABLE_INSTALL)
# install as a subdirectory only # install as a subdirectory only
install(EXPORT ${PROJECT_NAME}Targets install(EXPORT ${PROJECT_NAME}Targets
NAMESPACE absl:: NAMESPACE absl::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
) )
configure_package_config_file( configure_package_config_file(
CMake/abslConfig.cmake.in CMake/abslConfig.cmake.in
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" INSTALL_DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
) )
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" DESTINATION "${ABSL_INSTALL_CONFIGDIR}"
) )
# Abseil only has a version in LTS releases. This mechanism is accomplished # Abseil only has a version in LTS releases. This mechanism is accomplished
@ -199,12 +162,12 @@ if(ABSL_ENABLE_INSTALL)
) )
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" DESTINATION ${ABSL_INSTALL_CONFIGDIR}
) )
endif() # absl_VERSION endif() # absl_VERSION
install(DIRECTORY absl install(DIRECTORY absl
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} DESTINATION ${ABSL_INSTALL_INCLUDEDIR}
FILES_MATCHING FILES_MATCHING
PATTERN "*.inc" PATTERN "*.inc"
PATTERN "*.h" PATTERN "*.h"

@ -27,10 +27,7 @@ compiler, there several ways to do this:
file](https://docs.bazel.build/versions/master/guide.html#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 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. If you `set(CMAKE_CXX_STANDARD 17)` to your top level `CMakeLists.txt` file. See the
are developing a library designed to be used by other clients, you should
instead leave `CMAKE_CXX_STANDARD` unset and configure the minimum C++ standard
required by each of your library targets via `target_compile_features`. See the
[CMake build [CMake build
instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md) instructions](https://github.com/abseil/abseil-cpp/blob/master/CMake/README.md)
for more information. for more information.

@ -0,0 +1,16 @@
# Long Term Support (LTS) Branches
This repository contains periodic snapshots of the Abseil codebase that are
Long Term Support (LTS) branches. An LTS branch allows you to use a known
version of Abseil without interfering with other projects which may also, in
turn, use Abseil. (For more information about our releases, see the
[Abseil Release Management](https://abseil.io/about/releases) guide.)
## LTS Branches
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/)
* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/)

@ -9,9 +9,7 @@ standard library.
- [About Abseil](#about) - [About Abseil](#about)
- [Quickstart](#quickstart) - [Quickstart](#quickstart)
- [Building Abseil](#build) - [Building Abseil](#build)
- [Support](#support)
- [Codemap](#codemap) - [Codemap](#codemap)
- [Releases](#releases)
- [License](#license) - [License](#license)
- [Links](#links) - [Links](#links)
@ -44,22 +42,14 @@ the Abseil code, running tests, and getting a simple binary working.
<a name="build"></a> <a name="build"></a>
## Building Abseil ## Building Abseil
[Bazel](https://bazel.build) and [CMake](https://cmake.org/) are the official [Bazel](https://bazel.build) is the official build system for Abseil,
build systems for Abseil. which is supported on most major platforms (Linux, Windows, macOS, for example)
and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for
more information on building Abseil using the Bazel build system.
See the [quickstart](https://abseil.io/docs/cpp/quickstart) for more information <a name="cmake"></a>
on building Abseil using the Bazel build system. If you require CMake support, please check the
[CMake build instructions](CMake/README.md).
If you require CMake support, please check the [CMake build
instructions](CMake/README.md) and [CMake
Quickstart](https://abseil.io/docs/cpp/quickstart-cmake).
## Support
Abseil is officially supported on many platforms. See the [Abseil
platform support
guide](https://abseil.io/docs/cpp/platforms/platforms) for details on
supported operating systems, compilers, CPUs, etc.
## Codemap ## Codemap
@ -72,9 +62,6 @@ Abseil contains the following C++ library components:
* [`algorithm`](absl/algorithm/) * [`algorithm`](absl/algorithm/)
<br /> The `algorithm` library contains additions to the C++ `<algorithm>` <br /> The `algorithm` library contains additions to the C++ `<algorithm>`
library and container-based versions of such algorithms. library and container-based versions of such algorithms.
* [`cleanup`](absl/cleanup/)
<br /> The `cleanup` library contains the control-flow-construct-like type
`absl::Cleanup` which is used for executing a callback on scope exit.
* [`container`](absl/container/) * [`container`](absl/container/)
<br /> The `container` library contains additional STL-style containers, <br /> The `container` library contains additional STL-style containers,
including Abseil's unordered "Swiss table" containers. including Abseil's unordered "Swiss table" containers.
@ -92,12 +79,6 @@ Abseil contains the following C++ library components:
available within C++14 and C++17 versions of the C++ `<type_traits>` library. available within C++14 and C++17 versions of the C++ `<type_traits>` library.
* [`numeric`](absl/numeric/) * [`numeric`](absl/numeric/)
<br /> The `numeric` library contains C++11-compatible 128-bit integers. <br /> The `numeric` library contains C++11-compatible 128-bit integers.
* [`profiling`](absl/profiling/)
<br /> The `profiling` library contains utility code for profiling C++
entities. It is currently a private dependency of other Abseil libraries.
* [`status`](absl/status/)
<br /> The `status` contains abstractions for error handling, specifically
`absl::Status` and `absl::StatusOr<T>`.
* [`strings`](absl/strings/) * [`strings`](absl/strings/)
<br /> The `strings` library contains a variety of strings routines and <br /> The `strings` library contains a variety of strings routines and
utilities, including a C++11-compatible version of the C++17 utilities, including a C++11-compatible version of the C++17
@ -116,15 +97,6 @@ Abseil contains the following C++ library components:
* [`utility`](absl/utility/) * [`utility`](absl/utility/)
<br /> The `utility` library contains utility and helper code. <br /> The `utility` library contains utility and helper code.
## Releases
Abseil recommends users "live-at-head" (update to the latest commit from the
master branch as often as possible). However, we realize this philosophy doesn't
work for every project, so we also provide [Long Term Support
Releases](https://github.com/abseil/abseil-cpp/releases) to which we backport
fixes for severe bugs. See our [release
management](https://abseil.io/about/releases) document for more details.
## License ## License
The Abseil C++ library is licensed under the terms of the Apache The Abseil C++ library is licensed under the terms of the Apache

@ -15,47 +15,30 @@
# #
workspace(name = "com_google_absl") workspace(name = "com_google_absl")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# GoogleTest/GoogleMock framework. Used by most unit-tests. # GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive( http_archive(
name = "com_google_googletest", name = "com_google_googletest",
sha256 = "ce7366fe57eb49928311189cb0e40e0a8bf3d3682fca89af30d884c25e983786", urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"], # 2020-06-12T22:24:28Z
strip_prefix = "googletest-release-1.12.0", strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
# Keep this URL in sync with ABSL_GOOGLETEST_COMMIT in ci/cmake_common.sh. sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
urls = ["https://github.com/google/googletest/archive/refs/tags/release-1.12.0.zip"],
)
# RE2 (the regular expression library used by GoogleTest)
# Note this must use a commit from the `abseil` branch of the RE2 project.
# https://github.com/google/re2/tree/abseil
http_archive(
name = "com_googlesource_code_re2",
sha256 = "0a890c2aa0bb05b2ce906a15efb520d0f5ad4c7d37b8db959c43772802991887",
strip_prefix = "re2-a427f10b9fb4622dd6d8643032600aa1b50fbd12",
urls = ["https://github.com/google/re2/archive/a427f10b9fb4622dd6d8643032600aa1b50fbd12.zip"], # 2022-06-09
) )
# Google benchmark. # Google benchmark.
http_archive( http_archive(
name = "com_github_google_benchmark", # 2021-09-20T09:19:51Z name = "com_github_google_benchmark",
sha256 = "62e2f2e6d8a744d67e4bbc212fcfd06647080de4253c97ad5c6749e09faf2cb0", urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"],
strip_prefix = "benchmark-0baacde3618ca617da95375e0af13ce1baadea47", strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be",
urls = ["https://github.com/google/benchmark/archive/0baacde3618ca617da95375e0af13ce1baadea47.zip"], sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3",
)
# Bazel Skylib.
http_archive(
name = "bazel_skylib",
urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz"],
sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728",
) )
# Bazel platform rules. # C++ rules for Bazel.
http_archive( http_archive(
name = "platforms", name = "rules_cc",
sha256 = "a879ea428c6d56ab0ec18224f976515948822451473a80d06c2e50af0bbe5121", sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
strip_prefix = "platforms-da5541f26b7de1dc8e04c075c99df5351742a4a2", strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
urls = ["https://github.com/bazelbuild/platforms/archive/da5541f26b7de1dc8e04c075c99df5351742a4a2.zip"], # 2022-05-27 urls = [
"https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
],
) )

@ -12,106 +12,57 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
#
load("@bazel_skylib//lib:selects.bzl", "selects") load(
":compiler_config_setting.bzl",
"create_llvm_config",
)
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) licenses(["notice"])
config_setting( create_llvm_config(
name = "clang_compiler", name = "llvm_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "clang",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "msvc_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "msvc-cl",
},
visibility = [":__subpackages__"],
)
config_setting(
name = "clang-cl_compiler",
flag_values = {
"@bazel_tools//tools/cpp:compiler": "clang-cl",
},
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
config_setting( config_setting(
name = "osx", name = "osx",
constraint_values = [ constraint_values = [
"@platforms//os:osx", "@bazel_tools//platforms:osx",
], ],
) )
config_setting( config_setting(
name = "ios", name = "ios",
constraint_values = [ constraint_values = [
"@platforms//os:ios", "@bazel_tools//platforms:ios",
], ],
) )
config_setting( config_setting(
name = "ppc", name = "windows",
values = { constraint_values = [
"cpu": "ppc", "@bazel_tools//platforms:x86_64",
}, "@bazel_tools//platforms:windows",
visibility = [":__subpackages__"], ],
)
config_setting(
name = "cpu_wasm",
values = {
"cpu": "wasm",
},
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
config_setting( config_setting(
name = "cpu_wasm32", name = "ppc",
values = { values = {
"cpu": "wasm32", "cpu": "ppc",
}, },
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
config_setting( config_setting(
name = "platforms_wasm32",
constraint_values = [
"@platforms//cpu:wasm32",
],
visibility = [":__subpackages__"],
)
config_setting(
name = "platforms_wasm64",
constraint_values = [
"@platforms//cpu:wasm64",
],
visibility = [":__subpackages__"],
)
selects.config_setting_group(
name = "wasm", name = "wasm",
match_any = [
":cpu_wasm",
":cpu_wasm32",
":platforms_wasm32",
":platforms_wasm64",
],
visibility = [":__subpackages__"],
)
config_setting(
name = "fuchsia",
values = { values = {
"cpu": "fuchsia", "cpu": "wasm32",
}, },
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )

@ -16,7 +16,6 @@
add_subdirectory(base) add_subdirectory(base)
add_subdirectory(algorithm) add_subdirectory(algorithm)
add_subdirectory(cleanup)
add_subdirectory(container) add_subdirectory(container)
add_subdirectory(debugging) add_subdirectory(debugging)
add_subdirectory(flags) add_subdirectory(flags)
@ -25,7 +24,6 @@ add_subdirectory(hash)
add_subdirectory(memory) add_subdirectory(memory)
add_subdirectory(meta) add_subdirectory(meta)
add_subdirectory(numeric) add_subdirectory(numeric)
add_subdirectory(profiling)
add_subdirectory(random) add_subdirectory(random)
add_subdirectory(status) add_subdirectory(status)
add_subdirectory(strings) add_subdirectory(strings)

@ -40,8 +40,8 @@ Pod::Spec.new do |s|
'USE_HEADERMAP' => 'NO', 'USE_HEADERMAP' => 'NO',
'ALWAYS_SEARCH_USER_PATHS' => 'NO', 'ALWAYS_SEARCH_USER_PATHS' => 'NO',
} }
s.ios.deployment_target = '9.0' s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.10' s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '9.0' s.tvos.deployment_target = '9.0'
s.watchos.deployment_target = '2.0' s.watchos.deployment_target = '2.0'
""" """

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
# #
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load( load(
"//absl:copts/configure_copts.bzl", "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
@ -43,7 +44,6 @@ cc_test(
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":algorithm", ":algorithm",
"//absl/base:config",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )

@ -35,8 +35,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::algorithm absl::algorithm
absl::config gmock_main
GTest::gmock_main
) )
absl_cc_library( absl_cc_library(
@ -66,5 +65,5 @@ absl_cc_test(
absl::core_headers absl::core_headers
absl::memory absl::memory
absl::span absl::span
GTest::gmock_main gmock_main
) )

@ -20,7 +20,6 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/config.h"
namespace { namespace {
@ -51,15 +50,7 @@ TEST(EqualTest, EmptyRange) {
std::vector<int> empty1; std::vector<int> empty1;
std::vector<int> empty2; std::vector<int> empty2;
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105705
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end())); EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end()));
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
#pragma GCC diagnostic pop
#endif
EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end())); EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end()));
EXPECT_TRUE( EXPECT_TRUE(
absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end())); absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end()));

@ -90,10 +90,10 @@ using ContainerPointerType =
// lookup of std::begin and std::end, i.e. // lookup of std::begin and std::end, i.e.
// using std::begin; // using std::begin;
// using std::end; // using std::end;
// std::foo(begin(c), end(c)); // std::foo(begin(c), end(c);
// becomes // becomes
// std::foo(container_algorithm_internal::begin(c), // std::foo(container_algorithm_internal::begin(c),
// container_algorithm_internal::end(c)); // container_algorithm_internal::end(c));
// These are meant for internal use only. // These are meant for internal use only.
template <typename C> template <typename C>
@ -166,7 +166,7 @@ container_algorithm_internal::ContainerDifferenceType<const C> c_distance(
// c_all_of() // c_all_of()
// //
// Container-based version of the <algorithm> `std::all_of()` function to // Container-based version of the <algorithm> `std::all_of()` function to
// test if all elements within a container satisfy a condition. // test a condition on all elements within a container.
template <typename C, typename Pred> template <typename C, typename Pred>
bool c_all_of(const C& c, Pred&& pred) { bool c_all_of(const C& c, Pred&& pred) {
return std::all_of(container_algorithm_internal::c_begin(c), return std::all_of(container_algorithm_internal::c_begin(c),
@ -188,7 +188,7 @@ bool c_any_of(const C& c, Pred&& pred) {
// c_none_of() // c_none_of()
// //
// Container-based version of the <algorithm> `std::none_of()` function to // Container-based version of the <algorithm> `std::none_of()` function to
// test if no elements in a container fulfill a condition. // test if no elements in a container fulfil a condition.
template <typename C, typename Pred> template <typename C, typename Pred>
bool c_none_of(const C& c, Pred&& pred) { bool c_none_of(const C& c, Pred&& pred) {
return std::none_of(container_algorithm_internal::c_begin(c), return std::none_of(container_algorithm_internal::c_begin(c),
@ -905,11 +905,11 @@ void c_sort(C& c) {
// Overload of c_sort() for performing a `comp` comparison other than the // Overload of c_sort() for performing a `comp` comparison other than the
// default `operator<`. // default `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
void c_sort(C& c, LessThan&& comp) { void c_sort(C& c, Compare&& comp) {
std::sort(container_algorithm_internal::c_begin(c), std::sort(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_stable_sort() // c_stable_sort()
@ -925,11 +925,11 @@ void c_stable_sort(C& c) {
// Overload of c_stable_sort() for performing a `comp` comparison other than the // Overload of c_stable_sort() for performing a `comp` comparison other than the
// default `operator<`. // default `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
void c_stable_sort(C& c, LessThan&& comp) { void c_stable_sort(C& c, Compare&& comp) {
std::stable_sort(container_algorithm_internal::c_begin(c), std::stable_sort(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_is_sorted() // c_is_sorted()
@ -944,11 +944,11 @@ bool c_is_sorted(const C& c) {
// c_is_sorted() overload for performing a `comp` comparison other than the // c_is_sorted() overload for performing a `comp` comparison other than the
// default `operator<`. // default `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
bool c_is_sorted(const C& c, LessThan&& comp) { bool c_is_sorted(const C& c, Compare&& comp) {
return std::is_sorted(container_algorithm_internal::c_begin(c), return std::is_sorted(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_partial_sort() // c_partial_sort()
@ -966,14 +966,14 @@ void c_partial_sort(
// Overload of c_partial_sort() for performing a `comp` comparison other than // Overload of c_partial_sort() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_partial_sort( void c_partial_sort(
RandomAccessContainer& sequence, RandomAccessContainer& sequence,
container_algorithm_internal::ContainerIter<RandomAccessContainer> middle, container_algorithm_internal::ContainerIter<RandomAccessContainer> middle,
LessThan&& comp) { Compare&& comp) {
std::partial_sort(container_algorithm_internal::c_begin(sequence), middle, std::partial_sort(container_algorithm_internal::c_begin(sequence), middle,
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_partial_sort_copy() // c_partial_sort_copy()
@ -994,15 +994,15 @@ c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
// Overload of c_partial_sort_copy() for performing a `comp` comparison other // Overload of c_partial_sort_copy() for performing a `comp` comparison other
// than the default `operator<`. // than the default `operator<`.
template <typename C, typename RandomAccessContainer, typename LessThan> template <typename C, typename RandomAccessContainer, typename Compare>
container_algorithm_internal::ContainerIter<RandomAccessContainer> container_algorithm_internal::ContainerIter<RandomAccessContainer>
c_partial_sort_copy(const C& sequence, RandomAccessContainer& result, c_partial_sort_copy(const C& sequence, RandomAccessContainer& result,
LessThan&& comp) { Compare&& comp) {
return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence), return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
container_algorithm_internal::c_begin(result), container_algorithm_internal::c_begin(result),
container_algorithm_internal::c_end(result), container_algorithm_internal::c_end(result),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_is_sorted_until() // c_is_sorted_until()
@ -1018,12 +1018,12 @@ container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) {
// Overload of c_is_sorted_until() for performing a `comp` comparison other than // Overload of c_is_sorted_until() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
container_algorithm_internal::ContainerIter<C> c_is_sorted_until( container_algorithm_internal::ContainerIter<C> c_is_sorted_until(
C& c, LessThan&& comp) { C& c, Compare&& comp) {
return std::is_sorted_until(container_algorithm_internal::c_begin(c), return std::is_sorted_until(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_nth_element() // c_nth_element()
@ -1043,14 +1043,14 @@ void c_nth_element(
// Overload of c_nth_element() for performing a `comp` comparison other than // Overload of c_nth_element() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_nth_element( void c_nth_element(
RandomAccessContainer& sequence, RandomAccessContainer& sequence,
container_algorithm_internal::ContainerIter<RandomAccessContainer> nth, container_algorithm_internal::ContainerIter<RandomAccessContainer> nth,
LessThan&& comp) { Compare&& comp) {
std::nth_element(container_algorithm_internal::c_begin(sequence), nth, std::nth_element(container_algorithm_internal::c_begin(sequence), nth,
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1072,12 +1072,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
// Overload of c_lower_bound() for performing a `comp` comparison other than // Overload of c_lower_bound() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename Sequence, typename T, typename LessThan> template <typename Sequence, typename T, typename Compare>
container_algorithm_internal::ContainerIter<Sequence> c_lower_bound( container_algorithm_internal::ContainerIter<Sequence> c_lower_bound(
Sequence& sequence, T&& value, LessThan&& comp) { Sequence& sequence, T&& value, Compare&& comp) {
return std::lower_bound(container_algorithm_internal::c_begin(sequence), return std::lower_bound(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<T>(value), std::forward<LessThan>(comp)); std::forward<T>(value), std::forward<Compare>(comp));
} }
// c_upper_bound() // c_upper_bound()
@ -1095,12 +1095,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
// Overload of c_upper_bound() for performing a `comp` comparison other than // Overload of c_upper_bound() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename Sequence, typename T, typename LessThan> template <typename Sequence, typename T, typename Compare>
container_algorithm_internal::ContainerIter<Sequence> c_upper_bound( container_algorithm_internal::ContainerIter<Sequence> c_upper_bound(
Sequence& sequence, T&& value, LessThan&& comp) { Sequence& sequence, T&& value, Compare&& comp) {
return std::upper_bound(container_algorithm_internal::c_begin(sequence), return std::upper_bound(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<T>(value), std::forward<LessThan>(comp)); std::forward<T>(value), std::forward<Compare>(comp));
} }
// c_equal_range() // c_equal_range()
@ -1118,12 +1118,12 @@ c_equal_range(Sequence& sequence, T&& value) {
// Overload of c_equal_range() for performing a `comp` comparison other than // Overload of c_equal_range() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename Sequence, typename T, typename LessThan> template <typename Sequence, typename T, typename Compare>
container_algorithm_internal::ContainerIterPairType<Sequence, Sequence> container_algorithm_internal::ContainerIterPairType<Sequence, Sequence>
c_equal_range(Sequence& sequence, T&& value, LessThan&& comp) { c_equal_range(Sequence& sequence, T&& value, Compare&& comp) {
return std::equal_range(container_algorithm_internal::c_begin(sequence), return std::equal_range(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<T>(value), std::forward<LessThan>(comp)); std::forward<T>(value), std::forward<Compare>(comp));
} }
// c_binary_search() // c_binary_search()
@ -1140,12 +1140,12 @@ bool c_binary_search(Sequence&& sequence, T&& value) {
// Overload of c_binary_search() for performing a `comp` comparison other than // Overload of c_binary_search() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename Sequence, typename T, typename LessThan> template <typename Sequence, typename T, typename Compare>
bool c_binary_search(Sequence&& sequence, T&& value, LessThan&& comp) { bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) {
return std::binary_search(container_algorithm_internal::c_begin(sequence), return std::binary_search(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<T>(value), std::forward<T>(value),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1166,14 +1166,14 @@ OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) {
// Overload of c_merge() for performing a `comp` comparison other than // Overload of c_merge() for performing a `comp` comparison other than
// the default `operator<`. // the default `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename LessThan> template <typename C1, typename C2, typename OutputIterator, typename Compare>
OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result, OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result,
LessThan&& comp) { Compare&& comp) {
return std::merge(container_algorithm_internal::c_begin(c1), return std::merge(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), result, container_algorithm_internal::c_end(c2), result,
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_inplace_merge() // c_inplace_merge()
@ -1189,13 +1189,13 @@ void c_inplace_merge(C& c,
// Overload of c_inplace_merge() for performing a merge using a `comp` other // Overload of c_inplace_merge() for performing a merge using a `comp` other
// than `operator<`. // than `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
void c_inplace_merge(C& c, void c_inplace_merge(C& c,
container_algorithm_internal::ContainerIter<C> middle, container_algorithm_internal::ContainerIter<C> middle,
LessThan&& comp) { Compare&& comp) {
std::inplace_merge(container_algorithm_internal::c_begin(c), middle, std::inplace_merge(container_algorithm_internal::c_begin(c), middle,
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_includes() // c_includes()
@ -1213,13 +1213,13 @@ bool c_includes(const C1& c1, const C2& c2) {
// Overload of c_includes() for performing a merge using a `comp` other than // Overload of c_includes() for performing a merge using a `comp` other than
// `operator<`. // `operator<`.
template <typename C1, typename C2, typename LessThan> template <typename C1, typename C2, typename Compare>
bool c_includes(const C1& c1, const C2& c2, LessThan&& comp) { bool c_includes(const C1& c1, const C2& c2, Compare&& comp) {
return std::includes(container_algorithm_internal::c_begin(c1), return std::includes(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), container_algorithm_internal::c_end(c2),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_set_union() // c_set_union()
@ -1243,7 +1243,7 @@ OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) {
// Overload of c_set_union() for performing a merge using a `comp` other than // Overload of c_set_union() for performing a merge using a `comp` other than
// `operator<`. // `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename LessThan, template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if< typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value, !container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type, void>::type,
@ -1251,18 +1251,18 @@ template <typename C1, typename C2, typename OutputIterator, typename LessThan,
!container_algorithm_internal::IsUnorderedContainer<C2>::value, !container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type> void>::type>
OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output,
LessThan&& comp) { Compare&& comp) {
return std::set_union(container_algorithm_internal::c_begin(c1), return std::set_union(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), output, container_algorithm_internal::c_end(c2), output,
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_set_intersection() // c_set_intersection()
// //
// Container-based version of the <algorithm> `std::set_intersection()` function // Container-based version of the <algorithm> `std::set_intersection()` function
// to return an iterator containing the intersection of two sorted containers. // to return an iterator containing the intersection of two containers.
template <typename C1, typename C2, typename OutputIterator, template <typename C1, typename C2, typename OutputIterator,
typename = typename std::enable_if< typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value, !container_algorithm_internal::IsUnorderedContainer<C1>::value,
@ -1272,11 +1272,6 @@ template <typename C1, typename C2, typename OutputIterator,
void>::type> void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output) { OutputIterator output) {
// In debug builds, ensure that both containers are sorted with respect to the
// default comparator. std::set_intersection requires the containers be sorted
// using operator<.
assert(absl::c_is_sorted(c1));
assert(absl::c_is_sorted(c2));
return std::set_intersection(container_algorithm_internal::c_begin(c1), return std::set_intersection(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
@ -1285,7 +1280,7 @@ OutputIterator c_set_intersection(const C1& c1, const C2& c2,
// Overload of c_set_intersection() for performing a merge using a `comp` other // Overload of c_set_intersection() for performing a merge using a `comp` other
// than `operator<`. // than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename LessThan, template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if< typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value, !container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type, void>::type,
@ -1293,17 +1288,12 @@ template <typename C1, typename C2, typename OutputIterator, typename LessThan,
!container_algorithm_internal::IsUnorderedContainer<C2>::value, !container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type> void>::type>
OutputIterator c_set_intersection(const C1& c1, const C2& c2, OutputIterator c_set_intersection(const C1& c1, const C2& c2,
OutputIterator output, LessThan&& comp) { OutputIterator output, Compare&& comp) {
// In debug builds, ensure that both containers are sorted with respect to the
// default comparator. std::set_intersection requires the containers be sorted
// using the same comparator.
assert(absl::c_is_sorted(c1, comp));
assert(absl::c_is_sorted(c2, comp));
return std::set_intersection(container_algorithm_internal::c_begin(c1), return std::set_intersection(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), output, container_algorithm_internal::c_end(c2), output,
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_set_difference() // c_set_difference()
@ -1328,7 +1318,7 @@ OutputIterator c_set_difference(const C1& c1, const C2& c2,
// Overload of c_set_difference() for performing a merge using a `comp` other // Overload of c_set_difference() for performing a merge using a `comp` other
// than `operator<`. // than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename LessThan, template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if< typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value, !container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type, void>::type,
@ -1336,12 +1326,12 @@ template <typename C1, typename C2, typename OutputIterator, typename LessThan,
!container_algorithm_internal::IsUnorderedContainer<C2>::value, !container_algorithm_internal::IsUnorderedContainer<C2>::value,
void>::type> void>::type>
OutputIterator c_set_difference(const C1& c1, const C2& c2, OutputIterator c_set_difference(const C1& c1, const C2& c2,
OutputIterator output, LessThan&& comp) { OutputIterator output, Compare&& comp) {
return std::set_difference(container_algorithm_internal::c_begin(c1), return std::set_difference(container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), output, container_algorithm_internal::c_end(c2), output,
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_set_symmetric_difference() // c_set_symmetric_difference()
@ -1367,7 +1357,7 @@ OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
// Overload of c_set_symmetric_difference() for performing a merge using a // Overload of c_set_symmetric_difference() for performing a merge using a
// `comp` other than `operator<`. // `comp` other than `operator<`.
template <typename C1, typename C2, typename OutputIterator, typename LessThan, template <typename C1, typename C2, typename OutputIterator, typename Compare,
typename = typename std::enable_if< typename = typename std::enable_if<
!container_algorithm_internal::IsUnorderedContainer<C1>::value, !container_algorithm_internal::IsUnorderedContainer<C1>::value,
void>::type, void>::type,
@ -1376,13 +1366,13 @@ template <typename C1, typename C2, typename OutputIterator, typename LessThan,
void>::type> void>::type>
OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2,
OutputIterator output, OutputIterator output,
LessThan&& comp) { Compare&& comp) {
return std::set_symmetric_difference( return std::set_symmetric_difference(
container_algorithm_internal::c_begin(c1), container_algorithm_internal::c_begin(c1),
container_algorithm_internal::c_end(c1), container_algorithm_internal::c_end(c1),
container_algorithm_internal::c_begin(c2), container_algorithm_internal::c_begin(c2),
container_algorithm_internal::c_end(c2), output, container_algorithm_internal::c_end(c2), output,
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1401,11 +1391,11 @@ void c_push_heap(RandomAccessContainer& sequence) {
// Overload of c_push_heap() for performing a push operation on a heap using a // Overload of c_push_heap() for performing a push operation on a heap using a
// `comp` other than `operator<`. // `comp` other than `operator<`.
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_push_heap(RandomAccessContainer& sequence, LessThan&& comp) { void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) {
std::push_heap(container_algorithm_internal::c_begin(sequence), std::push_heap(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_pop_heap() // c_pop_heap()
@ -1420,11 +1410,11 @@ void c_pop_heap(RandomAccessContainer& sequence) {
// Overload of c_pop_heap() for performing a pop operation on a heap using a // Overload of c_pop_heap() for performing a pop operation on a heap using a
// `comp` other than `operator<`. // `comp` other than `operator<`.
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_pop_heap(RandomAccessContainer& sequence, LessThan&& comp) { void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) {
std::pop_heap(container_algorithm_internal::c_begin(sequence), std::pop_heap(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_make_heap() // c_make_heap()
@ -1439,11 +1429,11 @@ void c_make_heap(RandomAccessContainer& sequence) {
// Overload of c_make_heap() for performing heap comparisons using a // Overload of c_make_heap() for performing heap comparisons using a
// `comp` other than `operator<` // `comp` other than `operator<`
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_make_heap(RandomAccessContainer& sequence, LessThan&& comp) { void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) {
std::make_heap(container_algorithm_internal::c_begin(sequence), std::make_heap(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_sort_heap() // c_sort_heap()
@ -1458,11 +1448,11 @@ void c_sort_heap(RandomAccessContainer& sequence) {
// Overload of c_sort_heap() for performing heap comparisons using a // Overload of c_sort_heap() for performing heap comparisons using a
// `comp` other than `operator<` // `comp` other than `operator<`
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
void c_sort_heap(RandomAccessContainer& sequence, LessThan&& comp) { void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) {
std::sort_heap(container_algorithm_internal::c_begin(sequence), std::sort_heap(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_is_heap() // c_is_heap()
@ -1477,11 +1467,11 @@ bool c_is_heap(const RandomAccessContainer& sequence) {
// Overload of c_is_heap() for performing heap comparisons using a // Overload of c_is_heap() for performing heap comparisons using a
// `comp` other than `operator<` // `comp` other than `operator<`
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
bool c_is_heap(const RandomAccessContainer& sequence, LessThan&& comp) { bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) {
return std::is_heap(container_algorithm_internal::c_begin(sequence), return std::is_heap(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_is_heap_until() // c_is_heap_until()
@ -1497,12 +1487,12 @@ c_is_heap_until(RandomAccessContainer& sequence) {
// Overload of c_is_heap_until() for performing heap comparisons using a // Overload of c_is_heap_until() for performing heap comparisons using a
// `comp` other than `operator<` // `comp` other than `operator<`
template <typename RandomAccessContainer, typename LessThan> template <typename RandomAccessContainer, typename Compare>
container_algorithm_internal::ContainerIter<RandomAccessContainer> container_algorithm_internal::ContainerIter<RandomAccessContainer>
c_is_heap_until(RandomAccessContainer& sequence, LessThan&& comp) { c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) {
return std::is_heap_until(container_algorithm_internal::c_begin(sequence), return std::is_heap_until(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1523,12 +1513,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_min_element(
// Overload of c_min_element() for performing a `comp` comparison other than // Overload of c_min_element() for performing a `comp` comparison other than
// `operator<`. // `operator<`.
template <typename Sequence, typename LessThan> template <typename Sequence, typename Compare>
container_algorithm_internal::ContainerIter<Sequence> c_min_element( container_algorithm_internal::ContainerIter<Sequence> c_min_element(
Sequence& sequence, LessThan&& comp) { Sequence& sequence, Compare&& comp) {
return std::min_element(container_algorithm_internal::c_begin(sequence), return std::min_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_max_element() // c_max_element()
@ -1545,12 +1535,12 @@ container_algorithm_internal::ContainerIter<Sequence> c_max_element(
// Overload of c_max_element() for performing a `comp` comparison other than // Overload of c_max_element() for performing a `comp` comparison other than
// `operator<`. // `operator<`.
template <typename Sequence, typename LessThan> template <typename Sequence, typename Compare>
container_algorithm_internal::ContainerIter<Sequence> c_max_element( container_algorithm_internal::ContainerIter<Sequence> c_max_element(
Sequence& sequence, LessThan&& comp) { Sequence& sequence, Compare&& comp) {
return std::max_element(container_algorithm_internal::c_begin(sequence), return std::max_element(container_algorithm_internal::c_begin(sequence),
container_algorithm_internal::c_end(sequence), container_algorithm_internal::c_end(sequence),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_minmax_element() // c_minmax_element()
@ -1568,12 +1558,12 @@ c_minmax_element(C& c) {
// Overload of c_minmax_element() for performing `comp` comparisons other than // Overload of c_minmax_element() for performing `comp` comparisons other than
// `operator<`. // `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
container_algorithm_internal::ContainerIterPairType<C, C> container_algorithm_internal::ContainerIterPairType<C, C>
c_minmax_element(C& c, LessThan&& comp) { c_minmax_element(C& c, Compare&& comp) {
return std::minmax_element(container_algorithm_internal::c_begin(c), return std::minmax_element(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1598,15 +1588,15 @@ bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) {
// Overload of c_lexicographical_compare() for performing a lexicographical // Overload of c_lexicographical_compare() for performing a lexicographical
// comparison using a `comp` operator instead of `operator<`. // comparison using a `comp` operator instead of `operator<`.
template <typename Sequence1, typename Sequence2, typename LessThan> template <typename Sequence1, typename Sequence2, typename Compare>
bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2, bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2,
LessThan&& comp) { Compare&& comp) {
return std::lexicographical_compare( return std::lexicographical_compare(
container_algorithm_internal::c_begin(sequence1), container_algorithm_internal::c_begin(sequence1),
container_algorithm_internal::c_end(sequence1), container_algorithm_internal::c_end(sequence1),
container_algorithm_internal::c_begin(sequence2), container_algorithm_internal::c_begin(sequence2),
container_algorithm_internal::c_end(sequence2), container_algorithm_internal::c_end(sequence2),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_next_permutation() // c_next_permutation()
@ -1622,11 +1612,11 @@ bool c_next_permutation(C& c) {
// Overload of c_next_permutation() for performing a lexicographical // Overload of c_next_permutation() for performing a lexicographical
// comparison using a `comp` operator instead of `operator<`. // comparison using a `comp` operator instead of `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
bool c_next_permutation(C& c, LessThan&& comp) { bool c_next_permutation(C& c, Compare&& comp) {
return std::next_permutation(container_algorithm_internal::c_begin(c), return std::next_permutation(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
// c_prev_permutation() // c_prev_permutation()
@ -1642,11 +1632,11 @@ bool c_prev_permutation(C& c) {
// Overload of c_prev_permutation() for performing a lexicographical // Overload of c_prev_permutation() for performing a lexicographical
// comparison using a `comp` operator instead of `operator<`. // comparison using a `comp` operator instead of `operator<`.
template <typename C, typename LessThan> template <typename C, typename Compare>
bool c_prev_permutation(C& c, LessThan&& comp) { bool c_prev_permutation(C& c, Compare&& comp) {
return std::prev_permutation(container_algorithm_internal::c_begin(c), return std::prev_permutation(container_algorithm_internal::c_begin(c),
container_algorithm_internal::c_end(c), container_algorithm_internal::c_end(c),
std::forward<LessThan>(comp)); std::forward<Compare>(comp));
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
# #
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load( load(
"//absl:copts/configure_copts.bzl", "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
@ -75,7 +76,6 @@ cc_library(
":atomic_hook", ":atomic_hook",
":config", ":config",
":core_headers", ":core_headers",
":errno_saver",
":log_severity", ":log_severity",
], ],
) )
@ -158,12 +158,9 @@ cc_library(
"internal/direct_mmap.h", "internal/direct_mmap.h",
"internal/low_level_alloc.h", "internal/low_level_alloc.h",
], ],
copts = ABSL_DEFAULT_COPTS + select({ copts = ABSL_DEFAULT_COPTS,
"//conditions:default": [],
}),
linkopts = select({ linkopts = select({
"//absl:msvc_compiler": [], "//absl:windows": [],
"//absl:clang-cl_compiler": [],
"//absl:wasm": [], "//absl:wasm": [],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS, }) + ABSL_DEFAULT_LINKOPTS,
@ -223,10 +220,7 @@ cc_library(
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = select({ linkopts = select({
"//absl:msvc_compiler": [ "//absl:windows": [
"-DEFAULTLIB:advapi32.lib",
],
"//absl:clang-cl_compiler": [
"-DEFAULTLIB:advapi32.lib", "-DEFAULTLIB:advapi32.lib",
], ],
"//absl:wasm": [], "//absl:wasm": [],
@ -435,9 +429,6 @@ cc_test(
srcs = ["spinlock_test_common.cc"], srcs = ["spinlock_test_common.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_wasm",
],
deps = [ deps = [
":base", ":base",
":base_internal", ":base_internal",
@ -488,7 +479,6 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":base",
":config", ":config",
":core_headers", ":core_headers",
], ],
@ -561,10 +551,7 @@ cc_test(
srcs = ["internal/low_level_alloc_test.cc"], srcs = ["internal/low_level_alloc_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [ tags = ["no_test_ios_x86_64"],
"no_test_ios_x86_64",
"no_test_wasm",
],
deps = [ deps = [
":malloc_internal", ":malloc_internal",
"//absl/container:node_hash_map", "//absl/container:node_hash_map",
@ -577,9 +564,6 @@ cc_test(
srcs = ["internal/thread_identity_test.cc"], srcs = ["internal/thread_identity_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_wasm",
],
deps = [ deps = [
":base", ":base",
":core_headers", ":core_headers",
@ -602,6 +586,100 @@ cc_test(
], ],
) )
cc_library(
name = "bits",
hdrs = ["internal/bits.h"],
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
":core_headers",
],
)
cc_test(
name = "bits_test",
size = "small",
srcs = ["internal/bits_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bits",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "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( cc_library(
name = "scoped_set_env", name = "scoped_set_env",
testonly = 1, testonly = 1,
@ -712,31 +790,6 @@ cc_test(
], ],
) )
cc_library(
name = "prefetch",
hdrs = ["internal/prefetch.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
],
)
cc_test(
name = "prefetch_test",
size = "small",
srcs = ["internal/prefetch_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":prefetch",
"@com_google_googletest//:gtest_main",
],
)
cc_test( cc_test(
name = "unique_small_name_test", name = "unique_small_name_test",
size = "small", size = "small",

@ -16,7 +16,6 @@
find_library(LIBRT rt) find_library(LIBRT rt)
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
atomic_hook atomic_hook
@ -29,7 +28,6 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
errno_saver errno_saver
@ -54,7 +52,6 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
raw_logging_internal raw_logging_internal
@ -66,13 +63,11 @@ absl_cc_library(
absl::atomic_hook absl::atomic_hook
absl::config absl::config
absl::core_headers absl::core_headers
absl::errno_saver
absl::log_severity absl::log_severity
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
spinlock_wait spinlock_wait
@ -136,7 +131,6 @@ absl_cc_library(
PUBLIC PUBLIC
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
malloc_internal malloc_internal
@ -157,7 +151,6 @@ absl_cc_library(
Threads::Threads Threads::Threads
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
base_internal base_internal
@ -214,7 +207,6 @@ absl_cc_library(
PUBLIC PUBLIC
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
throw_delegate throw_delegate
@ -229,7 +221,6 @@ absl_cc_library(
absl::raw_logging_internal absl::raw_logging_internal
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
exception_testing exception_testing
@ -239,11 +230,10 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::config absl::config
GTest::gtest gtest
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
pretty_function pretty_function
@ -253,7 +243,6 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
exception_safety_testing exception_safety_testing
@ -270,7 +259,7 @@ absl_cc_library(
absl::meta absl::meta
absl::strings absl::strings
absl::utility absl::utility
GTest::gtest gtest
TESTONLY TESTONLY
) )
@ -284,10 +273,9 @@ absl_cc_test(
DEPS DEPS
absl::exception_safety_testing absl::exception_safety_testing
absl::memory absl::memory
GTest::gtest_main gtest_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
atomic_hook_test_helper atomic_hook_test_helper
@ -312,8 +300,8 @@ absl_cc_test(
absl::atomic_hook_test_helper absl::atomic_hook_test_helper
absl::atomic_hook absl::atomic_hook
absl::core_headers absl::core_headers
GTest::gmock gmock
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -326,7 +314,7 @@ absl_cc_test(
DEPS DEPS
absl::base absl::base
absl::core_headers absl::core_headers
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -339,8 +327,8 @@ absl_cc_test(
DEPS DEPS
absl::errno_saver absl::errno_saver
absl::strerror absl::strerror
GTest::gmock gmock
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -354,7 +342,7 @@ absl_cc_test(
absl::base absl::base
absl::config absl::config
absl::throw_delegate absl::throw_delegate
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -369,7 +357,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::base_internal absl::base_internal
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -383,11 +371,10 @@ absl_cc_test(
absl::base_internal absl::base_internal
absl::memory absl::memory
absl::strings absl::strings
GTest::gmock gmock
GTest::gtest_main gtest_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
spinlock_test_common spinlock_test_common
@ -401,7 +388,7 @@ absl_cc_library(
absl::base_internal absl::base_internal
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
GTest::gtest gtest
TESTONLY TESTONLY
) )
@ -419,10 +406,9 @@ absl_cc_test(
absl::config absl::config
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
GTest::gtest_main gtest_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
endian endian
@ -432,7 +418,6 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::base
absl::config absl::config
absl::core_headers absl::core_headers
PUBLIC PUBLIC
@ -449,7 +434,7 @@ absl_cc_test(
absl::base absl::base
absl::config absl::config
absl::endian absl::endian
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -462,7 +447,7 @@ absl_cc_test(
DEPS DEPS
absl::config absl::config
absl::synchronization absl::synchronization
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -476,7 +461,7 @@ absl_cc_test(
absl::base absl::base
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -489,7 +474,7 @@ absl_cc_test(
DEPS DEPS
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -502,7 +487,7 @@ absl_cc_test(
DEPS DEPS
absl::base absl::base
absl::synchronization absl::synchronization
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -530,10 +515,87 @@ absl_cc_test(
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
Threads::Threads Threads::Threads
GTest::gtest_main gtest_main
)
absl_cc_library(
NAME
bits
HDRS
"internal/bits.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::config
absl::core_headers
)
absl_cc_test(
NAME
bits_test
SRCS
"internal/bits_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::bits
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
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
scoped_set_env scoped_set_env
@ -557,7 +619,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::scoped_set_env absl::scoped_set_env
GTest::gtest_main gtest_main
) )
absl_cc_test( absl_cc_test(
@ -581,11 +643,10 @@ absl_cc_test(
absl::flags_marshalling absl::flags_marshalling
absl::log_severity absl::log_severity
absl::strings absl::strings
GTest::gmock gmock
GTest::gtest_main gtest_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
strerror strerror
@ -613,11 +674,10 @@ absl_cc_test(
DEPS DEPS
absl::strerror absl::strerror
absl::strings absl::strings
GTest::gmock gmock
GTest::gtest_main gtest_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
fast_type_id fast_type_id
@ -640,33 +700,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::fast_type_id absl::fast_type_id
GTest::gtest_main gtest_main
)
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
prefetch
HDRS
"internal/prefetch.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
)
absl_cc_test(
NAME
prefetch_test
SRCS
"internal/prefetch_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::prefetch
GTest::gtest_main
) )
absl_cc_test( absl_cc_test(
@ -679,5 +713,5 @@ absl_cc_test(
DEPS DEPS
absl::core_headers absl::core_headers
absl::optional absl::optional
GTest::gtest_main gtest_main
) )

@ -18,6 +18,8 @@
// These macros are used within Abseil and allow the compiler to optimize, where // These macros are used within Abseil and allow the compiler to optimize, where
// applicable, certain function calls. // applicable, certain function calls.
// //
// This file is used for both C and C++!
//
// Most macros here are exposing GCC or Clang features, and are stubbed out for // Most macros here are exposing GCC or Clang features, and are stubbed out for
// other compilers. // other compilers.
// //
@ -119,7 +121,7 @@
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls) #if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls)) #define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__) #elif defined(__GNUC__) && !defined(__clang__)
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 #define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \ #define ABSL_ATTRIBUTE_NO_TAIL_CALL \
__attribute__((optimize("no-optimize-sibling-calls"))) __attribute__((optimize("no-optimize-sibling-calls")))
@ -131,15 +133,14 @@
// ABSL_ATTRIBUTE_WEAK // ABSL_ATTRIBUTE_WEAK
// //
// Tags a function as weak for the purposes of compilation and linking. // Tags a function as weak for the purposes of compilation and linking.
// Weak attributes did not work properly in LLVM's Windows backend before // Weak attributes currently do not work properly in LLVM's Windows backend,
// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598 // so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
// for further information. // for further information.
// The MinGW compiler doesn't complain about the weak attribute until the link // The MinGW compiler doesn't complain about the weak attribute until the link
// step, presumably because Windows doesn't use ELF binaries. // step, presumably because Windows doesn't use ELF binaries.
#if (ABSL_HAVE_ATTRIBUTE(weak) || \ #if (ABSL_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \ (defined(__GNUC__) && !defined(__clang__))) && \
(!defined(_WIN32) || (defined(__clang__) && __clang_major__ >= 9)) && \ !(defined(__llvm__) && defined(_WIN32)) && !defined(__MINGW32__)
!defined(__MINGW32__)
#undef ABSL_ATTRIBUTE_WEAK #undef ABSL_ATTRIBUTE_WEAK
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) #define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
#define ABSL_HAVE_ATTRIBUTE_WEAK 1 #define ABSL_HAVE_ATTRIBUTE_WEAK 1
@ -213,9 +214,6 @@
// https://gcc.gnu.org/gcc-4.8/changes.html // https://gcc.gnu.org/gcc-4.8/changes.html
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_address) #if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#elif defined(_MSC_VER) && _MSC_VER >= 1928
// https://docs.microsoft.com/en-us/cpp/cpp/no-sanitize-address
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec(no_sanitize_address)
#else #else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif #endif
@ -285,7 +283,10 @@
// ABSL_ATTRIBUTE_RETURNS_NONNULL // ABSL_ATTRIBUTE_RETURNS_NONNULL
// //
// Tells the compiler that a particular function never returns a null pointer. // Tells the compiler that a particular function never returns a null pointer.
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) #if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \
(defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
!defined(__clang__))
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) #define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else #else
#define ABSL_ATTRIBUTE_RETURNS_NONNULL #define ABSL_ATTRIBUTE_RETURNS_NONNULL
@ -315,22 +316,15 @@
__attribute__((section(#name))) __attribute__((noinline)) __attribute__((section(#name))) __attribute__((noinline))
#endif #endif
// ABSL_ATTRIBUTE_SECTION_VARIABLE // ABSL_ATTRIBUTE_SECTION_VARIABLE
// //
// Tells the compiler/linker to put a given variable into a section and define // Tells the compiler/linker to put a given variable into a section and define
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. // `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
// This functionality is supported by GNU linker. // This functionality is supported by GNU linker.
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE #ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
#ifdef _AIX
// __attribute__((section(#name))) on AIX is achived by using the `.csect` psudo
// op which includes an additional integer as part of its syntax indcating
// alignment. If data fall under different alignments then you might get a
// compilation error indicating a `Section type conflict`.
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
#else
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name))) #define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
#endif #endif
#endif
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS // ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
// //
@ -341,8 +335,8 @@
// a no-op on ELF but not on Mach-O. // a no-op on ELF but not on Mach-O.
// //
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS #ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \ #define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \ extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
#endif #endif
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS #ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
@ -403,9 +397,6 @@
// //
// Tells the compiler to warn about unused results. // Tells the compiler to warn about unused results.
// //
// For code or headers that are assured to only build with C++17 and up, prefer
// just using the standard `[[nodiscard]]` directly over this macro.
//
// When annotating a function, it must appear as the first part of the // When annotating a function, it must appear as the first part of the
// declaration or definition. The compiler will warn if the return value from // declaration or definition. The compiler will warn if the return value from
// such a function is unused: // such a function is unused:
@ -432,10 +423,9 @@
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
// //
// Note: past advice was to place the macro after the argument list. // Note: past advice was to place the macro after the argument list.
// #if ABSL_HAVE_ATTRIBUTE(nodiscard)
// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is #define ABSL_MUST_USE_RESULT [[nodiscard]]
// compliant with the stricter [[nodiscard]]. #elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) #define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
#else #else
#define ABSL_MUST_USE_RESULT #define ABSL_MUST_USE_RESULT
@ -505,7 +495,7 @@
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] #define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args) #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
#define ABSL_XRAY_LOG_ARGS(N) \ #define ABSL_XRAY_LOG_ARGS(N) \
[[clang::xray_always_instrument, clang::xray_log_args(N)]] [[clang::xray_always_instrument, clang::xray_log_args(N)]]
#else #else
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]] #define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
#endif #endif
@ -536,13 +526,6 @@
// ABSL_ATTRIBUTE_UNUSED // ABSL_ATTRIBUTE_UNUSED
// //
// Prevents the compiler from complaining about variables that appear unused. // Prevents the compiler from complaining about variables that appear unused.
//
// For code or headers that are assured to only build with C++17 and up, prefer
// just using the standard '[[maybe_unused]]' directly over this macro.
//
// Due to differences in positioning requirements between the old, compiler
// specific __attribute__ syntax and the now standard [[maybe_unused]], this
// macro does not attempt to take advantage of '[[maybe_unused]]'.
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) #if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef ABSL_ATTRIBUTE_UNUSED #undef ABSL_ATTRIBUTE_UNUSED
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) #define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
@ -563,19 +546,13 @@
// ABSL_ATTRIBUTE_PACKED // ABSL_ATTRIBUTE_PACKED
// //
// Instructs the compiler not to use natural alignment for a tagged data // Instructs the compiler not to use natural alignment for a tagged data
// structure, but instead to reduce its alignment to 1. // 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
// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing // entirety. Applying this attribute (judiciously) to a structure in its
// so can cause atomic variables to be mis-aligned and silently violate // entirety to optimize the memory footprint of very commonly-used structs is
// atomicity on x86. // 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,
// This attribute can either be applied to members of a structure or to a // apply this attribute only to structure members that need it.
// 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 // When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
// natural alignment of structure members not annotated is preserved. Aligned // natural alignment of structure members not annotated is preserved. Aligned
@ -620,24 +597,30 @@
// case 42: // case 42:
// ... // ...
// //
// Notes: When supported, GCC and Clang can issue a warning on switch labels // Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See // macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
// clang documentation on language extensions for details: // when performing switch labels fall-through diagnostic
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
// for details:
// https://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 // When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
// no effect on diagnostics. In any case this macro has no effect on runtime // has no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code. // behavior and performance of code.
#ifdef ABSL_FALLTHROUGH_INTENDED #ifdef ABSL_FALLTHROUGH_INTENDED
#error "ABSL_FALLTHROUGH_INTENDED should not be defined." #error "ABSL_FALLTHROUGH_INTENDED should not be defined."
#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough) #endif
#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]]
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough) // TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
#if defined(__clang__) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] #define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough) #endif
#elif defined(__GNUC__) && __GNUC__ >= 7
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] #define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#else #endif
#ifndef ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED \ #define ABSL_FALLTHROUGH_INTENDED \
do { \ do { \
} while (0) } while (0)
@ -649,9 +632,6 @@
// declarations. The macro argument is used as a custom diagnostic message (e.g. // declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative). // suggestion of a better alternative).
// //
// For code or headers that are assured to only build with C++14 and up, prefer
// just using the standard `[[deprecated("message")]]` directly over this macro.
//
// Examples: // Examples:
// //
// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; // class ABSL_DEPRECATED("Use Bar instead") Foo {...};
@ -662,17 +642,14 @@
// ABSL_DEPRECATED("Use DoThat() instead") // ABSL_DEPRECATED("Use DoThat() instead")
// void DoThis(); // void DoThis();
// //
// enum FooEnum {
// kBar ABSL_DEPRECATED("Use kBaz instead"),
// };
//
// Every usage of a deprecated entity will trigger a warning when compiled with // Every usage of a deprecated entity will trigger a warning when compiled with
// GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain // clang's `-Wdeprecated-declarations` option. This option is turned off by
// turns this warning off by default, instead relying on clang-tidy to report // default, but the warnings will be reported by clang-tidy.
// new uses of deprecated code. #if defined(__clang__) && __cplusplus >= 201103L
#if ABSL_HAVE_ATTRIBUTE(deprecated)
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) #define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#else #endif
#ifndef ABSL_DEPRECATED
#define ABSL_DEPRECATED(message) #define ABSL_DEPRECATED(message)
#endif #endif
@ -682,18 +659,9 @@
// not compile (on supported platforms) unless the variable has a constant // not compile (on supported platforms) unless the variable has a constant
// initializer. This is useful for variables with static and thread storage // initializer. This is useful for variables with static and thread storage
// duration, because it guarantees that they will not suffer from the so-called // duration, because it guarantees that they will not suffer from the so-called
// "static init order fiasco". // "static init order fiasco". Prefer to put this attribute on the most visible
// // declaration of the variable, if there's more than one, because code that
// This attribute must be placed on the initializing declaration of the // accesses the variable can then use the attribute for optimization.
// variable. Some compilers will give a -Wmissing-constinit warning when this
// attribute is placed on some other declaration but missing from the
// initializing declaration.
//
// In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can
// also be used in a non-initializing declaration to tell the compiler that a
// variable is already initialized, reducing overhead that would otherwise be
// incurred by a hidden guard variable. Thus annotating all declarations with
// this attribute is recommended to potentially enhance optimization.
// //
// Example: // Example:
// //
@ -702,61 +670,13 @@
// ABSL_CONST_INIT static MyType my_var; // ABSL_CONST_INIT static MyType my_var;
// }; // };
// //
// ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...); // MyType MyClass::my_var = MakeMyType(...);
//
// For code or headers that are assured to only build with C++20 and up, prefer
// just using the standard `constinit` keyword directly over this macro.
// //
// Note that this attribute is redundant if the variable is declared constexpr. // Note that this attribute is redundant if the variable is declared constexpr.
#if defined(__cpp_constinit) && __cpp_constinit >= 201907L #if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
#define ABSL_CONST_INIT constinit
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
#define ABSL_CONST_INIT [[clang::require_constant_initialization]] #define ABSL_CONST_INIT [[clang::require_constant_initialization]]
#else #else
#define ABSL_CONST_INIT #define ABSL_CONST_INIT
#endif #endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
// ABSL_ATTRIBUTE_PURE_FUNCTION
//
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
// functions. A function is pure if its return value is only a function of its
// arguments. The pure attribute prohibits a function from modifying the state
// of the program that is observable by means other than inspecting the
// function's return value. Declaring such functions with the pure attribute
// allows the compiler to avoid emitting some calls in repeated invocations of
// the function with the same argument values.
//
// Example:
//
// ABSL_ATTRIBUTE_PURE_FUNCTION int64_t ToInt64Milliseconds(Duration d);
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
#elif ABSL_HAVE_ATTRIBUTE(pure)
#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
#else
#define ABSL_ATTRIBUTE_PURE_FUNCTION
#endif
// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function
// parameter or implicit object parameter is retained by the return value of the
// annotated function (or, for a parameter of a constructor, in the value of the
// constructed object). This attribute causes warnings to be produced if a
// temporary object does not live long enough.
//
// When applied to a reference parameter, the referenced object is assumed to be
// retained by the return value of the function. When applied to a non-reference
// parameter (for example, a pointer or a class type), all temporaries
// referenced by the parameter are assumed to be retained by the return value of
// the function.
//
// See also the upstream documentation:
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]]
#elif ABSL_HAVE_ATTRIBUTE(lifetimebound)
#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound))
#else
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
#endif
#endif // ABSL_BASE_ATTRIBUTES_H_ #endif // ABSL_BASE_ATTRIBUTES_H_

@ -177,8 +177,15 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
scheduling_mode) == kOnceInit) { scheduling_mode) == kOnceInit) {
base_internal::invoke(std::forward<Callable>(fn), base_internal::invoke(std::forward<Callable>(fn),
std::forward<Args>(args)...); std::forward<Args>(args)...);
old_control = // The call to SpinLockWake below is an optimization, because the waiter
control->exchange(base_internal::kOnceDone, std::memory_order_release); // 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) { if (old_control == base_internal::kOnceWaiter) {
base_internal::SpinLockWake(control, true); base_internal::SpinLockWake(control, true);
} }

@ -29,10 +29,6 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
#include <bit> // For std::bit_cast.
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
#include "absl/base/internal/identity.h" #include "absl/base/internal/identity.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
@ -40,6 +36,19 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace internal_casts {
template <class Dest, class Source>
struct is_bitcastable
: std::integral_constant<
bool,
sizeof(Dest) == sizeof(Source) &&
type_traits_internal::is_trivially_copyable<Source>::value &&
type_traits_internal::is_trivially_copyable<Dest>::value &&
std::is_default_constructible<Dest>::value> {};
} // namespace internal_casts
// implicit_cast() // implicit_cast()
// //
// Performs an implicit conversion between types following the language // Performs an implicit conversion between types following the language
@ -96,83 +105,81 @@ constexpr To implicit_cast(typename absl::internal::identity_t<To> to) {
// bit_cast() // bit_cast()
// //
// Creates a value of the new type `Dest` whose representation is the same as // Performs a bitwise cast on a type without changing the underlying bit
// that of the argument, which is of (deduced) type `Source` (a "bitwise cast"; // representation of that type's value. The two types must be of the same size
// every bit in the value representation of the result is equal to the // and both types must be trivially copyable. As with most casts, use with
// corresponding bit in the object representation of the source). Source and // caution. A `bit_cast()` might be needed when you need to temporarily treat a
// destination types must be of the same size, and both types must be trivially // type as some other type, such as in the following cases:
// copyable.
// //
// As with most casts, use with caution. A `bit_cast()` might be needed when you // * Serialization (casting temporarily to `char *` for those purposes is
// need to treat a value as the value of some other type, for example, to access // always allowed by the C++ standard)
// the individual bits of an object which are not normally accessible through // * Managing the individual bits of a type within mathematical operations
// the object's type, such as for working with the binary representation of a // that are not normally accessible through that type
// floating point value: // * Casting non-pointer types to pointer types (casting the other way is
// allowed by `reinterpret_cast()` but round-trips cannot occur the other
// way).
//
// Example:
// //
// float f = 3.14159265358979; // float f = 3.14159265358979;
// int i = bit_cast<int>(f); // int i = bit_cast<int32_t>(f);
// // i = 0x40490fdb // // i = 0x40490fdb
// //
// Reinterpreting and accessing a value directly as a different type (as shown // Casting non-pointer types to pointer types and then dereferencing them
// below) usually results in undefined behavior. // traditionally produces undefined behavior.
// //
// Example: // Example:
// //
// // WRONG // // WRONG
// float f = 3.14159265358979; // float f = 3.14159265358979; // WRONG
// int i = reinterpret_cast<int&>(f); // Wrong // int i = * reinterpret_cast<int*>(&f); // WRONG
// int j = *reinterpret_cast<int*>(&f); // Equally wrong
// int k = *bit_cast<int*>(&f); // Equally wrong
// //
// Reinterpret-casting results in undefined behavior according to the ISO C++ // The address-casting method produces undefined behavior according to the ISO
// specification, section [basic.lval]. Roughly, this section says: if an object // C++ specification section [basic.lval]. Roughly, this section says: if an
// in memory has one type, and a program accesses it with a different type, the // object in memory has one type, and a program accesses it with a different
// result is undefined behavior for most "different type". // type, the result is undefined behavior for most values of "different type".
//
// Using bit_cast on a pointer and then dereferencing it is no better than using
// reinterpret_cast. You should only use bit_cast on the value itself.
// //
// Such casting results in type punning: holding an object in memory of one type // Such casting results in type punning: holding an object in memory of one type
// and reading its bits back using a different type. A `bit_cast()` avoids this // and reading its bits back using a different type. A `bit_cast()` avoids this
// issue by copying the object representation to a new value, which avoids // issue by implementing its casts using `memcpy()`, which avoids introducing
// introducing this undefined behavior (since the original value is never // this undefined behavior.
// accessed in the wrong way). //
// // NOTE: The requirements here are more strict than the bit_cast of standard
// The requirements of `absl::bit_cast` are more strict than that of // proposal p0476 due to the need for workarounds and lack of intrinsics.
// `std::bit_cast` unless compiler support is available. Specifically, without // Specifically, this implementation also requires `Dest` to be
// compiler support, this implementation also requires `Dest` to be // default-constructible.
// default-constructible. In C++20, `absl::bit_cast` is replaced by template <
// `std::bit_cast`. typename Dest, typename Source,
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value,
int>::type = 0>
using std::bit_cast;
#else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
template <typename Dest, typename Source,
typename std::enable_if<
sizeof(Dest) == sizeof(Source) &&
type_traits_internal::is_trivially_copyable<Source>::value &&
type_traits_internal::is_trivially_copyable<Dest>::value
#if !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
&& std::is_default_constructible<Dest>::value
#endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
,
int>::type = 0>
#if ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline constexpr Dest bit_cast(const Source& source) {
return __builtin_bit_cast(Dest, source);
}
#else // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
inline Dest bit_cast(const Source& source) { inline Dest bit_cast(const Source& source) {
Dest dest; Dest dest;
memcpy(static_cast<void*>(std::addressof(dest)), memcpy(static_cast<void*>(std::addressof(dest)),
static_cast<const void*>(std::addressof(source)), sizeof(dest)); static_cast<const void*>(std::addressof(source)), sizeof(dest));
return dest; return dest;
} }
#endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L // NOTE: This overload is only picked if the requirements of bit_cast are
// not met. It is therefore UB, but is provided temporarily as previous
// versions of this function template were unchecked. Do not use this in
// new code.
template <
typename Dest, typename Source,
typename std::enable_if<
!internal_casts::is_bitcastable<Dest, Source>::value,
int>::type = 0>
ABSL_DEPRECATED(
"absl::bit_cast type requirements were violated. Update the types "
"being used such that they are the same size and are both "
"TriviallyCopyable.")
inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source),
"Source and destination types should have equal sizes.");
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;
}
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -56,25 +56,6 @@
#include <cstddef> #include <cstddef>
#endif // __cplusplus #endif // __cplusplus
// ABSL_INTERNAL_CPLUSPLUS_LANG
//
// MSVC does not set the value of __cplusplus correctly, but instead uses
// _MSVC_LANG as a stand-in.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
//
// However, there are reports that MSVC even sets _MSVC_LANG incorrectly at
// times, for example:
// https://github.com/microsoft/vscode-cpptools/issues/1770
// https://reviews.llvm.org/D70996
//
// For this reason, this symbol is considered INTERNAL and code outside of
// Abseil must not use it.
#if defined(_MSVC_LANG)
#define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG
#elif defined(__cplusplus)
#define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus
#endif
#if defined(__APPLE__) #if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED, // Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0. // __IPHONE_8_0.
@ -85,35 +66,6 @@
#include "absl/base/options.h" #include "absl/base/options.h"
#include "absl/base/policy_checks.h" #include "absl/base/policy_checks.h"
// Abseil long-term support (LTS) releases will define
// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the
// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the
// integer representing the patch-level for that release.
//
// For example, for LTS release version "20300401.2", this would give us
// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2
//
// These symbols will not be defined in non-LTS code.
//
// Abseil recommends that clients live-at-head. Therefore, if you are using
// these symbols to assert a minimum version requirement, we recommend you do it
// as
//
// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401
// #error Project foo requires Abseil LTS version >= 20300401
// #endif
//
// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes
// live-at-head clients from the minimum version assertion.
//
// See https://abseil.io/about/releases for more information on Abseil release
// management.
//
// LTS releases can be obtained from
// https://github.com/abseil/abseil-cpp/releases.
#define ABSL_LTS_RELEASE_VERSION 20220623
#define ABSL_LTS_RELEASE_PATCH_LEVEL 0
// Helper macro to convert a CPP variable to a string literal. // Helper macro to convert a CPP variable to a string literal.
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x #define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x) #define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
@ -169,16 +121,10 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0 #if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
#define ABSL_NAMESPACE_BEGIN #define ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_END #define ABSL_NAMESPACE_END
#define ABSL_INTERNAL_C_SYMBOL(x) x
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1 #elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
#define ABSL_NAMESPACE_BEGIN \ #define ABSL_NAMESPACE_BEGIN \
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME { inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
#define ABSL_NAMESPACE_END } #define ABSL_NAMESPACE_END }
#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
#define ABSL_INTERNAL_C_SYMBOL(x) \
ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
#else #else
#error options.h is misconfigured. #error options.h is misconfigured.
#endif #endif
@ -202,35 +148,24 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#define ABSL_HAVE_BUILTIN(x) 0 #define ABSL_HAVE_BUILTIN(x) 0
#endif #endif
#ifdef __has_feature #if defined(__is_identifier)
#define ABSL_HAVE_FEATURE(f) __has_feature(f) #define ABSL_INTERNAL_HAS_KEYWORD(x) !(__is_identifier(x))
#else
#define ABSL_HAVE_FEATURE(f) 0
#endif
// Portable check for GCC minimum version:
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else #else
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0 #define ABSL_INTERNAL_HAS_KEYWORD(x) 0
#endif #endif
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) #ifdef __has_feature
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \ #define ABSL_HAVE_FEATURE(f) __has_feature(f)
(__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
#else #else
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0 #define ABSL_HAVE_FEATURE(f) 0
#endif #endif
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported. // ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
// We assume __thread is supported on Linux or Asylo when compiled with Clang or // We assume __thread is supported on Linux when compiled with Clang or compiled
// compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined. // against libstdc++ with _GLIBCXX_HAVE_TLS defined.
#ifdef ABSL_HAVE_TLS #ifdef ABSL_HAVE_TLS
#error ABSL_HAVE_TLS cannot be directly set #error ABSL_HAVE_TLS cannot be directly set
#elif (defined(__linux__) || defined(__ASYLO__)) && \ #elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
(defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
#define ABSL_HAVE_TLS 1 #define ABSL_HAVE_TLS 1
#endif #endif
@ -242,9 +177,10 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// gcc >= 4.8.1 using libstdc++, and Visual Studio. // gcc >= 4.8.1 using libstdc++, and Visual Studio.
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE #ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set #error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \ #elif defined(_LIBCPP_VERSION) || \
(!defined(__clang__) && defined(__GLIBCXX__) && \ (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \
ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8)) (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \
defined(_MSC_VER)
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1 #define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif #endif
@ -257,22 +193,32 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// //
// Checks whether `std::is_trivially_copy_assignable<T>` is supported. // Checks whether `std::is_trivially_copy_assignable<T>` is supported.
// Notes: Clang with libc++ supports these features, as does gcc >= 7.4 with // Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with
// libstdc++, or gcc >= 8.2 with libc++, and Visual Studio (but not NVCC). // either libc++ or libstdc++, and Visual Studio (but not NVCC).
#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) #if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set #error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE) #elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set #error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \ #elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
(!defined(__clang__) && \ (!defined(__clang__) && defined(__GNUC__) && \
((ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(7, 4) && defined(__GLIBCXX__)) || \ (__GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ >= 4)) && \
(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(8, 2) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
defined(_LIBCPP_VERSION)))) || \
(defined(_MSC_VER) && !defined(__NVCC__)) (defined(_MSC_VER) && !defined(__NVCC__))
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 #define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 #define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif #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 // ABSL_HAVE_THREAD_LOCAL
// //
// Checks whether C++11's `thread_local` storage duration specifier is // Checks whether C++11's `thread_local` storage duration specifier is
@ -365,21 +311,25 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// For further details, consult the compiler's documentation. // For further details, consult the compiler's documentation.
#ifdef ABSL_HAVE_EXCEPTIONS #ifdef ABSL_HAVE_EXCEPTIONS
#error ABSL_HAVE_EXCEPTIONS cannot be directly set. #error ABSL_HAVE_EXCEPTIONS cannot be directly set.
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
#elif defined(__clang__)
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
// Clang >= 3.6 // Clang >= 3.6
#if ABSL_HAVE_FEATURE(cxx_exceptions) #if ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1 #define ABSL_HAVE_EXCEPTIONS 1
#endif // ABSL_HAVE_FEATURE(cxx_exceptions) #endif // ABSL_HAVE_FEATURE(cxx_exceptions)
#elif defined(__clang__) #else
// Clang < 3.6 // Clang < 3.6
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro // http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) #if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1 #define ABSL_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions) #endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
// Handle remaining special cases and default to exceptions being supported. // Handle remaining special cases and default to exceptions being supported.
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \ #elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
!(ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 0) && \ !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
!defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND)) !(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define ABSL_HAVE_EXCEPTIONS 1 #define ABSL_HAVE_EXCEPTIONS 1
#endif #endif
@ -411,12 +361,10 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// POSIX.1-2001. // POSIX.1-2001.
#ifdef ABSL_HAVE_MMAP #ifdef ABSL_HAVE_MMAP
#error ABSL_HAVE_MMAP cannot be directly set #error ABSL_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__native_client__) || \ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__asmjs__) || defined(__wasm__) || defined(__Fuchsia__) || \ defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
defined(__sun) || defined(__ASYLO__) || defined(__myriad2__) || \ defined(__ASYLO__)
defined(__HAIKU__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
defined(__QNX__)
#define ABSL_HAVE_MMAP 1 #define ABSL_HAVE_MMAP 1
#endif #endif
@ -427,20 +375,10 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM #ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set #error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \ defined(__ros__)
defined(__NetBSD__)
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 #define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
#endif #endif
// ABSL_HAVE_SCHED_GETCPU
//
// Checks whether sched_getcpu is available.
#ifdef ABSL_HAVE_SCHED_GETCPU
#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
#elif defined(__linux__)
#define ABSL_HAVE_SCHED_GETCPU 1
#endif
// ABSL_HAVE_SCHED_YIELD // ABSL_HAVE_SCHED_YIELD
// //
// Checks whether the platform implements sched_yield(2) as defined in // Checks whether the platform implements sched_yield(2) as defined in
@ -523,41 +461,22 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#error "absl endian detection needs to be set up for your compiler" #error "absl endian detection needs to be set up for your compiler"
#endif #endif
// macOS < 10.13 and iOS < 11 don't let you use <any>, <optional>, or <variant> // macOS 10.13 and iOS 10.11 don't let you use <any>, <optional>, or <variant>
// even though the headers exist and are publicly noted to work, because the // even though the headers exist and are publicly noted to work. See
// libc++ shared library shipped on the system doesn't have the requisite // https://github.com/abseil/abseil-cpp/issues/207 and
// exported symbols. See https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes // https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
//
// libc++ spells out the availability requirements in the file // libc++ spells out the availability requirements in the file
// llvm-project/libcxx/include/__config via the #define // llvm-project/libcxx/include/__config via the #define
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. // _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
// #if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
// Unfortunately, Apple initially mis-stated the requirements as macOS < 10.14 ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
// and iOS < 12 in the libc++ headers. This was corrected by __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
// https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953 (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
// which subsequently made it into the XCode 12.5 release. We need to match the __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
// old (incorrect) conditions when built with old XCode, but can use the (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
// corrected earlier versions with new XCode. __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
((_LIBCPP_VERSION >= 11000 && /* XCode 12.5 or later: */ \ __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 110000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 40000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 110000))) || \
(_LIBCPP_VERSION < 11000 && /* Pre-XCode 12.5: */ \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else #else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
@ -571,7 +490,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<any>) && defined(__cplusplus) && __cplusplus >= 201703L && \ #if __has_include(<any>) && __cplusplus >= 201703L && \
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_ANY 1 #define ABSL_HAVE_STD_ANY 1
#endif #endif
@ -585,8 +504,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<optional>) && defined(__cplusplus) && \ #if __has_include(<optional>) && __cplusplus >= 201703L && \
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_OPTIONAL 1
#endif #endif
#endif #endif
@ -599,8 +518,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<variant>) && defined(__cplusplus) && \ #if __has_include(<variant>) && __cplusplus >= 201703L && \
__cplusplus >= 201703L && !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE !ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
#define ABSL_HAVE_STD_VARIANT 1 #define ABSL_HAVE_STD_VARIANT 1
#endif #endif
#endif #endif
@ -613,8 +532,7 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#ifdef __has_include #ifdef __has_include
#if __has_include(<string_view>) && defined(__cplusplus) && \ #if __has_include(<string_view>) && __cplusplus >= 201703L
__cplusplus >= 201703L
#define ABSL_HAVE_STD_STRING_VIEW 1 #define ABSL_HAVE_STD_STRING_VIEW 1
#endif #endif
#endif #endif
@ -626,9 +544,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language // not correctly set by MSVC, so we use `_MSVC_LANG` to check the language
// version. // version.
// TODO(zhangxy): fix tests before enabling aliasing for `std::any`. // TODO(zhangxy): fix tests before enabling aliasing for `std::any`.
#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ #if defined(_MSC_VER) && _MSC_VER >= 1910 && \
((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || \ ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402)
(defined(__cplusplus) && __cplusplus > 201402))
// #define ABSL_HAVE_STD_ANY 1 // #define ABSL_HAVE_STD_ANY 1
#define ABSL_HAVE_STD_OPTIONAL 1 #define ABSL_HAVE_STD_OPTIONAL 1
#define ABSL_HAVE_STD_VARIANT 1 #define ABSL_HAVE_STD_VARIANT 1
@ -727,6 +644,8 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#endif #endif
#undef ABSL_INTERNAL_HAS_KEYWORD
// ABSL_DLL // ABSL_DLL
// //
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)` // When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
@ -752,6 +671,12 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// a compiler instrumentation module and a run-time library. // a compiler instrumentation module and a run-time library.
#ifdef ABSL_HAVE_MEMORY_SANITIZER #ifdef ABSL_HAVE_MEMORY_SANITIZER
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set." #error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
#elif defined(MEMORY_SANITIZER)
// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_MEMORY_SANITIZER 1
#elif defined(__SANITIZE_MEMORY__)
#define ABSL_HAVE_MEMORY_SANITIZER 1
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer) #elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
#define ABSL_HAVE_MEMORY_SANITIZER 1 #define ABSL_HAVE_MEMORY_SANITIZER 1
#endif #endif
@ -761,6 +686,10 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// ThreadSanitizer (TSan) is a fast data race detector. // ThreadSanitizer (TSan) is a fast data race detector.
#ifdef ABSL_HAVE_THREAD_SANITIZER #ifdef ABSL_HAVE_THREAD_SANITIZER
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set." #error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
#elif defined(THREAD_SANITIZER)
// The THREAD_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_THREAD_SANITIZER 1
#elif defined(__SANITIZE_THREAD__) #elif defined(__SANITIZE_THREAD__)
#define ABSL_HAVE_THREAD_SANITIZER 1 #define ABSL_HAVE_THREAD_SANITIZER 1
#elif ABSL_HAVE_FEATURE(thread_sanitizer) #elif ABSL_HAVE_FEATURE(thread_sanitizer)
@ -772,142 +701,14 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// AddressSanitizer (ASan) is a fast memory error detector. // AddressSanitizer (ASan) is a fast memory error detector.
#ifdef ABSL_HAVE_ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set." #error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
#elif defined(ADDRESS_SANITIZER)
// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif defined(__SANITIZE_ADDRESS__) #elif defined(__SANITIZE_ADDRESS__)
#define ABSL_HAVE_ADDRESS_SANITIZER 1 #define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(address_sanitizer) #elif ABSL_HAVE_FEATURE(address_sanitizer)
#define ABSL_HAVE_ADDRESS_SANITIZER 1 #define ABSL_HAVE_ADDRESS_SANITIZER 1
#endif #endif
// ABSL_HAVE_HWADDRESS_SANITIZER
//
// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan
// memory error detector which can use CPU features like ARM TBI, Intel LAM or
// AMD UAI.
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set."
#elif defined(__SANITIZE_HWADDRESS__)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer)
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
#endif
// ABSL_HAVE_LEAK_SANITIZER
//
// LeakSanitizer (or lsan) is a detector of memory leaks.
// https://clang.llvm.org/docs/LeakSanitizer.html
// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
//
// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time
// whether the LeakSanitizer is potentially available. However, just because the
// LeakSanitizer is available does not mean it is active. Use the
// always-available run-time interface in //absl/debugging/leak_check.h for
// interacting with LeakSanitizer.
#ifdef ABSL_HAVE_LEAK_SANITIZER
#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set."
#elif defined(LEAK_SANITIZER)
// GCC provides no method for detecting the presense of the standalone
// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also
// use -DLEAK_SANITIZER.
#define ABSL_HAVE_LEAK_SANITIZER 1
// Clang standalone LeakSanitizer (-fsanitize=leak)
#elif ABSL_HAVE_FEATURE(leak_sanitizer)
#define ABSL_HAVE_LEAK_SANITIZER 1
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER)
// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer.
#define ABSL_HAVE_LEAK_SANITIZER 1
#endif
// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
//
// Class template argument deduction is a language feature added in C++17.
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
#elif defined(__cpp_deduction_guides)
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
#endif
// ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
//
// Prior to C++17, static constexpr variables defined in classes required a
// separate definition outside of the class body, for example:
//
// class Foo {
// static constexpr int kBar = 0;
// };
// constexpr int Foo::kBar;
//
// In C++17, these variables defined in classes are considered inline variables,
// and the extra declaration is redundant. Since some compilers warn on the
// extra declarations, ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL can be used
// conditionally ignore them:
//
// #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
// constexpr int Foo::kBar;
// #endif
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
#define ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
#endif
// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
// RTTI support.
#ifdef ABSL_INTERNAL_HAS_RTTI
#error ABSL_INTERNAL_HAS_RTTI cannot be directly set
#elif !defined(__GNUC__) || defined(__GXX_RTTI)
#define ABSL_INTERNAL_HAS_RTTI 1
#endif // !defined(__GNUC__) || defined(__GXX_RTTI)
// ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE
#error ABSL_INTERNAL_HAVE_SSE cannot be directly set
#elif defined(__SSE__)
#define ABSL_INTERNAL_HAVE_SSE 1
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1
// indicates that at least SSE was targeted with the /arch:SSE option.
// All x86-64 processors support SSE, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE 1
#endif
// ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
#ifdef ABSL_INTERNAL_HAVE_SSE2
#error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set
#elif defined(__SSE2__)
#define ABSL_INTERNAL_HAVE_SSE2 1
#elif defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2
// indicates that at least SSE2 was targeted with the /arch:SSE2 option.
// All x86-64 processors support SSE2, so support can be assumed.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define ABSL_INTERNAL_HAVE_SSE2 1
#endif
// ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support.
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
// which architectures support the various x86 instruction sets.
//
// MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3
// with MSVC requires either assuming that the code will only every run on CPUs
// that support SSSE3, otherwise __cpuid() can be used to detect support at
// runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported
// by the CPU.
#ifdef ABSL_INTERNAL_HAVE_SSSE3
#error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set
#elif defined(__SSSE3__)
#define ABSL_INTERNAL_HAVE_SSSE3 1
#endif
// ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM
// SIMD).
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
#elif defined(__ARM_NEON)
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
#endif
#endif // ABSL_BASE_CONFIG_H_ #endif // ABSL_BASE_CONFIG_H_

@ -110,9 +110,6 @@
// Define race annotations. // Define race annotations.
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1 #if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
// defined by the compiler-based santizer implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
// ------------------------------------------------------------- // -------------------------------------------------------------
// Annotations that suppress errors. It is usually better to express the // Annotations that suppress errors. It is usually better to express the
@ -289,22 +286,17 @@ ABSL_INTERNAL_END_EXTERN_C
// Define IGNORE_READS_BEGIN/_END annotations. // Define IGNORE_READS_BEGIN/_END annotations.
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1 #if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
// defined by the compiler-based implementation, not by the Abseil
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
// Request the analysis tool to ignore all reads in the current thread until // Request the analysis tool to ignore all reads in the current thread until
// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey // ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
// reads, while still checking other reads and all writes. // reads, while still checking other reads and all writes.
// See also ABSL_ANNOTATE_UNPROTECTED_READ. // See also ABSL_ANNOTATE_UNPROTECTED_READ.
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
(__FILE__, __LINE__)
// Stop ignoring reads. // Stop ignoring reads.
#define ABSL_ANNOTATE_IGNORE_READS_END() \ #define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \ ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
(__FILE__, __LINE__)
// Function prototypes of annotations provided by the compiler-based sanitizer // Function prototypes of annotations provided by the compiler-based sanitizer
// implementation. // implementation.
@ -324,22 +316,16 @@ ABSL_INTERNAL_END_EXTERN_C
// TODO(delesley) -- The exclusive lock here ignores writes as well, but // TODO(delesley) -- The exclusive lock here ignores writes as well, but
// allows IGNORE_READS_AND_WRITES to work properly. // allows IGNORE_READS_AND_WRITES to work properly.
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
ABSL_INTERNAL_GLOBAL_SCOPED( \ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
()
#define ABSL_ANNOTATE_IGNORE_READS_END() \ #define ABSL_ANNOTATE_IGNORE_READS_END() \
ABSL_INTERNAL_GLOBAL_SCOPED( \ ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
()
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsBegin()
AbslInternalAnnotateIgnoreReadsBegin)()
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {} ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL( ABSL_INTERNAL_STATIC_INLINE void AbslInternalAnnotateIgnoreReadsEnd()
AbslInternalAnnotateIgnoreReadsEnd)()
ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {} ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
#else #else
@ -433,6 +419,31 @@ ABSL_NAMESPACE_END
#endif #endif
#ifdef __cplusplus
#ifdef ABSL_HAVE_THREAD_SANITIZER
ABSL_INTERNAL_BEGIN_EXTERN_C
int RunningOnValgrind();
double ValgrindSlowdown();
ABSL_INTERNAL_END_EXTERN_C
#else
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
ABSL_DEPRECATED(
"Don't use this interface. It is misleading and is being deleted.")
ABSL_ATTRIBUTE_ALWAYS_INLINE inline int RunningOnValgrind() { return 0; }
ABSL_DEPRECATED(
"Don't use this interface. It is misleading and is being deleted.")
ABSL_ATTRIBUTE_ALWAYS_INLINE inline double ValgrindSlowdown() { return 1.0; }
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
using absl::base_internal::RunningOnValgrind;
using absl::base_internal::ValgrindSlowdown;
#endif
#endif
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Address sanitizer annotations // Address sanitizer annotations
@ -446,7 +457,7 @@ ABSL_NAMESPACE_END
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ #define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
struct { \ struct { \
alignas(8) char x[8]; \ char x[8] __attribute__((aligned(8))); \
} name } name
#else #else

@ -701,10 +701,7 @@ struct BasicGuaranteeWithExtraContracts : public NonNegative {
static constexpr int kExceptionSentinel = 9999; static constexpr int kExceptionSentinel = 9999;
}; };
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel; constexpr int BasicGuaranteeWithExtraContracts::kExceptionSentinel;
#endif
TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) { TEST(ExceptionCheckTest, BasicGuaranteeWithExtraContracts) {
auto tester_with_val = auto tester_with_val =

@ -0,0 +1,219 @@
// 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_BASE_INTERNAL_BITS_H_
#define ABSL_BASE_INTERNAL_BITS_H_
// This file contains bitwise ops which are implementation details of various
// absl libraries.
#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) && !defined(__clang__)
#include <intrin.h>
#if defined(_M_X64)
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_BitScanForward64)
#endif
#pragma intrinsic(_BitScanReverse)
#pragma intrinsic(_BitScanForward)
#endif
#include "absl/base/attributes.h"
#if defined(_MSC_VER) && !defined(__clang__)
// We can achieve something similar to attribute((always_inline)) with MSVC by
// using the __forceinline keyword, however this is not perfect. MSVC is
// much less aggressive about inlining, and even with the __forceinline keyword.
#define ABSL_BASE_INTERNAL_FORCEINLINE __forceinline
#else
// Use default attribute inline.
#define ABSL_BASE_INTERNAL_FORCEINLINE inline ABSL_ATTRIBUTE_ALWAYS_INLINE
#endif
namespace absl {
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;
}
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) {
return 63 - result;
}
return 64;
#elif defined(_MSC_VER) && !defined(__clang__)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) &&
_BitScanReverse(&result, static_cast<unsigned long>(n >> 32))) {
return 31 - result;
}
if (_BitScanReverse(&result, static_cast<unsigned long>(n))) {
return 63 - result;
}
return 64;
#elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clzll, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_clzll does not take 64-bit arg");
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
if (n == 0) {
return 64;
}
return __builtin_clzll(n);
#else
return CountLeadingZeros64Slow(n);
#endif
}
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;
}
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse(&result, n)) {
return 31 - result;
}
return 32;
#elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clz, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(int) == sizeof(n),
"__builtin_clz does not take 32-bit arg");
// Handle 0 as a special case because __builtin_clz(0) is undefined.
if (n == 0) {
return 32;
}
return __builtin_clz(n);
#else
return CountLeadingZeros32Slow(n);
#endif
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
int c = 63;
n &= ~n + 1;
if (n & 0x00000000FFFFFFFF) c -= 32;
if (n & 0x0000FFFF0000FFFF) c -= 16;
if (n & 0x00FF00FF00FF00FF) c -= 8;
if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
if (n & 0x3333333333333333) c -= 2;
if (n & 0x5555555555555555) c -= 1;
return c;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward64(&result, n);
return result;
#elif defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
if (static_cast<uint32_t>(n) == 0) {
_BitScanForward(&result, static_cast<unsigned long>(n >> 32));
return result + 32;
}
_BitScanForward(&result, static_cast<unsigned long>(n));
return result;
#elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_ctzll does not take 64-bit arg");
return __builtin_ctzll(n);
#else
return CountTrailingZerosNonZero64Slow(n);
#endif
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
int c = 31;
n &= ~n + 1;
if (n & 0x0000FFFF) c -= 16;
if (n & 0x00FF00FF) c -= 8;
if (n & 0x0F0F0F0F) c -= 4;
if (n & 0x33333333) c -= 2;
if (n & 0x55555555) c -= 1;
return c;
}
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward(&result, n);
return result;
#elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(int) == sizeof(n),
"__builtin_ctz does not take 32-bit arg");
return __builtin_ctz(n);
#else
return CountTrailingZerosNonZero32Slow(n);
#endif
}
#undef ABSL_BASE_INTERNAL_FORCEINLINE
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_BITS_H_

@ -0,0 +1,97 @@
// 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/bits.h"
#include "gtest/gtest.h"
namespace {
int CLZ64(uint64_t n) {
int fast = absl::base_internal::CountLeadingZeros64(n);
int slow = absl::base_internal::CountLeadingZeros64Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountLeadingZeros64) {
EXPECT_EQ(64, CLZ64(uint64_t{}));
EXPECT_EQ(0, CLZ64(~uint64_t{}));
for (int index = 0; index < 64; index++) {
uint64_t x = static_cast<uint64_t>(1) << index;
const auto cnt = 63 - index;
ASSERT_EQ(cnt, CLZ64(x)) << index;
ASSERT_EQ(cnt, CLZ64(x + x - 1)) << index;
}
}
int CLZ32(uint32_t n) {
int fast = absl::base_internal::CountLeadingZeros32(n);
int slow = absl::base_internal::CountLeadingZeros32Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountLeadingZeros32) {
EXPECT_EQ(32, CLZ32(uint32_t{}));
EXPECT_EQ(0, CLZ32(~uint32_t{}));
for (int index = 0; index < 32; index++) {
uint32_t x = static_cast<uint32_t>(1) << index;
const auto cnt = 31 - index;
ASSERT_EQ(cnt, CLZ32(x)) << index;
ASSERT_EQ(cnt, CLZ32(x + x - 1)) << index;
ASSERT_EQ(CLZ64(x), CLZ32(x) + 32);
}
}
int CTZ64(uint64_t n) {
int fast = absl::base_internal::CountTrailingZerosNonZero64(n);
int slow = absl::base_internal::CountTrailingZerosNonZero64Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountTrailingZerosNonZero64) {
EXPECT_EQ(0, CTZ64(~uint64_t{}));
for (int index = 0; index < 64; index++) {
uint64_t x = static_cast<uint64_t>(1) << index;
const auto cnt = index;
ASSERT_EQ(cnt, CTZ64(x)) << index;
ASSERT_EQ(cnt, CTZ64(~(x - 1))) << index;
}
}
int CTZ32(uint32_t n) {
int fast = absl::base_internal::CountTrailingZerosNonZero32(n);
int slow = absl::base_internal::CountTrailingZerosNonZero32Slow(n);
EXPECT_EQ(fast, slow) << n;
return fast;
}
TEST(BitsTest, CountTrailingZerosNonZero32) {
EXPECT_EQ(0, CTZ32(~uint32_t{}));
for (int index = 0; index < 32; index++) {
uint32_t x = static_cast<uint32_t>(1) << index;
const auto cnt = index;
ASSERT_EQ(cnt, CTZ32(x)) << index;
ASSERT_EQ(cnt, CTZ32(~(x - 1))) << index;
}
}
} // namespace

@ -25,8 +25,6 @@
#include <atomic> #include <atomic>
#include <chrono> // NOLINT(build/c++11) #include <chrono> // NOLINT(build/c++11)
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/unscaledcycleclock.h" #include "absl/base/internal/unscaledcycleclock.h"
namespace absl { namespace absl {
@ -35,20 +33,44 @@ namespace base_internal {
#if ABSL_USE_UNSCALED_CYCLECLOCK #if ABSL_USE_UNSCALED_CYCLECLOCK
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL namespace {
constexpr int32_t CycleClock::kShift;
constexpr double CycleClock::kFrequencyScale; #ifdef NDEBUG
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
static constexpr int32_t kShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
static constexpr int32_t kShift = 0;
#endif
#else
// In debug mode use a different shift to discourage depending on a
// particular shift value.
static constexpr int32_t kShift = 2;
#endif #endif
ABSL_CONST_INIT std::atomic<CycleClockSourceFunc> static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
CycleClock::cycle_clock_source_{nullptr}; static std::atomic<CycleClockSourceFunc> cycle_clock_source;
void CycleClockSource::Register(CycleClockSourceFunc source) { CycleClockSourceFunc LoadCycleClockSource() {
// Corresponds to the load(std::memory_order_acquire) in LoadCycleClockSource. // Optimize for the common case (no callback) by first doing a relaxed load;
CycleClock::cycle_clock_source_.store(source, std::memory_order_release); // this is significantly faster on non-x86 platforms.
if (cycle_clock_source.load(std::memory_order_relaxed) == nullptr) {
return nullptr;
}
// This corresponds to the store(std::memory_order_release) in
// CycleClockSource::Register, and makes sure that any updates made prior to
// registering the callback are visible to this thread before the callback is
// invoked.
return cycle_clock_source.load(std::memory_order_acquire);
} }
#ifdef _WIN32 } // namespace
int64_t CycleClock::Now() { int64_t CycleClock::Now() {
auto fn = LoadCycleClockSource(); auto fn = LoadCycleClockSource();
if (fn == nullptr) { if (fn == nullptr) {
@ -56,7 +78,15 @@ int64_t CycleClock::Now() {
} }
return fn() >> kShift; return fn() >> kShift;
} }
#endif
double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
void CycleClockSource::Register(CycleClockSourceFunc source) {
// Corresponds to the load(std::memory_order_acquire) in LoadCycleClockSource.
cycle_clock_source.store(source, std::memory_order_release);
}
#else #else

@ -42,19 +42,14 @@
#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_ #ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_ #define ABSL_BASE_INTERNAL_CYCLECLOCK_H_
#include <atomic>
#include <cstdint> #include <cstdint>
#include "absl/base/attributes.h"
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/unscaledcycleclock.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
using CycleClockSourceFunc = int64_t (*)();
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// CycleClock // CycleClock
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -73,38 +68,13 @@ class CycleClock {
static double Frequency(); static double Frequency();
private: private:
#if ABSL_USE_UNSCALED_CYCLECLOCK
static CycleClockSourceFunc LoadCycleClockSource();
#ifdef NDEBUG
#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
// Not debug mode and the UnscaledCycleClock frequency is the CPU
// frequency. Scale the CycleClock to prevent overflow if someone
// tries to represent the time as cycles since the Unix epoch.
static constexpr int32_t kShift = 1;
#else
// Not debug mode and the UnscaledCycleClock isn't operating at the
// raw CPU frequency. There is no need to do any scaling, so don't
// needlessly sacrifice precision.
static constexpr int32_t kShift = 0;
#endif
#else // NDEBUG
// In debug mode use a different shift to discourage depending on a
// particular shift value.
static constexpr int32_t kShift = 2;
#endif // NDEBUG
static constexpr double kFrequencyScale = 1.0 / (1 << kShift);
ABSL_CONST_INIT static std::atomic<CycleClockSourceFunc> cycle_clock_source_;
#endif // ABSL_USE_UNSCALED_CYCLECLOC
CycleClock() = delete; // no instances CycleClock() = delete; // no instances
CycleClock(const CycleClock&) = delete; CycleClock(const CycleClock&) = delete;
CycleClock& operator=(const CycleClock&) = delete; CycleClock& operator=(const CycleClock&) = delete;
friend class CycleClockSource;
}; };
using CycleClockSourceFunc = int64_t (*)();
class CycleClockSource { class CycleClockSource {
private: private:
// CycleClockSource::Register() // CycleClockSource::Register()
@ -117,41 +87,6 @@ class CycleClockSource {
static void Register(CycleClockSourceFunc source); static void Register(CycleClockSourceFunc source);
}; };
#if ABSL_USE_UNSCALED_CYCLECLOCK
inline CycleClockSourceFunc CycleClock::LoadCycleClockSource() {
#if !defined(__x86_64__)
// Optimize for the common case (no callback) by first doing a relaxed load;
// this is significantly faster on non-x86 platforms.
if (cycle_clock_source_.load(std::memory_order_relaxed) == nullptr) {
return nullptr;
}
#endif // !defined(__x86_64__)
// This corresponds to the store(std::memory_order_release) in
// CycleClockSource::Register, and makes sure that any updates made prior to
// registering the callback are visible to this thread before the callback
// is invoked.
return cycle_clock_source_.load(std::memory_order_acquire);
}
// Accessing globals in inlined code in Window DLLs is problematic.
#ifndef _WIN32
inline int64_t CycleClock::Now() {
auto fn = LoadCycleClockSource();
if (fn == nullptr) {
return base_internal::UnscaledCycleClock::Now() >> kShift;
}
return fn() >> kShift;
}
#endif
inline double CycleClock::Frequency() {
return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency();
}
#endif // ABSL_USE_UNSCALED_CYCLECLOCK
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -20,7 +20,7 @@
#include "absl/base/config.h" #include "absl/base/config.h"
#ifdef ABSL_HAVE_MMAP #if ABSL_HAVE_MMAP
#include <sys/mman.h> #include <sys/mman.h>
@ -41,13 +41,13 @@
#ifdef __mips__ #ifdef __mips__
// Include definitions of the ABI currently in use. // Include definitions of the ABI currently in use.
#if defined(__BIONIC__) || !defined(__GLIBC__) #ifdef __BIONIC__
// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the // Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the
// definitions we need. // definitions we need.
#include <asm/sgidefs.h> #include <asm/sgidefs.h>
#else #else
#include <sgidefs.h> #include <sgidefs.h>
#endif // __BIONIC__ || !__GLIBC__ #endif // __BIONIC__
#endif // __mips__ #endif // __mips__
// SYS_mmap and SYS_munmap are not defined in Android. // SYS_mmap and SYS_munmap are not defined in Android.
@ -74,13 +74,10 @@ namespace base_internal {
inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
off64_t offset) noexcept { off64_t offset) noexcept {
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
defined(__m68k__) || defined(__sh__) || \
(defined(__hppa__) && !defined(__LP64__)) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \ (defined(__PPC__) && !defined(__PPC64__)) || \
(defined(__riscv) && __riscv_xlen == 32) || \ (defined(__riscv) && __riscv_xlen == 32) || \
(defined(__s390__) && !defined(__s390x__)) || \ (defined(__s390__) && !defined(__s390x__))
(defined(__sparc__) && !defined(__arch64__))
// On these architectures, implement mmap with mmap2. // On these architectures, implement mmap with mmap2.
static int pagesize = 0; static int pagesize = 0;
if (pagesize == 0) { if (pagesize == 0) {

@ -16,10 +16,16 @@
#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_ #ifndef ABSL_BASE_INTERNAL_ENDIAN_H_
#define ABSL_BASE_INTERNAL_ENDIAN_H_ #define ABSL_BASE_INTERNAL_ENDIAN_H_
#include <cstdint> // The following guarantees declaration of the byte swap functions
#include <cstdlib> #ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
#include <byteswap.h> // IWYU pragma: export
#endif
#include "absl/base/casts.h" #include <cstdint>
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/unaligned_access.h" #include "absl/base/internal/unaligned_access.h"
#include "absl/base/port.h" #include "absl/base/port.h"
@ -27,11 +33,47 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN 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.
// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
// For simplicity, we enable them all only for GCC 4.8.0 or later.
#if defined(__clang__) || \
(defined(__GNUC__) && \
((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
inline uint64_t gbswap_64(uint64_t host_int) { inline uint64_t gbswap_64(uint64_t host_int) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
return __builtin_bswap64(host_int); return __builtin_bswap64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return __builtin_bswap32(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return __builtin_bswap16(host_int);
}
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
inline uint64_t gbswap_64(uint64_t host_int) {
return _byteswap_uint64(host_int); return _byteswap_uint64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return _byteswap_ulong(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return _byteswap_ushort(host_int);
}
#else
inline uint64_t gbswap_64(uint64_t host_int) {
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
// Adapted from /usr/include/byteswap.h. Not available on Mac.
if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int);
} else {
uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result;
}
#elif defined(__GLIBC__)
return bswap_64(host_int);
#else #else
return (((host_int & uint64_t{0xFF}) << 56) | return (((host_int & uint64_t{0xFF}) << 56) |
((host_int & uint64_t{0xFF00}) << 40) | ((host_int & uint64_t{0xFF00}) << 40) |
@ -41,14 +83,12 @@ inline uint64_t gbswap_64(uint64_t host_int) {
((host_int & uint64_t{0xFF0000000000}) >> 24) | ((host_int & uint64_t{0xFF0000000000}) >> 24) |
((host_int & uint64_t{0xFF000000000000}) >> 40) | ((host_int & uint64_t{0xFF000000000000}) >> 40) |
((host_int & uint64_t{0xFF00000000000000}) >> 56)); ((host_int & uint64_t{0xFF00000000000000}) >> 56));
#endif #endif // bswap_64
} }
inline uint32_t gbswap_32(uint32_t host_int) { inline uint32_t gbswap_32(uint32_t host_int) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__) #if defined(__GLIBC__)
return __builtin_bswap32(host_int); return bswap_32(host_int);
#elif defined(_MSC_VER)
return _byteswap_ulong(host_int);
#else #else
return (((host_int & uint32_t{0xFF}) << 24) | return (((host_int & uint32_t{0xFF}) << 24) |
((host_int & uint32_t{0xFF00}) << 8) | ((host_int & uint32_t{0xFF00}) << 8) |
@ -58,29 +98,33 @@ inline uint32_t gbswap_32(uint32_t host_int) {
} }
inline uint16_t gbswap_16(uint16_t host_int) { inline uint16_t gbswap_16(uint16_t host_int) {
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__) #if defined(__GLIBC__)
return __builtin_bswap16(host_int); return bswap_16(host_int);
#elif defined(_MSC_VER)
return _byteswap_ushort(host_int);
#else #else
return (((host_int & uint16_t{0xFF}) << 8) | return (((host_int & uint16_t{0xFF}) << 8) |
((host_int & uint16_t{0xFF00}) >> 8)); ((host_int & uint16_t{0xFF00}) >> 8));
#endif #endif
} }
#endif // intrinsics available
#ifdef ABSL_IS_LITTLE_ENDIAN #ifdef ABSL_IS_LITTLE_ENDIAN
// Portable definitions for htonl (host-to-network) and friends on little-endian // Definitions for ntohl etc. that don't require us to include
// architectures. // netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
// than just #defining them because in debug mode, gcc doesn't
// correctly handle the (rather involved) definitions of bswap_32.
// gcc guarantees that inline functions are as fast as macros, so
// this isn't a performance hit.
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); } inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); } inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); } inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
#elif defined ABSL_IS_BIG_ENDIAN #elif defined ABSL_IS_BIG_ENDIAN
// Portable definitions for htonl (host-to-network) etc on big-endian // These definitions are simpler on big-endian machines
// architectures. These definitions are simpler since the host byte order is the // These are functions instead of macros to avoid self-assignment warnings
// same as network byte order. // on calls such as "i = ghtnol(i);". This also provides type checking.
inline uint16_t ghtons(uint16_t x) { return x; } inline uint16_t ghtons(uint16_t x) { return x; }
inline uint32_t ghtonl(uint32_t x) { return x; } inline uint32_t ghtonl(uint32_t x) { return x; }
inline uint64_t ghtonll(uint64_t x) { return x; } inline uint64_t ghtonll(uint64_t x) { return x; }
@ -129,36 +173,6 @@ inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */ #endif /* ENDIAN */
inline uint8_t FromHost(uint8_t x) { return x; }
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
inline uint8_t ToHost(uint8_t x) { return x; }
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
inline int8_t FromHost(int8_t x) { return x; }
inline int16_t FromHost(int16_t x) {
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x) {
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x) {
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x) { return x; }
inline int16_t ToHost(int16_t x) {
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x) {
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x) {
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}
// Functions to do unaligned loads and stores in little-endian order. // Functions to do unaligned loads and stores in little-endian order.
inline uint16_t Load16(const void *p) { inline uint16_t Load16(const void *p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
@ -219,36 +233,6 @@ inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */ #endif /* ENDIAN */
inline uint8_t FromHost(uint8_t x) { return x; }
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
inline uint8_t ToHost(uint8_t x) { return x; }
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
inline int8_t FromHost(int8_t x) { return x; }
inline int16_t FromHost(int16_t x) {
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
}
inline int32_t FromHost(int32_t x) {
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
}
inline int64_t FromHost(int64_t x) {
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
}
inline int8_t ToHost(int8_t x) { return x; }
inline int16_t ToHost(int16_t x) {
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
}
inline int32_t ToHost(int32_t x) {
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
}
inline int64_t ToHost(int64_t x) {
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
}
// Functions to do unaligned loads and stores in big-endian order. // Functions to do unaligned loads and stores in big-endian order.
inline uint16_t Load16(const void *p) { inline uint16_t Load16(const void *p) {
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));

@ -536,22 +536,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
} }
// Memory management operators // Memory management operators
static void* operator new(size_t s) noexcept( // Args.. allows us to overload regular and placement new in one shot
IsSpecified(TypeSpec::kNoThrowNew)) {
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
}
return ::operator new(s);
}
static void* operator new[](size_t s) noexcept(
IsSpecified(TypeSpec::kNoThrowNew)) {
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
}
return ::operator new[](s);
}
template <typename... Args> template <typename... Args>
static void* operator new(size_t s, Args&&... args) noexcept( static void* operator new(size_t s, Args&&... args) noexcept(
IsSpecified(TypeSpec::kNoThrowNew)) { IsSpecified(TypeSpec::kNoThrowNew)) {
@ -572,6 +557,12 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
// Abseil doesn't support throwing overloaded operator delete. These are // Abseil doesn't support throwing overloaded operator delete. These are
// provided so a throwing operator-new can clean up after itself. // provided so a throwing operator-new can clean up after itself.
//
// We provide both regular and templated operator delete because if only the
// templated version is provided as we did with operator new, the compiler has
// no way of knowing which overload of operator delete to call. See
// https://en.cppreference.com/w/cpp/memory/new/operator_delete and
// https://en.cppreference.com/w/cpp/language/delete for the gory details.
void operator delete(void* p) noexcept { ::operator delete(p); } void operator delete(void* p) noexcept { ::operator delete(p); }
template <typename... Args> template <typename... Args>
@ -735,8 +726,9 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
ThrowingAllocator select_on_container_copy_construction() noexcept( ThrowingAllocator select_on_container_copy_construction() noexcept(
IsSpecified(AllocSpec::kNoThrowAllocate)) { IsSpecified(AllocSpec::kNoThrowAllocate)) {
auto& out = *this;
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
return *this; return out;
} }
template <typename U> template <typename U>

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/profiling/internal/exponential_biased.h" #include "absl/base/internal/exponential_biased.h"
#include <stdint.h> #include <stdint.h>
@ -26,7 +26,7 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
// The algorithm generates a random number between 0 and 1 and applies the // The algorithm generates a random number between 0 and 1 and applies the
// inverse cumulative distribution function for an exponential. Specifically: // inverse cumulative distribution function for an exponential. Specifically:
@ -64,7 +64,7 @@ int64_t ExponentialBiased::GetSkipCount(int64_t mean) {
// Assume huge values are bias neutral, retain bias for next call. // Assume huge values are bias neutral, retain bias for next call.
return std::numeric_limits<int64_t>::max() / 2; return std::numeric_limits<int64_t>::max() / 2;
} }
double value = std::rint(interval); double value = std::round(interval);
bias_ = interval - value; bias_ = interval - value;
return value; return value;
} }
@ -88,6 +88,6 @@ void ExponentialBiased::Initialize() {
initialized_ = true; initialized_ = true;
} }
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ #ifndef ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
#define ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ #define ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_
#include <stdint.h> #include <stdint.h>
@ -22,7 +22,7 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
// ExponentialBiased provides a small and fast random number generator for a // ExponentialBiased provides a small and fast random number generator for a
// rounded exponential distribution. This generator manages very little state, // rounded exponential distribution. This generator manages very little state,
@ -66,7 +66,7 @@ namespace profiling_internal {
// Adjusting with rounding bias is relatively trivial: // Adjusting with rounding bias is relatively trivial:
// //
// double value = bias_ + exponential_distribution(mean)(); // double value = bias_ + exponential_distribution(mean)();
// double rounded_value = std::rint(value); // double rounded_value = std::round(value);
// bias_ = value - rounded_value; // bias_ = value - rounded_value;
// return rounded_value; // return rounded_value;
// //
@ -123,8 +123,8 @@ inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) {
return (prng_mult * rnd + prng_add) & prng_mod_mask; return (prng_mult * rnd + prng_add) & prng_mod_mask;
} }
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#endif // ABSL_PROFILING_INTERNAL_EXPONENTIAL_BIASED_H_ #endif // ABSL_BASE_INTERNAL_EXPONENTIAL_BIASED_H_

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/profiling/internal/exponential_biased.h" #include "absl/base/internal/exponential_biased.h"
#include <stddef.h> #include <stddef.h>
@ -28,8 +28,7 @@ using ::testing::Ge;
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
namespace {
MATCHER_P2(IsBetween, a, b, MATCHER_P2(IsBetween, a, b,
absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a, absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a,
@ -186,7 +185,7 @@ TEST(ExponentialBiasedTest, InitializationModes) {
ABSL_CONST_INIT static ExponentialBiased eb_static; ABSL_CONST_INIT static ExponentialBiased eb_static;
EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0)); EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
#ifdef ABSL_HAVE_THREAD_LOCAL #if ABSL_HAVE_THREAD_LOCAL
thread_local ExponentialBiased eb_thread; thread_local ExponentialBiased eb_thread;
EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0)); EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
#endif #endif
@ -195,7 +194,6 @@ TEST(ExponentialBiasedTest, InitializationModes) {
EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0)); EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0));
} }
} // namespace } // namespace base_internal
} // namespace profiling_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -28,10 +28,8 @@ struct FastTypeTag {
constexpr static char dummy_var = 0; constexpr static char dummy_var = 0;
}; };
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
template <typename Type> template <typename Type>
constexpr char FastTypeTag<Type>::dummy_var; constexpr char FastTypeTag<Type>::dummy_var;
#endif
// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the // FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
// passed-in type. These are meant to be good match for keys into maps or // passed-in type. These are meant to be good match for keys into maps or

@ -14,8 +14,6 @@
// //
// absl::base_internal::invoke(f, args...) is an implementation of // absl::base_internal::invoke(f, args...) is an implementation of
// INVOKE(f, args...) from section [func.require] of the C++ standard. // INVOKE(f, args...) from section [func.require] of the C++ standard.
// When compiled as C++17 and later versions, it is implemented as an alias of
// std::invoke.
// //
// [func.require] // [func.require]
// Define INVOKE (f, t1, t2, ..., tN) as follows: // Define INVOKE (f, t1, t2, ..., tN) as follows:
@ -37,26 +35,6 @@
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_ #ifndef ABSL_BASE_INTERNAL_INVOKE_H_
#define ABSL_BASE_INTERNAL_INVOKE_H_ #define ABSL_BASE_INTERNAL_INVOKE_H_
#include "absl/base/config.h"
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#include <functional>
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
using std::invoke;
using std::invoke_result_t;
using std::is_invocable_r;
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#include <algorithm> #include <algorithm>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -102,18 +80,8 @@ struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
static decltype((std::declval<Obj>().* static decltype((std::declval<Obj>().*
std::declval<MemFun>())(std::declval<Args>()...)) std::declval<MemFun>())(std::declval<Args>()...))
Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) { Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
// Ignore bogus GCC warnings on this line.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example.
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
return (std::forward<Obj>(obj).* return (std::forward<Obj>(obj).*
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
#pragma GCC diagnostic pop
#endif
} }
}; };
@ -212,30 +180,8 @@ invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
template <typename AlwaysVoid, typename, typename, typename...>
struct IsInvocableRImpl : std::false_type {};
template <typename R, typename F, typename... Args>
struct IsInvocableRImpl<
absl::void_t<absl::base_internal::invoke_result_t<F, Args...> >, R, F,
Args...>
: std::integral_constant<
bool,
std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>,
R>::value ||
std::is_void<R>::value> {};
// Type trait whose member `value` is true if invoking `F` with `Args` is valid,
// and either the return type is convertible to `R`, or `R` is void.
// C++11-compatible version of `std::is_invocable_r`.
template <typename R, typename F, typename... Args>
using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>;
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
#endif // ABSL_BASE_INTERNAL_INVOKE_H_ #endif // ABSL_BASE_INTERNAL_INVOKE_H_

@ -21,10 +21,6 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#include "absl/container/node_hash_map.h" #include "absl/container/node_hash_map.h"
namespace absl { namespace absl {
@ -86,7 +82,7 @@ static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
AllocMap::iterator it; AllocMap::iterator it;
BlockDesc block_desc; BlockDesc block_desc;
int rnd; int rnd;
LowLevelAlloc::Arena *arena = nullptr; LowLevelAlloc::Arena *arena = 0;
if (use_new_arena) { if (use_new_arena) {
int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0; int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0;
arena = LowLevelAlloc::NewArena(flags); arena = LowLevelAlloc::NewArena(flags);
@ -101,10 +97,11 @@ static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
case 0: // coin came up heads: add a block case 0: // coin came up heads: add a block
using_low_level_alloc = true; using_low_level_alloc = true;
block_desc.len = rand() & 0x3fff; block_desc.len = rand() & 0x3fff;
block_desc.ptr = reinterpret_cast<char *>( block_desc.ptr =
arena == nullptr reinterpret_cast<char *>(
? LowLevelAlloc::Alloc(block_desc.len) arena == 0
: LowLevelAlloc::AllocWithArena(block_desc.len, arena)); ? LowLevelAlloc::Alloc(block_desc.len)
: LowLevelAlloc::AllocWithArena(block_desc.len, arena));
using_low_level_alloc = false; using_low_level_alloc = false;
RandomizeBlockDesc(&block_desc); RandomizeBlockDesc(&block_desc);
rnd = rand(); rnd = rand();
@ -161,20 +158,5 @@ ABSL_NAMESPACE_END
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// The actual test runs in the global constructor of `before_main`. // The actual test runs in the global constructor of `before_main`.
printf("PASS\n"); printf("PASS\n");
#ifdef __EMSCRIPTEN__
// clang-format off
// This is JS here. Don't try to format it.
MAIN_THREAD_EM_ASM({
if (ENVIRONMENT_IS_WEB) {
if (typeof TEST_FINISH === 'function') {
TEST_FINISH($0);
} else {
console.error('Attempted to exit with status ' + $0);
console.error('But TEST_FINSIHED is not a function.');
}
}
}, 0);
// clang-format on
#endif
return 0; return 0;
} }

@ -61,8 +61,6 @@ class SchedulingGuard {
public: public:
// Returns true iff the calling thread may be cooperatively rescheduled. // Returns true iff the calling thread may be cooperatively rescheduled.
static bool ReschedulingIsAllowed(); static bool ReschedulingIsAllowed();
SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
private: private:
// Disable cooperative rescheduling of the calling thread. It may still // Disable cooperative rescheduling of the calling thread. It may still
@ -103,6 +101,9 @@ class SchedulingGuard {
friend class SchedulingHelper; friend class SchedulingHelper;
friend class SpinLock; friend class SpinLock;
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode); friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

@ -12,15 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/profiling/internal/periodic_sampler.h" #include "absl/base/internal/periodic_sampler.h"
#include <atomic> #include <atomic>
#include "absl/profiling/internal/exponential_biased.h" #include "absl/base/internal/exponential_biased.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept { int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept {
return rng_.GetStride(period); return rng_.GetStride(period);
@ -48,6 +48,6 @@ bool PeriodicSamplerBase::SubtleConfirmSample() noexcept {
return true; return true;
} }
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -12,19 +12,19 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ #ifndef ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
#define ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ #define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
#include <stdint.h> #include <stdint.h>
#include <atomic> #include <atomic>
#include "absl/base/internal/exponential_biased.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/profiling/internal/exponential_biased.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
// PeriodicSamplerBase provides the basic period sampler implementation. // PeriodicSamplerBase provides the basic period sampler implementation.
// //
@ -149,7 +149,7 @@ class PeriodicSamplerBase {
// ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD // ICC x64 (OK) : https://gcc.godbolt.org/z/ptTNfD
// MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5 // MSVC x64 (OK) : https://gcc.godbolt.org/z/76j4-5
uint64_t stride_ = 0; uint64_t stride_ = 0;
absl::profiling_internal::ExponentialBiased rng_; ExponentialBiased rng_;
}; };
inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept { inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept {
@ -204,8 +204,8 @@ class PeriodicSampler final : public PeriodicSamplerBase {
template <typename Tag, int default_period> template <typename Tag, int default_period>
std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period); std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period);
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#endif // ABSL_PROFILING_INTERNAL_PERIODIC_SAMPLER_H_ #endif // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/profiling/internal/periodic_sampler.h"
#include "benchmark/benchmark.h" #include "benchmark/benchmark.h"
#include "absl/base/internal/periodic_sampler.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
namespace { namespace {
template <typename Sampler> template <typename Sampler>
@ -74,6 +74,6 @@ void BM_PeriodicSampler_Disabled(benchmark::State& state) {
BENCHMARK(BM_PeriodicSampler_Disabled); BENCHMARK(BM_PeriodicSampler_Disabled);
} // namespace } // namespace
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "absl/profiling/internal/periodic_sampler.h" #include "absl/base/internal/periodic_sampler.h"
#include <thread> // NOLINT(build/c++11) #include <thread> // NOLINT(build/c++11)
@ -23,7 +23,7 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace profiling_internal { namespace base_internal {
namespace { namespace {
using testing::Eq; using testing::Eq;
@ -172,6 +172,6 @@ TEST(PeriodicSamplerTest, SetGlobalPeriod) {
} }
} // namespace } // namespace
} // namespace profiling_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -1,138 +0,0 @@
// Copyright 2022 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_PREFETCH_H_
#define ABSL_BASE_INTERNAL_PREFETCH_H_
#include "absl/base/config.h"
#ifdef __SSE__
#include <xmmintrin.h>
#endif
#if defined(_MSC_VER) && defined(ABSL_INTERNAL_HAVE_SSE)
#include <intrin.h>
#pragma intrinsic(_mm_prefetch)
#endif
// Compatibility wrappers around __builtin_prefetch, to prefetch data
// for read if supported by the toolchain.
// Move data into the cache before it is read, or "prefetch" it.
//
// The value of `addr` is the address of the memory to prefetch. If
// the target and compiler support it, data prefetch instructions are
// generated. If the prefetch is done some time before the memory is
// read, it may be in the cache by the time the read occurs.
//
// The function names specify the temporal locality heuristic applied,
// using the names of Intel prefetch instructions:
//
// T0 - high degree of temporal locality; data should be left in as
// many levels of the cache possible
// T1 - moderate degree of temporal locality
// T2 - low degree of temporal locality
// Nta - no temporal locality, data need not be left in the cache
// after the read
//
// Incorrect or gratuitous use of these functions can degrade
// performance, so use them only when representative benchmarks show
// an improvement.
//
// Example usage:
//
// absl::base_internal::PrefetchT0(addr);
//
// Currently, the different prefetch calls behave on some Intel
// architectures as follows:
//
// SNB..SKL SKX
// PrefetchT0() L1/L2/L3 L1/L2
// PrefetchT1() L2/L3 L2
// PrefetchT2() L2/L3 L2
// PrefetchNta() L1/--/L3 L1*
//
// * On SKX PrefetchNta() will bring the line into L1 but will evict
// from L3 cache. This might result in surprising behavior.
//
// SNB = Sandy Bridge, SKL = Skylake, SKX = Skylake Xeon.
//
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
void PrefetchT0(const void* addr);
void PrefetchT1(const void* addr);
void PrefetchT2(const void* addr);
void PrefetchNta(const void* addr);
// Implementation details follow.
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
#define ABSL_INTERNAL_HAVE_PREFETCH 1
// See __builtin_prefetch:
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
//
// These functions speculatively load for read only. This is
// safe for all currently supported platforms. However, prefetch for
// store may have problems depending on the target platform.
//
inline void PrefetchT0(const void* addr) {
// Note: this uses prefetcht0 on Intel.
__builtin_prefetch(addr, 0, 3);
}
inline void PrefetchT1(const void* addr) {
// Note: this uses prefetcht1 on Intel.
__builtin_prefetch(addr, 0, 2);
}
inline void PrefetchT2(const void* addr) {
// Note: this uses prefetcht2 on Intel.
__builtin_prefetch(addr, 0, 1);
}
inline void PrefetchNta(const void* addr) {
// Note: this uses prefetchtnta on Intel.
__builtin_prefetch(addr, 0, 0);
}
#elif defined(ABSL_INTERNAL_HAVE_SSE)
#define ABSL_INTERNAL_HAVE_PREFETCH 1
inline void PrefetchT0(const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0);
}
inline void PrefetchT1(const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T1);
}
inline void PrefetchT2(const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T2);
}
inline void PrefetchNta(const void* addr) {
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA);
}
#else
inline void PrefetchT0(const void*) {}
inline void PrefetchT1(const void*) {}
inline void PrefetchT2(const void*) {}
inline void PrefetchNta(const void*) {}
#endif
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_PREFETCH_H_

@ -1,43 +0,0 @@
// Copyright 2022 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "absl/base/internal/prefetch.h"
#include "gtest/gtest.h"
namespace {
int number = 42;
TEST(Prefetch, TemporalLocalityNone) {
absl::base_internal::PrefetchNta(&number);
EXPECT_EQ(number, 42);
}
TEST(Prefetch, TemporalLocalityLow) {
absl::base_internal::PrefetchT2(&number);
EXPECT_EQ(number, 42);
}
TEST(Prefetch, TemporalLocalityMedium) {
absl::base_internal::PrefetchT1(&number);
EXPECT_EQ(number, 42);
}
TEST(Prefetch, TemporalLocalityHigh) {
absl::base_internal::PrefetchT0(&number);
EXPECT_EQ(number, 42);
}
} // namespace

@ -14,17 +14,15 @@
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include <stddef.h>
#include <cstdarg> #include <cstdarg>
#include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <string>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h" #include "absl/base/internal/atomic_hook.h"
#include "absl/base/internal/errno_saver.h"
#include "absl/base/log_severity.h" #include "absl/base/log_severity.h"
// We know how to perform low-level writes to stderr in POSIX and Windows. For // We know how to perform low-level writes to stderr in POSIX and Windows. For
@ -38,8 +36,8 @@
// This preprocessor token is also defined in raw_io.cc. If you need to copy // This preprocessor token is also defined in raw_io.cc. If you need to copy
// this, consider moving both to config.h instead. // this, consider moving both to config.h instead.
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__Fuchsia__) || defined(__native_client__) || \ defined(__Fuchsia__) || defined(__native_client__) || \
defined(__OpenBSD__) || defined(__EMSCRIPTEN__) || defined(__ASYLO__) defined(__EMSCRIPTEN__) || defined(__ASYLO__)
#include <unistd.h> #include <unistd.h>
@ -52,8 +50,7 @@
// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall // ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
// syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len); // syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
// for low level operations that want to avoid libc. // for low level operations that want to avoid libc.
#if (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)) && \ #if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
!defined(__ANDROID__)
#include <sys/syscall.h> #include <sys/syscall.h>
#define ABSL_HAVE_SYSCALL_WRITE 1 #define ABSL_HAVE_SYSCALL_WRITE 1
#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1 #define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
@ -70,25 +67,28 @@
#undef ABSL_HAVE_RAW_IO #undef ABSL_HAVE_RAW_IO
#endif #endif
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace raw_logging_internal {
namespace {
// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. // TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
// Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for // Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
// a selected set of platforms for which we expect not to be able to raw log. // selected set of platforms for which we expect not to be able to raw log.
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 #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
constexpr char kTruncated[] = " ... (message truncated)\n"; static const char kTruncated[] = " ... (message truncated)\n";
// sprintf the format to the buffer, adjusting *buf and *size to reflect the // sprintf the format to the buffer, adjusting *buf and *size to reflect the
// consumed bytes, and return whether the message fit without truncation. If // consumed bytes, and return whether the message fit without truncation. If
// truncation occurred, if possible leave room in the buffer for the message // truncation occurred, if possible leave room in the buffer for the message
// kTruncated[]. // kTruncated[].
bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) inline static bool VADoRawLog(char** buf, int* size, const char* format,
ABSL_PRINTF_ATTRIBUTE(3, 0); va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0);
bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) { inline static bool VADoRawLog(char** buf, int* size,
const char* format, va_list ap) {
int n = vsnprintf(*buf, *size, format, ap); int n = vsnprintf(*buf, *size, format, ap);
bool result = true; bool result = true;
if (n < 0 || n > *size) { if (n < 0 || n > *size) {
@ -96,7 +96,7 @@ bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
if (static_cast<size_t>(*size) > sizeof(kTruncated)) { if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
n = *size - sizeof(kTruncated); // room for truncation message n = *size - sizeof(kTruncated); // room for truncation message
} else { } else {
n = 0; // no room for truncation message n = 0; // no room for truncation message
} }
} }
*size -= n; *size -= n;
@ -105,7 +105,9 @@ bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
} }
#endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED #endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED
constexpr int kLogBufSize = 3000; static constexpr int kLogBufSize = 3000;
namespace {
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// that invoke malloc() and getenv() that might acquire some locks. // that invoke malloc() and getenv() that might acquire some locks.
@ -126,18 +128,6 @@ bool DoRawLog(char** buf, int* size, const char* format, ...) {
return true; return true;
} }
bool DefaultLogFilterAndPrefix(absl::LogSeverity, const char* file, int line,
char** buf, int* buf_size) {
DoRawLog(buf, buf_size, "[%s : %d] RAW: ", file, line);
return true;
}
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
absl::base_internal::AtomicHook<LogFilterAndPrefixHook>
log_filter_and_prefix_hook(DefaultLogFilterAndPrefix);
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
absl::base_internal::AtomicHook<AbortHook> abort_hook;
void RawLogVA(absl::LogSeverity severity, const char* file, int line, void RawLogVA(absl::LogSeverity severity, const char* file, int line,
const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0); const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
void RawLogVA(absl::LogSeverity severity, const char* file, int line, void RawLogVA(absl::LogSeverity severity, const char* file, int line,
@ -158,7 +148,14 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
} }
#endif #endif
enabled = log_filter_and_prefix_hook(severity, file, line, &buf, &size); auto log_prefix_hook_ptr = log_prefix_hook.Load();
if (log_prefix_hook_ptr) {
enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size);
} else {
if (enabled) {
DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line);
}
}
const char* const prefix_end = buf; const char* const prefix_end = buf;
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
@ -169,12 +166,11 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
} else { } else {
DoRawLog(&buf, &size, "%s", kTruncated); DoRawLog(&buf, &size, "%s", kTruncated);
} }
AsyncSignalSafeWriteToStderr(buffer, strlen(buffer)); absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer));
} }
#else #else
static_cast<void>(format); static_cast<void>(format);
static_cast<void>(ap); static_cast<void>(ap);
static_cast<void>(enabled);
#endif #endif
// Abort the process after logging a FATAL message, even if the output itself // Abort the process after logging a FATAL message, even if the output itself
@ -185,23 +181,13 @@ void RawLogVA(absl::LogSeverity severity, const char* file, int line,
} }
} }
// Non-formatting version of RawLog().
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
const std::string& message) {
RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
message.data());
}
} // namespace } // namespace
void AsyncSignalSafeWriteToStderr(const char* s, size_t len) { namespace absl {
absl::base_internal::ErrnoSaver errno_saver; ABSL_NAMESPACE_BEGIN
namespace raw_logging_internal {
void SafeWriteToStderr(const char *s, size_t len) {
#if defined(ABSL_HAVE_SYSCALL_WRITE) #if defined(ABSL_HAVE_SYSCALL_WRITE)
// We prefer calling write via `syscall` to minimize the risk of libc doing
// something "helpful".
syscall(SYS_write, STDERR_FILENO, s, len); syscall(SYS_write, STDERR_FILENO, s, len);
#elif defined(ABSL_HAVE_POSIX_WRITE) #elif defined(ABSL_HAVE_POSIX_WRITE)
write(STDERR_FILENO, s, len); write(STDERR_FILENO, s, len);
@ -214,6 +200,8 @@ void AsyncSignalSafeWriteToStderr(const char* s, size_t len) {
#endif #endif
} }
void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
void RawLog(absl::LogSeverity severity, const char* file, int line, void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) { const char* format, ...) {
va_list ap; va_list ap;
@ -222,6 +210,15 @@ void RawLog(absl::LogSeverity severity, const char* file, int line,
va_end(ap); va_end(ap);
} }
// Non-formatting version of RawLog().
//
// TODO(gfalcon): When string_view no longer depends on base, change this
// interface to take its message as a string_view instead.
static void DefaultInternalLog(absl::LogSeverity severity, const char* file,
int line, const std::string& message) {
RawLog(severity, file, line, "%s", message.c_str());
}
bool RawLoggingFullySupported() { bool RawLoggingFullySupported() {
#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
return true; return true;
@ -234,12 +231,6 @@ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
absl::base_internal::AtomicHook<InternalLogFunction> absl::base_internal::AtomicHook<InternalLogFunction>
internal_log_function(DefaultInternalLog); internal_log_function(DefaultInternalLog);
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func) {
log_filter_and_prefix_hook.Store(func);
}
void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
void RegisterInternalLogFunction(InternalLogFunction func) { void RegisterInternalLogFunction(InternalLogFunction func) {
internal_log_function.Store(func); internal_log_function.Store(func);
} }

@ -72,14 +72,12 @@
// //
// The API is a subset of the above: each macro only takes two arguments. Use // The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message. // StrCat if you need to build a richer message.
#define ABSL_INTERNAL_LOG(severity, message) \ #define ABSL_INTERNAL_LOG(severity, message) \
do { \ do { \
constexpr const char* absl_raw_logging_internal_filename = __FILE__; \ constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
::absl::raw_logging_internal::internal_log_function( \ ::absl::raw_logging_internal::internal_log_function( \
ABSL_RAW_LOGGING_INTERNAL_##severity, \ ABSL_RAW_LOGGING_INTERNAL_##severity, \
absl_raw_logging_internal_filename, __LINE__, message); \ absl_raw_logging_internal_filename, __LINE__, message); \
if (ABSL_RAW_LOGGING_INTERNAL_##severity == ::absl::LogSeverity::kFatal) \
ABSL_INTERNAL_UNREACHABLE; \
} while (0) } while (0)
#define ABSL_INTERNAL_CHECK(condition, message) \ #define ABSL_INTERNAL_CHECK(condition, message) \
@ -109,9 +107,12 @@ namespace raw_logging_internal {
void RawLog(absl::LogSeverity severity, const char* file, int line, void RawLog(absl::LogSeverity severity, const char* file, int line,
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
// Writes the provided buffer directly to stderr, in a signal-safe, low-level // Writes the provided buffer directly to stderr, in a safe, low-level manner.
// manner. //
void AsyncSignalSafeWriteToStderr(const char* s, size_t len); // In POSIX this means calling write(), which is async-signal safe and does
// not malloc. If the platform supports the SYS_write syscall, we invoke that
// directly to side-step any libc interception.
void SafeWriteToStderr(const char *s, size_t len);
// compile-time function to get the "base" filename, that is, the part of // compile-time function to get the "base" filename, that is, the part of
// a filename after the last "/" or "\" path separator. The search starts at // a filename after the last "/" or "\" path separator. The search starts at
@ -145,12 +146,11 @@ bool RawLoggingFullySupported();
// 'severity' is the severity level of the message being written. // 'severity' is the severity level of the message being written.
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro // 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
// was located. // was located.
// 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the // 'buffer' and 'buf_size' are pointers to the buffer and buffer size. If the
// hook writes a prefix, it must increment *buf and decrement *buf_size // hook writes a prefix, it must increment *buffer and decrement *buf_size
// accordingly. // accordingly.
using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity, using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file,
const char* file, int line, char** buf, int line, char** buffer, int* buf_size);
int* buf_size);
// Function type for a raw_logging customization hook called to abort a process // Function type for a raw_logging customization hook called to abort a process
// when a FATAL message is logged. If the provided AbortHook() returns, the // when a FATAL message is logged. If the provided AbortHook() returns, the
@ -160,10 +160,7 @@ using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity,
// was located. // was located.
// The NUL-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 // and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
// buffer (as written by the LogFilterAndPrefixHook.) // buffer (as written by the LogPrefixHook.)
//
// The lifetime of the filename and message buffers will not end while the
// process remains alive.
using AbortHook = void (*)(const char* file, int line, const char* buf_start, using AbortHook = void (*)(const char* file, int line, const char* buf_start,
const char* prefix_end, const char* buf_end); const char* prefix_end, const char* buf_end);
@ -179,14 +176,6 @@ ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
InternalLogFunction> InternalLogFunction>
internal_log_function; internal_log_function;
// Registers hooks of the above types. Only a single hook of each type may be
// registered. It is an error to call these functions multiple times with
// different input arguments.
//
// These functions are safe to call at any point during initialization; they do
// not block or malloc, and are async-signal safe.
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);
void RegisterAbortHook(AbortHook func);
void RegisterInternalLogFunction(InternalLogFunction func); void RegisterInternalLogFunction(InternalLogFunction func);
} // namespace raw_logging_internal } // namespace raw_logging_internal

@ -19,7 +19,6 @@
#include <limits> #include <limits>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/atomic_hook.h" #include "absl/base/internal/atomic_hook.h"
#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/cycleclock.h"
#include "absl/base/internal/spinlock_wait.h" #include "absl/base/internal/spinlock_wait.h"
@ -67,14 +66,12 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
submit_profile_data.Store(fn); submit_profile_data.Store(fn);
} }
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
// Static member variable definitions. // Static member variable definitions.
constexpr uint32_t SpinLock::kSpinLockHeld; constexpr uint32_t SpinLock::kSpinLockHeld;
constexpr uint32_t SpinLock::kSpinLockCooperative; constexpr uint32_t SpinLock::kSpinLockCooperative;
constexpr uint32_t SpinLock::kSpinLockDisabledScheduling; constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
constexpr uint32_t SpinLock::kSpinLockSleeper; constexpr uint32_t SpinLock::kSpinLockSleeper;
constexpr uint32_t SpinLock::kWaitTimeMask; constexpr uint32_t SpinLock::kWaitTimeMask;
#endif
// Uncommon constructors. // Uncommon constructors.
SpinLock::SpinLock(base_internal::SchedulingMode mode) SpinLock::SpinLock(base_internal::SchedulingMode mode)
@ -128,9 +125,8 @@ void SpinLock::SlowLock() {
// it as having a sleeper. // it as having a sleeper.
if ((lock_value & kWaitTimeMask) == 0) { if ((lock_value & kWaitTimeMask) == 0) {
// Here, just "mark" that the thread is going to sleep. Don't store the // Here, just "mark" that the thread is going to sleep. Don't store the
// lock wait time in the lock -- the lock word stores the amount of time // lock wait time in the lock as that will cause the current lock
// that the current holder waited before acquiring the lock, not the wait // owner to think it experienced contention.
// time of any thread currently waiting to acquire it.
if (lockword_.compare_exchange_strong( if (lockword_.compare_exchange_strong(
lock_value, lock_value | kSpinLockSleeper, lock_value, lock_value | kSpinLockSleeper,
std::memory_order_relaxed, std::memory_order_relaxed)) { std::memory_order_relaxed, std::memory_order_relaxed)) {
@ -144,14 +140,6 @@ void SpinLock::SlowLock() {
// this thread obtains the lock. // this thread obtains the lock.
lock_value = TryLockInternal(lock_value, wait_cycles); lock_value = TryLockInternal(lock_value, wait_cycles);
continue; // Skip the delay at the end of the loop. continue; // Skip the delay at the end of the loop.
} else if ((lock_value & kWaitTimeMask) == 0) {
// The lock is still held, without a waiter being marked, but something
// else about the lock word changed, causing our CAS to fail. For
// example, a new lock holder may have acquired the lock with
// kSpinLockDisabledScheduling set, whereas the previous holder had not
// set that flag. In this case, attempt again to mark ourselves as a
// waiter.
continue;
} }
} }

@ -15,16 +15,17 @@
// //
// Most users requiring mutual exclusion should use Mutex. // Most users requiring mutual exclusion should use Mutex.
// SpinLock is provided for use in two situations: // SpinLock is provided for use in three situations:
// - for use by Abseil internal code that Mutex itself depends on // - for use in code that Mutex itself depends on
// - to get a faster fast-path release under low contention (without an
// atomic read-modify-write) In return, SpinLock has worse behaviour under
// contention, which is why Mutex is preferred in most situations.
// - for async signal safety (see below) // - for async signal safety (see below)
// SpinLock is async signal safe. If a spinlock is used within a signal // SpinLock is async signal safe. If a spinlock is used within a signal
// handler, all code that acquires the lock must ensure that the signal cannot // handler, all code that acquires the lock must ensure that the signal cannot
// arrive while they are holding the lock. Typically, this is done by blocking // arrive while they are holding the lock. Typically, this is done by blocking
// the signal. // the signal.
//
// Threads waiting on a SpinLock may be woken in an arbitrary order.
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_ #ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
#define ABSL_BASE_INTERNAL_SPINLOCK_H_ #define ABSL_BASE_INTERNAL_SPINLOCK_H_
@ -120,14 +121,6 @@ class ABSL_LOCKABLE SpinLock {
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0; return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
} }
// Return immediately if this thread holds the SpinLock exclusively.
// Otherwise, report an error by crashing with a diagnostic.
inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() {
if (!IsHeld()) {
ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
}
}
protected: protected:
// These should not be exported except for testing. // These should not be exported except for testing.
@ -147,20 +140,8 @@ class ABSL_LOCKABLE SpinLock {
// //
// bit[0] encodes whether a lock is being held. // bit[0] encodes whether a lock is being held.
// bit[1] encodes whether a lock uses cooperative scheduling. // bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether the current lock holder disabled scheduling when // bit[2] encodes whether a lock disables scheduling.
// acquiring the lock. Only set when kSpinLockHeld is also set.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int. // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
// This is set by the lock holder to indicate how long it waited on
// the lock before eventually acquiring it. The number of cycles is
// encoded as a 29-bit unsigned int, or in the case that the current
// holder did not wait but another waiter is queued, the LSB
// (kSpinLockSleeper) is set. The implementation does not explicitly
// track the number of queued waiters beyond this. It must always be
// assumed that waiters may exist if the current holder was required to
// queue.
//
// Invariant: if the lock is not held, the value is either 0 or
// kSpinLockCooperative.
static constexpr uint32_t kSpinLockHeld = 1; static constexpr uint32_t kSpinLockHeld = 1;
static constexpr uint32_t kSpinLockCooperative = 2; static constexpr uint32_t kSpinLockCooperative = 2;
static constexpr uint32_t kSpinLockDisabledScheduling = 4; static constexpr uint32_t kSpinLockDisabledScheduling = 4;

@ -20,7 +20,7 @@
extern "C" { extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */,
int /* loop */, absl::base_internal::SchedulingMode /* mode */) { int /* loop */, absl::base_internal::SchedulingMode /* mode */) {
// In Akaros, one must take care not to call anything that could cause a // In Akaros, one must take care not to call anything that could cause a
@ -29,7 +29,7 @@ ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
// arbitrary code. // arbitrary code.
} }
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C" } // extern "C"

@ -56,15 +56,18 @@ static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
extern "C" { extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int, std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode) { absl::base_internal::SchedulingMode) {
absl::base_internal::ErrnoSaver errno_saver; absl::base_internal::ErrnoSaver errno_saver;
syscall(SYS_futex, w, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, value, nullptr); 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);
} }
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(std::atomic<uint32_t> *w,
std::atomic<uint32_t> *w, bool all) { bool all) {
syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0); syscall(SYS_futex, w, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, all ? INT_MAX : 1, 0);
} }

@ -25,7 +25,7 @@
extern "C" { extern "C" {
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop, std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) { absl::base_internal::SchedulingMode /* mode */) {
absl::base_internal::ErrnoSaver errno_saver; absl::base_internal::ErrnoSaver errno_saver;
@ -40,7 +40,7 @@ ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
} }
} }
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake(
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} std::atomic<uint32_t>* /* lock_word */, bool /* all */) {}
} // extern "C" } // extern "C"

@ -39,22 +39,22 @@ struct SpinLockWaitTransition {
// satisfying 0<=i<n && trans[i].done, atomically make the transition, // satisfying 0<=i<n && trans[i].done, atomically make the transition,
// then return the old value of *w. Make any other atomic transitions // then return the old value of *w. Make any other atomic transitions
// where !trans[i].done, but continue waiting. // where !trans[i].done, but continue waiting.
//
// Wakeups for threads blocked on SpinLockWait do not respect priorities.
uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n,
const SpinLockWaitTransition trans[], const SpinLockWaitTransition trans[],
SchedulingMode scheduling_mode); SchedulingMode scheduling_mode);
// If possible, wake some thread that has called SpinLockDelay(w, ...). If `all` // If possible, wake some thread that has called SpinLockDelay(w, ...). If
// is true, wake all such threads. On some systems, this may be a no-op; on // "all" is true, wake all such threads. This call is a hint, and on some
// those systems, threads calling SpinLockDelay() will always wake eventually // systems it may be a no-op; threads calling SpinLockDelay() will always wake
// even if SpinLockWake() is never called. // eventually even if SpinLockWake() is never called.
void SpinLockWake(std::atomic<uint32_t> *w, bool all); void SpinLockWake(std::atomic<uint32_t> *w, bool all);
// Wait for an appropriate spin delay on iteration "loop" of a // Wait for an appropriate spin delay on iteration "loop" of a
// spin loop on location *w, whose previously observed value was "value". // spin loop on location *w, whose previously observed value was "value".
// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, // SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick,
// or may wait for a call to SpinLockWake(w). // or may wait for a delay that can be truncated by a call to SpinLockWake(w).
// In all cases, it must return in bounded time even if SpinLockWake() is not
// called.
void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop,
base_internal::SchedulingMode scheduling_mode); base_internal::SchedulingMode scheduling_mode);
@ -73,23 +73,21 @@ ABSL_NAMESPACE_END
// By changing our extension points to be extern "C", we dodge this // By changing our extension points to be extern "C", we dodge this
// check. // check.
extern "C" { extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(std::atomic<uint32_t> *w, void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all);
bool all); void AbslInternalSpinLockDelay(
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
std::atomic<uint32_t> *w, uint32_t value, int loop, std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode); absl::base_internal::SchedulingMode scheduling_mode);
} }
inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w, inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w,
bool all) { bool all) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)(w, all); AbslInternalSpinLockWake(w, all);
} }
inline void absl::base_internal::SpinLockDelay( inline void absl::base_internal::SpinLockDelay(
std::atomic<uint32_t> *w, uint32_t value, int loop, std::atomic<uint32_t> *w, uint32_t value, int loop,
absl::base_internal::SchedulingMode scheduling_mode) { absl::base_internal::SchedulingMode scheduling_mode) {
ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay) AbslInternalSpinLockDelay(w, value, loop, scheduling_mode);
(w, value, loop, scheduling_mode);
} }
#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ #endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_

@ -20,9 +20,9 @@
extern "C" { extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)( void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */,
std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop, uint32_t /* value */, int loop,
absl::base_internal::SchedulingMode /* mode */) { absl::base_internal::SchedulingMode /* mode */) {
if (loop == 0) { if (loop == 0) {
} else if (loop == 1) { } else if (loop == 1) {
Sleep(0); Sleep(0);
@ -31,7 +31,7 @@ void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockDelay)(
} }
} }
void ABSL_INTERNAL_C_SYMBOL(AbslInternalSpinLockWake)( void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */,
std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} bool /* all */) {}
} // extern "C" } // extern "C"

@ -51,6 +51,7 @@ const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
} }
std::string StrErrorInternal(int errnum) { std::string StrErrorInternal(int errnum) {
absl::base_internal::ErrnoSaver errno_saver;
char buf[100]; char buf[100];
const char* str = StrErrorAdaptor(errnum, buf, sizeof buf); const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
if (*str == '\0') { if (*str == '\0') {
@ -75,7 +76,6 @@ std::array<std::string, kSysNerr>* NewStrErrorTable() {
} // namespace } // namespace
std::string StrError(int errnum) { std::string StrError(int errnum) {
absl::base_internal::ErrnoSaver errno_saver;
static const auto* table = NewStrErrorTable(); static const auto* table = NewStrErrorTable();
if (errnum >= 0 && errnum < static_cast<int>(table->size())) { if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
return (*table)[errnum]; return (*table)[errnum];

@ -62,14 +62,12 @@ TEST(StrErrorTest, MultipleThreads) {
++counter; ++counter;
errno = ERANGE; errno = ERANGE;
const std::string value = absl::base_internal::StrError(i); const std::string value = absl::base_internal::StrError(i);
// EXPECT_* could change errno. Stash it first.
int check_err = errno;
EXPECT_THAT(check_err, Eq(ERANGE));
// Only the GNU implementation is guaranteed to provide the // Only the GNU implementation is guaranteed to provide the
// string "Unknown error nnn". POSIX doesn't say anything. // string "Unknown error nnn". POSIX doesn't say anything.
if (!absl::StartsWith(value, "Unknown error ")) { if (!absl::StartsWith(value, "Unknown error ")) {
EXPECT_THAT(value, Eq(expected_strings[i])); EXPECT_THAT(absl::base_internal::StrError(i), Eq(expected_strings[i]));
} }
EXPECT_THAT(errno, Eq(ERANGE));
} }
}; };

@ -61,77 +61,9 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
namespace {
#if defined(_WIN32)
// Returns number of bits set in `bitMask`
DWORD Win32CountSetBits(ULONG_PTR bitMask) {
for (DWORD bitSetCount = 0; ; ++bitSetCount) {
if (bitMask == 0) return bitSetCount;
bitMask &= bitMask - 1;
}
}
// Returns the number of logical CPUs using GetLogicalProcessorInformation(), or
// 0 if the number of processors is not available or can not be computed.
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformation
int Win32NumCPUs() {
#pragma comment(lib, "kernel32.lib")
using Info = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
DWORD info_size = sizeof(Info);
Info* info(static_cast<Info*>(malloc(info_size)));
if (info == nullptr) return 0;
bool success = GetLogicalProcessorInformation(info, &info_size);
if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
free(info);
info = static_cast<Info*>(malloc(info_size));
if (info == nullptr) return 0;
success = GetLogicalProcessorInformation(info, &info_size);
}
DWORD logicalProcessorCount = 0;
if (success) {
Info* ptr = info;
DWORD byteOffset = 0;
while (byteOffset + sizeof(Info) <= info_size) {
switch (ptr->Relationship) {
case RelationProcessorCore:
logicalProcessorCount += Win32CountSetBits(ptr->ProcessorMask);
break;
case RelationNumaNode:
case RelationCache:
case RelationProcessorPackage:
// Ignore other entries
break;
default:
// Ignore unknown entries
break;
}
byteOffset += sizeof(Info);
ptr++;
}
}
free(info);
return logicalProcessorCount;
}
#endif
} // namespace
static int GetNumCPUs() { static int GetNumCPUs() {
#if defined(__myriad2__) #if defined(__myriad2__)
return 1; return 1;
#elif defined(_WIN32)
const unsigned hardware_concurrency = Win32NumCPUs();
return hardware_concurrency ? hardware_concurrency : 1;
#elif defined(_AIX)
return sysconf(_SC_NPROCESSORS_ONLN);
#else #else
// Other possibilities: // Other possibilities:
// - Read /sys/devices/system/cpu/online and use cpumask_parse() // - Read /sys/devices/system/cpu/online and use cpumask_parse()
@ -494,7 +426,7 @@ pid_t GetTID() {
// userspace construct) to avoid unnecessary system calls. Without this caching, // userspace construct) to avoid unnecessary system calls. Without this caching,
// it can take roughly 98ns, while it takes roughly 1ns with this caching. // it can take roughly 98ns, while it takes roughly 1ns with this caching.
pid_t GetCachedTID() { pid_t GetCachedTID() {
#ifdef ABSL_HAVE_THREAD_LOCAL #if ABSL_HAVE_THREAD_LOCAL
static thread_local pid_t thread_id = GetTID(); static thread_local pid_t thread_id = GetTID();
return thread_id; return thread_id;
#else #else

@ -37,6 +37,18 @@ TEST(SysinfoTest, NumCPUs) {
<< "NumCPUs() should not have the default value of 0"; << "NumCPUs() should not have the default value of 0";
} }
TEST(SysinfoTest, NominalCPUFrequency) {
#if !(defined(__aarch64__) && defined(__linux__)) && !defined(__EMSCRIPTEN__)
EXPECT_GE(NominalCPUFrequency(), 1000.0)
<< "NominalCPUFrequency() did not return a reasonable value";
#else
// Aarch64 cannot read the CPU frequency from sysfs, so we get back 1.0.
// Emscripten does not have a sysfs to read from at all.
EXPECT_EQ(NominalCPUFrequency(), 1.0)
<< "CPU frequency detection was fixed! Please update unittest.";
#endif
}
TEST(SysinfoTest, GetTID) { TEST(SysinfoTest, GetTID) {
EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test. EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test.
#ifdef __native_client__ #ifdef __native_client__

@ -14,7 +14,7 @@
#include "absl/base/internal/thread_identity.h" #include "absl/base/internal/thread_identity.h"
#if !defined(_WIN32) || defined(__MINGW32__) #ifndef _WIN32
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#endif #endif
@ -23,7 +23,6 @@
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include "absl/base/attributes.h"
#include "absl/base/call_once.h" #include "absl/base/call_once.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h" #include "absl/base/internal/spinlock.h"
@ -54,12 +53,9 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
// exist within a process (via dlopen() or similar), references to // exist within a process (via dlopen() or similar), references to
// thread_identity_ptr from each instance of the code will refer to // thread_identity_ptr from each instance of the code will refer to
// *different* instances of this ptr. // *different* instances of this ptr.
// Apple platforms have the visibility attribute, but issue a compile warning #ifdef __GNUC__
// that protected visibility is unsupported.
ABSL_CONST_INIT // Must come before __attribute__((visibility("protected")))
#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
__attribute__((visibility("protected"))) __attribute__((visibility("protected")))
#endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__) #endif // __GNUC__
#if ABSL_PER_THREAD_TLS #if ABSL_PER_THREAD_TLS
// Prefer __thread to thread_local as benchmarks indicate it is a bit faster. // Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr; ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
@ -121,10 +117,10 @@ void SetCurrentThreadIdentity(
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
// Please see the comment on `CurrentThreadIdentityIfPresent` in // Please see the comment on `CurrentThreadIdentityIfPresent` in
// thread_identity.h. When we cannot expose thread_local variables in // thread_identity.h. Because DLLs cannot expose thread_local variables in
// headers, we opt for the correct-but-slower option of not inlining this // headers, we opt for the correct-but-slower option of placing the definition
// function. // of this function only in a translation unit inside DLL.
#ifndef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT #if defined(ABSL_BUILD_DLL) || defined(ABSL_CONSUME_DLL)
ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; } ThreadIdentity* CurrentThreadIdentityIfPresent() { return thread_identity_ptr; }
#endif #endif
#endif #endif

@ -32,7 +32,6 @@
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/per_thread_tls.h" #include "absl/base/internal/per_thread_tls.h"
#include "absl/base/optimization.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
@ -70,28 +69,30 @@ struct PerThreadSynch {
// is using this PerThreadSynch as a terminator. Its // is using this PerThreadSynch as a terminator. Its
// skip field must not be filled in because the loop // skip field must not be filled in because the loop
// might then skip over the terminator. // might then skip over the terminator.
bool wake; // This thread is to be woken from a Mutex.
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the // The wait parameters of the current wait. waitp is null if the
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await. // thread is not waiting. Transitions from null to non-null must
// // occur before the enqueue commit point (state = kQueued in
// The value of "x->cond_waiter" is meaningless if "x" is not on a // Enqueue() and CondVarEnqueue()). Transitions from non-null to
// Mutex waiter list. // null must occur after the wait is finished (state = kAvailable in
bool cond_waiter; // Mutex::Block() and CondVar::WaitCommon()). This field may be
bool maybe_unlocking; // Valid at head of Mutex waiter queue; // changed only by the thread that describes this PerThreadSynch. A
// true if UnlockSlow could be searching // special case is Fer(), which calls Enqueue() on another thread,
// for a waiter to wake. Used for an optimization // but with an identical SynchWaitParams pointer, thus leaving the
// in Enqueue(). true is always a valid value. // pointer unchanged.
// Can be reset to false when the unlocker or any SynchWaitParams *waitp;
// writer releases the lock, or a reader fully
// releases the lock. It may not be set to false bool suppress_fatal_errors; // If true, try to proceed even in the face of
// by a reader that decrements the count to // broken invariants. This is used within fatal
// non-zero. protected by mutex spinlock // signal handlers to improve the chances of
bool suppress_fatal_errors; // If true, try to proceed even in the face // debug logging information being output
// of broken invariants. This is used within // successfully.
// fatal signal handlers to improve the
// chances of debug logging information being intptr_t readers; // Number of readers in mutex.
// output successfully. int priority; // Priority of thread (updated every so often).
int priority; // Priority of thread (updated every so often).
// When priority will next be read (cycles).
int64_t next_priority_read_cycles;
// State values: // State values:
// kAvailable: This PerThreadSynch is available. // kAvailable: This PerThreadSynch is available.
@ -110,30 +111,30 @@ struct PerThreadSynch {
}; };
std::atomic<State> state; std::atomic<State> state;
// The wait parameters of the current wait. waitp is null if the bool maybe_unlocking; // Valid at head of Mutex waiter queue;
// thread is not waiting. Transitions from null to non-null must // true if UnlockSlow could be searching
// occur before the enqueue commit point (state = kQueued in // for a waiter to wake. Used for an optimization
// Enqueue() and CondVarEnqueue()). Transitions from non-null to // in Enqueue(). true is always a valid value.
// null must occur after the wait is finished (state = kAvailable in // Can be reset to false when the unlocker or any
// Mutex::Block() and CondVar::WaitCommon()). This field may be // writer releases the lock, or a reader fully releases
// changed only by the thread that describes this PerThreadSynch. A // the lock. It may not be set to false by a reader
// special case is Fer(), which calls Enqueue() on another thread, // that decrements the count to non-zero.
// but with an identical SynchWaitParams pointer, thus leaving the // protected by mutex spinlock
// pointer unchanged.
SynchWaitParams* waitp;
intptr_t readers; // Number of readers in mutex. bool wake; // This thread is to be woken from a Mutex.
// When priority will next be read (cycles). // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
int64_t next_priority_read_cycles; // waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
//
// The value of "x->cond_waiter" is meaningless if "x" is not on a
// Mutex waiter list.
bool cond_waiter;
// Locks held; used during deadlock detection. // Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld *all_locks; SynchLocksHeld *all_locks;
}; };
// The instances of this class are allocated in NewThreadIdentity() with an
// alignment of PerThreadSynch::kAlignment.
struct ThreadIdentity { struct ThreadIdentity {
// Must be the first member. The Mutex implementation requires that // Must be the first member. The Mutex implementation requires that
// the PerThreadSynch object associated with each thread is // the PerThreadSynch object associated with each thread is
@ -143,7 +144,7 @@ struct ThreadIdentity {
// Private: Reserved for absl::synchronization_internal::Waiter. // Private: Reserved for absl::synchronization_internal::Waiter.
struct WaiterState { struct WaiterState {
alignas(void*) char data[128]; char data[128];
} waiter_state; } waiter_state;
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter(). // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
@ -188,32 +189,30 @@ void ClearCurrentThreadIdentity();
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode // May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
// index> // index>
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC #ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set #error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set
#else #else
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0 #define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
#endif #endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS #ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set #error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set
#else #else
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1 #define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
#endif #endif
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11 #ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set #error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set
#else #else
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2 #define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
#endif #endif
#ifdef ABSL_THREAD_IDENTITY_MODE #ifdef ABSL_THREAD_IDENTITY_MODE
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set #error ABSL_THREAD_IDENTITY_MODE cannot be direcly set
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE) #elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE #define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
#elif defined(_WIN32) && !defined(__MINGW32__) #elif defined(_WIN32) && !defined(__MINGW32__)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 #define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL) #elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
(__GOOGLE_GRTE_VERSION__ >= 20140228L) (__GOOGLE_GRTE_VERSION__ >= 20140228L)
// Support for async-safe TLS was specifically added in GRTEv4. It's not // Support for async-safe TLS was specifically added in GRTEv4. It's not
// present in the upstream eglibc. // present in the upstream eglibc.
@ -236,18 +235,13 @@ ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
#error Thread-local storage not detected on this platform #error Thread-local storage not detected on this platform
#endif #endif
// thread_local variables cannot be in headers exposed by DLLs or in certain // thread_local variables cannot be in headers exposed by DLLs. However, it is
// build configurations on Apple platforms. However, it is important for // important for performance reasons in general that
// performance reasons in general that `CurrentThreadIdentityIfPresent` be // `CurrentThreadIdentityIfPresent` be inlined. This is not possible across a
// inlined. In the other cases we opt to have the function not be inlined. Note // DLL boundary so, with DLLs, we opt to have the function not be inlined. Note
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude // that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
// this entire inline definition. // this entire inline definition when compiling as a DLL.
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \ #if !defined(ABSL_BUILD_DLL) && !defined(ABSL_CONSUME_DLL)
!defined(ABSL_CONSUME_DLL)
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
#endif
#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
inline ThreadIdentity* CurrentThreadIdentityIfPresent() { inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
return thread_identity_ptr; return thread_identity_ptr;
} }

@ -18,7 +18,6 @@
#include <functional> #include <functional>
#include <new> #include <new>
#include <stdexcept> #include <stdexcept>
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
@ -26,186 +25,83 @@ namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
// NOTE: The various STL exception throwing functions are placed within the
// #ifdef blocks so the symbols aren't exposed on platforms that don't support
// them, such as the Android NDK. For example, ANGLE fails to link when building
// within AOSP without them, since the STL functions don't exist.
namespace { namespace {
#ifdef ABSL_HAVE_EXCEPTIONS
template <typename T> template <typename T>
[[noreturn]] void Throw(const T& error) { [[noreturn]] void Throw(const T& error) {
#ifdef ABSL_HAVE_EXCEPTIONS
throw error; throw error;
} #else
ABSL_RAW_LOG(FATAL, "%s", error.what());
std::abort();
#endif #endif
}
} // namespace } // namespace
void ThrowStdLogicError(const std::string& what_arg) { void ThrowStdLogicError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::logic_error(what_arg)); Throw(std::logic_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdLogicError(const char* what_arg) { void ThrowStdLogicError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::logic_error(what_arg)); Throw(std::logic_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdInvalidArgument(const std::string& what_arg) { void ThrowStdInvalidArgument(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::invalid_argument(what_arg)); Throw(std::invalid_argument(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdInvalidArgument(const char* what_arg) { void ThrowStdInvalidArgument(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::invalid_argument(what_arg)); Throw(std::invalid_argument(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdDomainError(const std::string& what_arg) { void ThrowStdDomainError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::domain_error(what_arg)); Throw(std::domain_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdDomainError(const char* what_arg) { void ThrowStdDomainError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::domain_error(what_arg)); Throw(std::domain_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdLengthError(const std::string& what_arg) { void ThrowStdLengthError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::length_error(what_arg)); Throw(std::length_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdLengthError(const char* what_arg) { void ThrowStdLengthError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::length_error(what_arg)); Throw(std::length_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdOutOfRange(const std::string& what_arg) { void ThrowStdOutOfRange(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::out_of_range(what_arg)); Throw(std::out_of_range(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdOutOfRange(const char* what_arg) { void ThrowStdOutOfRange(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::out_of_range(what_arg)); Throw(std::out_of_range(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdRuntimeError(const std::string& what_arg) { void ThrowStdRuntimeError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::runtime_error(what_arg)); Throw(std::runtime_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdRuntimeError(const char* what_arg) { void ThrowStdRuntimeError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::runtime_error(what_arg)); Throw(std::runtime_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdRangeError(const std::string& what_arg) { void ThrowStdRangeError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::range_error(what_arg)); Throw(std::range_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdRangeError(const char* what_arg) { void ThrowStdRangeError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::range_error(what_arg)); Throw(std::range_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdOverflowError(const std::string& what_arg) { void ThrowStdOverflowError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::overflow_error(what_arg)); Throw(std::overflow_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdOverflowError(const char* what_arg) { void ThrowStdOverflowError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::overflow_error(what_arg)); Throw(std::overflow_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdUnderflowError(const std::string& what_arg) { void ThrowStdUnderflowError(const std::string& what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::underflow_error(what_arg)); Throw(std::underflow_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg.c_str());
std::abort();
#endif
} }
void ThrowStdUnderflowError(const char* what_arg) { void ThrowStdUnderflowError(const char* what_arg) {
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::underflow_error(what_arg)); Throw(std::underflow_error(what_arg));
#else
ABSL_RAW_LOG(FATAL, "%s", what_arg);
std::abort();
#endif
} }
void ThrowStdBadFunctionCall() { void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::bad_function_call());
#else
std::abort();
#endif
}
void ThrowStdBadAlloc() { void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
#ifdef ABSL_HAVE_EXCEPTIONS
Throw(std::bad_alloc());
#else
std::abort();
#endif
}
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END

@ -31,6 +31,80 @@
// The unaligned API is C++ only. The declarations use C++ features // The unaligned API is C++ only. The declarations use C++ features
// (namespaces, inline) which are absent or incompatible in C. // (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus) #if defined(__cplusplus)
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
defined(ABSL_HAVE_THREAD_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
// Consider we have an unaligned load/store of 4 bytes from address 0x...05.
// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
// will miss a bug if 08 is the first unaddressable byte.
// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
// miss a race between this access and some other accesses to 08.
// MemorySanitizer will correctly propagate the shadow on unaligned stores
// and correctly report bugs on unaligned loads, but it may not properly
// update and report the origin of the uninitialized memory.
// For all three tools, replacing an unaligned access with a tool-specific
// callback solves the problem.
// Make sure uint16_t/uint32_t/uint64_t are defined.
#include <stdint.h>
extern "C" {
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t v);
void __sanitizer_unaligned_store32(void *p, uint32_t v);
void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32_t UnalignedLoad32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64_t UnalignedLoad64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void UnalignedStore16(void *p, uint16_t v) {
__sanitizer_unaligned_store16(p, v);
}
inline void UnalignedStore32(void *p, uint32_t v) {
__sanitizer_unaligned_store32(p, v);
}
inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
(absl::base_internal::UnalignedLoad16(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
(absl::base_internal::UnalignedLoad32(_p))
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
(absl::base_internal::UnalignedLoad64(_p))
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
(absl::base_internal::UnalignedStore16(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
(absl::base_internal::UnalignedStore32(_p, _val))
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val))
#else
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
@ -77,6 +151,8 @@ ABSL_NAMESPACE_END
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ #define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
(absl::base_internal::UnalignedStore64(_p, _val)) (absl::base_internal::UnalignedStore64(_p, _val))
#endif
#endif // defined(__cplusplus), end of unaligned API #endif // defined(__cplusplus), end of unaligned API
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ #endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_

@ -24,13 +24,8 @@
#ifdef __GLIBC__ #ifdef __GLIBC__
#include <sys/platform/ppc.h> #include <sys/platform/ppc.h>
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
// clang-format off
// This order does actually matter =(.
#include <sys/types.h>
#include <sys/sysctl.h> #include <sys/sysctl.h>
// clang-format on #include <sys/types.h>
#include "absl/base/call_once.h"
#endif #endif
#endif #endif
@ -54,6 +49,12 @@ double UnscaledCycleClock::Frequency() {
#elif defined(__x86_64__) #elif defined(__x86_64__)
int64_t UnscaledCycleClock::Now() {
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
}
double UnscaledCycleClock::Frequency() { double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency(); return base_internal::NominalCPUFrequency();
} }
@ -86,10 +87,6 @@ int64_t UnscaledCycleClock::Now() {
double UnscaledCycleClock::Frequency() { double UnscaledCycleClock::Frequency() {
#ifdef __GLIBC__ #ifdef __GLIBC__
return __ppc_get_timebase_freq(); return __ppc_get_timebase_freq();
#elif defined(_AIX)
// This is the same constant value as returned by
// __ppc_get_timebase_freq().
return static_cast<double>(512000000);
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
static once_flag init_timebase_frequency_once; static once_flag init_timebase_frequency_once;
static double timebase_frequency = 0.0; static double timebase_frequency = 0.0;
@ -122,23 +119,13 @@ double UnscaledCycleClock::Frequency() {
return aarch64_timer_frequency; return aarch64_timer_frequency;
} }
#elif defined(__riscv)
int64_t UnscaledCycleClock::Now() {
int64_t virtual_timer_value;
asm volatile("rdcycle %0" : "=r"(virtual_timer_value));
return virtual_timer_value;
}
double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency();
}
#elif defined(_M_IX86) || defined(_M_X64) #elif defined(_M_IX86) || defined(_M_X64)
#pragma intrinsic(__rdtsc) #pragma intrinsic(__rdtsc)
int64_t UnscaledCycleClock::Now() { return __rdtsc(); } int64_t UnscaledCycleClock::Now() {
return __rdtsc();
}
double UnscaledCycleClock::Frequency() { double UnscaledCycleClock::Frequency() {
return base_internal::NominalCPUFrequency(); return base_internal::NominalCPUFrequency();

@ -46,8 +46,8 @@
// The following platforms have an implementation of a hardware counter. // The following platforms have an implementation of a hardware counter.
#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__riscv) || \ defined(__powerpc__) || defined(__ppc__) || \
defined(_M_IX86) || (defined(_M_X64) && !defined(_M_ARM64EC)) defined(_M_IX86) || defined(_M_X64)
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1 #define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1
#else #else
#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0 #define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0
@ -59,7 +59,8 @@
// CycleClock that runs at atleast 1 MHz. We've found some Android // CycleClock that runs at atleast 1 MHz. We've found some Android
// ARM64 devices where this is not the case, so we disable it by // ARM64 devices where this is not the case, so we disable it by
// default on Android ARM64. // default on Android ARM64.
#if defined(__native_client__) || (defined(__APPLE__)) || \ #if defined(__native_client__) || \
(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || \
(defined(__ANDROID__) && defined(__aarch64__)) (defined(__ANDROID__) && defined(__aarch64__))
#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0 #define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0
#else #else
@ -79,8 +80,8 @@
// This macro can be used to test if UnscaledCycleClock::Frequency() // This macro can be used to test if UnscaledCycleClock::Frequency()
// is NominalCPUFrequency() on a particular platform. // is NominalCPUFrequency() on a particular platform.
#if (defined(__i386__) || defined(__x86_64__) || defined(__riscv) || \ #if (defined(__i386__) || defined(__x86_64__) || \
defined(_M_IX86) || defined(_M_X64)) defined(_M_IX86) || defined(_M_X64))
#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY #define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY
#endif #endif
@ -114,16 +115,6 @@ class UnscaledCycleClock {
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency; friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
}; };
#if defined(__x86_64__)
inline int64_t UnscaledCycleClock::Now() {
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
}
#endif
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -31,14 +31,6 @@ namespace {
int Function(int a, int b) { return a - b; } int Function(int a, int b) { return a - b; }
void VoidFunction(int& a, int& b) {
a += b;
b = a - b;
a -= b;
}
int ZeroArgFunction() { return -1937; }
int Sink(std::unique_ptr<int> p) { int Sink(std::unique_ptr<int> p) {
return *p; return *p;
} }
@ -231,100 +223,6 @@ TEST(InvokeTest, SfinaeFriendly) {
EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42)); EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42));
} }
TEST(IsInvocableRTest, CallableExactMatch) {
static_assert(
base_internal::is_invocable_r<int, decltype(Function), int, int>::value,
"Should be true for exact match of types on a free function");
}
TEST(IsInvocableRTest, CallableArgumentConversionMatch) {
static_assert(
base_internal::is_invocable_r<int, decltype(Function), char, int>::value,
"Should be true for convertible argument type");
}
TEST(IsInvocableRTest, CallableReturnConversionMatch) {
static_assert(base_internal::is_invocable_r<double, decltype(Function), int,
int>::value,
"Should be true for convertible return type");
}
TEST(IsInvocableRTest, CallableReturnVoid) {
static_assert(base_internal::is_invocable_r<void, decltype(VoidFunction),
int&, int&>::value,
"Should be true for void expected and actual return types");
static_assert(
base_internal::is_invocable_r<void, decltype(Function), int, int>::value,
"Should be true for void expected and non-void actual return types");
}
TEST(IsInvocableRTest, CallableRefQualifierMismatch) {
static_assert(!base_internal::is_invocable_r<void, decltype(VoidFunction),
int&, const int&>::value,
"Should be false for reference constness mismatch");
static_assert(!base_internal::is_invocable_r<void, decltype(VoidFunction),
int&&, int&>::value,
"Should be false for reference value category mismatch");
}
TEST(IsInvocableRTest, CallableArgumentTypeMismatch) {
static_assert(!base_internal::is_invocable_r<int, decltype(Function),
std::string, int>::value,
"Should be false for argument type mismatch");
}
TEST(IsInvocableRTest, CallableReturnTypeMismatch) {
static_assert(!base_internal::is_invocable_r<std::string, decltype(Function),
int, int>::value,
"Should be false for return type mismatch");
}
TEST(IsInvocableRTest, CallableTooFewArgs) {
static_assert(
!base_internal::is_invocable_r<int, decltype(Function), int>::value,
"Should be false for too few arguments");
}
TEST(IsInvocableRTest, CallableTooManyArgs) {
static_assert(!base_internal::is_invocable_r<int, decltype(Function), int,
int, int>::value,
"Should be false for too many arguments");
}
TEST(IsInvocableRTest, MemberFunctionAndReference) {
static_assert(base_internal::is_invocable_r<int, decltype(&Class::Method),
Class&, int, int>::value,
"Should be true for exact match of types on a member function "
"and class reference");
}
TEST(IsInvocableRTest, MemberFunctionAndPointer) {
static_assert(base_internal::is_invocable_r<int, decltype(&Class::Method),
Class*, int, int>::value,
"Should be true for exact match of types on a member function "
"and class pointer");
}
TEST(IsInvocableRTest, DataMemberAndReference) {
static_assert(base_internal::is_invocable_r<int, decltype(&Class::member),
Class&>::value,
"Should be true for exact match of types on a data member and "
"class reference");
}
TEST(IsInvocableRTest, DataMemberAndPointer) {
static_assert(base_internal::is_invocable_r<int, decltype(&Class::member),
Class*>::value,
"Should be true for exact match of types on a data member and "
"class pointer");
}
TEST(IsInvocableRTest, CallableZeroArgs) {
static_assert(
base_internal::is_invocable_r<int, decltype(ZeroArgFunction)>::value,
"Should be true for exact match for a zero-arg free function");
}
} // namespace } // namespace
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END

@ -16,8 +16,6 @@
#include <ostream> #include <ostream>
#include "absl/base/attributes.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
@ -25,31 +23,5 @@ std::ostream& operator<<(std::ostream& os, absl::LogSeverity s) {
if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s); if (s == absl::NormalizeLogSeverity(s)) return os << absl::LogSeverityName(s);
return os << "absl::LogSeverity(" << static_cast<int>(s) << ")"; return os << "absl::LogSeverity(" << static_cast<int>(s) << ")";
} }
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s) {
switch (s) {
case absl::LogSeverityAtLeast::kInfo:
case absl::LogSeverityAtLeast::kWarning:
case absl::LogSeverityAtLeast::kError:
case absl::LogSeverityAtLeast::kFatal:
return os << ">=" << static_cast<absl::LogSeverity>(s);
case absl::LogSeverityAtLeast::kInfinity:
return os << "INFINITY";
}
return os;
}
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s) {
switch (s) {
case absl::LogSeverityAtMost::kInfo:
case absl::LogSeverityAtMost::kWarning:
case absl::LogSeverityAtMost::kError:
case absl::LogSeverityAtMost::kFatal:
return os << "<=" << static_cast<absl::LogSeverity>(s);
case absl::LogSeverityAtMost::kNegativeInfinity:
return os << "NEGATIVE_INFINITY";
}
return os;
}
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef ABSL_BASE_LOG_SEVERITY_H_ #ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#define ABSL_BASE_LOG_SEVERITY_H_ #define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_
#include <array> #include <array>
#include <ostream> #include <ostream>
@ -36,7 +36,7 @@ ABSL_NAMESPACE_BEGIN
// such values to a defined severity level, however in some cases values other // such values to a defined severity level, however in some cases values other
// than the defined levels are useful for comparison. // than the defined levels are useful for comparison.
// //
// Example: // Exmaple:
// //
// // Effectively disables all logging: // // Effectively disables all logging:
// SetMinLogLevel(static_cast<absl::LogSeverity>(100)); // SetMinLogLevel(static_cast<absl::LogSeverity>(100));
@ -115,58 +115,7 @@ constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
// unspecified; do not rely on it. // unspecified; do not rely on it.
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s); std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
// Enums representing a lower bound for LogSeverity. APIs that only operate on
// messages of at least a certain level (for example, `SetMinLogLevel()`) use
// this type to specify that level. absl::LogSeverityAtLeast::kInfinity is
// a level above all threshold levels and therefore no log message will
// ever meet this threshold.
enum class LogSeverityAtLeast : int {
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
kInfinity = 1000,
};
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s);
// Enums representing an upper bound for LogSeverity. APIs that only operate on
// messages of at most a certain level (for example, buffer all messages at or
// below a certain level) use this type to specify that level.
// absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold
// levels and therefore will exclude all log messages.
enum class LogSeverityAtMost : int {
kNegativeInfinity = -1000,
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
kError = static_cast<int>(absl::LogSeverity::kError),
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
};
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s);
#define COMPOP(op1, op2, T) \
constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) { \
return static_cast<absl::LogSeverity>(lhs) op1 rhs; \
} \
constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) { \
return lhs op2 static_cast<absl::LogSeverity>(rhs); \
}
// Comparisons between `LogSeverity` and `LogSeverityAtLeast`/
// `LogSeverityAtMost` are only supported in one direction.
// Valid checks are:
// LogSeverity >= LogSeverityAtLeast
// LogSeverity < LogSeverityAtLeast
// LogSeverity <= LogSeverityAtMost
// LogSeverity > LogSeverityAtMost
COMPOP(>, <, LogSeverityAtLeast)
COMPOP(<=, >=, LogSeverityAtLeast)
COMPOP(<, >, LogSeverityAtMost)
COMPOP(>=, <=, LogSeverityAtMost)
#undef COMPOP
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
#endif // ABSL_BASE_LOG_SEVERITY_H_ #endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_

@ -35,8 +35,7 @@ using ::testing::IsTrue;
using ::testing::TestWithParam; using ::testing::TestWithParam;
using ::testing::Values; using ::testing::Values;
template <typename T> std::string StreamHelper(absl::LogSeverity value) {
std::string StreamHelper(T value) {
std::ostringstream stream; std::ostringstream stream;
stream << value; stream << value;
return stream.str(); return stream.str();
@ -53,9 +52,9 @@ TEST(StreamTest, Works) {
Eq("absl::LogSeverity(4)")); Eq("absl::LogSeverity(4)"));
} }
static_assert(absl::flags_internal::FlagUseValueAndInitBitStorage< static_assert(
absl::LogSeverity>::value, absl::flags_internal::FlagUseOneWordStorage<absl::LogSeverity>::value,
"Flags of type absl::LogSeverity ought to be lock-free."); "Flags of type absl::LogSeverity ought to be lock-free.");
using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>; using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -202,44 +201,4 @@ TEST_P(UnparseFlagToOtherIntegerTest, ReturnsExpectedValueAndRoundTrips) {
IsTrue()); IsTrue());
EXPECT_THAT(reparsed_value, Eq(to_unparse)); EXPECT_THAT(reparsed_value, Eq(to_unparse));
} }
TEST(LogThresholdTest, LogSeverityAtLeastTest) {
EXPECT_LT(absl::LogSeverity::kError, absl::LogSeverityAtLeast::kFatal);
EXPECT_GT(absl::LogSeverityAtLeast::kError, absl::LogSeverity::kInfo);
EXPECT_LE(absl::LogSeverityAtLeast::kInfo, absl::LogSeverity::kError);
EXPECT_GE(absl::LogSeverity::kError, absl::LogSeverityAtLeast::kInfo);
}
TEST(LogThresholdTest, LogSeverityAtMostTest) {
EXPECT_GT(absl::LogSeverity::kError, absl::LogSeverityAtMost::kWarning);
EXPECT_LT(absl::LogSeverityAtMost::kError, absl::LogSeverity::kFatal);
EXPECT_GE(absl::LogSeverityAtMost::kFatal, absl::LogSeverity::kError);
EXPECT_LE(absl::LogSeverity::kWarning, absl::LogSeverityAtMost::kError);
}
TEST(LogThresholdTest, Extremes) {
EXPECT_LT(absl::LogSeverity::kFatal, absl::LogSeverityAtLeast::kInfinity);
EXPECT_GT(absl::LogSeverity::kInfo,
absl::LogSeverityAtMost::kNegativeInfinity);
}
TEST(LogThresholdTest, Output) {
EXPECT_THAT(StreamHelper(absl::LogSeverityAtLeast::kInfo), Eq(">=INFO"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtLeast::kWarning),
Eq(">=WARNING"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtLeast::kError), Eq(">=ERROR"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtLeast::kFatal), Eq(">=FATAL"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtLeast::kInfinity),
Eq("INFINITY"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtMost::kInfo), Eq("<=INFO"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtMost::kWarning), Eq("<=WARNING"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtMost::kError), Eq("<=ERROR"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtMost::kFatal), Eq("<=FATAL"));
EXPECT_THAT(StreamHelper(absl::LogSeverityAtMost::kNegativeInfinity),
Eq("NEGATIVE_INFINITY"));
}
} // namespace } // namespace

@ -144,15 +144,4 @@ ABSL_NAMESPACE_END
#define ABSL_INTERNAL_RETHROW do {} while (false) #define ABSL_INTERNAL_RETHROW do {} while (false)
#endif // ABSL_HAVE_EXCEPTIONS #endif // ABSL_HAVE_EXCEPTIONS
// `ABSL_INTERNAL_UNREACHABLE` is an unreachable statement. A program which
// reaches one has undefined behavior, and the compiler may optimize
// accordingly.
#if defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_INTERNAL_UNREACHABLE __builtin_unreachable()
#elif defined(_MSC_VER)
#define ABSL_INTERNAL_UNREACHABLE __assume(0)
#else
#define ABSL_INTERNAL_UNREACHABLE
#endif
#endif // ABSL_BASE_MACROS_H_ #endif // ABSL_BASE_MACROS_H_

@ -22,15 +22,13 @@
#ifndef ABSL_BASE_OPTIMIZATION_H_ #ifndef ABSL_BASE_OPTIMIZATION_H_
#define ABSL_BASE_OPTIMIZATION_H_ #define ABSL_BASE_OPTIMIZATION_H_
#include <assert.h>
#include "absl/base/config.h" #include "absl/base/config.h"
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION // ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
// //
// Instructs the compiler to avoid optimizing tail-call recursion. This macro is // Instructs the compiler to avoid optimizing tail-call recursion. Use of this
// useful when you wish to preserve the existing function order within a stack // macro is useful when you wish to preserve the existing function order within
// trace for logging, debugging, or profiling purposes. // a stack trace for logging, debugging, or profiling purposes.
// //
// Example: // Example:
// //
@ -106,10 +104,9 @@
// Cacheline aligning objects properly allows constructive memory sharing and // Cacheline aligning objects properly allows constructive memory sharing and
// prevents destructive (or "false") memory sharing. // prevents destructive (or "false") memory sharing.
// //
// NOTE: callers should replace uses of this macro with `alignas()` using // NOTE: this macro should be replaced with usage of `alignas()` using
// `std::hardware_constructive_interference_size` and/or // `std::hardware_constructive_interference_size` and/or
// `std::hardware_destructive_interference_size` when C++17 becomes available to // `std::hardware_destructive_interference_size` when available within C++17.
// them.
// //
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html // See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
// for more information. // for more information.
@ -181,43 +178,35 @@
#define ABSL_PREDICT_TRUE(x) (x) #define ABSL_PREDICT_TRUE(x) (x)
#endif #endif
// ABSL_ASSUME(cond) // ABSL_INTERNAL_ASSUME(cond)
// // Informs the compiler than a condition is always true and that it can assume
// Informs the compiler that a condition is always true and that it can assume // it to be true for optimization purposes. The call has undefined behavior if
// it to be true for optimization purposes. // the condition is false.
//
// WARNING: If the condition is false, the program can produce undefined and
// potentially dangerous behavior.
//
// In !NDEBUG mode, the condition is checked with an assert(). // In !NDEBUG mode, the condition is checked with an assert().
// // NOTE: The expression must not have side effects, as it will only be evaluated
// NOTE: The expression must not have side effects, as it may only be evaluated // in some compilation modes and not others.
// in some compilation modes and not others. Some compilers may issue a warning
// if the compiler cannot prove the expression has no side effects. For example,
// the expression should not use a function call since the compiler cannot prove
// that a function call does not have side effects.
// //
// Example: // Example:
// //
// int x = ...; // int x = ...;
// ABSL_ASSUME(x >= 0); // ABSL_INTERNAL_ASSUME(x >= 0);
// // The compiler can optimize the division to a simple right shift using the // // The compiler can optimize the division to a simple right shift using the
// // assumption specified above. // // assumption specified above.
// int y = x / 16; // int y = x / 16;
// //
#if !defined(NDEBUG) #if !defined(NDEBUG)
#define ABSL_ASSUME(cond) assert(cond) #define ABSL_INTERNAL_ASSUME(cond) assert(cond)
#elif ABSL_HAVE_BUILTIN(__builtin_assume) #elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_ASSUME(cond) __builtin_assume(cond) #define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable) #elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_ASSUME(cond) \ #define ABSL_INTERNAL_ASSUME(cond) \
do { \ do { \
if (!(cond)) __builtin_unreachable(); \ if (!(cond)) __builtin_unreachable(); \
} while (0) } while (0)
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define ABSL_ASSUME(cond) __assume(cond) #define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
#else #else
#define ABSL_ASSUME(cond) \ #define ABSL_INTERNAL_ASSUME(cond) \
do { \ do { \
static_cast<void>(false && (cond)); \ static_cast<void>(false && (cond)); \
} while (0) } while (0)
@ -227,7 +216,7 @@
// This macro forces small unique name on a static file level symbols like // This macro forces small unique name on a static file level symbols like
// static local variables or static functions. This is intended to be used in // static local variables or static functions. This is intended to be used in
// macro definitions to optimize the cost of generated code. Do NOT use it on // macro definitions to optimize the cost of generated code. Do NOT use it on
// symbols exported from translation unit since it may cause a link time // symbols exported from translation unit since it may casue a link time
// conflict. // conflict.
// //
// Example: // Example:

@ -206,7 +206,7 @@
// allowed. // allowed.
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20220623 #define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_09_23
// ABSL_OPTION_HARDENED // ABSL_OPTION_HARDENED
// //

@ -14,6 +14,7 @@
// //
// This files is a forwarding header for other headers containing various // This files is a forwarding header for other headers containing various
// portability macros and functions. // portability macros and functions.
// This file is used for both C and C++!
#ifndef ABSL_BASE_PORT_H_ #ifndef ABSL_BASE_PORT_H_
#define ABSL_BASE_PORT_H_ #define ABSL_BASE_PORT_H_

@ -92,7 +92,6 @@ static void TestFunction(int thread_salt, SpinLock* spinlock) {
static void ThreadedTest(SpinLock* spinlock) { static void ThreadedTest(SpinLock* spinlock) {
std::vector<std::thread> threads; std::vector<std::thread> threads;
threads.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i) { for (int i = 0; i < kNumThreads; ++i) {
threads.push_back(std::thread(TestFunction, i, spinlock)); threads.push_back(std::thread(TestFunction, i, spinlock));
} }

@ -154,8 +154,8 @@
// ABSL_LOCKS_EXCLUDED() // ABSL_LOCKS_EXCLUDED()
// //
// Documents the locks that cannot be held by callers of this function, as they // Documents the locks acquired in the body of the function. These locks
// might be acquired by this function (Abseil's `Mutex` locks are // cannot be held when calling this function (as Abseil's `Mutex` locks are
// non-reentrant). // non-reentrant).
#if ABSL_HAVE_ATTRIBUTE(locks_excluded) #if ABSL_HAVE_ATTRIBUTE(locks_excluded)
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__))) #define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
@ -317,7 +317,7 @@ namespace base_internal {
// Takes a reference to a guarded data member, and returns an unguarded // Takes a reference to a guarded data member, and returns an unguarded
// reference. // reference.
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead. // Do not used this function directly, use ABSL_TS_UNCHECKED_READ instead.
template <typename T> template <typename T>
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS { inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
return v; return v;

@ -1,65 +0,0 @@
# Copyright 2021 The Abseil Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load(
"//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS",
"ABSL_DEFAULT_LINKOPTS",
"ABSL_TEST_COPTS",
)
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
cc_library(
name = "cleanup_internal",
hdrs = ["internal/cleanup.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:base_internal",
"//absl/base:core_headers",
"//absl/utility",
],
)
cc_library(
name = "cleanup",
hdrs = [
"cleanup.h",
],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":cleanup_internal",
"//absl/base:config",
"//absl/base:core_headers",
],
)
cc_test(
name = "cleanup_test",
size = "small",
srcs = [
"cleanup_test.cc",
],
copts = ABSL_TEST_COPTS,
deps = [
":cleanup",
"//absl/base:config",
"//absl/utility",
"@com_google_googletest//:gtest_main",
],
)

@ -1,56 +0,0 @@
# Copyright 2021 The Abseil Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
cleanup_internal
HDRS
"internal/cleanup.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::base_internal
absl::core_headers
absl::utility
PUBLIC
)
absl_cc_library(
NAME
cleanup
HDRS
"cleanup.h"
COPTS
${ABSL_DEFAULT_COPTS}
DEPS
absl::cleanup_internal
absl::config
absl::core_headers
PUBLIC
)
absl_cc_test(
NAME
cleanup_test
SRCS
"cleanup_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::cleanup
absl::config
absl::utility
GTest::gmock_main
)

@ -1,140 +0,0 @@
// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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: cleanup.h
// -----------------------------------------------------------------------------
//
// `absl::Cleanup` implements the scope guard idiom, invoking the contained
// callback's `operator()() &&` on scope exit.
//
// Example:
//
// ```
// absl::Status CopyGoodData(const char* source_path, const char* sink_path) {
// FILE* source_file = fopen(source_path, "r");
// if (source_file == nullptr) {
// return absl::NotFoundError("No source file"); // No cleanups execute
// }
//
// // C++17 style cleanup using class template argument deduction
// absl::Cleanup source_closer = [source_file] { fclose(source_file); };
//
// FILE* sink_file = fopen(sink_path, "w");
// if (sink_file == nullptr) {
// return absl::NotFoundError("No sink file"); // First cleanup executes
// }
//
// // C++11 style cleanup using the factory function
// auto sink_closer = absl::MakeCleanup([sink_file] { fclose(sink_file); });
//
// Data data;
// while (ReadData(source_file, &data)) {
// if (!data.IsGood()) {
// absl::Status result = absl::FailedPreconditionError("Read bad data");
// return result; // Both cleanups execute
// }
// SaveData(sink_file, &data);
// }
//
// return absl::OkStatus(); // Both cleanups execute
// }
// ```
//
// Methods:
//
// `std::move(cleanup).Cancel()` will prevent the callback from executing.
//
// `std::move(cleanup).Invoke()` will execute the callback early, before
// destruction, and prevent the callback from executing in the destructor.
//
// Usage:
//
// `absl::Cleanup` is not an interface type. It is only intended to be used
// within the body of a function. It is not a value type and instead models a
// control flow construct. Check out `defer` in Golang for something similar.
#ifndef ABSL_CLEANUP_CLEANUP_H_
#define ABSL_CLEANUP_CLEANUP_H_
#include <utility>
#include "absl/base/config.h"
#include "absl/base/macros.h"
#include "absl/cleanup/internal/cleanup.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
template <typename Arg, typename Callback = void()>
class ABSL_MUST_USE_RESULT Cleanup final {
static_assert(cleanup_internal::WasDeduced<Arg>(),
"Explicit template parameters are not supported.");
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
"Callbacks that return values are not supported.");
public:
Cleanup(Callback callback) : storage_(std::move(callback)) {} // NOLINT
Cleanup(Cleanup&& other) = default;
void Cancel() && {
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
storage_.DestroyCallback();
}
void Invoke() && {
ABSL_HARDENING_ASSERT(storage_.IsCallbackEngaged());
storage_.InvokeCallback();
storage_.DestroyCallback();
}
~Cleanup() {
if (storage_.IsCallbackEngaged()) {
storage_.InvokeCallback();
storage_.DestroyCallback();
}
}
private:
cleanup_internal::Storage<Callback> storage_;
};
// `absl::Cleanup c = /* callback */;`
//
// C++17 type deduction API for creating an instance of `absl::Cleanup`
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
template <typename Callback>
Cleanup(Callback callback) -> Cleanup<cleanup_internal::Tag, Callback>;
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
// `auto c = absl::MakeCleanup(/* callback */);`
//
// C++11 type deduction API for creating an instance of `absl::Cleanup`
template <typename... Args, typename Callback>
absl::Cleanup<cleanup_internal::Tag, Callback> MakeCleanup(Callback callback) {
static_assert(cleanup_internal::WasDeduced<cleanup_internal::Tag, Args...>(),
"Explicit template parameters are not supported.");
static_assert(cleanup_internal::ReturnsVoid<Callback>(),
"Callbacks that return values are not supported.");
return {std::move(callback)};
}
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CLEANUP_CLEANUP_H_

@ -1,311 +0,0 @@
// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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/cleanup/cleanup.h"
#include <functional>
#include <type_traits>
#include <utility>
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/utility/utility.h"
namespace {
using Tag = absl::cleanup_internal::Tag;
template <typename Type1, typename Type2>
constexpr bool IsSame() {
return (std::is_same<Type1, Type2>::value);
}
struct IdentityFactory {
template <typename Callback>
static Callback AsCallback(Callback callback) {
return Callback(std::move(callback));
}
};
// `FunctorClass` is a type used for testing `absl::Cleanup`. It is intended to
// represent users that make their own move-only callback types outside of
// `std::function` and lambda literals.
class FunctorClass {
using Callback = std::function<void()>;
public:
explicit FunctorClass(Callback callback) : callback_(std::move(callback)) {}
FunctorClass(FunctorClass&& other)
: callback_(absl::exchange(other.callback_, Callback())) {}
FunctorClass(const FunctorClass&) = delete;
FunctorClass& operator=(const FunctorClass&) = delete;
FunctorClass& operator=(FunctorClass&&) = delete;
void operator()() const& = delete;
void operator()() && {
ASSERT_TRUE(callback_);
callback_();
callback_ = nullptr;
}
private:
Callback callback_;
};
struct FunctorClassFactory {
template <typename Callback>
static FunctorClass AsCallback(Callback callback) {
return FunctorClass(std::move(callback));
}
};
struct StdFunctionFactory {
template <typename Callback>
static std::function<void()> AsCallback(Callback callback) {
return std::function<void()>(std::move(callback));
}
};
using CleanupTestParams =
::testing::Types<IdentityFactory, FunctorClassFactory, StdFunctionFactory>;
template <typename>
struct CleanupTest : public ::testing::Test {};
TYPED_TEST_SUITE(CleanupTest, CleanupTestParams);
bool fn_ptr_called = false;
void FnPtrFunction() { fn_ptr_called = true; }
TYPED_TEST(CleanupTest, FactoryProducesCorrectType) {
{
auto callback = TypeParam::AsCallback([] {});
auto cleanup = absl::MakeCleanup(std::move(callback));
static_assert(
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
"");
}
{
auto cleanup = absl::MakeCleanup(&FnPtrFunction);
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
{
auto cleanup = absl::MakeCleanup(FnPtrFunction);
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
}
#if defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
TYPED_TEST(CleanupTest, CTADProducesCorrectType) {
{
auto callback = TypeParam::AsCallback([] {});
absl::Cleanup cleanup = std::move(callback);
static_assert(
IsSame<absl::Cleanup<Tag, decltype(callback)>, decltype(cleanup)>(),
"");
}
{
absl::Cleanup cleanup = &FnPtrFunction;
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
{
absl::Cleanup cleanup = FnPtrFunction;
static_assert(IsSame<absl::Cleanup<Tag, void (*)()>, decltype(cleanup)>(),
"");
}
}
TYPED_TEST(CleanupTest, FactoryAndCTADProduceSameType) {
{
auto callback = IdentityFactory::AsCallback([] {});
auto factory_cleanup = absl::MakeCleanup(callback);
absl::Cleanup deduction_cleanup = callback;
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup =
absl::MakeCleanup(FunctorClassFactory::AsCallback([] {}));
absl::Cleanup deduction_cleanup = FunctorClassFactory::AsCallback([] {});
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup =
absl::MakeCleanup(StdFunctionFactory::AsCallback([] {}));
absl::Cleanup deduction_cleanup = StdFunctionFactory::AsCallback([] {});
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup = absl::MakeCleanup(&FnPtrFunction);
absl::Cleanup deduction_cleanup = &FnPtrFunction;
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
{
auto factory_cleanup = absl::MakeCleanup(FnPtrFunction);
absl::Cleanup deduction_cleanup = FnPtrFunction;
static_assert(
IsSame<decltype(factory_cleanup), decltype(deduction_cleanup)>(), "");
}
}
#endif // defined(ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION)
TYPED_TEST(CleanupTest, BasicUsage) {
bool called = false;
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
}
EXPECT_TRUE(called); // Destructor should invoke the callback
}
TYPED_TEST(CleanupTest, BasicUsageWithFunctionPointer) {
fn_ptr_called = false;
{
auto cleanup = absl::MakeCleanup(TypeParam::AsCallback(&FnPtrFunction));
EXPECT_FALSE(fn_ptr_called); // Constructor shouldn't invoke the callback
}
EXPECT_TRUE(fn_ptr_called); // Destructor should invoke the callback
}
TYPED_TEST(CleanupTest, Cancel) {
bool called = false;
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
std::move(cleanup).Cancel();
EXPECT_FALSE(called); // Cancel shouldn't invoke the callback
}
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
}
TYPED_TEST(CleanupTest, Invoke) {
bool called = false;
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
std::move(cleanup).Invoke();
EXPECT_TRUE(called); // Invoke should invoke the callback
called = false; // Reset tracker before destructor runs
}
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
}
TYPED_TEST(CleanupTest, Move) {
bool called = false;
{
auto moved_from_cleanup =
absl::MakeCleanup(TypeParam::AsCallback([&called] { called = true; }));
EXPECT_FALSE(called); // Constructor shouldn't invoke the callback
{
auto moved_to_cleanup = std::move(moved_from_cleanup);
EXPECT_FALSE(called); // Move shouldn't invoke the callback
}
EXPECT_TRUE(called); // Destructor should invoke the callback
called = false; // Reset tracker before destructor runs
}
EXPECT_FALSE(called); // Destructor shouldn't invoke the callback
}
int DestructionCount = 0;
struct DestructionCounter {
void operator()() {}
~DestructionCounter() { ++DestructionCount; }
};
TYPED_TEST(CleanupTest, DestructorDestroys) {
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
DestructionCount = 0;
}
EXPECT_EQ(DestructionCount, 1); // Engaged cleanup destroys
}
TYPED_TEST(CleanupTest, CancelDestroys) {
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
DestructionCount = 0;
std::move(cleanup).Cancel();
EXPECT_EQ(DestructionCount, 1); // Cancel destroys
}
EXPECT_EQ(DestructionCount, 1); // Canceled cleanup does not double destroy
}
TYPED_TEST(CleanupTest, InvokeDestroys) {
{
auto cleanup =
absl::MakeCleanup(TypeParam::AsCallback(DestructionCounter()));
DestructionCount = 0;
std::move(cleanup).Invoke();
EXPECT_EQ(DestructionCount, 1); // Invoke destroys
}
EXPECT_EQ(DestructionCount, 1); // Invoked cleanup does not double destroy
}
} // namespace

@ -1,100 +0,0 @@
// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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_CLEANUP_INTERNAL_CLEANUP_H_
#define ABSL_CLEANUP_INTERNAL_CLEANUP_H_
#include <new>
#include <type_traits>
#include <utility>
#include "absl/base/internal/invoke.h"
#include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
#include "absl/utility/utility.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace cleanup_internal {
struct Tag {};
template <typename Arg, typename... Args>
constexpr bool WasDeduced() {
return (std::is_same<cleanup_internal::Tag, Arg>::value) &&
(sizeof...(Args) == 0);
}
template <typename Callback>
constexpr bool ReturnsVoid() {
return (std::is_same<base_internal::invoke_result_t<Callback>, void>::value);
}
template <typename Callback>
class Storage {
public:
Storage() = delete;
explicit Storage(Callback callback) {
// Placement-new into a character buffer is used for eager destruction when
// the cleanup is invoked or cancelled. To ensure this optimizes well, the
// behavior is implemented locally instead of using an absl::optional.
::new (GetCallbackBuffer()) Callback(std::move(callback));
is_callback_engaged_ = true;
}
Storage(Storage&& other) {
ABSL_HARDENING_ASSERT(other.IsCallbackEngaged());
::new (GetCallbackBuffer()) Callback(std::move(other.GetCallback()));
is_callback_engaged_ = true;
other.DestroyCallback();
}
Storage(const Storage& other) = delete;
Storage& operator=(Storage&& other) = delete;
Storage& operator=(const Storage& other) = delete;
void* GetCallbackBuffer() { return static_cast<void*>(+callback_buffer_); }
Callback& GetCallback() {
return *reinterpret_cast<Callback*>(GetCallbackBuffer());
}
bool IsCallbackEngaged() const { return is_callback_engaged_; }
void DestroyCallback() {
is_callback_engaged_ = false;
GetCallback().~Callback();
}
void InvokeCallback() ABSL_NO_THREAD_SAFETY_ANALYSIS {
std::move(GetCallback())();
}
private:
bool is_callback_engaged_;
alignas(Callback) char callback_buffer_[sizeof(Callback)];
};
} // namespace cleanup_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_CLEANUP_INTERNAL_CLEANUP_H_

@ -0,0 +1,38 @@
#
# 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.
"""Creates config_setting that allows selecting based on 'compiler' value."""
def create_llvm_config(name, visibility):
# The "do_not_use_tools_cpp_compiler_present" attribute exists to
# distinguish between older versions of Bazel that do not support
# "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do.
# In the future, the only way to select on the compiler will be through
# flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can
# be removed.
if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"):
native.config_setting(
name = name,
flag_values = {
"@bazel_tools//tools/cpp:compiler": "llvm",
},
visibility = visibility,
)
else:
native.config_setting(
name = name,
values = {"compiler": "llvm"},
visibility = visibility,
)

@ -14,6 +14,7 @@
# limitations under the License. # limitations under the License.
# #
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load( load(
"//absl:copts/configure_copts.bzl", "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
@ -217,6 +218,11 @@ cc_test(
], ],
) )
NOTEST_TAGS_NONMOBILE = [
"no_test_darwin_x86_64",
"no_test_loonix",
]
NOTEST_TAGS_MOBILE = [ NOTEST_TAGS_MOBILE = [
"no_test_android_arm", "no_test_android_arm",
"no_test_android_arm64", "no_test_android_arm64",
@ -224,6 +230,8 @@ NOTEST_TAGS_MOBILE = [
"no_test_ios_x86_64", "no_test_ios_x86_64",
] ]
NOTEST_TAGS = NOTEST_TAGS_MOBILE + NOTEST_TAGS_NONMOBILE
cc_library( cc_library(
name = "flat_hash_map", name = "flat_hash_map",
hdrs = ["flat_hash_map.h"], hdrs = ["flat_hash_map.h"],
@ -234,7 +242,6 @@ cc_library(
":hash_function_defaults", ":hash_function_defaults",
":raw_hash_map", ":raw_hash_map",
"//absl/algorithm:container", "//absl/algorithm:container",
"//absl/base:core_headers",
"//absl/memory", "//absl/memory",
], ],
) )
@ -244,7 +251,7 @@ cc_test(
srcs = ["flat_hash_map_test.cc"], srcs = ["flat_hash_map_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":flat_hash_map", ":flat_hash_map",
":hash_generator_testing", ":hash_generator_testing",
@ -278,7 +285,7 @@ cc_test(
srcs = ["flat_hash_set_test.cc"], srcs = ["flat_hash_set_test.cc"],
copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":flat_hash_set", ":flat_hash_set",
":hash_generator_testing", ":hash_generator_testing",
@ -301,10 +308,9 @@ cc_library(
deps = [ deps = [
":container_memory", ":container_memory",
":hash_function_defaults", ":hash_function_defaults",
":node_slot_policy", ":node_hash_policy",
":raw_hash_map", ":raw_hash_map",
"//absl/algorithm:container", "//absl/algorithm:container",
"//absl/base:core_headers",
"//absl/memory", "//absl/memory",
], ],
) )
@ -314,7 +320,7 @@ cc_test(
srcs = ["node_hash_map_test.cc"], srcs = ["node_hash_map_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":hash_generator_testing", ":hash_generator_testing",
":node_hash_map", ":node_hash_map",
@ -334,10 +340,9 @@ cc_library(
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":hash_function_defaults", ":hash_function_defaults",
":node_slot_policy", ":node_hash_policy",
":raw_hash_set", ":raw_hash_set",
"//absl/algorithm:container", "//absl/algorithm:container",
"//absl/base:core_headers",
"//absl/memory", "//absl/memory",
], ],
) )
@ -347,7 +352,7 @@ cc_test(
srcs = ["node_hash_set_test.cc"], srcs = ["node_hash_set_test.cc"],
copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"], copts = ABSL_TEST_COPTS + ["-DUNORDERED_SET_CXX17"],
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":node_hash_set", ":node_hash_set",
":unordered_set_constructor_test", ":unordered_set_constructor_test",
@ -376,7 +381,7 @@ cc_test(
srcs = ["internal/container_memory_test.cc"], srcs = ["internal/container_memory_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":container_memory", ":container_memory",
":test_instance_tracker", ":test_instance_tracker",
@ -403,7 +408,7 @@ cc_test(
srcs = ["internal/hash_function_defaults_test.cc"], srcs = ["internal/hash_function_defaults_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], tags = NOTEST_TAGS,
deps = [ deps = [
":hash_function_defaults", ":hash_function_defaults",
"//absl/hash", "//absl/hash",
@ -502,13 +507,12 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":have_sse",
"//absl/base", "//absl/base",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:exponential_biased",
"//absl/debugging:stacktrace", "//absl/debugging:stacktrace",
"//absl/memory", "//absl/memory",
"//absl/profiling:exponential_biased",
"//absl/profiling:sample_recorder",
"//absl/synchronization", "//absl/synchronization",
"//absl/utility", "//absl/utility",
], ],
@ -518,14 +522,10 @@ cc_test(
name = "hashtablez_sampler_test", name = "hashtablez_sampler_test",
srcs = ["internal/hashtablez_sampler_test.cc"], srcs = ["internal/hashtablez_sampler_test.cc"],
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = [
"no_test_wasm",
],
deps = [ deps = [
":hashtablez_sampler", ":hashtablez_sampler",
"//absl/base:config", ":have_sse",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/profiling:sample_recorder",
"//absl/synchronization", "//absl/synchronization",
"//absl/synchronization:thread_pool", "//absl/synchronization:thread_pool",
"//absl/time", "//absl/time",
@ -534,21 +534,21 @@ cc_test(
) )
cc_library( cc_library(
name = "node_slot_policy", name = "node_hash_policy",
hdrs = ["internal/node_slot_policy.h"], hdrs = ["internal/node_hash_policy.h"],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = ["//absl/base:config"], deps = ["//absl/base:config"],
) )
cc_test( cc_test(
name = "node_slot_policy_test", name = "node_hash_policy_test",
srcs = ["internal/node_slot_policy_test.cc"], srcs = ["internal/node_hash_policy_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":hash_policy_traits", ":hash_policy_traits",
":node_slot_policy", ":node_hash_policy",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
@ -565,6 +565,14 @@ cc_library(
], ],
) )
cc_library(
name = "have_sse",
hdrs = ["internal/have_sse.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = ["//visibility:private"],
)
cc_library( cc_library(
name = "common", name = "common",
hdrs = ["internal/common.h"], hdrs = ["internal/common.h"],
@ -589,13 +597,14 @@ cc_library(
":hash_policy_traits", ":hash_policy_traits",
":hashtable_debug_hooks", ":hashtable_debug_hooks",
":hashtablez_sampler", ":hashtablez_sampler",
":have_sse",
":layout",
"//absl/base:bits",
"//absl/base:config", "//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:endian", "//absl/base:endian",
"//absl/base:prefetch",
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/numeric:bits",
"//absl/utility", "//absl/utility",
], ],
) )
@ -605,7 +614,7 @@ cc_test(
srcs = ["internal/raw_hash_set_test.cc"], srcs = ["internal/raw_hash_set_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkstatic = 1, linkstatic = 1,
tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], tags = NOTEST_TAGS,
deps = [ deps = [
":container_memory", ":container_memory",
":hash_function_defaults", ":hash_function_defaults",
@ -615,52 +624,12 @@ cc_test(
"//absl/base", "//absl/base",
"//absl/base:config", "//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:prefetch",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/strings", "//absl/strings",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_binary(
name = "raw_hash_set_benchmark",
testonly = 1,
srcs = ["internal/raw_hash_set_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":hash_function_defaults",
":raw_hash_set",
"//absl/base:raw_logging_internal",
"//absl/strings:str_format",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_binary(
name = "raw_hash_set_probe_benchmark",
testonly = 1,
srcs = ["internal/raw_hash_set_probe_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = select({
"//conditions:default": [],
}) + ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":flat_hash_map",
":hash_function_defaults",
":hashtable_debug",
":raw_hash_set",
"//absl/random",
"//absl/random:distributions",
"//absl/strings",
"//absl/strings:str_format",
],
)
cc_test( cc_test(
name = "raw_hash_set_allocator_test", name = "raw_hash_set_allocator_test",
size = "small", size = "small",
@ -696,7 +665,7 @@ cc_test(
srcs = ["internal/layout_test.cc"], srcs = ["internal/layout_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = NOTEST_TAGS_MOBILE + ["no_test_loonix"], tags = NOTEST_TAGS,
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":layout", ":layout",
@ -708,22 +677,6 @@ cc_test(
], ],
) )
cc_binary(
name = "layout_benchmark",
testonly = 1,
srcs = ["internal/layout_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":layout",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_library( cc_library(
name = "tracked", name = "tracked",
testonly = 1, testonly = 1,
@ -843,7 +796,7 @@ cc_test(
srcs = ["internal/unordered_set_test.cc"], srcs = ["internal/unordered_set_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":unordered_set_constructor_test", ":unordered_set_constructor_test",
":unordered_set_lookup_test", ":unordered_set_lookup_test",
@ -858,7 +811,7 @@ cc_test(
srcs = ["internal/unordered_map_test.cc"], srcs = ["internal/unordered_map_test.cc"],
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"], tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":unordered_map_constructor_test", ":unordered_map_constructor_test",
":unordered_map_lookup_test", ":unordered_map_lookup_test",
@ -868,22 +821,6 @@ cc_test(
], ],
) )
cc_test(
name = "sample_element_size_test",
srcs = ["sample_element_size_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_loonix"],
visibility = ["//visibility:private"],
deps = [
":flat_hash_map",
":flat_hash_set",
":node_hash_map",
":node_hash_set",
"@com_google_googletest//:gtest_main",
],
)
cc_library( cc_library(
name = "btree", name = "btree",
srcs = [ srcs = [
@ -903,7 +840,6 @@ cc_library(
":container_memory", ":container_memory",
":layout", ":layout",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate", "//absl/base:throw_delegate",
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
@ -939,10 +875,6 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
shard_count = 10, shard_count = 10,
tags = [
"no_test_ios",
"no_test_wasm",
],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":btree", ":btree",

@ -14,6 +14,15 @@
# limitations under the License. # limitations under the License.
# #
# This is deprecated and will be removed in the future. It also doesn't do
# anything anyways. Prefer to use the library associated with the API you are
# using.
absl_cc_library(
NAME
container
PUBLIC
)
absl_cc_library( absl_cc_library(
NAME NAME
btree btree
@ -35,14 +44,12 @@ absl_cc_library(
absl::core_headers absl::core_headers
absl::layout absl::layout
absl::memory absl::memory
absl::raw_logging_internal
absl::strings absl::strings
absl::throw_delegate absl::throw_delegate
absl::type_traits absl::type_traits
absl::utility absl::utility
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
btree_test_common btree_test_common
@ -82,10 +89,9 @@ absl_cc_test(
absl::strings absl::strings
absl::test_instance_tracker absl::test_instance_tracker
absl::type_traits absl::type_traits
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
compressed_tuple compressed_tuple
@ -112,7 +118,7 @@ absl_cc_test(
absl::optional absl::optional
absl::test_instance_tracker absl::test_instance_tracker
absl::utility absl::utility
GTest::gmock_main gmock_main
) )
absl_cc_library( absl_cc_library(
@ -147,7 +153,7 @@ absl_cc_test(
absl::exception_testing absl::exception_testing
absl::hash_testing absl::hash_testing
absl::memory absl::memory
GTest::gmock_main gmock_main
) )
absl_cc_test( absl_cc_test(
@ -161,10 +167,9 @@ absl_cc_test(
absl::fixed_array absl::fixed_array
absl::config absl::config
absl::exception_safety_testing absl::exception_safety_testing
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
inlined_vector_internal inlined_vector_internal
@ -197,7 +202,6 @@ absl_cc_library(
PUBLIC PUBLIC
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
counting_allocator counting_allocator
@ -227,7 +231,7 @@ absl_cc_test(
absl::memory absl::memory
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
GTest::gmock_main gmock_main
) )
absl_cc_test( absl_cc_test(
@ -241,10 +245,9 @@ absl_cc_test(
absl::inlined_vector absl::inlined_vector
absl::config absl::config
absl::exception_safety_testing absl::exception_safety_testing
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
test_instance_tracker test_instance_tracker
@ -268,7 +271,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::test_instance_tracker absl::test_instance_tracker
GTest::gmock_main gmock_main
) )
absl_cc_library( absl_cc_library(
@ -280,7 +283,6 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::container_memory absl::container_memory
absl::core_headers
absl::hash_function_defaults absl::hash_function_defaults
absl::raw_hash_map absl::raw_hash_map
absl::algorithm_container absl::algorithm_container
@ -304,7 +306,7 @@ absl_cc_test(
absl::unordered_map_modifiers_test absl::unordered_map_modifiers_test
absl::any absl::any
absl::raw_logging_internal absl::raw_logging_internal
GTest::gmock_main gmock_main
) )
absl_cc_library( absl_cc_library(
@ -342,7 +344,7 @@ absl_cc_test(
absl::memory absl::memory
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
GTest::gmock_main gmock_main
) )
absl_cc_library( absl_cc_library(
@ -354,9 +356,8 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::container_memory absl::container_memory
absl::core_headers
absl::hash_function_defaults absl::hash_function_defaults
absl::node_slot_policy absl::node_hash_policy
absl::raw_hash_map absl::raw_hash_map
absl::algorithm_container absl::algorithm_container
absl::memory absl::memory
@ -378,7 +379,7 @@ absl_cc_test(
absl::unordered_map_lookup_test absl::unordered_map_lookup_test
absl::unordered_map_members_test absl::unordered_map_members_test
absl::unordered_map_modifiers_test absl::unordered_map_modifiers_test
GTest::gmock_main gmock_main
) )
absl_cc_library( absl_cc_library(
@ -389,9 +390,8 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::core_headers
absl::hash_function_defaults absl::hash_function_defaults
absl::node_slot_policy absl::node_hash_policy
absl::raw_hash_set absl::raw_hash_set
absl::algorithm_container absl::algorithm_container
absl::memory absl::memory
@ -413,10 +413,9 @@ absl_cc_test(
absl::unordered_set_lookup_test absl::unordered_set_lookup_test
absl::unordered_set_members_test absl::unordered_set_members_test
absl::unordered_set_modifiers_test absl::unordered_set_modifiers_test
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
container_memory container_memory
@ -443,10 +442,9 @@ absl_cc_test(
absl::container_memory absl::container_memory
absl::strings absl::strings
absl::test_instance_tracker absl::test_instance_tracker
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hash_function_defaults hash_function_defaults
@ -476,10 +474,9 @@ absl_cc_test(
absl::hash absl::hash
absl::random_random absl::random_random
absl::strings absl::strings
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hash_generator_testing hash_generator_testing
@ -497,7 +494,6 @@ absl_cc_library(
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hash_policy_testing hash_policy_testing
@ -520,10 +516,9 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hash_policy_traits hash_policy_traits
@ -545,10 +540,9 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::hash_policy_traits absl::hash_policy_traits
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hashtablez_sampler hashtablez_sampler
@ -561,9 +555,8 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::base absl::base
absl::config
absl::exponential_biased absl::exponential_biased
absl::sample_recorder absl::have_sse
absl::synchronization absl::synchronization
) )
@ -575,12 +568,11 @@ absl_cc_test(
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::config
absl::hashtablez_sampler absl::hashtablez_sampler
GTest::gmock_main absl::have_sse
gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hashtable_debug hashtable_debug
@ -592,7 +584,6 @@ absl_cc_library(
absl::hashtable_debug_hooks absl::hashtable_debug_hooks
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
hashtable_debug_hooks hashtable_debug_hooks
@ -605,12 +596,20 @@ absl_cc_library(
PUBLIC PUBLIC
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
node_slot_policy have_sse
HDRS HDRS
"internal/node_slot_policy.h" "internal/have_sse.h"
COPTS
${ABSL_DEFAULT_COPTS}
)
absl_cc_library(
NAME
node_hash_policy
HDRS
"internal/node_hash_policy.h"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
@ -620,18 +619,17 @@ absl_cc_library(
absl_cc_test( absl_cc_test(
NAME NAME
node_slot_policy_test node_hash_policy_test
SRCS SRCS
"internal/node_slot_policy_test.cc" "internal/node_hash_policy_test.cc"
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::hash_policy_traits absl::hash_policy_traits
absl::node_slot_policy absl::node_hash_policy
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
raw_hash_map raw_hash_map
@ -646,7 +644,6 @@ absl_cc_library(
PUBLIC PUBLIC
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
container_common container_common
@ -658,7 +655,6 @@ absl_cc_library(
absl::type_traits absl::type_traits
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
raw_hash_set raw_hash_set
@ -678,10 +674,11 @@ absl_cc_library(
absl::endian absl::endian
absl::hash_policy_traits absl::hash_policy_traits
absl::hashtable_debug_hooks absl::hashtable_debug_hooks
absl::have_sse
absl::layout
absl::memory absl::memory
absl::meta absl::meta
absl::optional absl::optional
absl::prefetch
absl::utility absl::utility
absl::hashtablez_sampler absl::hashtablez_sampler
PUBLIC PUBLIC
@ -703,10 +700,9 @@ absl_cc_test(
absl::base absl::base
absl::config absl::config
absl::core_headers absl::core_headers
absl::prefetch
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
GTest::gmock_main gmock_main
) )
absl_cc_test( absl_cc_test(
@ -720,10 +716,9 @@ absl_cc_test(
absl::raw_hash_set absl::raw_hash_set
absl::tracked absl::tracked
absl::core_headers absl::core_headers
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
layout layout
@ -754,10 +749,9 @@ absl_cc_test(
absl::core_headers absl::core_headers
absl::raw_logging_internal absl::raw_logging_internal
absl::span absl::span
GTest::gmock_main gmock_main
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
tracked tracked
@ -770,7 +764,6 @@ absl_cc_library(
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_map_constructor_test unordered_map_constructor_test
@ -781,11 +774,10 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_map_lookup_test unordered_map_lookup_test
@ -796,11 +788,10 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_map_members_test unordered_map_members_test
@ -810,11 +801,10 @@ absl_cc_library(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::type_traits absl::type_traits
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_map_modifiers_test unordered_map_modifiers_test
@ -825,11 +815,10 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_set_constructor_test unordered_set_constructor_test
@ -840,11 +829,10 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_set_lookup_test unordered_set_lookup_test
@ -855,11 +843,10 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_set_members_test unordered_set_members_test
@ -869,11 +856,10 @@ absl_cc_library(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::type_traits absl::type_traits
GTest::gmock gmock
TESTONLY TESTONLY
) )
# Internal-only target, do not depend on directly.
absl_cc_library( absl_cc_library(
NAME NAME
unordered_set_modifiers_test unordered_set_modifiers_test
@ -884,7 +870,7 @@ absl_cc_library(
DEPS DEPS
absl::hash_generator_testing absl::hash_generator_testing
absl::hash_policy_testing absl::hash_policy_testing
GTest::gmock gmock
TESTONLY TESTONLY
) )
@ -900,7 +886,7 @@ absl_cc_test(
absl::unordered_set_lookup_test absl::unordered_set_lookup_test
absl::unordered_set_members_test absl::unordered_set_members_test
absl::unordered_set_modifiers_test absl::unordered_set_modifiers_test
GTest::gmock_main gmock_main
) )
absl_cc_test( absl_cc_test(
@ -915,20 +901,5 @@ absl_cc_test(
absl::unordered_map_lookup_test absl::unordered_map_lookup_test
absl::unordered_map_members_test absl::unordered_map_members_test
absl::unordered_map_modifiers_test absl::unordered_map_modifiers_test
GTest::gmock_main gmock_main
)
absl_cc_test(
NAME
sample_element_size_test
SRCS
"sample_element_size_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::flat_hash_map
absl::flat_hash_set
absl::node_hash_map
absl::node_hash_set
GTest::gmock_main
) )

@ -26,7 +26,6 @@
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
#include "benchmark/benchmark.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/container/btree_map.h" #include "absl/container/btree_map.h"
#include "absl/container/btree_set.h" #include "absl/container/btree_set.h"
@ -40,6 +39,7 @@
#include "absl/strings/cord.h" #include "absl/strings/cord.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/time/time.h" #include "absl/time/time.h"
#include "benchmark/benchmark.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
@ -101,6 +101,39 @@ void BM_InsertSorted(benchmark::State& state) {
BM_InsertImpl<T>(state, true); 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));
}
}
// Benchmark inserting the first few elements in a container. In b-tree, this is // Benchmark inserting the first few elements in a container. In b-tree, this is
// when the root node grows. // when the root node grows.
template <typename T> template <typename T>
@ -153,9 +186,9 @@ void BM_FullLookup(benchmark::State& state) {
BM_LookupImpl<T>(state, true); BM_LookupImpl<T>(state, true);
} }
// Benchmark erasing values from a container. // Benchmark deletion of values from a container.
template <typename T> template <typename T>
void BM_Erase(benchmark::State& state) { void BM_Delete(benchmark::State& state) {
using V = typename remove_pair_const<typename T::value_type>::type; using V = typename remove_pair_const<typename T::value_type>::type;
typename KeyOfValue<typename T::key_type, V>::type key_of_value; typename KeyOfValue<typename T::key_type, V>::type key_of_value;
std::vector<V> values = GenerateValues<V>(kBenchmarkValues); std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
@ -180,9 +213,9 @@ void BM_Erase(benchmark::State& state) {
} }
} }
// Benchmark erasing multiple values from a container. // Benchmark deletion of multiple values from a container.
template <typename T> template <typename T>
void BM_EraseRange(benchmark::State& state) { void BM_DeleteRange(benchmark::State& state) {
using V = typename remove_pair_const<typename T::value_type>::type; using V = typename remove_pair_const<typename T::value_type>::type;
typename KeyOfValue<typename T::key_type, V>::type key_of_value; typename KeyOfValue<typename T::key_type, V>::type key_of_value;
std::vector<V> values = GenerateValues<V>(kBenchmarkValues); std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
@ -222,40 +255,6 @@ void BM_EraseRange(benchmark::State& state) {
} }
} }
// Predicate that erases every other element. We can't use a lambda because
// C++11 doesn't support generic lambdas.
// TODO(b/207389011): consider adding benchmarks that remove different fractions
// of keys (e.g. 10%, 90%).
struct EraseIfPred {
uint64_t i = 0;
template <typename T>
bool operator()(const T&) {
return ++i % 2;
}
};
// Benchmark erasing multiple values from a container with a predicate.
template <typename T>
void BM_EraseIf(benchmark::State& state) {
using V = typename remove_pair_const<typename T::value_type>::type;
std::vector<V> values = GenerateValues<V>(kBenchmarkValues);
// Removes half of the keys per batch.
const int batch_size = (kBenchmarkValues + 1) / 2;
EraseIfPred pred;
while (state.KeepRunningBatch(batch_size)) {
state.PauseTiming();
{
T container(values.begin(), values.end());
state.ResumeTiming();
erase_if(container, pred);
benchmark::DoNotOptimize(container);
state.PauseTiming();
}
state.ResumeTiming();
}
}
// Benchmark steady-state insert (into first half of range) and remove (from // Benchmark steady-state insert (into first half of range) and remove (from
// second half of range), treating the container approximately like a queue with // 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 // log-time access for all elements. This benchmark does not test the case where
@ -511,14 +510,15 @@ BTREE_TYPES(Time);
void BM_##type##_##func(benchmark::State& state) { BM_##func<type>(state); } \ void BM_##type##_##func(benchmark::State& state) { BM_##func<type>(state); } \
BENCHMARK(BM_##type##_##func) BENCHMARK(BM_##type##_##func)
#define MY_BENCHMARK3_STL(type) \ #define MY_BENCHMARK3(type) \
MY_BENCHMARK4(type, Insert); \ MY_BENCHMARK4(type, Insert); \
MY_BENCHMARK4(type, InsertSorted); \ MY_BENCHMARK4(type, InsertSorted); \
MY_BENCHMARK4(type, InsertEnd); \
MY_BENCHMARK4(type, InsertSmall); \ MY_BENCHMARK4(type, InsertSmall); \
MY_BENCHMARK4(type, Lookup); \ MY_BENCHMARK4(type, Lookup); \
MY_BENCHMARK4(type, FullLookup); \ MY_BENCHMARK4(type, FullLookup); \
MY_BENCHMARK4(type, Erase); \ MY_BENCHMARK4(type, Delete); \
MY_BENCHMARK4(type, EraseRange); \ MY_BENCHMARK4(type, DeleteRange); \
MY_BENCHMARK4(type, QueueAddRem); \ MY_BENCHMARK4(type, QueueAddRem); \
MY_BENCHMARK4(type, MixedAddRem); \ MY_BENCHMARK4(type, MixedAddRem); \
MY_BENCHMARK4(type, Fifo); \ MY_BENCHMARK4(type, Fifo); \
@ -526,13 +526,9 @@ BTREE_TYPES(Time);
MY_BENCHMARK4(type, InsertRangeRandom); \ MY_BENCHMARK4(type, InsertRangeRandom); \
MY_BENCHMARK4(type, InsertRangeSorted) MY_BENCHMARK4(type, InsertRangeSorted)
#define MY_BENCHMARK3(type) \
MY_BENCHMARK4(type, EraseIf); \
MY_BENCHMARK3_STL(type)
#define MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type) \ #define MY_BENCHMARK2_SUPPORTS_MULTI_ONLY(type) \
MY_BENCHMARK3_STL(stl_##type); \ MY_BENCHMARK3(stl_##type); \
MY_BENCHMARK3_STL(stl_unordered_##type); \ MY_BENCHMARK3(stl_unordered_##type); \
MY_BENCHMARK3(btree_256_##type) MY_BENCHMARK3(btree_256_##type)
#define MY_BENCHMARK2(type) \ #define MY_BENCHMARK2(type) \
@ -722,12 +718,12 @@ double ContainerInfo(const btree_map<int, BigTypePtr<Size>>& b) {
btree_set<BigTypePtr<SIZE>>; \ btree_set<BigTypePtr<SIZE>>; \
using btree_256_map_size##SIZE##copies##SIZE##ptr = \ using btree_256_map_size##SIZE##copies##SIZE##ptr = \
btree_map<int, BigTypePtr<SIZE>>; \ btree_map<int, BigTypePtr<SIZE>>; \
MY_BENCHMARK3_STL(stl_set_size##SIZE##copies##SIZE##ptr); \ MY_BENCHMARK3(stl_set_size##SIZE##copies##SIZE##ptr); \
MY_BENCHMARK3_STL(stl_unordered_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(flat_hash_set_size##SIZE##copies##SIZE##ptr); \
MY_BENCHMARK3(btree_256_set_size##SIZE##copies##SIZE##ptr); \ MY_BENCHMARK3(btree_256_set_size##SIZE##copies##SIZE##ptr); \
MY_BENCHMARK3_STL(stl_map_size##SIZE##copies##SIZE##ptr); \ MY_BENCHMARK3(stl_map_size##SIZE##copies##SIZE##ptr); \
MY_BENCHMARK3_STL(stl_unordered_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(flat_hash_map_size##SIZE##copies##SIZE##ptr); \
MY_BENCHMARK3(btree_256_map_size##SIZE##copies##SIZE##ptr) MY_BENCHMARK3(btree_256_map_size##SIZE##copies##SIZE##ptr)

@ -35,17 +35,14 @@
// //
// However, these types should not be considered drop-in replacements for // However, these types should not be considered drop-in replacements for
// `std::map` and `std::multimap` as there are some API differences, which are // `std::map` and `std::multimap` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to // noted in this header file.
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
// //
// Importantly, insertions and deletions may invalidate outstanding iterators, // Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only // pointers, and references to elements. Such invalidations are typically only
// an issue if insertion and deletion operations are interleaved with the use of // an issue if insertion and deletion operations are interleaved with the use of
// more than one iterator, pointer, or reference simultaneously. For this // more than one iterator, pointer, or reference simultaneously. For this
// reason, `insert()` and `erase()` return a valid iterator at the current // reason, `insert()` and `erase()` return a valid iterator at the current
// position. Another important difference is that key-types must be // position.
// copy-constructible.
#ifndef ABSL_CONTAINER_BTREE_MAP_H_ #ifndef ABSL_CONTAINER_BTREE_MAP_H_
#define ABSL_CONTAINER_BTREE_MAP_H_ #define ABSL_CONTAINER_BTREE_MAP_H_
@ -56,14 +53,6 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename Key, typename Data, typename Compare, typename Alloc,
int TargetNodeSize, bool IsMulti>
struct map_params;
} // namespace container_internal
// absl::btree_map<> // absl::btree_map<>
// //
// An `absl::btree_map<K, V>` is an ordered associative container of // An `absl::btree_map<K, V>` is an ordered associative container of
@ -85,7 +74,7 @@ class btree_map
: public container_internal::btree_map_container< : public container_internal::btree_map_container<
container_internal::btree<container_internal::map_params< container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256, Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>> { /*Multi=*/false>>> {
using Base = typename btree_map::btree_map_container; using Base = typename btree_map::btree_map_container;
public: public:
@ -377,8 +366,8 @@ class btree_map
// Determines whether an element comparing equal to the given `key` exists // Determines whether an element comparing equal to the given `key` exists
// within the `btree_map`, returning `true` if so or `false` otherwise. // within the `btree_map`, returning `true` if so or `false` otherwise.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::contains; using Base::contains;
// btree_map::count() // btree_map::count()
@ -389,14 +378,15 @@ class btree_map
// the `btree_map`. Note that this function will return either `1` or `0` // the `btree_map`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_map`. // since duplicate elements are not allowed within a `btree_map`.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::count; using Base::count;
// btree_map::equal_range() // btree_map::equal_range()
// //
// Returns a half-open range [first, last), defined by a `std::pair` of two // 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`. // iterators, containing all elements with the passed key in the
// `btree_map`.
using Base::equal_range; using Base::equal_range;
// btree_map::find() // btree_map::find()
@ -406,34 +396,10 @@ class btree_map
// //
// Finds an element with the passed `key` within the `btree_map`. // Finds an element with the passed `key` within the `btree_map`.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::find; using Base::find;
// btree_map::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_map::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_map`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_map::operator[]() // btree_map::operator[]()
// //
// Returns a reference to the value mapped to the passed key within the // Returns a reference to the value mapped to the passed key within the
@ -478,11 +444,15 @@ void swap(btree_map<K, V, C, A> &x, btree_map<K, V, C, A> &y) {
// absl::erase_if(absl::btree_map<>, Pred) // absl::erase_if(absl::btree_map<>, Pred)
// //
// Erases all elements that satisfy the predicate pred from the container. // Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename V, typename C, typename A, typename Pred> template <typename K, typename V, typename C, typename A, typename Pred>
typename btree_map<K, V, C, A>::size_type erase_if( void erase_if(btree_map<K, V, C, A> &map, Pred pred) {
btree_map<K, V, C, A> &map, Pred pred) { for (auto it = map.begin(); it != map.end();) {
return container_internal::btree_access::erase_if(map, std::move(pred)); if (pred(*it)) {
it = map.erase(it);
} else {
++it;
}
}
} }
// absl::btree_multimap // absl::btree_multimap
@ -507,7 +477,7 @@ class btree_multimap
: public container_internal::btree_multimap_container< : public container_internal::btree_multimap_container<
container_internal::btree<container_internal::map_params< container_internal::btree<container_internal::map_params<
Key, Value, Compare, Alloc, /*TargetNodeSize=*/256, Key, Value, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>> { /*Multi=*/true>>> {
using Base = typename btree_multimap::btree_multimap_container; using Base = typename btree_multimap::btree_multimap_container;
public: public:
@ -700,8 +670,9 @@ class btree_multimap
// btree_multimap::merge() // btree_multimap::merge()
// //
// Extracts all elements from a given `source` btree_multimap into this // Extracts elements from a given `source` btree_multimap into this
// `btree_multimap`. // `btree_multimap`. If the destination `btree_multimap` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge; using Base::merge;
// btree_multimap::swap(btree_multimap& other) // btree_multimap::swap(btree_multimap& other)
@ -721,8 +692,8 @@ class btree_multimap
// Determines whether an element comparing equal to the given `key` exists // Determines whether an element comparing equal to the given `key` exists
// within the `btree_multimap`, returning `true` if so or `false` otherwise. // within the `btree_multimap`, returning `true` if so or `false` otherwise.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::contains; using Base::contains;
// btree_multimap::count() // btree_multimap::count()
@ -732,13 +703,13 @@ class btree_multimap
// Returns the number of elements comparing equal to the given `key` within // Returns the number of elements comparing equal to the given `key` within
// the `btree_multimap`. // the `btree_multimap`.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::count; using Base::count;
// btree_multimap::equal_range() // btree_multimap::equal_range()
// //
// Returns a half-open range [first, last), defined by a `std::pair` of two // Returns a closed range [first, last], defined by a `std::pair` of two
// iterators, containing all elements with the passed key in the // iterators, containing all elements with the passed key in the
// `btree_multimap`. // `btree_multimap`.
using Base::equal_range; using Base::equal_range;
@ -750,34 +721,10 @@ class btree_multimap
// //
// Finds an element with the passed `key` within the `btree_multimap`. // Finds an element with the passed `key` within the `btree_multimap`.
// //
// Supports heterogeneous lookup, provided that the map has a compatible // Supports heterogeneous lookup, provided that the map is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::find; using Base::find;
// btree_multimap::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element with a key that is not less than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_multimap::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element with a key that is greater than `key` within the
// `btree_multimap`.
//
// Supports heterogeneous lookup, provided that the map has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_multimap::get_allocator() // btree_multimap::get_allocator()
// //
// Returns the allocator function associated with this `btree_multimap`. // Returns the allocator function associated with this `btree_multimap`.
@ -805,45 +752,16 @@ void swap(btree_multimap<K, V, C, A> &x, btree_multimap<K, V, C, A> &y) {
// absl::erase_if(absl::btree_multimap<>, Pred) // absl::erase_if(absl::btree_multimap<>, Pred)
// //
// Erases all elements that satisfy the predicate pred from the container. // Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename V, typename C, typename A, typename Pred> template <typename K, typename V, typename C, typename A, typename Pred>
typename btree_multimap<K, V, C, A>::size_type erase_if( void erase_if(btree_multimap<K, V, C, A> &map, Pred pred) {
btree_multimap<K, V, C, A> &map, Pred pred) { for (auto it = map.begin(); it != map.end();) {
return container_internal::btree_access::erase_if(map, std::move(pred)); if (pred(*it)) {
} it = map.erase(it);
} else {
namespace container_internal { ++it;
}
// A parameters structure for holding the type parameters for a btree_map.
// Compare and Alloc should be nothrow copy-constructible.
template <typename Key, typename Data, typename Compare, typename Alloc,
int TargetNodeSize, bool IsMulti>
struct map_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/true, map_slot_policy<Key, Data>> {
using super_type = typename map_params::common_params;
using mapped_type = Data;
// This type allows us to move keys when it is safe to do so. It is safe
// for maps in which value_type and mutable_value_type are layout compatible.
using slot_policy = typename super_type::slot_policy;
using slot_type = typename super_type::slot_type;
using value_type = typename super_type::value_type;
using init_type = typename super_type::init_type;
template <typename V>
static auto key(const V &value) -> decltype(value.first) {
return value.first;
} }
static const Key &key(const slot_type *s) { return slot_policy::key(s); } }
static const Key &key(slot_type *s) { return slot_policy::key(s); }
// For use in node handle.
static auto mutable_key(slot_type *s)
-> decltype(slot_policy::mutable_key(s)) {
return slot_policy::mutable_key(s);
}
static mapped_type &value(value_type *value) { return value->second; }
};
} // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

@ -35,9 +35,7 @@
// //
// However, these types should not be considered drop-in replacements for // However, these types should not be considered drop-in replacements for
// `std::set` and `std::multiset` as there are some API differences, which are // `std::set` and `std::multiset` as there are some API differences, which are
// noted in this header file. The most consequential differences with respect to // noted in this header file.
// migrating to b-tree from the STL types are listed in the next paragraph.
// Other API differences are minor.
// //
// Importantly, insertions and deletions may invalidate outstanding iterators, // Importantly, insertions and deletions may invalidate outstanding iterators,
// pointers, and references to elements. Such invalidations are typically only // pointers, and references to elements. Such invalidations are typically only
@ -55,17 +53,6 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace container_internal {
template <typename Key>
struct set_slot_policy;
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
bool IsMulti>
struct set_params;
} // namespace container_internal
// absl::btree_set<> // absl::btree_set<>
// //
// An `absl::btree_set<K>` is an ordered associative container of unique key // An `absl::btree_set<K>` is an ordered associative container of unique key
@ -87,7 +74,7 @@ class btree_set
: public container_internal::btree_set_container< : public container_internal::btree_set_container<
container_internal::btree<container_internal::set_params< container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256, Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/false>>> { /*Multi=*/false>>> {
using Base = typename btree_set::btree_set_container; using Base = typename btree_set::btree_set_container;
public: public:
@ -313,8 +300,8 @@ class btree_set
// Determines whether an element comparing equal to the given `key` exists // Determines whether an element comparing equal to the given `key` exists
// within the `btree_set`, returning `true` if so or `false` otherwise. // within the `btree_set`, returning `true` if so or `false` otherwise.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::contains; using Base::contains;
// btree_set::count() // btree_set::count()
@ -325,8 +312,8 @@ class btree_set
// the `btree_set`. Note that this function will return either `1` or `0` // the `btree_set`. Note that this function will return either `1` or `0`
// since duplicate elements are not allowed within a `btree_set`. // since duplicate elements are not allowed within a `btree_set`.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::count; using Base::count;
// btree_set::equal_range() // btree_set::equal_range()
@ -343,32 +330,10 @@ class btree_set
// //
// Finds an element with the passed `key` within the `btree_set`. // Finds an element with the passed `key` within the `btree_set`.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::find; using Base::find;
// btree_set::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_set::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the `btree_set`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_set::get_allocator() // btree_set::get_allocator()
// //
// Returns the allocator function associated with this `btree_set`. // Returns the allocator function associated with this `btree_set`.
@ -398,11 +363,15 @@ void swap(btree_set<K, C, A> &x, btree_set<K, C, A> &y) {
// absl::erase_if(absl::btree_set<>, Pred) // absl::erase_if(absl::btree_set<>, Pred)
// //
// Erases all elements that satisfy the predicate pred from the container. // Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename C, typename A, typename Pred> template <typename K, typename C, typename A, typename Pred>
typename btree_set<K, C, A>::size_type erase_if(btree_set<K, C, A> &set, void erase_if(btree_set<K, C, A> &set, Pred pred) {
Pred pred) { for (auto it = set.begin(); it != set.end();) {
return container_internal::btree_access::erase_if(set, std::move(pred)); if (pred(*it)) {
it = set.erase(it);
} else {
++it;
}
}
} }
// absl::btree_multiset<> // absl::btree_multiset<>
@ -427,7 +396,7 @@ class btree_multiset
: public container_internal::btree_multiset_container< : public container_internal::btree_multiset_container<
container_internal::btree<container_internal::set_params< container_internal::btree<container_internal::set_params<
Key, Compare, Alloc, /*TargetNodeSize=*/256, Key, Compare, Alloc, /*TargetNodeSize=*/256,
/*IsMulti=*/true>>> { /*Multi=*/true>>> {
using Base = typename btree_multiset::btree_multiset_container; using Base = typename btree_multiset::btree_multiset_container;
public: public:
@ -613,8 +582,9 @@ class btree_multiset
// btree_multiset::merge() // btree_multiset::merge()
// //
// Extracts all elements from a given `source` btree_multiset into this // Extracts elements from a given `source` btree_multiset into this
// `btree_multiset`. // `btree_multiset`. If the destination `btree_multiset` already contains an
// element with an equivalent key, that element is not extracted.
using Base::merge; using Base::merge;
// btree_multiset::swap(btree_multiset& other) // btree_multiset::swap(btree_multiset& other)
@ -634,8 +604,8 @@ class btree_multiset
// Determines whether an element comparing equal to the given `key` exists // Determines whether an element comparing equal to the given `key` exists
// within the `btree_multiset`, returning `true` if so or `false` otherwise. // within the `btree_multiset`, returning `true` if so or `false` otherwise.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::contains; using Base::contains;
// btree_multiset::count() // btree_multiset::count()
@ -645,8 +615,8 @@ class btree_multiset
// Returns the number of elements comparing equal to the given `key` within // Returns the number of elements comparing equal to the given `key` within
// the `btree_multiset`. // the `btree_multiset`.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::count; using Base::count;
// btree_multiset::equal_range() // btree_multiset::equal_range()
@ -663,34 +633,10 @@ class btree_multiset
// //
// Finds an element with the passed `key` within the `btree_multiset`. // Finds an element with the passed `key` within the `btree_multiset`.
// //
// Supports heterogeneous lookup, provided that the set has a compatible // Supports heterogeneous lookup, provided that the set is provided a
// heterogeneous comparator. // compatible heterogeneous comparator.
using Base::find; using Base::find;
// btree_multiset::lower_bound()
//
// template <typename K> iterator lower_bound(const K& key):
// template <typename K> const_iterator lower_bound(const K& key) const:
//
// Finds the first element that is not less than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::lower_bound;
// btree_multiset::upper_bound()
//
// template <typename K> iterator upper_bound(const K& key):
// template <typename K> const_iterator upper_bound(const K& key) const:
//
// Finds the first element that is greater than `key` within the
// `btree_multiset`.
//
// Supports heterogeneous lookup, provided that the set has a compatible
// heterogeneous comparator.
using Base::upper_bound;
// btree_multiset::get_allocator() // btree_multiset::get_allocator()
// //
// Returns the allocator function associated with this `btree_multiset`. // Returns the allocator function associated with this `btree_multiset`.
@ -720,72 +666,16 @@ void swap(btree_multiset<K, C, A> &x, btree_multiset<K, C, A> &y) {
// absl::erase_if(absl::btree_multiset<>, Pred) // absl::erase_if(absl::btree_multiset<>, Pred)
// //
// Erases all elements that satisfy the predicate pred from the container. // Erases all elements that satisfy the predicate pred from the container.
// Returns the number of erased elements.
template <typename K, typename C, typename A, typename Pred> template <typename K, typename C, typename A, typename Pred>
typename btree_multiset<K, C, A>::size_type erase_if( void erase_if(btree_multiset<K, C, A> &set, Pred pred) {
btree_multiset<K, C, A> & set, Pred pred) { for (auto it = set.begin(); it != set.end();) {
return container_internal::btree_access::erase_if(set, std::move(pred)); if (pred(*it)) {
} it = set.erase(it);
} else {
namespace container_internal { ++it;
}
// This type implements the necessary functions from the
// absl::container_internal::slot_type interface for btree_(multi)set.
template <typename Key>
struct set_slot_policy {
using slot_type = Key;
using value_type = Key;
using mutable_value_type = Key;
static value_type &element(slot_type *slot) { return *slot; }
static const value_type &element(const slot_type *slot) { return *slot; }
template <typename Alloc, class... Args>
static void construct(Alloc *alloc, slot_type *slot, Args &&...args) {
absl::allocator_traits<Alloc>::construct(*alloc, slot,
std::forward<Args>(args)...);
}
template <typename Alloc>
static void construct(Alloc *alloc, slot_type *slot, slot_type *other) {
absl::allocator_traits<Alloc>::construct(*alloc, slot, std::move(*other));
}
template <typename Alloc>
static void construct(Alloc *alloc, slot_type *slot, const slot_type *other) {
absl::allocator_traits<Alloc>::construct(*alloc, slot, *other);
}
template <typename Alloc>
static void destroy(Alloc *alloc, slot_type *slot) {
absl::allocator_traits<Alloc>::destroy(*alloc, slot);
} }
}
template <typename Alloc>
static void transfer(Alloc *alloc, slot_type *new_slot, slot_type *old_slot) {
construct(alloc, new_slot, old_slot);
destroy(alloc, old_slot);
}
};
// A parameters structure for holding the type parameters for a btree_set.
// Compare and Alloc should be nothrow copy-constructible.
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize,
bool IsMulti>
struct set_params : common_params<Key, Compare, Alloc, TargetNodeSize, IsMulti,
/*IsMap=*/false, set_slot_policy<Key>> {
using value_type = Key;
using slot_type = typename set_params::common_params::slot_type;
template <typename V>
static const V &key(const V &value) {
return value;
}
static const Key &key(const slot_type *slot) { return *slot; }
static const Key &key(slot_type *slot) { return *slot; }
};
} // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl

File diff suppressed because it is too large Load Diff

@ -73,6 +73,11 @@ constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
// uninitialized (e.g. int, int[4], double), and others default-constructed. // uninitialized (e.g. int, int[4], double), and others default-constructed.
// This matches the behavior of c-style arrays and `std::array`, but not // This matches the behavior of c-style arrays and `std::array`, but not
// `std::vector`. // `std::vector`.
//
// Note that `FixedArray` does not provide a public allocator; if it requires a
// heap allocation, it will do so with global `::operator new[]()` and
// `::operator delete[]()`, even if T provides class-scope overrides for these
// operators.
template <typename T, size_t N = kFixedArrayUseDefault, template <typename T, size_t N = kFixedArrayUseDefault,
typename A = std::allocator<T>> typename A = std::allocator<T>>
class FixedArray { class FixedArray {
@ -227,8 +232,8 @@ class FixedArray {
// FixedArray::at // FixedArray::at
// //
// Bounds-checked access. Returns a reference to the ith element of the fixed // Bounds-checked access. Returns a reference to the ith element of the
// array, or throws std::out_of_range // fiexed array, or throws std::out_of_range
reference at(size_type i) { reference at(size_type i) {
if (ABSL_PREDICT_FALSE(i >= size())) { if (ABSL_PREDICT_FALSE(i >= size())) {
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
@ -489,14 +494,12 @@ class FixedArray {
Storage storage_; Storage storage_;
}; };
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault; constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
constexpr typename FixedArray<T, N, A>::size_type constexpr typename FixedArray<T, N, A>::size_type
FixedArray<T, N, A>::inline_elements; FixedArray<T, N, A>::inline_elements;
#endif
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct( void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(

@ -36,7 +36,6 @@
#include <utility> #include <utility>
#include "absl/algorithm/container.h" #include "absl/algorithm/container.h"
#include "absl/base/macros.h"
#include "absl/container/internal/container_memory.h" #include "absl/container/internal/container_memory.h"
#include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export #include "absl/container/internal/hash_function_defaults.h" // IWYU pragma: export
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export #include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
@ -76,10 +75,6 @@ struct FlatHashMapPolicy;
// absl/hash/hash.h for information on extending Abseil hashing to user-defined // absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types. // types.
// //
// Using `absl::flat_hash_map` at interface boundaries in dynamically loaded
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
// be randomized across dynamically loaded libraries.
//
// NOTE: A `flat_hash_map` stores its value types directly inside its // NOTE: A `flat_hash_map` stores its value types directly inside its
// implementation array to avoid memory indirection. Because a `flat_hash_map` // implementation array to avoid memory indirection. Because a `flat_hash_map`
// is designed to move data when rehashed, map values will not retain pointer // is designed to move data when rehashed, map values will not retain pointer
@ -361,8 +356,8 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
// `flat_hash_map`. // `flat_hash_map`.
// //
// iterator try_emplace(const_iterator hint, // iterator try_emplace(const_iterator hint,
// const key_type& k, Args&&... args): // const init_type& k, Args&&... args):
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args): // iterator try_emplace(const_iterator hint, init_type&& k, Args&&... args):
// //
// Inserts (via copy or move) the element of the specified key into the // Inserts (via copy or move) the element of the specified key into the
// `flat_hash_map` using the position of `hint` as a non-binding suggestion // `flat_hash_map` using the position of `hint` as a non-binding suggestion
@ -546,12 +541,10 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
// erase_if(flat_hash_map<>, Pred) // erase_if(flat_hash_map<>, Pred)
// //
// Erases all elements that satisfy the predicate `pred` from the container `c`. // Erases all elements that satisfy the predicate `pred` from the container `c`.
// Returns the number of erased elements.
template <typename K, typename V, typename H, typename E, typename A, template <typename K, typename V, typename H, typename E, typename A,
typename Predicate> typename Predicate>
typename flat_hash_map<K, V, H, E, A>::size_type erase_if( void erase_if(flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
flat_hash_map<K, V, H, E, A>& c, Predicate pred) { container_internal::EraseIf(pred, &c);
return container_internal::EraseIf(pred, &c);
} }
namespace container_internal { namespace container_internal {

@ -236,36 +236,33 @@ TEST(FlatHashMap, EraseIf) {
// Erase all elements. // Erase all elements.
{ {
flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
EXPECT_EQ(erase_if(s, [](std::pair<const int, int>) { return true; }), 5); erase_if(s, [](std::pair<const int, int>) { return true; });
EXPECT_THAT(s, IsEmpty()); EXPECT_THAT(s, IsEmpty());
} }
// Erase no elements. // Erase no elements.
{ {
flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
EXPECT_EQ(erase_if(s, [](std::pair<const int, int>) { return false; }), 0); erase_if(s, [](std::pair<const int, int>) { return false; });
EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3), EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(2, 2), Pair(3, 3),
Pair(4, 4), Pair(5, 5))); Pair(4, 4), Pair(5, 5)));
} }
// Erase specific elements. // Erase specific elements.
{ {
flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
EXPECT_EQ(erase_if(s, erase_if(s,
[](std::pair<const int, int> kvp) { [](std::pair<const int, int> kvp) { return kvp.first % 2 == 1; });
return kvp.first % 2 == 1;
}),
3);
EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4))); EXPECT_THAT(s, UnorderedElementsAre(Pair(2, 2), Pair(4, 4)));
} }
// Predicate is function reference. // Predicate is function reference.
{ {
flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
EXPECT_EQ(erase_if(s, FirstIsEven), 2); erase_if(s, FirstIsEven);
EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5))); EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
} }
// Predicate is function pointer. // Predicate is function pointer.
{ {
flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}}; flat_hash_map<int, int> s = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}};
EXPECT_EQ(erase_if(s, &FirstIsEven), 2); erase_if(s, &FirstIsEven);
EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5))); EXPECT_THAT(s, UnorderedElementsAre(Pair(1, 1), Pair(3, 3), Pair(5, 5)));
} }
} }
@ -285,32 +282,6 @@ TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
} }
#endif #endif
TEST(FlatHashMap, Reserve) {
// Verify that if we reserve(size() + n) then we can perform n insertions
// without a rehash, i.e., without invalidating any references.
for (size_t trial = 0; trial < 20; ++trial) {
for (size_t initial = 3; initial < 100; ++initial) {
// Fill in `initial` entries, then erase 2 of them, then reserve space for
// two inserts and check for reference stability while doing the inserts.
flat_hash_map<size_t, size_t> map;
for (size_t i = 0; i < initial; ++i) {
map[i] = i;
}
map.erase(0);
map.erase(1);
map.reserve(map.size() + 2);
size_t& a2 = map[2];
// In the event of a failure, asan will complain in one of these two
// assignments.
map[initial] = a2;
map[initial + 1] = a2;
// Fail even when not under asan:
size_t& a2new = map[2];
EXPECT_EQ(&a2, &a2new);
}
}
}
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END

@ -67,15 +67,11 @@ struct FlatHashSetPolicy;
// //
// By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All // By default, `flat_hash_set` uses the `absl::Hash` hashing framework. All
// fundamental and Abseil types that support the `absl::Hash` framework have a // fundamental and Abseil types that support the `absl::Hash` framework have a
// compatible equality operator for comparing insertions into `flat_hash_set`. // compatible equality operator for comparing insertions into `flat_hash_map`.
// If your type is not yet supported by the `absl::Hash` framework, see // If your type is not yet supported by the `absl::Hash` framework, see
// absl/hash/hash.h for information on extending Abseil hashing to user-defined // absl/hash/hash.h for information on extending Abseil hashing to user-defined
// types. // types.
// //
// Using `absl::flat_hash_set` at interface boundaries in dynamically loaded
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
// be randomized across dynamically loaded libraries.
//
// NOTE: A `flat_hash_set` stores its keys directly inside its implementation // NOTE: A `flat_hash_set` stores its keys directly inside its implementation
// array to avoid memory indirection. Because a `flat_hash_set` is designed to // array to avoid memory indirection. Because a `flat_hash_set` is designed to
// move data when rehashed, set keys will not retain pointer stability. If you // move data when rehashed, set keys will not retain pointer stability. If you
@ -110,7 +106,7 @@ class flat_hash_set
public: public:
// Constructors and Assignment Operators // Constructors and Assignment Operators
// //
// A flat_hash_set supports the same overload set as `std::unordered_set` // A flat_hash_set supports the same overload set as `std::unordered_map`
// for construction and assignment: // for construction and assignment:
// //
// * Default constructor // * Default constructor
@ -177,7 +173,7 @@ class flat_hash_set
// available within the `flat_hash_set`. // available within the `flat_hash_set`.
// //
// NOTE: this member function is particular to `absl::flat_hash_set` and is // NOTE: this member function is particular to `absl::flat_hash_set` and is
// not provided in the `std::unordered_set` API. // not provided in the `std::unordered_map` API.
using Base::capacity; using Base::capacity;
// flat_hash_set::empty() // flat_hash_set::empty()
@ -328,7 +324,7 @@ class flat_hash_set
// flat_hash_set::merge() // flat_hash_set::merge()
// //
// Extracts elements from a given `source` flat hash set into this // Extracts elements from a given `source` flat hash map into this
// `flat_hash_set`. If the destination `flat_hash_set` already contains an // `flat_hash_set`. If the destination `flat_hash_set` already contains an
// element with an equivalent key, that element is not extracted. // element with an equivalent key, that element is not extracted.
using Base::merge; using Base::merge;
@ -336,7 +332,7 @@ class flat_hash_set
// flat_hash_set::swap(flat_hash_set& other) // flat_hash_set::swap(flat_hash_set& other)
// //
// Exchanges the contents of this `flat_hash_set` with those of the `other` // Exchanges the contents of this `flat_hash_set` with those of the `other`
// flat hash set, avoiding invocation of any move, copy, or swap operations on // flat hash map, avoiding invocation of any move, copy, or swap operations on
// individual elements. // individual elements.
// //
// All iterators and references on the `flat_hash_set` remain valid, excepting // All iterators and references on the `flat_hash_set` remain valid, excepting
@ -344,7 +340,7 @@ class flat_hash_set
// //
// `swap()` requires that the flat hash set's hashing and key equivalence // `swap()` requires that the flat hash set's hashing and key equivalence
// functions be Swappable, and are exchaged using unqualified calls to // functions be Swappable, and are exchaged using unqualified calls to
// non-member `swap()`. If the set's allocator has // non-member `swap()`. If the map's allocator has
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value` // `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
// set to `true`, the allocators are also exchanged using an unqualified call // set to `true`, the allocators are also exchanged using an unqualified call
// to non-member `swap()`; otherwise, the allocators are not swapped. // to non-member `swap()`; otherwise, the allocators are not swapped.
@ -399,14 +395,14 @@ class flat_hash_set
// flat_hash_set::bucket_count() // flat_hash_set::bucket_count()
// //
// Returns the number of "buckets" within the `flat_hash_set`. Note that // Returns the number of "buckets" within the `flat_hash_set`. Note that
// because a flat hash set contains all elements within its internal storage, // because a flat hash map contains all elements within its internal storage,
// this value simply equals the current capacity of the `flat_hash_set`. // this value simply equals the current capacity of the `flat_hash_set`.
using Base::bucket_count; using Base::bucket_count;
// flat_hash_set::load_factor() // flat_hash_set::load_factor()
// //
// Returns the current load factor of the `flat_hash_set` (the average number // Returns the current load factor of the `flat_hash_set` (the average number
// of slots occupied with a value within the hash set). // of slots occupied with a value within the hash map).
using Base::load_factor; using Base::load_factor;
// flat_hash_set::max_load_factor() // flat_hash_set::max_load_factor()
@ -447,11 +443,9 @@ class flat_hash_set
// erase_if(flat_hash_set<>, Pred) // erase_if(flat_hash_set<>, Pred)
// //
// Erases all elements that satisfy the predicate `pred` from the container `c`. // Erases all elements that satisfy the predicate `pred` from the container `c`.
// Returns the number of erased elements.
template <typename T, typename H, typename E, typename A, typename Predicate> template <typename T, typename H, typename E, typename A, typename Predicate>
typename flat_hash_set<T, H, E, A>::size_type erase_if( void erase_if(flat_hash_set<T, H, E, A>& c, Predicate pred) {
flat_hash_set<T, H, E, A>& c, Predicate pred) { container_internal::EraseIf(pred, &c);
return container_internal::EraseIf(pred, &c);
} }
namespace container_internal { namespace container_internal {

@ -143,31 +143,31 @@ TEST(FlatHashSet, EraseIf) {
// Erase all elements. // Erase all elements.
{ {
flat_hash_set<int> s = {1, 2, 3, 4, 5}; flat_hash_set<int> s = {1, 2, 3, 4, 5};
EXPECT_EQ(erase_if(s, [](int) { return true; }), 5); erase_if(s, [](int) { return true; });
EXPECT_THAT(s, IsEmpty()); EXPECT_THAT(s, IsEmpty());
} }
// Erase no elements. // Erase no elements.
{ {
flat_hash_set<int> s = {1, 2, 3, 4, 5}; flat_hash_set<int> s = {1, 2, 3, 4, 5};
EXPECT_EQ(erase_if(s, [](int) { return false; }), 0); erase_if(s, [](int) { return false; });
EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5)); EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5));
} }
// Erase specific elements. // Erase specific elements.
{ {
flat_hash_set<int> s = {1, 2, 3, 4, 5}; flat_hash_set<int> s = {1, 2, 3, 4, 5};
EXPECT_EQ(erase_if(s, [](int k) { return k % 2 == 1; }), 3); erase_if(s, [](int k) { return k % 2 == 1; });
EXPECT_THAT(s, UnorderedElementsAre(2, 4)); EXPECT_THAT(s, UnorderedElementsAre(2, 4));
} }
// Predicate is function reference. // Predicate is function reference.
{ {
flat_hash_set<int> s = {1, 2, 3, 4, 5}; flat_hash_set<int> s = {1, 2, 3, 4, 5};
EXPECT_EQ(erase_if(s, IsEven), 2); erase_if(s, IsEven);
EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5)); EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
} }
// Predicate is function pointer. // Predicate is function pointer.
{ {
flat_hash_set<int> s = {1, 2, 3, 4, 5}; flat_hash_set<int> s = {1, 2, 3, 4, 5};
EXPECT_EQ(erase_if(s, &IsEven), 2); erase_if(s, &IsEven);
EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5)); EXPECT_THAT(s, UnorderedElementsAre(1, 3, 5));
} }
} }

@ -36,6 +36,7 @@
#define ABSL_CONTAINER_INLINED_VECTOR_H_ #define ABSL_CONTAINER_INLINED_VECTOR_H_
#include <algorithm> #include <algorithm>
#include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -71,43 +72,37 @@ class InlinedVector {
using Storage = inlined_vector_internal::Storage<T, N, A>; using Storage = inlined_vector_internal::Storage<T, N, A>;
template <typename TheA> using AllocatorTraits = typename Storage::AllocatorTraits;
using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>; using RValueReference = typename Storage::RValueReference;
template <typename TheA> using MoveIterator = typename Storage::MoveIterator;
using MoveIterator = inlined_vector_internal::MoveIterator<TheA>; using IsMemcpyOk = typename Storage::IsMemcpyOk;
template <typename TheA>
using IsMemcpyOk = inlined_vector_internal::IsMemcpyOk<TheA>;
template <typename TheA, typename Iterator> template <typename Iterator>
using IteratorValueAdapter = using IteratorValueAdapter =
inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>; typename Storage::template IteratorValueAdapter<Iterator>;
template <typename TheA> using CopyValueAdapter = typename Storage::CopyValueAdapter;
using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>; using DefaultValueAdapter = typename Storage::DefaultValueAdapter;
template <typename TheA>
using DefaultValueAdapter =
inlined_vector_internal::DefaultValueAdapter<TheA>;
template <typename Iterator> template <typename Iterator>
using EnableIfAtLeastForwardIterator = absl::enable_if_t< using EnableIfAtLeastForwardIterator = absl::enable_if_t<
inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>; inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
template <typename Iterator> template <typename Iterator>
using DisableIfAtLeastForwardIterator = absl::enable_if_t< using DisableIfAtLeastForwardIterator = absl::enable_if_t<
!inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value, int>; !inlined_vector_internal::IsAtLeastForwardIterator<Iterator>::value>;
public: public:
using allocator_type = A; using allocator_type = typename Storage::allocator_type;
using value_type = inlined_vector_internal::ValueType<A>; using value_type = typename Storage::value_type;
using pointer = inlined_vector_internal::Pointer<A>; using pointer = typename Storage::pointer;
using const_pointer = inlined_vector_internal::ConstPointer<A>; using const_pointer = typename Storage::const_pointer;
using size_type = inlined_vector_internal::SizeType<A>; using size_type = typename Storage::size_type;
using difference_type = inlined_vector_internal::DifferenceType<A>; using difference_type = typename Storage::difference_type;
using reference = inlined_vector_internal::Reference<A>; using reference = typename Storage::reference;
using const_reference = inlined_vector_internal::ConstReference<A>; using const_reference = typename Storage::const_reference;
using iterator = inlined_vector_internal::Iterator<A>; using iterator = typename Storage::iterator;
using const_iterator = inlined_vector_internal::ConstIterator<A>; using const_iterator = typename Storage::const_iterator;
using reverse_iterator = inlined_vector_internal::ReverseIterator<A>; using reverse_iterator = typename Storage::reverse_iterator;
using const_reverse_iterator = using const_reverse_iterator = typename Storage::const_reverse_iterator;
inlined_vector_internal::ConstReverseIterator<A>;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// InlinedVector Constructors and Destructor // InlinedVector Constructors and Destructor
@ -116,28 +111,28 @@ class InlinedVector {
// Creates an empty inlined vector with a value-initialized allocator. // Creates an empty inlined vector with a value-initialized allocator.
InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {} InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
// Creates an empty inlined vector with a copy of `allocator`. // Creates an empty inlined vector with a copy of `alloc`.
explicit InlinedVector(const allocator_type& allocator) noexcept explicit InlinedVector(const allocator_type& alloc) noexcept
: storage_(allocator) {} : storage_(alloc) {}
// Creates an inlined vector with `n` copies of `value_type()`. // Creates an inlined vector with `n` copies of `value_type()`.
explicit InlinedVector(size_type n, explicit InlinedVector(size_type n,
const allocator_type& allocator = allocator_type()) const allocator_type& alloc = allocator_type())
: storage_(allocator) { : storage_(alloc) {
storage_.Initialize(DefaultValueAdapter<A>(), n); storage_.Initialize(DefaultValueAdapter(), n);
} }
// Creates an inlined vector with `n` copies of `v`. // Creates an inlined vector with `n` copies of `v`.
InlinedVector(size_type n, const_reference v, InlinedVector(size_type n, const_reference v,
const allocator_type& allocator = allocator_type()) const allocator_type& alloc = allocator_type())
: storage_(allocator) { : storage_(alloc) {
storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n); storage_.Initialize(CopyValueAdapter(v), n);
} }
// Creates an inlined vector with copies of the elements of `list`. // Creates an inlined vector with copies of the elements of `list`.
InlinedVector(std::initializer_list<value_type> list, InlinedVector(std::initializer_list<value_type> list,
const allocator_type& allocator = allocator_type()) const allocator_type& alloc = allocator_type())
: InlinedVector(list.begin(), list.end(), allocator) {} : InlinedVector(list.begin(), list.end(), alloc) {}
// Creates an inlined vector with elements constructed from the provided // Creates an inlined vector with elements constructed from the provided
// forward iterator range [`first`, `last`). // forward iterator range [`first`, `last`).
@ -146,40 +141,37 @@ class InlinedVector {
// this constructor with two integral arguments and a call to the above // this constructor with two integral arguments and a call to the above
// `InlinedVector(size_type, const_reference)` constructor. // `InlinedVector(size_type, const_reference)` constructor.
template <typename ForwardIterator, template <typename ForwardIterator,
EnableIfAtLeastForwardIterator<ForwardIterator> = 0> EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
InlinedVector(ForwardIterator first, ForwardIterator last, InlinedVector(ForwardIterator first, ForwardIterator last,
const allocator_type& allocator = allocator_type()) const allocator_type& alloc = allocator_type())
: storage_(allocator) { : storage_(alloc) {
storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first), storage_.Initialize(IteratorValueAdapter<ForwardIterator>(first),
static_cast<size_t>(std::distance(first, last))); std::distance(first, last));
} }
// Creates an inlined vector with elements constructed from the provided input // Creates an inlined vector with elements constructed from the provided input
// iterator range [`first`, `last`). // iterator range [`first`, `last`).
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator> = 0> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
InlinedVector(InputIterator first, InputIterator last, InlinedVector(InputIterator first, InputIterator last,
const allocator_type& allocator = allocator_type()) const allocator_type& alloc = allocator_type())
: storage_(allocator) { : storage_(alloc) {
std::copy(first, last, std::back_inserter(*this)); std::copy(first, last, std::back_inserter(*this));
} }
// Creates an inlined vector by copying the contents of `other` using // Creates an inlined vector by copying the contents of `other` using
// `other`'s allocator. // `other`'s allocator.
InlinedVector(const InlinedVector& other) InlinedVector(const InlinedVector& other)
: InlinedVector(other, other.storage_.GetAllocator()) {} : InlinedVector(other, *other.storage_.GetAllocPtr()) {}
// Creates an inlined vector by copying the contents of `other` using the // Creates an inlined vector by copying the contents of `other` using `alloc`.
// provided `allocator`. InlinedVector(const InlinedVector& other, const allocator_type& alloc)
InlinedVector(const InlinedVector& other, const allocator_type& allocator) : storage_(alloc) {
: storage_(allocator) { if (IsMemcpyOk::value && !other.storage_.GetIsAllocated()) {
if (other.empty()) {
// Empty; nothing to do.
} else if (IsMemcpyOk<A>::value && !other.storage_.GetIsAllocated()) {
// Memcpy-able and do not need allocation.
storage_.MemcpyFrom(other.storage_); storage_.MemcpyFrom(other.storage_);
} else { } else {
storage_.InitFrom(other.storage_); storage_.Initialize(IteratorValueAdapter<const_pointer>(other.data()),
other.size());
} }
} }
@ -200,23 +192,23 @@ class InlinedVector {
InlinedVector(InlinedVector&& other) noexcept( InlinedVector(InlinedVector&& other) noexcept(
absl::allocator_is_nothrow<allocator_type>::value || absl::allocator_is_nothrow<allocator_type>::value ||
std::is_nothrow_move_constructible<value_type>::value) std::is_nothrow_move_constructible<value_type>::value)
: storage_(other.storage_.GetAllocator()) { : storage_(*other.storage_.GetAllocPtr()) {
if (IsMemcpyOk<A>::value) { if (IsMemcpyOk::value) {
storage_.MemcpyFrom(other.storage_); storage_.MemcpyFrom(other.storage_);
other.storage_.SetInlinedSize(0); other.storage_.SetInlinedSize(0);
} else if (other.storage_.GetIsAllocated()) { } else if (other.storage_.GetIsAllocated()) {
storage_.SetAllocation({other.storage_.GetAllocatedData(), storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
other.storage_.GetAllocatedCapacity()}); other.storage_.GetAllocatedCapacity());
storage_.SetAllocatedSize(other.storage_.GetSize()); storage_.SetAllocatedSize(other.storage_.GetSize());
other.storage_.SetInlinedSize(0); other.storage_.SetInlinedSize(0);
} else { } else {
IteratorValueAdapter<A, MoveIterator<A>> other_values( IteratorValueAdapter<MoveIterator> other_values(
MoveIterator<A>(other.storage_.GetInlinedData())); MoveIterator(other.storage_.GetInlinedData()));
inlined_vector_internal::ConstructElements<A>( inlined_vector_internal::ConstructElements(
storage_.GetAllocator(), storage_.GetInlinedData(), other_values, storage_.GetAllocPtr(), storage_.GetInlinedData(), &other_values,
other.storage_.GetSize()); other.storage_.GetSize());
storage_.SetInlinedSize(other.storage_.GetSize()); storage_.SetInlinedSize(other.storage_.GetSize());
@ -224,32 +216,30 @@ class InlinedVector {
} }
// Creates an inlined vector by moving in the contents of `other` with a copy // Creates an inlined vector by moving in the contents of `other` with a copy
// of `allocator`. // of `alloc`.
// //
// NOTE: if `other`'s allocator is not equal to `allocator`, even if `other` // NOTE: if `other`'s allocator is not equal to `alloc`, even if `other`
// contains allocated memory, this move constructor will still allocate. Since // contains allocated memory, this move constructor will still allocate. Since
// allocation is performed, this constructor can only be `noexcept` if the // allocation is performed, this constructor can only be `noexcept` if the
// specified allocator is also `noexcept`. // specified allocator is also `noexcept`.
InlinedVector( InlinedVector(InlinedVector&& other, const allocator_type& alloc) noexcept(
InlinedVector&& other, absl::allocator_is_nothrow<allocator_type>::value)
const allocator_type& : storage_(alloc) {
allocator) noexcept(absl::allocator_is_nothrow<allocator_type>::value) if (IsMemcpyOk::value) {
: storage_(allocator) {
if (IsMemcpyOk<A>::value) {
storage_.MemcpyFrom(other.storage_); storage_.MemcpyFrom(other.storage_);
other.storage_.SetInlinedSize(0); other.storage_.SetInlinedSize(0);
} else if ((storage_.GetAllocator() == other.storage_.GetAllocator()) && } else if ((*storage_.GetAllocPtr() == *other.storage_.GetAllocPtr()) &&
other.storage_.GetIsAllocated()) { other.storage_.GetIsAllocated()) {
storage_.SetAllocation({other.storage_.GetAllocatedData(), storage_.SetAllocatedData(other.storage_.GetAllocatedData(),
other.storage_.GetAllocatedCapacity()}); other.storage_.GetAllocatedCapacity());
storage_.SetAllocatedSize(other.storage_.GetSize()); storage_.SetAllocatedSize(other.storage_.GetSize());
other.storage_.SetInlinedSize(0); other.storage_.SetInlinedSize(0);
} else { } else {
storage_.Initialize(IteratorValueAdapter<A, MoveIterator<A>>( storage_.Initialize(
MoveIterator<A>(other.data())), IteratorValueAdapter<MoveIterator>(MoveIterator(other.data())),
other.size()); other.size());
} }
} }
@ -450,7 +440,7 @@ class InlinedVector {
// `InlinedVector::get_allocator()` // `InlinedVector::get_allocator()`
// //
// Returns a copy of the inlined vector's allocator. // Returns a copy of the inlined vector's allocator.
allocator_type get_allocator() const { return storage_.GetAllocator(); } allocator_type get_allocator() const { return *storage_.GetAllocPtr(); }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// InlinedVector Member Mutators // InlinedVector Member Mutators
@ -484,16 +474,16 @@ class InlinedVector {
// unspecified state. // unspecified state.
InlinedVector& operator=(InlinedVector&& other) { InlinedVector& operator=(InlinedVector&& other) {
if (ABSL_PREDICT_TRUE(this != std::addressof(other))) { if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
if (IsMemcpyOk<A>::value || other.storage_.GetIsAllocated()) { if (IsMemcpyOk::value || other.storage_.GetIsAllocated()) {
inlined_vector_internal::DestroyAdapter<A>::DestroyElements( inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
storage_.GetAllocator(), data(), size()); size());
storage_.DeallocateIfAllocated(); storage_.DeallocateIfAllocated();
storage_.MemcpyFrom(other.storage_); storage_.MemcpyFrom(other.storage_);
other.storage_.SetInlinedSize(0); other.storage_.SetInlinedSize(0);
} else { } else {
storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>( storage_.Assign(IteratorValueAdapter<MoveIterator>(
MoveIterator<A>(other.storage_.GetInlinedData())), MoveIterator(other.storage_.GetInlinedData())),
other.size()); other.size());
} }
} }
@ -505,7 +495,7 @@ class InlinedVector {
// //
// Replaces the contents of the inlined vector with `n` copies of `v`. // Replaces the contents of the inlined vector with `n` copies of `v`.
void assign(size_type n, const_reference v) { void assign(size_type n, const_reference v) {
storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n); storage_.Assign(CopyValueAdapter(v), n);
} }
// Overload of `InlinedVector::assign(...)` that replaces the contents of the // Overload of `InlinedVector::assign(...)` that replaces the contents of the
@ -519,10 +509,10 @@ class InlinedVector {
// //
// NOTE: this overload is for iterators that are "forward" category or better. // NOTE: this overload is for iterators that are "forward" category or better.
template <typename ForwardIterator, template <typename ForwardIterator,
EnableIfAtLeastForwardIterator<ForwardIterator> = 0> EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
void assign(ForwardIterator first, ForwardIterator last) { void assign(ForwardIterator first, ForwardIterator last) {
storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first), storage_.Assign(IteratorValueAdapter<ForwardIterator>(first),
static_cast<size_t>(std::distance(first, last))); std::distance(first, last));
} }
// Overload of `InlinedVector::assign(...)` to replace the contents of the // Overload of `InlinedVector::assign(...)` to replace the contents of the
@ -530,7 +520,7 @@ class InlinedVector {
// //
// NOTE: this overload is for iterators that are "input" category. // NOTE: this overload is for iterators that are "input" category.
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator> = 0> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
void assign(InputIterator first, InputIterator last) { void assign(InputIterator first, InputIterator last) {
size_type i = 0; size_type i = 0;
for (; i < size() && first != last; ++i, static_cast<void>(++first)) { for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
@ -549,7 +539,7 @@ class InlinedVector {
// is larger than `size()`, new elements are value-initialized. // is larger than `size()`, new elements are value-initialized.
void resize(size_type n) { void resize(size_type n) {
ABSL_HARDENING_ASSERT(n <= max_size()); ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(DefaultValueAdapter<A>(), n); storage_.Resize(DefaultValueAdapter(), n);
} }
// Overload of `InlinedVector::resize(...)` that resizes the inlined vector to // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
@ -559,7 +549,7 @@ class InlinedVector {
// is larger than `size()`, new elements are copied-constructed from `v`. // is larger than `size()`, new elements are copied-constructed from `v`.
void resize(size_type n, const_reference v) { void resize(size_type n, const_reference v) {
ABSL_HARDENING_ASSERT(n <= max_size()); ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n); storage_.Resize(CopyValueAdapter(v), n);
} }
// `InlinedVector::insert(...)` // `InlinedVector::insert(...)`
@ -572,7 +562,7 @@ class InlinedVector {
// Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
// move semantics, returning an `iterator` to the newly inserted element. // move semantics, returning an `iterator` to the newly inserted element.
iterator insert(const_iterator pos, value_type&& v) { iterator insert(const_iterator pos, RValueReference v) {
return emplace(pos, std::move(v)); return emplace(pos, std::move(v));
} }
@ -585,20 +575,7 @@ class InlinedVector {
if (ABSL_PREDICT_TRUE(n != 0)) { if (ABSL_PREDICT_TRUE(n != 0)) {
value_type dealias = v; value_type dealias = v;
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2 return storage_.Insert(pos, CopyValueAdapter(dealias), n);
// It appears that GCC thinks that since `pos` is a const pointer and may
// point to uninitialized memory at this point, a warning should be
// issued. But `pos` is actually only used to compute an array index to
// write to.
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)),
n);
#if !defined(__clang__) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
} else { } else {
return const_cast<iterator>(pos); return const_cast<iterator>(pos);
} }
@ -617,15 +594,14 @@ class InlinedVector {
// //
// NOTE: this overload is for iterators that are "forward" category or better. // NOTE: this overload is for iterators that are "forward" category or better.
template <typename ForwardIterator, template <typename ForwardIterator,
EnableIfAtLeastForwardIterator<ForwardIterator> = 0> EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
iterator insert(const_iterator pos, ForwardIterator first, iterator insert(const_iterator pos, ForwardIterator first,
ForwardIterator last) { ForwardIterator last) {
ABSL_HARDENING_ASSERT(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
if (ABSL_PREDICT_TRUE(first != last)) { if (ABSL_PREDICT_TRUE(first != last)) {
return storage_.Insert(pos, return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
IteratorValueAdapter<A, ForwardIterator>(first),
std::distance(first, last)); std::distance(first, last));
} else { } else {
return const_cast<iterator>(pos); return const_cast<iterator>(pos);
@ -638,7 +614,7 @@ class InlinedVector {
// //
// NOTE: this overload is for iterators that are "input" category. // NOTE: this overload is for iterators that are "input" category.
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator> = 0> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
iterator insert(const_iterator pos, InputIterator first, InputIterator last) { iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
ABSL_HARDENING_ASSERT(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
ABSL_HARDENING_ASSERT(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
@ -662,8 +638,8 @@ class InlinedVector {
value_type dealias(std::forward<Args>(args)...); value_type dealias(std::forward<Args>(args)...);
return storage_.Insert(pos, return storage_.Insert(pos,
IteratorValueAdapter<A, MoveIterator<A>>( IteratorValueAdapter<MoveIterator>(
MoveIterator<A>(std::addressof(dealias))), MoveIterator(std::addressof(dealias))),
1); 1);
} }
@ -683,7 +659,7 @@ class InlinedVector {
// Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()` // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
// using move semantics. // using move semantics.
void push_back(value_type&& v) { void push_back(RValueReference v) {
static_cast<void>(emplace_back(std::move(v))); static_cast<void>(emplace_back(std::move(v)));
} }
@ -693,7 +669,7 @@ class InlinedVector {
void pop_back() noexcept { void pop_back() noexcept {
ABSL_HARDENING_ASSERT(!empty()); ABSL_HARDENING_ASSERT(!empty());
AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1)); AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
storage_.SubtractSize(1); storage_.SubtractSize(1);
} }
@ -732,8 +708,8 @@ class InlinedVector {
// Destroys all elements in the inlined vector, setting the size to `0` and // Destroys all elements in the inlined vector, setting the size to `0` and
// deallocating any held memory. // deallocating any held memory.
void clear() noexcept { void clear() noexcept {
inlined_vector_internal::DestroyAdapter<A>::DestroyElements( inlined_vector_internal::DestroyElements(storage_.GetAllocPtr(), data(),
storage_.GetAllocator(), data(), size()); size());
storage_.DeallocateIfAllocated(); storage_.DeallocateIfAllocated();
storage_.SetInlinedSize(0); storage_.SetInlinedSize(0);
@ -746,12 +722,15 @@ class InlinedVector {
// `InlinedVector::shrink_to_fit()` // `InlinedVector::shrink_to_fit()`
// //
// Attempts to reduce memory usage by moving elements to (or keeping elements // Reduces memory usage by freeing unused memory. After being called, calls to
// in) the smallest available buffer sufficient for containing `size()` // `capacity()` will be equal to `max(N, size())`.
// elements. //
// If `size() <= N` and the inlined vector contains allocated memory, the
// elements will all be moved to the inlined space and the allocated memory
// will be deallocated.
// //
// If `size()` is sufficiently small, the elements will be moved into (or kept // If `size() > N` and `size() < capacity()`, the elements will be moved to a
// in) the inlined space. // smaller allocation.
void shrink_to_fit() { void shrink_to_fit() {
if (storage_.GetIsAllocated()) { if (storage_.GetIsAllocated()) {
storage_.ShrinkToFit(); storage_.ShrinkToFit();

@ -534,28 +534,6 @@ void BM_ConstructFromMove(benchmark::State& state) {
ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType); ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType);
ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType); ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType);
// Measure cost of copy-constructor+destructor.
void BM_CopyTrivial(benchmark::State& state) {
const int n = state.range(0);
InlVec<int64_t> src(n);
for (auto s : state) {
InlVec<int64_t> copy(src);
benchmark::DoNotOptimize(copy);
}
}
BENCHMARK(BM_CopyTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
// Measure cost of copy-constructor+destructor.
void BM_CopyNonTrivial(benchmark::State& state) {
const int n = state.range(0);
InlVec<InlVec<int64_t>> src(n);
for (auto s : state) {
InlVec<InlVec<int64_t>> copy(src);
benchmark::DoNotOptimize(copy);
}
}
BENCHMARK(BM_CopyNonTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize);
template <typename T, size_t FromSize, size_t ToSize> template <typename T, size_t FromSize, size_t ToSize>
void BM_AssignSizeRef(benchmark::State& state) { void BM_AssignSizeRef(benchmark::State& state) {
auto size = ToSize; auto size = ToSize;

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save