Roll chromium_revision c92ed25217..bcf2616e8e (559015:559838)
Change log:c92ed25217..bcf2616e8eFull diff:c92ed25217..bcf2616e8eRoll chromium third_party 51c08cf9af..9d65a3cdda Change log:51c08cf9af..9d65a3cddaChanged dependencies: * src/base:a7a2409f9b..b802985ef4* src/build:03f39fd800..fc8308f6b6* src/buildtools:a9e946f166..94288c26d2* src/ios:e070a93062..289c450460* src/testing:f5b31b58c6..a5fce03148* src/third_party/catapult: https://chromium.googlesource.com/catapult.git/+log/d8600ccc2d..ce9b3742a1 * src/third_party/depot_tools:8de3800ce5..8fe4d8cbef* src/third_party/googletest/src:045e7f9ee4..08d5b1f33a* src/tools:e024720629..6e6e398687* src/tools/swarming_client:88229872dd..833f5ebf89DEPS diff:c92ed25217..bcf2616e8e/DEPS No update to Clang. TBR=buildbot@webrtc.org, BUG=None CQ_INCLUDE_TRYBOTS=master.internal.tryserver.corp.webrtc:linux_internal Change-Id: I22bf301fcec0103a1987a92f95ebf86e324dade7 Reviewed-on: https://webrtc-review.googlesource.com/77625 Reviewed-by: WebRTC Buildbot <buildbot@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23296}
This commit is contained in:
parent
c948fe62fd
commit
460f53bb86
24
DEPS
24
DEPS
@ -10,12 +10,12 @@ vars = {
|
|||||||
'checkout_configuration': 'default',
|
'checkout_configuration': 'default',
|
||||||
'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"',
|
'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"',
|
||||||
'webrtc_git': 'https://webrtc.googlesource.com',
|
'webrtc_git': 'https://webrtc.googlesource.com',
|
||||||
'chromium_revision': 'c92ed252174bc9b9ece9d11a83852f4ab8765575',
|
'chromium_revision': 'bcf2616e8eb74191a038c9ad457344fa0354f420',
|
||||||
'boringssl_git': 'https://boringssl.googlesource.com',
|
'boringssl_git': 'https://boringssl.googlesource.com',
|
||||||
# Three lines of non-changing comments so that
|
# Three lines of non-changing comments so that
|
||||||
# the commit queue can handle CLs rolling swarming_client
|
# the commit queue can handle CLs rolling swarming_client
|
||||||
# and whatever else without interference from each other.
|
# and whatever else without interference from each other.
|
||||||
'swarming_revision': '88229872dd17e71658fe96763feaa77915d8cbd6',
|
'swarming_revision': '833f5ebf894be1e3e6d13678d5de8479bf12ff28',
|
||||||
# Three lines of non-changing comments so that
|
# Three lines of non-changing comments so that
|
||||||
# the commit queue can handle CLs rolling BoringSSL
|
# the commit queue can handle CLs rolling BoringSSL
|
||||||
# and whatever else without interference from each other.
|
# and whatever else without interference from each other.
|
||||||
@ -27,7 +27,7 @@ vars = {
|
|||||||
# Three lines of non-changing comments so that
|
# Three lines of non-changing comments so that
|
||||||
# the commit queue can handle CLs rolling catapult
|
# the commit queue can handle CLs rolling catapult
|
||||||
# and whatever else without interference from each other.
|
# and whatever else without interference from each other.
|
||||||
'catapult_revision': 'd8600ccc2ddeb2cc43ba6adccea9f687f5f1b2a9',
|
'catapult_revision': 'ce9b3742a10dc2f4c796a1b26e73155d0bfa674a',
|
||||||
# Three lines of non-changing comments so that
|
# Three lines of non-changing comments so that
|
||||||
# the commit queue can handle CLs rolling libFuzzer
|
# the commit queue can handle CLs rolling libFuzzer
|
||||||
# and whatever else without interference from each other.
|
# and whatever else without interference from each other.
|
||||||
@ -43,17 +43,17 @@ vars = {
|
|||||||
# Three lines of non-changing comments so that
|
# Three lines of non-changing comments so that
|
||||||
# the commit queue can handle CLs rolling Chromium third_party
|
# the commit queue can handle CLs rolling Chromium third_party
|
||||||
# and whatever else without interference from each other.
|
# and whatever else without interference from each other.
|
||||||
'chromium_third_party_revision': '51c08cf9af330cc4173d8e37974e49074431d5f4',
|
'chromium_third_party_revision': '9d65a3cddae9b8340d4c77b1ae9034d4501935b8',
|
||||||
}
|
}
|
||||||
deps = {
|
deps = {
|
||||||
# TODO(kjellander): Move this to be Android-only once the libevent dependency
|
# TODO(kjellander): Move this to be Android-only once the libevent dependency
|
||||||
# in base/third_party/libevent is solved.
|
# in base/third_party/libevent is solved.
|
||||||
'src/base':
|
'src/base':
|
||||||
Var('chromium_git') + '/chromium/src/base' + '@' + 'a7a2409f9b398da1abc5e7604a974a1fa2ade51d',
|
Var('chromium_git') + '/chromium/src/base' + '@' + 'b802985ef4661601e825640d1a566489cfcb6d8b',
|
||||||
'src/build':
|
'src/build':
|
||||||
Var('chromium_git') + '/chromium/src/build' + '@' + '03f39fd800ed8fd5fa1a8b43b5963c6fc063475b',
|
Var('chromium_git') + '/chromium/src/build' + '@' + 'fc8308f6b6c6212c6be8d2769c721611d5253b49',
|
||||||
'src/buildtools':
|
'src/buildtools':
|
||||||
Var('chromium_git') + '/chromium/buildtools.git' + '@' + 'a9e946f166b73f9dc170129f6586a1e68efb0ab3',
|
Var('chromium_git') + '/chromium/buildtools.git' + '@' + '94288c26d2ffe3aec9848c147839afee597acefd',
|
||||||
# Gradle 4.3-rc4. Used for testing Android Studio project generation for WebRTC.
|
# Gradle 4.3-rc4. Used for testing Android Studio project generation for WebRTC.
|
||||||
'src/examples/androidtests/third_party/gradle': {
|
'src/examples/androidtests/third_party/gradle': {
|
||||||
'url': Var('chromium_git') + '/external/github.com/gradle/gradle.git' + '@' +
|
'url': Var('chromium_git') + '/external/github.com/gradle/gradle.git' + '@' +
|
||||||
@ -61,11 +61,11 @@ deps = {
|
|||||||
'condition': 'checkout_android',
|
'condition': 'checkout_android',
|
||||||
},
|
},
|
||||||
'src/ios': {
|
'src/ios': {
|
||||||
'url': Var('chromium_git') + '/chromium/src/ios' + '@' + 'e070a9306253c327361423e1fce2ae02c419f6ba',
|
'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '289c450460f6a2faf57d1ee011ef7595691dd25b',
|
||||||
'condition': 'checkout_ios',
|
'condition': 'checkout_ios',
|
||||||
},
|
},
|
||||||
'src/testing':
|
'src/testing':
|
||||||
Var('chromium_git') + '/chromium/src/testing' + '@' + 'f5b31b58c69ca3bbcfe81d8c2028063931f6681e',
|
Var('chromium_git') + '/chromium/src/testing' + '@' + 'a5fce03148805a479c78b685b31f5a2392218ffd',
|
||||||
# This entry is used for chromium third_party rolling into webrtc third_party only.
|
# This entry is used for chromium third_party rolling into webrtc third_party only.
|
||||||
'src/third_party_chromium': {
|
'src/third_party_chromium': {
|
||||||
'url': Var('chromium_git') + '/chromium/src/third_party' + '@' + Var('chromium_third_party_revision'),
|
'url': Var('chromium_git') + '/chromium/src/third_party' + '@' + Var('chromium_third_party_revision'),
|
||||||
@ -94,7 +94,7 @@ deps = {
|
|||||||
'src/third_party/colorama/src':
|
'src/third_party/colorama/src':
|
||||||
Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
|
Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
|
||||||
'src/third_party/depot_tools':
|
'src/third_party/depot_tools':
|
||||||
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8de3800ce55ba459ffcbedcfa52ef5e6e59caab6',
|
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8fe4d8cbef3bff9d615de14d9a414679cf9ca8c3',
|
||||||
'src/third_party/errorprone/lib': {
|
'src/third_party/errorprone/lib': {
|
||||||
'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '980d49e839aa4984015efed34b0134d4b2c9b6d7',
|
'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '980d49e839aa4984015efed34b0134d4b2c9b6d7',
|
||||||
'condition': 'checkout_android',
|
'condition': 'checkout_android',
|
||||||
@ -113,7 +113,7 @@ deps = {
|
|||||||
'src/third_party/gtest-parallel':
|
'src/third_party/gtest-parallel':
|
||||||
Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + 'cb3514a0858be0f66281d892e2242d1073fd75fe',
|
Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + 'cb3514a0858be0f66281d892e2242d1073fd75fe',
|
||||||
'src/third_party/googletest/src':
|
'src/third_party/googletest/src':
|
||||||
Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '045e7f9ee4f969ac1a3fe428f79c4b880f0aff43',
|
Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '08d5b1f33af8c18785fb8ca02792b5fac81e248f',
|
||||||
'src/third_party/icu': {
|
'src/third_party/icu': {
|
||||||
'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f61e46dbee9d539a32551493e3bcc1dea92f83ec',
|
'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f61e46dbee9d539a32551493e3bcc1dea92f83ec',
|
||||||
},
|
},
|
||||||
@ -175,7 +175,7 @@ deps = {
|
|||||||
'src/third_party/yasm/source/patched-yasm':
|
'src/third_party/yasm/source/patched-yasm':
|
||||||
Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc',
|
Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc',
|
||||||
'src/tools':
|
'src/tools':
|
||||||
Var('chromium_git') + '/chromium/src/tools' + '@' + 'e0247206293ec06cc0aee950384e13721cd55d86',
|
Var('chromium_git') + '/chromium/src/tools' + '@' + '6e6e39868794fc2bfeaf64502ad903be79616a0b',
|
||||||
'src/tools/gyp':
|
'src/tools/gyp':
|
||||||
Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
|
Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
|
||||||
'src/tools/swarming_client':
|
'src/tools/swarming_client':
|
||||||
|
|||||||
15
third_party/abseil-cpp/CMake/AbseilHelpers.cmake
vendored
15
third_party/abseil-cpp/CMake/AbseilHelpers.cmake
vendored
@ -16,6 +16,11 @@
|
|||||||
|
|
||||||
include(CMakeParseArguments)
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
# The IDE folder for Abseil that will be used if Abseil is included in a CMake
|
||||||
|
# project that sets
|
||||||
|
# set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
# For example, Visual Studio supports folders.
|
||||||
|
set(ABSL_IDE_FOLDER Abseil)
|
||||||
|
|
||||||
#
|
#
|
||||||
# create a library in the absl namespace
|
# create a library in the absl namespace
|
||||||
@ -49,6 +54,8 @@ function(absl_library)
|
|||||||
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
|
PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS}
|
||||||
PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS}
|
PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||||
|
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
|
||||||
|
|
||||||
if(ABSL_LIB_EXPORT_NAME)
|
if(ABSL_LIB_EXPORT_NAME)
|
||||||
add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
|
add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME})
|
||||||
@ -93,6 +100,9 @@ function(absl_header_library)
|
|||||||
PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS}
|
PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||||
|
set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER})
|
||||||
|
|
||||||
if(ABSL_HO_LIB_EXPORT_NAME)
|
if(ABSL_HO_LIB_EXPORT_NAME)
|
||||||
add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
|
add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME})
|
||||||
endif()
|
endif()
|
||||||
@ -139,7 +149,10 @@ function(absl_test)
|
|||||||
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
|
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_test(${_NAME}_test ${_NAME}_bin)
|
# Add all Abseil targets to a a folder in the IDE for organization.
|
||||||
|
set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER})
|
||||||
|
|
||||||
|
add_test(${_NAME} ${_NAME}_bin)
|
||||||
endif(BUILD_TESTING)
|
endif(BUILD_TESTING)
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|||||||
15
third_party/abseil-cpp/CMake/CMakeLists.txt.in
vendored
Normal file
15
third_party/abseil-cpp/CMake/CMakeLists.txt.in
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.2)
|
||||||
|
|
||||||
|
project(googletest-download NONE)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(googletest
|
||||||
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||||
|
GIT_TAG master
|
||||||
|
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
|
||||||
|
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
||||||
32
third_party/abseil-cpp/CMake/DownloadGTest.cmake
vendored
Normal file
32
third_party/abseil-cpp/CMake/DownloadGTest.cmake
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Downloads and unpacks googletest at configure time. Based on the instructions
|
||||||
|
# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
|
||||||
|
|
||||||
|
# Download the latest googletest from Github master
|
||||||
|
configure_file(
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
|
||||||
|
googletest-download/CMakeLists.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
# Configure and build the downloaded googletest source
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download )
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} --build .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prevent overriding the parent project's compiler/linker settings on Windows
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
# Add googletest directly to our build. This defines the gtest and gtest_main
|
||||||
|
# targets.
|
||||||
|
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
|
||||||
|
${CMAKE_BINARY_DIR}/googletest-build
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
32
third_party/abseil-cpp/CMake/README.md
vendored
32
third_party/abseil-cpp/CMake/README.md
vendored
@ -52,14 +52,42 @@ if(MSVC)
|
|||||||
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
|
add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(googletest)
|
|
||||||
add_subdirectory(cctz)
|
|
||||||
add_subdirectory(abseil-cpp)
|
add_subdirectory(abseil-cpp)
|
||||||
|
|
||||||
add_executable(my_exe source.cpp)
|
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)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Running Abseil Tests with CMake
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
You will need to provide Abseil with a Googletest dependency. There are two
|
||||||
|
options for how to do this:
|
||||||
|
|
||||||
|
* Use `-DABSL_USE_GOOGLETEST_HEAD`. This will automatically download the latest
|
||||||
|
Googletest source into the build directory at configure time. Googletest will
|
||||||
|
then be compiled directly alongside Abseil's tests.
|
||||||
|
* Manually integrate Googletest with your build. See
|
||||||
|
https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake
|
||||||
|
for more information on using Googletest in a CMake project.
|
||||||
|
|
||||||
|
For example, to run just the Abseil tests, you could use this script:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd path/to/abseil-cpp
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON ..
|
||||||
|
make -j
|
||||||
|
ctest
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, we only run our tests with CMake in a Linux environment, but we are
|
||||||
|
working on the rest of our supported platforms. See
|
||||||
|
https://github.com/abseil/abseil-cpp/projects/1 and
|
||||||
|
https://github.com/abseil/abseil-cpp/issues/109 for more information.
|
||||||
|
|
||||||
### Available Abseil CMake Public Targets
|
### Available Abseil CMake Public Targets
|
||||||
|
|
||||||
Here's a non-exhaustive list of Abseil CMake public targets:
|
Here's a non-exhaustive list of Abseil CMake public targets:
|
||||||
|
|||||||
23
third_party/abseil-cpp/CMakeLists.txt
vendored
23
third_party/abseil-cpp/CMakeLists.txt
vendored
@ -16,9 +16,6 @@
|
|||||||
cmake_minimum_required(VERSION 2.8.12)
|
cmake_minimum_required(VERSION 2.8.12)
|
||||||
project(absl)
|
project(absl)
|
||||||
|
|
||||||
# enable ctest
|
|
||||||
include(CTest)
|
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake)
|
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
@ -56,7 +53,6 @@ list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
|
|||||||
|
|
||||||
# -std=X
|
# -std=X
|
||||||
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_WARNING_VLA} ${CMAKE_CXX_FLAGS} ")
|
|
||||||
|
|
||||||
# -fexceptions
|
# -fexceptions
|
||||||
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
|
set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
|
||||||
@ -65,12 +61,25 @@ set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}")
|
|||||||
## pthread
|
## pthread
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
# commented: used only for standalone test
|
option(ABSL_USE_GOOGLETEST_HEAD
|
||||||
# Don't remove these or else CMake CI will break
|
"If ON, abseil will download HEAD from googletest at config time." OFF)
|
||||||
#add_subdirectory(googletest)
|
|
||||||
|
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)
|
||||||
|
enable_testing()
|
||||||
|
endif()
|
||||||
|
|
||||||
## check targets
|
## check targets
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
|
|
||||||
|
if(${ABSL_USE_GOOGLETEST_HEAD})
|
||||||
|
include(CMake/DownloadGTest.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
check_target(gtest)
|
check_target(gtest)
|
||||||
check_target(gtest_main)
|
check_target(gtest_main)
|
||||||
check_target(gmock)
|
check_target(gmock)
|
||||||
|
|||||||
2
third_party/abseil-cpp/README.chromium
vendored
2
third_party/abseil-cpp/README.chromium
vendored
@ -4,7 +4,7 @@ URL: https://github.com/abseil/abseil-cpp
|
|||||||
License: Apache 2.0
|
License: Apache 2.0
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
Version: 0
|
Version: 0
|
||||||
Revision: af7882601aad93ada881486eeaabc562f1733961
|
Revision: 30de20488bb88dc22d23521c5c222ec6d924e289
|
||||||
Security Critical: yes
|
Security Critical: yes
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
|
|||||||
15
third_party/abseil-cpp/WORKSPACE
vendored
15
third_party/abseil-cpp/WORKSPACE
vendored
@ -3,11 +3,11 @@ workspace(name = "com_google_absl")
|
|||||||
http_archive(
|
http_archive(
|
||||||
name = "bazel_toolchains",
|
name = "bazel_toolchains",
|
||||||
urls = [
|
urls = [
|
||||||
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
|
"https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
|
||||||
"https://github.com/bazelbuild/bazel-toolchains/archive/r324073.tar.gz",
|
"https://github.com/bazelbuild/bazel-toolchains/archive/f8847f64e6950e8ab9fde1c0aba768550b0d9ab2.tar.gz",
|
||||||
],
|
],
|
||||||
strip_prefix = "bazel-toolchains-r324073",
|
strip_prefix = "bazel-toolchains-f8847f64e6950e8ab9fde1c0aba768550b0d9ab2",
|
||||||
sha256 = "71548c0d6cd53eddebbde4fa9962f5395e82645fb9992719e0890505b177f245",
|
sha256 = "794366f51fea224b3656a0b0f8f1518e739748646523a572fcd3d68614a0e670",
|
||||||
)
|
)
|
||||||
|
|
||||||
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
# GoogleTest/GoogleMock framework. Used by most unit-tests.
|
||||||
@ -17,6 +17,13 @@ http_archive(
|
|||||||
strip_prefix = "googletest-master",
|
strip_prefix = "googletest-master",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Google benchmark.
|
||||||
|
http_archive(
|
||||||
|
name = "com_github_google_benchmark",
|
||||||
|
urls = ["https://github.com/google/benchmark/archive/master.zip"],
|
||||||
|
strip_prefix = "benchmark-master",
|
||||||
|
)
|
||||||
|
|
||||||
# RE2 regular-expression framework. Used by some unit-tests.
|
# RE2 regular-expression framework. Used by some unit-tests.
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "com_googlesource_code_re2",
|
name = "com_googlesource_code_re2",
|
||||||
|
|||||||
@ -41,6 +41,18 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "algorithm_benchmark",
|
||||||
|
srcs = ["equal_benchmark.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS,
|
||||||
|
tags = ["benchmark"],
|
||||||
|
deps = [
|
||||||
|
":algorithm",
|
||||||
|
"//absl/base:core_headers",
|
||||||
|
"@com_github_google_benchmark//:benchmark",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "container",
|
name = "container",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
|
|||||||
128
third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc
vendored
Normal file
128
third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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 <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
#include "absl/algorithm/algorithm.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// The range of sequence sizes to benchmark.
|
||||||
|
constexpr int kMinBenchmarkSize = 1024;
|
||||||
|
constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
|
||||||
|
|
||||||
|
// A user-defined type for use in equality benchmarks. Note that we expect
|
||||||
|
// std::memcmp to win for this type: libstdc++'s std::equal only defers to
|
||||||
|
// memcmp for integral types. This is because it is not straightforward to
|
||||||
|
// guarantee that std::memcmp would produce a result "as-if" compared by
|
||||||
|
// operator== for other types (example gotchas: NaN floats, structs with
|
||||||
|
// padding).
|
||||||
|
struct EightBits {
|
||||||
|
explicit EightBits(int /* unused */) : data(0) {}
|
||||||
|
bool operator==(const EightBits& rhs) const { return data == rhs.data; }
|
||||||
|
uint8_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BM_absl_equal_benchmark(benchmark::State& state) {
|
||||||
|
std::vector<T> xs(state.range(0), T(0));
|
||||||
|
std::vector<T> ys = xs;
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
|
||||||
|
benchmark::DoNotOptimize(same);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BM_std_equal_benchmark(benchmark::State& state) {
|
||||||
|
std::vector<T> xs(state.range(0), T(0));
|
||||||
|
std::vector<T> ys = xs;
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
|
||||||
|
benchmark::DoNotOptimize(same);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void BM_memcmp_benchmark(benchmark::State& state) {
|
||||||
|
std::vector<T> xs(state.range(0), T(0));
|
||||||
|
std::vector<T> ys = xs;
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
const bool same =
|
||||||
|
std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
|
||||||
|
benchmark::DoNotOptimize(same);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The expectation is that the compiler should be able to elide the equality
|
||||||
|
// comparison altogether for sufficiently simple types.
|
||||||
|
template <typename T>
|
||||||
|
void BM_absl_equal_self_benchmark(benchmark::State& state) {
|
||||||
|
std::vector<T> xs(state.range(0), T(0));
|
||||||
|
while (state.KeepRunning()) {
|
||||||
|
const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
|
||||||
|
benchmark::DoNotOptimize(same);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
|
||||||
|
->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
25
third_party/abseil-cpp/absl/base/BUILD.bazel
vendored
25
third_party/abseil-cpp/absl/base/BUILD.bazel
vendored
@ -147,6 +147,18 @@ cc_library(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "atomic_hook_test",
|
||||||
|
size = "small",
|
||||||
|
srcs = ["internal/atomic_hook_test.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS,
|
||||||
|
deps = [
|
||||||
|
":base",
|
||||||
|
":core_headers",
|
||||||
|
"@com_google_googletest//:gtest_main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_test(
|
cc_test(
|
||||||
name = "bit_cast_test",
|
name = "bit_cast_test",
|
||||||
size = "small",
|
size = "small",
|
||||||
@ -393,3 +405,16 @@ cc_test(
|
|||||||
"@com_google_googletest//:gtest_main",
|
"@com_google_googletest//:gtest_main",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "thread_identity_benchmark",
|
||||||
|
srcs = ["internal/thread_identity_benchmark.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS,
|
||||||
|
tags = ["benchmark"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
deps = [
|
||||||
|
":base",
|
||||||
|
"//absl/synchronization",
|
||||||
|
"@com_github_google_benchmark//:benchmark",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
33
third_party/abseil-cpp/absl/base/CMakeLists.txt
vendored
33
third_party/abseil-cpp/absl/base/CMakeLists.txt
vendored
@ -99,14 +99,18 @@ absl_library(
|
|||||||
|
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
# exception-safety testing library
|
# exception-safety testing library
|
||||||
set(EXCEPTION_SAFETY_TESTING_SRC "internal/exception_safety_testing.cc")
|
set(EXCEPTION_SAFETY_TESTING_SRC
|
||||||
|
"internal/exception_safety_testing.h"
|
||||||
|
"internal/exception_safety_testing.cc"
|
||||||
|
)
|
||||||
set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
|
set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES
|
||||||
${ABSL_TEST_COMMON_LIBRARIES}
|
${ABSL_TEST_COMMON_LIBRARIES}
|
||||||
absl::base
|
absl::base
|
||||||
absl::memory
|
absl::memory
|
||||||
absl::meta
|
absl::meta
|
||||||
absl::strings
|
absl::strings
|
||||||
absl::types
|
absl::optional
|
||||||
|
gtest
|
||||||
)
|
)
|
||||||
|
|
||||||
absl_library(
|
absl_library(
|
||||||
@ -116,6 +120,8 @@ absl_library(
|
|||||||
${EXCEPTION_SAFETY_TESTING_SRC}
|
${EXCEPTION_SAFETY_TESTING_SRC}
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
|
${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES}
|
||||||
|
PRIVATE_COMPILE_FLAGS
|
||||||
|
${ABSL_EXCEPTIONS_FLAG}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -162,6 +168,20 @@ absl_library(
|
|||||||
## TESTS
|
## TESTS
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# call once test
|
||||||
|
set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc")
|
||||||
|
set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base)
|
||||||
|
|
||||||
|
absl_test(
|
||||||
|
TARGET
|
||||||
|
atomic_hook_test
|
||||||
|
SOURCES
|
||||||
|
${ATOMIC_HOOK_TEST_SRC}
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# call once test
|
# call once test
|
||||||
set(CALL_ONCE_TEST_SRC "call_once_test.cc")
|
set(CALL_ONCE_TEST_SRC "call_once_test.cc")
|
||||||
set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
|
set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization)
|
||||||
@ -344,7 +364,14 @@ absl_test(
|
|||||||
|
|
||||||
#test exceptions_safety_testing_test
|
#test exceptions_safety_testing_test
|
||||||
set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
|
set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc")
|
||||||
set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES absl::base absl::memory absl::meta absl::strings absl::optional)
|
set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES
|
||||||
|
absl::base
|
||||||
|
absl_base_internal_exception_safety_testing
|
||||||
|
absl::memory
|
||||||
|
absl::meta
|
||||||
|
absl::strings
|
||||||
|
absl::optional
|
||||||
|
)
|
||||||
|
|
||||||
absl_test(
|
absl_test(
|
||||||
TARGET
|
TARGET
|
||||||
|
|||||||
@ -52,7 +52,8 @@
|
|||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// // Enable branches in the Abseil code that are tagged for ASan:
|
// // Enable branches in the Abseil code that are tagged for ASan:
|
||||||
// $ bazel -D ADDRESS_SANITIZER -fsanitize=address *target*
|
// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address
|
||||||
|
// --linkopt=-fsanitize=address *target*
|
||||||
//
|
//
|
||||||
// Since these macro names are only supported by GCC and Clang, we only check
|
// Since these macro names are only supported by GCC and Clang, we only check
|
||||||
// for `__GNUC__` (GCC or Clang) and the above macros.
|
// for `__GNUC__` (GCC or Clang) and the above macros.
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
/* Each function is empty and called (via a macro) only in debug mode.
|
/* Each function is empty and called (via a macro) only in debug mode.
|
||||||
The arguments are captured by dynamic tools at runtime. */
|
The arguments are captured by dynamic tools at runtime. */
|
||||||
|
|
||||||
#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
|
#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
|
||||||
|
|
||||||
#if __has_feature(memory_sanitizer)
|
#if __has_feature(memory_sanitizer)
|
||||||
#include <sanitizer/msan_interface.h>
|
#include <sanitizer/msan_interface.h>
|
||||||
|
|||||||
@ -191,16 +191,16 @@
|
|||||||
#elif defined(ABSL_ANNOTALYSIS_ENABLED)
|
#elif defined(ABSL_ANNOTALYSIS_ENABLED)
|
||||||
|
|
||||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||||
AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
StaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__)
|
||||||
|
|
||||||
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||||
AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
StaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__)
|
||||||
|
|
||||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||||
AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
StaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__)
|
||||||
|
|
||||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
||||||
AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
StaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */
|
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */
|
||||||
@ -282,13 +282,13 @@ void AbslAnnotateIgnoreWritesEnd(const char *file, int line);
|
|||||||
allows IGNORE_READS_AND_WRITES to work properly. */
|
allows IGNORE_READS_AND_WRITES to work properly. */
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line)
|
static inline void StaticAnnotateIgnoreReadsBegin(const char *file, int line)
|
||||||
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
|
ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; }
|
||||||
static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line)
|
static inline void StaticAnnotateIgnoreReadsEnd(const char *file, int line)
|
||||||
ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
|
ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; }
|
||||||
static inline void AbslStaticAnnotateIgnoreWritesBegin(
|
static inline void StaticAnnotateIgnoreWritesBegin(
|
||||||
const char *file, int line) { (void)file; (void)line; }
|
const char *file, int line) { (void)file; (void)line; }
|
||||||
static inline void AbslStaticAnnotateIgnoreWritesEnd(
|
static inline void StaticAnnotateIgnoreWritesEnd(
|
||||||
const char *file, int line) { (void)file; (void)line; }
|
const char *file, int line) { (void)file; (void)line; }
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -25,11 +25,13 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "absl/memory/memory.h"
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace testing {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using ::absl::exceptions_internal::SetCountdown;
|
|
||||||
using ::absl::exceptions_internal::TestException;
|
using ::testing::exceptions_internal::SetCountdown;
|
||||||
using ::absl::exceptions_internal::UnsetCountdown;
|
using ::testing::exceptions_internal::TestException;
|
||||||
|
using ::testing::exceptions_internal::UnsetCountdown;
|
||||||
|
|
||||||
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
|
// EXPECT_NO_THROW can't inspect the thrown inspection in general.
|
||||||
template <typename F>
|
template <typename F>
|
||||||
@ -41,15 +43,7 @@ void ExpectNoThrow(const F& f) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThrowingValueTest : public ::testing::Test {
|
TEST(ThrowingValueTest, Throws) {
|
||||||
protected:
|
|
||||||
void SetUp() override { UnsetCountdown(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
ConstructorTracker clouseau_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, Throws) {
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
EXPECT_THROW(ThrowingValue<> bomb, TestException);
|
EXPECT_THROW(ThrowingValue<> bomb, TestException);
|
||||||
|
|
||||||
@ -60,6 +54,8 @@ TEST_F(ThrowingValueTest, Throws) {
|
|||||||
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
||||||
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
ExpectNoThrow([]() { ThrowingValue<> bomb; });
|
||||||
EXPECT_THROW(ThrowingValue<> bomb, TestException);
|
EXPECT_THROW(ThrowingValue<> bomb, TestException);
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that an operation throws when the countdown is at 0, doesn't throw when
|
// Tests that an operation throws when the countdown is at 0, doesn't throw when
|
||||||
@ -67,7 +63,6 @@ TEST_F(ThrowingValueTest, Throws) {
|
|||||||
// ThrowingValue if it throws
|
// ThrowingValue if it throws
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void TestOp(const F& f) {
|
void TestOp(const F& f) {
|
||||||
UnsetCountdown();
|
|
||||||
ExpectNoThrow(f);
|
ExpectNoThrow(f);
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
@ -75,7 +70,7 @@ void TestOp(const F& f) {
|
|||||||
UnsetCountdown();
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingCtors) {
|
TEST(ThrowingValueTest, ThrowingCtors) {
|
||||||
ThrowingValue<> bomb;
|
ThrowingValue<> bomb;
|
||||||
|
|
||||||
TestOp([]() { ThrowingValue<> bomb(1); });
|
TestOp([]() { ThrowingValue<> bomb(1); });
|
||||||
@ -83,14 +78,35 @@ TEST_F(ThrowingValueTest, ThrowingCtors) {
|
|||||||
TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
|
TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingAssignment) {
|
TEST(ThrowingValueTest, ThrowingAssignment) {
|
||||||
ThrowingValue<> bomb, bomb1;
|
ThrowingValue<> bomb, bomb1;
|
||||||
|
|
||||||
TestOp([&]() { bomb = bomb1; });
|
TestOp([&]() { bomb = bomb1; });
|
||||||
TestOp([&]() { bomb = std::move(bomb1); });
|
TestOp([&]() { bomb = std::move(bomb1); });
|
||||||
|
|
||||||
|
// Test that when assignment throws, the assignment should fail (lhs != rhs)
|
||||||
|
// and strong guarantee fails (lhs != lhs_copy).
|
||||||
|
{
|
||||||
|
ThrowingValue<> lhs(39), rhs(42);
|
||||||
|
ThrowingValue<> lhs_copy(lhs);
|
||||||
|
SetCountdown();
|
||||||
|
EXPECT_THROW(lhs = rhs, TestException);
|
||||||
|
UnsetCountdown();
|
||||||
|
EXPECT_NE(lhs, rhs);
|
||||||
|
EXPECT_NE(lhs_copy, lhs);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingValue<> lhs(39), rhs(42);
|
||||||
|
ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs);
|
||||||
|
SetCountdown();
|
||||||
|
EXPECT_THROW(lhs = std::move(rhs), TestException);
|
||||||
|
UnsetCountdown();
|
||||||
|
EXPECT_NE(lhs, rhs_copy);
|
||||||
|
EXPECT_NE(lhs_copy, lhs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingComparisons) {
|
TEST(ThrowingValueTest, ThrowingComparisons) {
|
||||||
ThrowingValue<> bomb1, bomb2;
|
ThrowingValue<> bomb1, bomb2;
|
||||||
TestOp([&]() { return bomb1 == bomb2; });
|
TestOp([&]() { return bomb1 == bomb2; });
|
||||||
TestOp([&]() { return bomb1 != bomb2; });
|
TestOp([&]() { return bomb1 != bomb2; });
|
||||||
@ -100,7 +116,7 @@ TEST_F(ThrowingValueTest, ThrowingComparisons) {
|
|||||||
TestOp([&]() { return bomb1 >= bomb2; });
|
TestOp([&]() { return bomb1 >= bomb2; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingArithmeticOps) {
|
TEST(ThrowingValueTest, ThrowingArithmeticOps) {
|
||||||
ThrowingValue<> bomb1(1), bomb2(2);
|
ThrowingValue<> bomb1(1), bomb2(2);
|
||||||
|
|
||||||
TestOp([&bomb1]() { +bomb1; });
|
TestOp([&bomb1]() { +bomb1; });
|
||||||
@ -118,7 +134,7 @@ TEST_F(ThrowingValueTest, ThrowingArithmeticOps) {
|
|||||||
TestOp([&]() { bomb1 >> 1; });
|
TestOp([&]() { bomb1 >> 1; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingLogicalOps) {
|
TEST(ThrowingValueTest, ThrowingLogicalOps) {
|
||||||
ThrowingValue<> bomb1, bomb2;
|
ThrowingValue<> bomb1, bomb2;
|
||||||
|
|
||||||
TestOp([&bomb1]() { !bomb1; });
|
TestOp([&bomb1]() { !bomb1; });
|
||||||
@ -126,7 +142,7 @@ TEST_F(ThrowingValueTest, ThrowingLogicalOps) {
|
|||||||
TestOp([&]() { bomb1 || bomb2; });
|
TestOp([&]() { bomb1 || bomb2; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingBitwiseOps) {
|
TEST(ThrowingValueTest, ThrowingBitwiseOps) {
|
||||||
ThrowingValue<> bomb1, bomb2;
|
ThrowingValue<> bomb1, bomb2;
|
||||||
|
|
||||||
TestOp([&bomb1]() { ~bomb1; });
|
TestOp([&bomb1]() { ~bomb1; });
|
||||||
@ -135,7 +151,7 @@ TEST_F(ThrowingValueTest, ThrowingBitwiseOps) {
|
|||||||
TestOp([&]() { bomb1 ^ bomb2; });
|
TestOp([&]() { bomb1 ^ bomb2; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
|
TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
|
||||||
ThrowingValue<> bomb1(1), bomb2(2);
|
ThrowingValue<> bomb1(1), bomb2(2);
|
||||||
|
|
||||||
TestOp([&]() { bomb1 += bomb2; });
|
TestOp([&]() { bomb1 += bomb2; });
|
||||||
@ -149,7 +165,7 @@ TEST_F(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
|
|||||||
TestOp([&]() { bomb1 *= bomb2; });
|
TestOp([&]() { bomb1 *= bomb2; });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingStreamOps) {
|
TEST(ThrowingValueTest, ThrowingStreamOps) {
|
||||||
ThrowingValue<> bomb;
|
ThrowingValue<> bomb;
|
||||||
|
|
||||||
TestOp([&]() { std::cin >> bomb; });
|
TestOp([&]() { std::cin >> bomb; });
|
||||||
@ -158,7 +174,6 @@ TEST_F(ThrowingValueTest, ThrowingStreamOps) {
|
|||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
void TestAllocatingOp(const F& f) {
|
void TestAllocatingOp(const F& f) {
|
||||||
UnsetCountdown();
|
|
||||||
ExpectNoThrow(f);
|
ExpectNoThrow(f);
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
@ -166,62 +181,90 @@ void TestAllocatingOp(const F& f) {
|
|||||||
UnsetCountdown();
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingAllocatingOps) {
|
TEST(ThrowingValueTest, ThrowingAllocatingOps) {
|
||||||
// make_unique calls unqualified operator new, so these exercise the
|
// make_unique calls unqualified operator new, so these exercise the
|
||||||
// ThrowingValue overloads.
|
// ThrowingValue overloads.
|
||||||
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
|
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); });
|
||||||
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
|
TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingMoveCtor) {
|
TEST(ThrowingValueTest, NonThrowingMoveCtor) {
|
||||||
ThrowingValue<NoThrow::kMoveCtor> nothrow_ctor;
|
ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([¬hrow_ctor]() {
|
ExpectNoThrow([¬hrow_ctor]() {
|
||||||
ThrowingValue<NoThrow::kMoveCtor> nothrow1 = std::move(nothrow_ctor);
|
ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor);
|
||||||
});
|
});
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingMoveAssign) {
|
TEST(ThrowingValueTest, NonThrowingMoveAssign) {
|
||||||
ThrowingValue<NoThrow::kMoveAssign> nothrow_assign1, nothrow_assign2;
|
ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {
|
ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {
|
||||||
nothrow_assign1 = std::move(nothrow_assign2);
|
nothrow_assign1 = std::move(nothrow_assign2);
|
||||||
});
|
});
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, ThrowingSwap) {
|
TEST(ThrowingValueTest, ThrowingCopyCtor) {
|
||||||
|
ThrowingValue<> tv;
|
||||||
|
|
||||||
|
TestOp([&]() { ThrowingValue<> tv_copy(tv); });
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ThrowingValueTest, ThrowingCopyAssign) {
|
||||||
|
ThrowingValue<> tv1, tv2;
|
||||||
|
|
||||||
|
TestOp([&]() { tv1 = tv2; });
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ThrowingValueTest, NonThrowingCopyCtor) {
|
||||||
|
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor;
|
||||||
|
|
||||||
|
SetCountdown();
|
||||||
|
ExpectNoThrow([¬hrow_ctor]() {
|
||||||
|
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor);
|
||||||
|
});
|
||||||
|
UnsetCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ThrowingValueTest, NonThrowingCopyAssign) {
|
||||||
|
ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2;
|
||||||
|
|
||||||
|
SetCountdown();
|
||||||
|
ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() {
|
||||||
|
nothrow_assign1 = nothrow_assign2;
|
||||||
|
});
|
||||||
|
UnsetCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ThrowingValueTest, ThrowingSwap) {
|
||||||
ThrowingValue<> bomb1, bomb2;
|
ThrowingValue<> bomb1, bomb2;
|
||||||
TestOp([&]() { std::swap(bomb1, bomb2); });
|
TestOp([&]() { std::swap(bomb1, bomb2); });
|
||||||
|
|
||||||
ThrowingValue<NoThrow::kMoveCtor> bomb3, bomb4;
|
|
||||||
TestOp([&]() { std::swap(bomb3, bomb4); });
|
|
||||||
|
|
||||||
ThrowingValue<NoThrow::kMoveAssign> bomb5, bomb6;
|
|
||||||
TestOp([&]() { std::swap(bomb5, bomb6); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingSwap) {
|
TEST(ThrowingValueTest, NonThrowingSwap) {
|
||||||
ThrowingValue<NoThrow::kMoveAssign | NoThrow::kMoveCtor> bomb1, bomb2;
|
ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2;
|
||||||
ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
|
ExpectNoThrow([&]() { std::swap(bomb1, bomb2); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingAllocation) {
|
TEST(ThrowingValueTest, NonThrowingAllocation) {
|
||||||
ThrowingValue<NoThrow::kAllocation>* allocated;
|
ThrowingValue<TypeSpec::kNoThrowNew>* allocated;
|
||||||
ThrowingValue<NoThrow::kAllocation>* array;
|
ThrowingValue<TypeSpec::kNoThrowNew>* array;
|
||||||
|
|
||||||
ExpectNoThrow([&allocated]() {
|
ExpectNoThrow([&allocated]() {
|
||||||
allocated = new ThrowingValue<NoThrow::kAllocation>(1);
|
allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1);
|
||||||
delete allocated;
|
delete allocated;
|
||||||
});
|
});
|
||||||
ExpectNoThrow([&array]() {
|
ExpectNoThrow([&array]() {
|
||||||
array = new ThrowingValue<NoThrow::kAllocation>[2];
|
array = new ThrowingValue<TypeSpec::kNoThrowNew>[2];
|
||||||
delete[] array;
|
delete[] array;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingDelete) {
|
TEST(ThrowingValueTest, NonThrowingDelete) {
|
||||||
auto* allocated = new ThrowingValue<>(1);
|
auto* allocated = new ThrowingValue<>(1);
|
||||||
auto* array = new ThrowingValue<>[2];
|
auto* array = new ThrowingValue<>[2];
|
||||||
|
|
||||||
@ -229,12 +272,14 @@ TEST_F(ThrowingValueTest, NonThrowingDelete) {
|
|||||||
ExpectNoThrow([allocated]() { delete allocated; });
|
ExpectNoThrow([allocated]() { delete allocated; });
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([array]() { delete[] array; });
|
ExpectNoThrow([array]() { delete[] array; });
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
using Storage =
|
using Storage =
|
||||||
absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
|
absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>;
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) {
|
TEST(ThrowingValueTest, NonThrowingPlacementDelete) {
|
||||||
constexpr int kArrayLen = 2;
|
constexpr int kArrayLen = 2;
|
||||||
// We intentionally create extra space to store the tag allocated by placement
|
// We intentionally create extra space to store the tag allocated by placement
|
||||||
// new[].
|
// new[].
|
||||||
@ -256,16 +301,19 @@ TEST_F(ThrowingValueTest, NonThrowingPlacementDelete) {
|
|||||||
for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
|
for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>();
|
||||||
ThrowingValue<>::operator delete[](placed_array, &array_buf);
|
ThrowingValue<>::operator delete[](placed_array, &array_buf);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingValueTest, NonThrowingDestructor) {
|
TEST(ThrowingValueTest, NonThrowingDestructor) {
|
||||||
auto* allocated = new ThrowingValue<>();
|
auto* allocated = new ThrowingValue<>();
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([allocated]() { delete allocated; });
|
ExpectNoThrow([allocated]() { delete allocated; });
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ThrowingBoolTest, ThrowingBool) {
|
TEST(ThrowingBoolTest, ThrowingBool) {
|
||||||
UnsetCountdown();
|
|
||||||
ThrowingBool t = true;
|
ThrowingBool t = true;
|
||||||
|
|
||||||
// Test that it's contextually convertible to bool
|
// Test that it's contextually convertible to bool
|
||||||
@ -276,15 +324,7 @@ TEST(ThrowingBoolTest, ThrowingBool) {
|
|||||||
TestOp([&]() { (void)!t; });
|
TestOp([&]() { (void)!t; });
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThrowingAllocatorTest : public ::testing::Test {
|
TEST(ThrowingAllocatorTest, MemoryManagement) {
|
||||||
protected:
|
|
||||||
void SetUp() override { UnsetCountdown(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
ConstructorTracker borlu_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, MemoryManagement) {
|
|
||||||
// Just exercise the memory management capabilities under LSan to make sure we
|
// Just exercise the memory management capabilities under LSan to make sure we
|
||||||
// don't leak.
|
// don't leak.
|
||||||
ThrowingAllocator<int> int_alloc;
|
ThrowingAllocator<int> int_alloc;
|
||||||
@ -293,24 +333,26 @@ TEST_F(ThrowingAllocatorTest, MemoryManagement) {
|
|||||||
int* i_array = int_alloc.allocate(2);
|
int* i_array = int_alloc.allocate(2);
|
||||||
int_alloc.deallocate(i_array, 2);
|
int_alloc.deallocate(i_array, 2);
|
||||||
|
|
||||||
ThrowingAllocator<ThrowingValue<>> ef_alloc;
|
ThrowingAllocator<ThrowingValue<>> tv_alloc;
|
||||||
ThrowingValue<>* efp = ef_alloc.allocate(1);
|
ThrowingValue<>* ptr = tv_alloc.allocate(1);
|
||||||
ef_alloc.deallocate(efp, 1);
|
tv_alloc.deallocate(ptr, 1);
|
||||||
ThrowingValue<>* ef_array = ef_alloc.allocate(2);
|
ThrowingValue<>* tv_array = tv_alloc.allocate(2);
|
||||||
ef_alloc.deallocate(ef_array, 2);
|
tv_alloc.deallocate(tv_array, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, CallsGlobalNew) {
|
TEST(ThrowingAllocatorTest, CallsGlobalNew) {
|
||||||
ThrowingAllocator<ThrowingValue<>, NoThrow::kNoThrow> nothrow_alloc;
|
ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc;
|
||||||
ThrowingValue<>* ptr;
|
ThrowingValue<>* ptr;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
// This will only throw if ThrowingValue::new is called.
|
// This will only throw if ThrowingValue::new is called.
|
||||||
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
|
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
|
||||||
nothrow_alloc.deallocate(ptr, 1);
|
nothrow_alloc.deallocate(ptr, 1);
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, ThrowingConstructors) {
|
TEST(ThrowingAllocatorTest, ThrowingConstructors) {
|
||||||
ThrowingAllocator<int> int_alloc;
|
ThrowingAllocator<int> int_alloc;
|
||||||
int* ip = nullptr;
|
int* ip = nullptr;
|
||||||
|
|
||||||
@ -323,22 +365,27 @@ TEST_F(ThrowingAllocatorTest, ThrowingConstructors) {
|
|||||||
EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
|
EXPECT_THROW(int_alloc.construct(ip, 2), TestException);
|
||||||
EXPECT_EQ(*ip, 1);
|
EXPECT_EQ(*ip, 1);
|
||||||
int_alloc.deallocate(ip, 1);
|
int_alloc.deallocate(ip, 1);
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) {
|
TEST(ThrowingAllocatorTest, NonThrowingConstruction) {
|
||||||
{
|
{
|
||||||
ThrowingAllocator<int, NoThrow::kNoThrow> int_alloc;
|
ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc;
|
||||||
int* ip = nullptr;
|
int* ip = nullptr;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
|
ExpectNoThrow([&]() { ip = int_alloc.allocate(1); });
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
|
ExpectNoThrow([&]() { int_alloc.construct(ip, 2); });
|
||||||
|
|
||||||
EXPECT_EQ(*ip, 2);
|
EXPECT_EQ(*ip, 2);
|
||||||
int_alloc.deallocate(ip, 1);
|
int_alloc.deallocate(ip, 1);
|
||||||
}
|
|
||||||
|
|
||||||
UnsetCountdown();
|
UnsetCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ThrowingAllocator<int> int_alloc;
|
ThrowingAllocator<int> int_alloc;
|
||||||
int* ip = nullptr;
|
int* ip = nullptr;
|
||||||
@ -348,37 +395,45 @@ TEST_F(ThrowingAllocatorTest, NonThrowingConstruction) {
|
|||||||
int_alloc.deallocate(ip, 1);
|
int_alloc.deallocate(ip, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsetCountdown();
|
|
||||||
{
|
{
|
||||||
ThrowingAllocator<ThrowingValue<NoThrow::kIntCtor>, NoThrow::kNoThrow>
|
ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate>
|
||||||
ef_alloc;
|
nothrow_alloc;
|
||||||
ThrowingValue<NoThrow::kIntCtor>* efp;
|
ThrowingValue<>* ptr;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { efp = ef_alloc.allocate(1); });
|
ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); });
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { ef_alloc.construct(efp, 2); });
|
ExpectNoThrow(
|
||||||
EXPECT_EQ(efp->Get(), 2);
|
[&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); });
|
||||||
ef_alloc.destroy(efp);
|
|
||||||
ef_alloc.deallocate(efp, 1);
|
EXPECT_EQ(ptr->Get(), 2);
|
||||||
}
|
nothrow_alloc.destroy(ptr);
|
||||||
|
nothrow_alloc.deallocate(ptr, 1);
|
||||||
|
|
||||||
UnsetCountdown();
|
UnsetCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
ThrowingAllocator<int> a;
|
ThrowingAllocator<int> a;
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
|
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; });
|
||||||
|
|
||||||
SetCountdown();
|
SetCountdown();
|
||||||
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
|
ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); });
|
||||||
|
|
||||||
|
UnsetCountdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
|
TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) {
|
||||||
ThrowingAllocator<int> a;
|
ThrowingAllocator<int> a;
|
||||||
TestOp([]() { ThrowingAllocator<int> a; });
|
TestOp([]() { ThrowingAllocator<int> a; });
|
||||||
TestOp([&]() { a.select_on_container_copy_construction(); });
|
TestOp([&]() { a.select_on_container_copy_construction(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, State) {
|
TEST(ThrowingAllocatorTest, State) {
|
||||||
ThrowingAllocator<int> a1, a2;
|
ThrowingAllocator<int> a1, a2;
|
||||||
EXPECT_NE(a1, a2);
|
EXPECT_NE(a1, a2);
|
||||||
|
|
||||||
@ -390,13 +445,13 @@ TEST_F(ThrowingAllocatorTest, State) {
|
|||||||
EXPECT_EQ(a3, a1);
|
EXPECT_EQ(a3, a1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, InVector) {
|
TEST(ThrowingAllocatorTest, InVector) {
|
||||||
std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
|
std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v;
|
||||||
for (int i = 0; i < 20; ++i) v.push_back({});
|
for (int i = 0; i < 20; ++i) v.push_back({});
|
||||||
for (int i = 0; i < 20; ++i) v.pop_back();
|
for (int i = 0; i < 20; ++i) v.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ThrowingAllocatorTest, InList) {
|
TEST(ThrowingAllocatorTest, InList) {
|
||||||
std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
|
std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l;
|
||||||
for (int i = 0; i < 20; ++i) l.push_back({});
|
for (int i = 0; i < 20; ++i) l.push_back({});
|
||||||
for (int i = 0; i < 20; ++i) l.pop_back();
|
for (int i = 0; i < 20; ++i) l.pop_back();
|
||||||
@ -443,15 +498,15 @@ TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {
|
|||||||
// Test that providing operation and inveriants still does not allow for the
|
// Test that providing operation and inveriants still does not allow for the
|
||||||
// the invocation of .Test() and .Test(op) because it lacks a factory
|
// the invocation of .Test() and .Test(op) because it lacks a factory
|
||||||
auto without_fac =
|
auto without_fac =
|
||||||
absl::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
|
testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants(
|
||||||
inv, absl::strong_guarantee);
|
inv, testing::strong_guarantee);
|
||||||
EXPECT_FALSE(HasNullaryTest(without_fac));
|
EXPECT_FALSE(HasNullaryTest(without_fac));
|
||||||
EXPECT_FALSE(HasUnaryTest(without_fac));
|
EXPECT_FALSE(HasUnaryTest(without_fac));
|
||||||
|
|
||||||
// Test that providing invariants and factory allows the invocation of
|
// Test that providing invariants and factory allows the invocation of
|
||||||
// .Test(op) but does not allow for .Test() because it lacks an operation
|
// .Test(op) but does not allow for .Test() because it lacks an operation
|
||||||
auto without_op = absl::MakeExceptionSafetyTester()
|
auto without_op = testing::MakeExceptionSafetyTester()
|
||||||
.WithInvariants(inv, absl::strong_guarantee)
|
.WithInvariants(inv, testing::strong_guarantee)
|
||||||
.WithFactory(fac);
|
.WithFactory(fac);
|
||||||
EXPECT_FALSE(HasNullaryTest(without_op));
|
EXPECT_FALSE(HasNullaryTest(without_op));
|
||||||
EXPECT_TRUE(HasUnaryTest(without_op));
|
EXPECT_TRUE(HasUnaryTest(without_op));
|
||||||
@ -459,7 +514,7 @@ TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) {
|
|||||||
// Test that providing operation and factory still does not allow for the
|
// Test that providing operation and factory still does not allow for the
|
||||||
// the invocation of .Test() and .Test(op) because it lacks invariants
|
// the invocation of .Test() and .Test(op) because it lacks invariants
|
||||||
auto without_inv =
|
auto without_inv =
|
||||||
absl::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
|
testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac);
|
||||||
EXPECT_FALSE(HasNullaryTest(without_inv));
|
EXPECT_FALSE(HasNullaryTest(without_inv));
|
||||||
EXPECT_FALSE(HasUnaryTest(without_inv));
|
EXPECT_FALSE(HasUnaryTest(without_inv));
|
||||||
}
|
}
|
||||||
@ -504,28 +559,28 @@ auto example_lambda_invariant = [](ExampleStruct* example_struct) {
|
|||||||
// lambdas can all be used with ExceptionSafetyTester
|
// lambdas can all be used with ExceptionSafetyTester
|
||||||
TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
|
TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) {
|
||||||
// function reference
|
// function reference
|
||||||
EXPECT_TRUE(absl::MakeExceptionSafetyTester()
|
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
|
||||||
.WithFactory(ExampleFunctionFactory)
|
.WithFactory(ExampleFunctionFactory)
|
||||||
.WithOperation(ExampleFunctionOperation)
|
.WithOperation(ExampleFunctionOperation)
|
||||||
.WithInvariants(ExampleFunctionInvariant)
|
.WithInvariants(ExampleFunctionInvariant)
|
||||||
.Test());
|
.Test());
|
||||||
|
|
||||||
// function pointer
|
// function pointer
|
||||||
EXPECT_TRUE(absl::MakeExceptionSafetyTester()
|
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
|
||||||
.WithFactory(&ExampleFunctionFactory)
|
.WithFactory(&ExampleFunctionFactory)
|
||||||
.WithOperation(&ExampleFunctionOperation)
|
.WithOperation(&ExampleFunctionOperation)
|
||||||
.WithInvariants(&ExampleFunctionInvariant)
|
.WithInvariants(&ExampleFunctionInvariant)
|
||||||
.Test());
|
.Test());
|
||||||
|
|
||||||
// struct
|
// struct
|
||||||
EXPECT_TRUE(absl::MakeExceptionSafetyTester()
|
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
|
||||||
.WithFactory(example_struct_factory)
|
.WithFactory(example_struct_factory)
|
||||||
.WithOperation(example_struct_operation)
|
.WithOperation(example_struct_operation)
|
||||||
.WithInvariants(example_struct_invariant)
|
.WithInvariants(example_struct_invariant)
|
||||||
.Test());
|
.Test());
|
||||||
|
|
||||||
// lambda
|
// lambda
|
||||||
EXPECT_TRUE(absl::MakeExceptionSafetyTester()
|
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
|
||||||
.WithFactory(example_lambda_factory)
|
.WithFactory(example_lambda_factory)
|
||||||
.WithOperation(example_lambda_operation)
|
.WithOperation(example_lambda_operation)
|
||||||
.WithInvariants(example_lambda_invariant)
|
.WithInvariants(example_lambda_invariant)
|
||||||
@ -553,9 +608,9 @@ struct {
|
|||||||
} invoker;
|
} invoker;
|
||||||
|
|
||||||
auto tester =
|
auto tester =
|
||||||
absl::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
|
testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants(
|
||||||
CheckNonNegativeInvariants);
|
CheckNonNegativeInvariants);
|
||||||
auto strong_tester = tester.WithInvariants(absl::strong_guarantee);
|
auto strong_tester = tester.WithInvariants(testing::strong_guarantee);
|
||||||
|
|
||||||
struct FailsBasicGuarantee : public NonNegative {
|
struct FailsBasicGuarantee : public NonNegative {
|
||||||
void operator()() {
|
void operator()() {
|
||||||
@ -659,7 +714,7 @@ TEST(ExceptionCheckTest, ModifyingChecker) {
|
|||||||
EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
|
EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{})
|
||||||
.WithInvariants(increment)
|
.WithInvariants(increment)
|
||||||
.Test());
|
.Test());
|
||||||
EXPECT_TRUE(absl::MakeExceptionSafetyTester()
|
EXPECT_TRUE(testing::MakeExceptionSafetyTester()
|
||||||
.WithInitialValue(HasReset{})
|
.WithInitialValue(HasReset{})
|
||||||
.WithInvariants(CheckHasResetInvariants)
|
.WithInvariants(CheckHasResetInvariants)
|
||||||
.Test(invoker));
|
.Test(invoker));
|
||||||
@ -734,7 +789,7 @@ template <typename T>
|
|||||||
unsigned char ExhaustivenessTester<T>::successes = 0;
|
unsigned char ExhaustivenessTester<T>::successes = 0;
|
||||||
|
|
||||||
TEST(ExceptionCheckTest, Exhaustiveness) {
|
TEST(ExceptionCheckTest, Exhaustiveness) {
|
||||||
auto exhaust_tester = absl::MakeExceptionSafetyTester()
|
auto exhaust_tester = testing::MakeExceptionSafetyTester()
|
||||||
.WithInvariants(CheckExhaustivenessTesterInvariants)
|
.WithInvariants(CheckExhaustivenessTesterInvariants)
|
||||||
.WithOperation(invoker);
|
.WithOperation(invoker);
|
||||||
|
|
||||||
@ -744,7 +799,7 @@ TEST(ExceptionCheckTest, Exhaustiveness) {
|
|||||||
|
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
|
exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{})
|
||||||
.WithInvariants(absl::strong_guarantee)
|
.WithInvariants(testing::strong_guarantee)
|
||||||
.Test());
|
.Test());
|
||||||
EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
|
EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF);
|
||||||
}
|
}
|
||||||
@ -763,7 +818,7 @@ struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject {
|
|||||||
int LeaksIfCtorThrows::counter = 0;
|
int LeaksIfCtorThrows::counter = 0;
|
||||||
|
|
||||||
TEST(ExceptionCheckTest, TestLeakyCtor) {
|
TEST(ExceptionCheckTest, TestLeakyCtor) {
|
||||||
absl::TestThrowingCtor<LeaksIfCtorThrows>();
|
testing::TestThrowingCtor<LeaksIfCtorThrows>();
|
||||||
EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
|
EXPECT_EQ(LeaksIfCtorThrows::counter, 1);
|
||||||
LeaksIfCtorThrows::counter = 0;
|
LeaksIfCtorThrows::counter = 0;
|
||||||
}
|
}
|
||||||
@ -772,19 +827,28 @@ struct Tracked : private exceptions_internal::TrackedObject {
|
|||||||
Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
|
Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ConstructorTrackerTest, Pass) {
|
TEST(ConstructorTrackerTest, CreatedBefore) {
|
||||||
ConstructorTracker javert;
|
Tracked a, b, c;
|
||||||
Tracked t;
|
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ConstructorTrackerTest, NotDestroyed) {
|
TEST(ConstructorTrackerTest, CreatedAfter) {
|
||||||
|
exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
|
||||||
|
Tracked a, b, c;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConstructorTrackerTest, NotDestroyedAfter) {
|
||||||
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
|
absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
|
||||||
EXPECT_NONFATAL_FAILURE(
|
EXPECT_NONFATAL_FAILURE(
|
||||||
{
|
{
|
||||||
ConstructorTracker gadget;
|
exceptions_internal::ConstructorTracker ct(
|
||||||
|
exceptions_internal::countdown);
|
||||||
new (&storage) Tracked;
|
new (&storage) Tracked;
|
||||||
},
|
},
|
||||||
"not destroyed");
|
"not destroyed");
|
||||||
|
|
||||||
|
// Manual destruction of the Tracked instance is not required because
|
||||||
|
// ~ConstructorTracker() handles that automatically when a leak is found
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ConstructorTrackerTest, DestroyedTwice) {
|
TEST(ConstructorTrackerTest, DestroyedTwice) {
|
||||||
@ -825,4 +889,5 @@ TEST(ThrowingAllocatorTraitsTest, Assignablility) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace absl
|
|
||||||
|
} // namespace testing
|
||||||
|
|||||||
@ -21,6 +21,12 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#ifdef _MSC_FULL_VER
|
||||||
|
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
|
||||||
|
#else
|
||||||
|
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace base_internal {
|
namespace base_internal {
|
||||||
|
|
||||||
@ -29,9 +35,15 @@ class AtomicHook;
|
|||||||
|
|
||||||
// AtomicHook is a helper class, templatized on a raw function pointer type, for
|
// AtomicHook is a helper class, templatized on a raw function pointer type, for
|
||||||
// implementing Abseil customization hooks. It is a callable object that
|
// implementing Abseil customization hooks. It is a callable object that
|
||||||
// dispatches to the registered hook, or performs a no-op (and returns a default
|
// dispatches to the registered hook.
|
||||||
|
//
|
||||||
|
// A default constructed object performs a no-op (and returns a default
|
||||||
// constructed object) if no hook has been registered.
|
// constructed object) if no hook has been registered.
|
||||||
//
|
//
|
||||||
|
// Hooks can be pre-registered via constant initialization, for example,
|
||||||
|
// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction);
|
||||||
|
// and then changed at runtime via a call to Store().
|
||||||
|
//
|
||||||
// Reads and writes guarantee memory_order_acquire/memory_order_release
|
// Reads and writes guarantee memory_order_acquire/memory_order_release
|
||||||
// semantics.
|
// semantics.
|
||||||
template <typename ReturnType, typename... Args>
|
template <typename ReturnType, typename... Args>
|
||||||
@ -39,7 +51,19 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
|||||||
public:
|
public:
|
||||||
using FnPtr = ReturnType (*)(Args...);
|
using FnPtr = ReturnType (*)(Args...);
|
||||||
|
|
||||||
constexpr AtomicHook() : hook_(kInitialValue) {}
|
// Constructs an object that by default performs a no-op (and
|
||||||
|
// returns a default constructed object) when no hook as been registered.
|
||||||
|
constexpr AtomicHook() : AtomicHook(DummyFunction) {}
|
||||||
|
|
||||||
|
// Constructs an object that by default dispatches to/returns the
|
||||||
|
// pre-registered default_fn when no hook has been registered at runtime.
|
||||||
|
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
|
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||||
|
: hook_(default_fn), default_fn_(default_fn) {}
|
||||||
|
#else
|
||||||
|
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||||
|
: hook_(kUninitialized), default_fn_(default_fn) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Stores the provided function pointer as the value for this hook.
|
// Stores the provided function pointer as the value for this hook.
|
||||||
//
|
//
|
||||||
@ -86,16 +110,7 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
|||||||
//
|
//
|
||||||
// This causes an issue when building with LLVM under Windows. To avoid this,
|
// This causes an issue when building with LLVM under Windows. To avoid this,
|
||||||
// we use a less-efficient, intptr_t-based implementation on Windows.
|
// we use a less-efficient, intptr_t-based implementation on Windows.
|
||||||
|
|
||||||
#ifdef _MSC_FULL_VER
|
|
||||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
|
|
||||||
#else
|
|
||||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
static constexpr FnPtr kInitialValue = &DummyFunction;
|
|
||||||
|
|
||||||
// Return the stored value, or DummyFunction if no value has been stored.
|
// Return the stored value, or DummyFunction if no value has been stored.
|
||||||
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
|
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
|
||||||
|
|
||||||
@ -103,10 +118,9 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
|||||||
// stored to this object.
|
// stored to this object.
|
||||||
bool DoStore(FnPtr fn) {
|
bool DoStore(FnPtr fn) {
|
||||||
assert(fn);
|
assert(fn);
|
||||||
FnPtr expected = DummyFunction;
|
FnPtr expected = default_fn_;
|
||||||
hook_.compare_exchange_strong(expected, fn, std::memory_order_acq_rel,
|
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||||
std::memory_order_acquire);
|
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||||
const bool store_succeeded = (expected == DummyFunction);
|
|
||||||
const bool same_value_already_stored = (expected == fn);
|
const bool same_value_already_stored = (expected == fn);
|
||||||
return store_succeeded || same_value_already_stored;
|
return store_succeeded || same_value_already_stored;
|
||||||
}
|
}
|
||||||
@ -114,15 +128,15 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
|||||||
std::atomic<FnPtr> hook_;
|
std::atomic<FnPtr> hook_;
|
||||||
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
|
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
// Use a sentinel value unlikely to be the address of an actual function.
|
// Use a sentinel value unlikely to be the address of an actual function.
|
||||||
static constexpr intptr_t kInitialValue = 0;
|
static constexpr intptr_t kUninitialized = 0;
|
||||||
|
|
||||||
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
|
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
|
||||||
"intptr_t can't contain a function pointer");
|
"intptr_t can't contain a function pointer");
|
||||||
|
|
||||||
FnPtr DoLoad() const {
|
FnPtr DoLoad() const {
|
||||||
const intptr_t value = hook_.load(std::memory_order_acquire);
|
const intptr_t value = hook_.load(std::memory_order_acquire);
|
||||||
if (value == 0) {
|
if (value == kUninitialized) {
|
||||||
return DummyFunction;
|
return default_fn_;
|
||||||
}
|
}
|
||||||
return reinterpret_cast<FnPtr>(value);
|
return reinterpret_cast<FnPtr>(value);
|
||||||
}
|
}
|
||||||
@ -130,16 +144,17 @@ class AtomicHook<ReturnType (*)(Args...)> {
|
|||||||
bool DoStore(FnPtr fn) {
|
bool DoStore(FnPtr fn) {
|
||||||
assert(fn);
|
assert(fn);
|
||||||
const auto value = reinterpret_cast<intptr_t>(fn);
|
const auto value = reinterpret_cast<intptr_t>(fn);
|
||||||
intptr_t expected = 0;
|
intptr_t expected = kUninitialized;
|
||||||
hook_.compare_exchange_strong(expected, value, std::memory_order_acq_rel,
|
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||||
std::memory_order_acquire);
|
expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||||
const bool store_succeeded = (expected == 0);
|
|
||||||
const bool same_value_already_stored = (expected == value);
|
const bool same_value_already_stored = (expected == value);
|
||||||
return store_succeeded || same_value_already_stored;
|
return store_succeeded || same_value_already_stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::atomic<intptr_t> hook_;
|
std::atomic<intptr_t> hook_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const FnPtr default_fn_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
|
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||||
|
|||||||
70
third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc
vendored
Normal file
70
third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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/atomic_hook.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
void TestHook(int x) { value = x; }
|
||||||
|
|
||||||
|
TEST(AtomicHookTest, NoDefaultFunction) {
|
||||||
|
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook;
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Test the default DummyFunction.
|
||||||
|
EXPECT_TRUE(hook.Load() == nullptr);
|
||||||
|
EXPECT_EQ(value, 0);
|
||||||
|
hook(1);
|
||||||
|
EXPECT_EQ(value, 0);
|
||||||
|
|
||||||
|
// Test a stored hook.
|
||||||
|
hook.Store(TestHook);
|
||||||
|
EXPECT_TRUE(hook.Load() == TestHook);
|
||||||
|
EXPECT_EQ(value, 0);
|
||||||
|
hook(1);
|
||||||
|
EXPECT_EQ(value, 1);
|
||||||
|
|
||||||
|
// Calling Store() with the same hook should not crash.
|
||||||
|
hook.Store(TestHook);
|
||||||
|
EXPECT_TRUE(hook.Load() == TestHook);
|
||||||
|
EXPECT_EQ(value, 1);
|
||||||
|
hook(2);
|
||||||
|
EXPECT_EQ(value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AtomicHookTest, WithDefaultFunction) {
|
||||||
|
// Set the default value to TestHook at compile-time.
|
||||||
|
ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook(
|
||||||
|
TestHook);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Test the default value is TestHook.
|
||||||
|
EXPECT_TRUE(hook.Load() == TestHook);
|
||||||
|
EXPECT_EQ(value, 0);
|
||||||
|
hook(1);
|
||||||
|
EXPECT_EQ(value, 1);
|
||||||
|
|
||||||
|
// Calling Store() with the same hook should not crash.
|
||||||
|
hook.Store(TestHook);
|
||||||
|
EXPECT_TRUE(hook.Load() == TestHook);
|
||||||
|
EXPECT_EQ(value, 1);
|
||||||
|
hook(2);
|
||||||
|
EXPECT_EQ(value, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
// SYS_mmap and SYS_munmap are not defined in Android.
|
// SYS_mmap and SYS_munmap are not defined in Android.
|
||||||
#ifdef __BIONIC__
|
#ifdef __BIONIC__
|
||||||
extern "C" void* __mmap2(void*, size_t, int, int, int, long);
|
extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
|
||||||
#if defined(__NR_mmap) && !defined(SYS_mmap)
|
#if defined(__NR_mmap) && !defined(SYS_mmap)
|
||||||
#define SYS_mmap __NR_mmap
|
#define SYS_mmap __NR_mmap
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -17,9 +17,14 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "absl/meta/type_traits.h"
|
#include "absl/meta/type_traits.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace testing {
|
||||||
|
|
||||||
exceptions_internal::NoThrowTag no_throw_ctor;
|
exceptions_internal::NoThrowTag nothrow_ctor;
|
||||||
|
|
||||||
|
bool nothrow_guarantee(const void*) {
|
||||||
|
return ::testing::AssertionFailure()
|
||||||
|
<< "Exception thrown violating NoThrow Guarantee";
|
||||||
|
}
|
||||||
exceptions_internal::StrongGuaranteeTagType strong_guarantee;
|
exceptions_internal::StrongGuaranteeTagType strong_guarantee;
|
||||||
|
|
||||||
namespace exceptions_internal {
|
namespace exceptions_internal {
|
||||||
@ -37,5 +42,7 @@ testing::AssertionResult FailureMessage(const TestException& e,
|
|||||||
int countdown) noexcept {
|
int countdown) noexcept {
|
||||||
return testing::AssertionFailure() << "Exception thrown from " << e.what();
|
return testing::AssertionFailure() << "Exception thrown from " << e.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace exceptions_internal
|
} // namespace exceptions_internal
|
||||||
} // namespace absl
|
|
||||||
|
} // namespace testing
|
||||||
|
|||||||
@ -35,40 +35,36 @@
|
|||||||
#include "absl/strings/substitute.h"
|
#include "absl/strings/substitute.h"
|
||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace testing {
|
||||||
|
|
||||||
struct ConstructorTracker;
|
enum class TypeSpec;
|
||||||
|
enum class AllocSpec;
|
||||||
|
|
||||||
// A configuration enum for Throwing*. Operations whose flags are set will
|
constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
|
||||||
// throw, everything else won't. This isn't meant to be exhaustive, more flags
|
using T = absl::underlying_type_t<TypeSpec>;
|
||||||
// can always be made in the future.
|
return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
|
||||||
enum class NoThrow : uint8_t {
|
|
||||||
kNone = 0,
|
|
||||||
kMoveCtor = 1,
|
|
||||||
kMoveAssign = 1 << 1,
|
|
||||||
kAllocation = 1 << 2,
|
|
||||||
kIntCtor = 1 << 3,
|
|
||||||
kNoThrow = static_cast<uint8_t>(-1)
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr NoThrow operator|(NoThrow a, NoThrow b) {
|
|
||||||
using T = absl::underlying_type_t<NoThrow>;
|
|
||||||
return static_cast<NoThrow>(static_cast<T>(a) | static_cast<T>(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr NoThrow operator&(NoThrow a, NoThrow b) {
|
constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
|
||||||
using T = absl::underlying_type_t<NoThrow>;
|
using T = absl::underlying_type_t<TypeSpec>;
|
||||||
return static_cast<NoThrow>(static_cast<T>(a) & static_cast<T>(b));
|
return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
|
||||||
|
using T = absl::underlying_type_t<AllocSpec>;
|
||||||
|
return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
|
||||||
|
using T = absl::underlying_type_t<AllocSpec>;
|
||||||
|
return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace exceptions_internal {
|
namespace exceptions_internal {
|
||||||
|
|
||||||
struct NoThrowTag {};
|
struct NoThrowTag {};
|
||||||
struct StrongGuaranteeTagType {};
|
struct StrongGuaranteeTagType {};
|
||||||
|
|
||||||
constexpr bool ThrowingAllowed(NoThrow flags, NoThrow flag) {
|
|
||||||
return !static_cast<bool>(flags & flag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A simple exception class. We throw this so that test code can catch
|
// A simple exception class. We throw this so that test code can catch
|
||||||
// exceptions specifically thrown by ThrowingValue.
|
// exceptions specifically thrown by ThrowingValue.
|
||||||
class TestException {
|
class TestException {
|
||||||
@ -105,6 +101,8 @@ void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
|
|||||||
testing::AssertionResult FailureMessage(const TestException& e,
|
testing::AssertionResult FailureMessage(const TestException& e,
|
||||||
int countdown) noexcept;
|
int countdown) noexcept;
|
||||||
|
|
||||||
|
class ConstructorTracker;
|
||||||
|
|
||||||
class TrackedObject {
|
class TrackedObject {
|
||||||
public:
|
public:
|
||||||
TrackedObject(const TrackedObject&) = delete;
|
TrackedObject(const TrackedObject&) = delete;
|
||||||
@ -112,31 +110,61 @@ class TrackedObject {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit TrackedObject(const char* child_ctor) {
|
explicit TrackedObject(const char* child_ctor) {
|
||||||
if (!GetAllocs().emplace(this, child_ctor).second) {
|
if (!GetInstanceMap().emplace(this, child_ctor).second) {
|
||||||
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
|
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
|
||||||
<< " re-constructed in ctor " << child_ctor;
|
<< " re-constructed in ctor " << child_ctor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unordered_map<TrackedObject*, absl::string_view>& GetAllocs() {
|
|
||||||
static auto* m =
|
|
||||||
new std::unordered_map<TrackedObject*, absl::string_view>();
|
|
||||||
return *m;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TrackedObject() noexcept {
|
~TrackedObject() noexcept {
|
||||||
if (GetAllocs().erase(this) == 0) {
|
if (GetInstanceMap().erase(this) == 0) {
|
||||||
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
|
ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
|
||||||
<< " destroyed improperly";
|
<< " destroyed improperly";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend struct ::absl::ConstructorTracker;
|
private:
|
||||||
|
using InstanceMap = std::unordered_map<TrackedObject*, absl::string_view>;
|
||||||
|
static InstanceMap& GetInstanceMap() {
|
||||||
|
static auto* instance_map = new InstanceMap();
|
||||||
|
return *instance_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class ConstructorTracker;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inspects the constructions and destructions of anything inheriting from
|
||||||
|
// TrackedObject. This allows us to safely "leak" TrackedObjects, as
|
||||||
|
// ConstructorTracker will destroy everything left over in its destructor.
|
||||||
|
class ConstructorTracker {
|
||||||
|
public:
|
||||||
|
explicit ConstructorTracker(int c)
|
||||||
|
: init_count_(c), init_instances_(TrackedObject::GetInstanceMap()) {}
|
||||||
|
~ConstructorTracker() {
|
||||||
|
auto& cur_instances = TrackedObject::GetInstanceMap();
|
||||||
|
for (auto it = cur_instances.begin(); it != cur_instances.end();) {
|
||||||
|
if (init_instances_.count(it->first) == 0) {
|
||||||
|
ADD_FAILURE() << "Object at address " << static_cast<void*>(it->first)
|
||||||
|
<< " constructed from " << it->second
|
||||||
|
<< " where the exception countdown was set to "
|
||||||
|
<< init_count_ << " was not destroyed";
|
||||||
|
// Erasing an item inside an unordered_map invalidates the existing
|
||||||
|
// iterator. A new one is returned for iteration to continue.
|
||||||
|
it = cur_instances.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int init_count_;
|
||||||
|
TrackedObject::InstanceMap init_instances_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Factory, typename Operation, typename Invariant>
|
template <typename Factory, typename Operation, typename Invariant>
|
||||||
absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
|
absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
|
||||||
const Factory& factory, const Operation& operation, int count,
|
const Factory& factory, Operation operation, int count,
|
||||||
const Invariant& invariant) {
|
const Invariant& invariant) {
|
||||||
auto t_ptr = factory();
|
auto t_ptr = factory();
|
||||||
absl::optional<testing::AssertionResult> current_res;
|
absl::optional<testing::AssertionResult> current_res;
|
||||||
@ -199,7 +227,9 @@ inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
|
|||||||
|
|
||||||
} // namespace exceptions_internal
|
} // namespace exceptions_internal
|
||||||
|
|
||||||
extern exceptions_internal::NoThrowTag no_throw_ctor;
|
extern exceptions_internal::NoThrowTag nothrow_ctor;
|
||||||
|
|
||||||
|
bool nothrow_guarantee(const void*);
|
||||||
extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
|
extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
|
||||||
|
|
||||||
// A test class which is convertible to bool. The conversion can be
|
// A test class which is convertible to bool. The conversion can be
|
||||||
@ -216,47 +246,71 @@ class ThrowingBool {
|
|||||||
bool b_;
|
bool b_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A testing class instrumented to throw an exception at a controlled time.
|
/*
|
||||||
//
|
* Configuration enum for the ThrowingValue type that defines behavior for the
|
||||||
// ThrowingValue implements a slightly relaxed version of the Regular concept --
|
* lifetime of the instance. Use testing::nothrow_ctor to prevent the integer
|
||||||
// that is it's a value type with the expected semantics. It also implements
|
* constructor from throwing.
|
||||||
// arithmetic operations. It doesn't implement member and pointer operators
|
*
|
||||||
// like operator-> or operator[].
|
* kEverythingThrows: Every operation can throw an exception
|
||||||
//
|
* kNoThrowCopy: Copy construction and copy assignment will not throw
|
||||||
// ThrowingValue can be instrumented to have certain operations be noexcept by
|
* kNoThrowMove: Move construction and move assignment will not throw
|
||||||
// using compile-time bitfield flag template arguments. That is, to make an
|
* kNoThrowNew: Overloaded operators new and new[] will not throw
|
||||||
// ThrowingValue which has a noexcept move constructor and noexcept move
|
*/
|
||||||
// assignment, use
|
enum class TypeSpec {
|
||||||
// ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign>.
|
kEverythingThrows = 0,
|
||||||
template <NoThrow Flags = NoThrow::kNone>
|
kNoThrowCopy = 1,
|
||||||
|
kNoThrowMove = 1 << 1,
|
||||||
|
kNoThrowNew = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A testing class instrumented to throw an exception at a controlled time.
|
||||||
|
*
|
||||||
|
* ThrowingValue implements a slightly relaxed version of the Regular concept --
|
||||||
|
* that is it's a value type with the expected semantics. It also implements
|
||||||
|
* arithmetic operations. It doesn't implement member and pointer operators
|
||||||
|
* like operator-> or operator[].
|
||||||
|
*
|
||||||
|
* ThrowingValue can be instrumented to have certain operations be noexcept by
|
||||||
|
* using compile-time bitfield template arguments. That is, to make an
|
||||||
|
* ThrowingValue which has noexcept move construction/assignment and noexcept
|
||||||
|
* copy construction/assignment, use the following:
|
||||||
|
* ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val};
|
||||||
|
*/
|
||||||
|
template <TypeSpec Spec = TypeSpec::kEverythingThrows>
|
||||||
class ThrowingValue : private exceptions_internal::TrackedObject {
|
class ThrowingValue : private exceptions_internal::TrackedObject {
|
||||||
|
static constexpr bool IsSpecified(TypeSpec spec) {
|
||||||
|
return static_cast<bool>(Spec & spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr int kBadValue = 938550620;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) {
|
ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
dummy_ = 0;
|
dummy_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue(const ThrowingValue& other)
|
ThrowingValue(const ThrowingValue& other) noexcept(
|
||||||
|
IsSpecified(TypeSpec::kNoThrowCopy))
|
||||||
: TrackedObject(ABSL_PRETTY_FUNCTION) {
|
: TrackedObject(ABSL_PRETTY_FUNCTION) {
|
||||||
|
if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
|
}
|
||||||
dummy_ = other.dummy_;
|
dummy_ = other.dummy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue(ThrowingValue&& other) noexcept(
|
ThrowingValue(ThrowingValue&& other) noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor))
|
IsSpecified(TypeSpec::kNoThrowMove))
|
||||||
: TrackedObject(ABSL_PRETTY_FUNCTION) {
|
: TrackedObject(ABSL_PRETTY_FUNCTION) {
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) {
|
if (!IsSpecified(TypeSpec::kNoThrowMove)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
}
|
}
|
||||||
dummy_ = other.dummy_;
|
dummy_ = other.dummy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit ThrowingValue(int i) noexcept(
|
explicit ThrowingValue(int i) : TrackedObject(ABSL_PRETTY_FUNCTION) {
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor))
|
|
||||||
: TrackedObject(ABSL_PRETTY_FUNCTION) {
|
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) {
|
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
}
|
|
||||||
dummy_ = i;
|
dummy_ = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,15 +320,20 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
// absl expects nothrow destructors
|
// absl expects nothrow destructors
|
||||||
~ThrowingValue() noexcept = default;
|
~ThrowingValue() noexcept = default;
|
||||||
|
|
||||||
ThrowingValue& operator=(const ThrowingValue& other) {
|
ThrowingValue& operator=(const ThrowingValue& other) noexcept(
|
||||||
|
IsSpecified(TypeSpec::kNoThrowCopy)) {
|
||||||
|
dummy_ = kBadValue;
|
||||||
|
if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
|
}
|
||||||
dummy_ = other.dummy_;
|
dummy_ = other.dummy_;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue& operator=(ThrowingValue&& other) noexcept(
|
ThrowingValue& operator=(ThrowingValue&& other) noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) {
|
IsSpecified(TypeSpec::kNoThrowMove)) {
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) {
|
dummy_ = kBadValue;
|
||||||
|
if (!IsSpecified(TypeSpec::kNoThrowMove)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
}
|
}
|
||||||
dummy_ = other.dummy_;
|
dummy_ = other.dummy_;
|
||||||
@ -284,22 +343,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
// Arithmetic Operators
|
// Arithmetic Operators
|
||||||
ThrowingValue operator+(const ThrowingValue& other) const {
|
ThrowingValue operator+(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ + other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator+() const {
|
ThrowingValue operator+() const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator-(const ThrowingValue& other) const {
|
ThrowingValue operator-(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ - other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator-() const {
|
ThrowingValue operator-() const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(-dummy_, no_throw_ctor);
|
return ThrowingValue(-dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue& operator++() {
|
ThrowingValue& operator++() {
|
||||||
@ -310,7 +369,7 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
|
|
||||||
ThrowingValue operator++(int) {
|
ThrowingValue operator++(int) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
auto out = ThrowingValue(dummy_, no_throw_ctor);
|
auto out = ThrowingValue(dummy_, nothrow_ctor);
|
||||||
++dummy_;
|
++dummy_;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -323,34 +382,34 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
|
|
||||||
ThrowingValue operator--(int) {
|
ThrowingValue operator--(int) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
auto out = ThrowingValue(dummy_, no_throw_ctor);
|
auto out = ThrowingValue(dummy_, nothrow_ctor);
|
||||||
--dummy_;
|
--dummy_;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator*(const ThrowingValue& other) const {
|
ThrowingValue operator*(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ * other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator/(const ThrowingValue& other) const {
|
ThrowingValue operator/(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ / other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator%(const ThrowingValue& other) const {
|
ThrowingValue operator%(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ % other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator<<(int shift) const {
|
ThrowingValue operator<<(int shift) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ << shift, no_throw_ctor);
|
return ThrowingValue(dummy_ << shift, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator>>(int shift) const {
|
ThrowingValue operator>>(int shift) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ >> shift, no_throw_ctor);
|
return ThrowingValue(dummy_ >> shift, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison Operators
|
// Comparison Operators
|
||||||
@ -406,22 +465,22 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
// Bitwise Logical Operators
|
// Bitwise Logical Operators
|
||||||
ThrowingValue operator~() const {
|
ThrowingValue operator~() const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(~dummy_, no_throw_ctor);
|
return ThrowingValue(~dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator&(const ThrowingValue& other) const {
|
ThrowingValue operator&(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ & other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator|(const ThrowingValue& other) const {
|
ThrowingValue operator|(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ | other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowingValue operator^(const ThrowingValue& other) const {
|
ThrowingValue operator^(const ThrowingValue& other) const {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return ThrowingValue(dummy_ ^ other.dummy_, no_throw_ctor);
|
return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compound Assignment operators
|
// Compound Assignment operators
|
||||||
@ -503,8 +562,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
// Args.. allows us to overload regular and placement new in one shot
|
// Args.. allows us to overload regular and placement new in one shot
|
||||||
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(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
|
IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
|
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
||||||
}
|
}
|
||||||
return ::operator new(s, std::forward<Args>(args)...);
|
return ::operator new(s, std::forward<Args>(args)...);
|
||||||
@ -512,8 +571,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
|
|
||||||
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(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
|
IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) {
|
if (!IsSpecified(TypeSpec::kNoThrowNew)) {
|
||||||
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
|
||||||
}
|
}
|
||||||
return ::operator new[](s, std::forward<Args>(args)...);
|
return ::operator new[](s, std::forward<Args>(args)...);
|
||||||
@ -551,20 +610,35 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
|
|||||||
};
|
};
|
||||||
// While not having to do with exceptions, explicitly delete comma operator, to
|
// While not having to do with exceptions, explicitly delete comma operator, to
|
||||||
// make sure we don't use it on user-supplied types.
|
// make sure we don't use it on user-supplied types.
|
||||||
template <NoThrow N, typename T>
|
template <TypeSpec Spec, typename T>
|
||||||
void operator,(const ThrowingValue<N>& ef, T&& t) = delete;
|
void operator,(const ThrowingValue<Spec>&, T&&) = delete;
|
||||||
template <NoThrow N, typename T>
|
template <TypeSpec Spec, typename T>
|
||||||
void operator,(T&& t, const ThrowingValue<N>& ef) = delete;
|
void operator,(T&&, const ThrowingValue<Spec>&) = delete;
|
||||||
|
|
||||||
// An allocator type which is instrumented to throw at a controlled time, or not
|
/*
|
||||||
// to throw, using NoThrow. The supported settings are the default of every
|
* Configuration enum for the ThrowingAllocator type that defines behavior for
|
||||||
// function which is allowed to throw in a conforming allocator possibly
|
* the lifetime of the instance.
|
||||||
// throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
|
*
|
||||||
// configuration macro.
|
* kEverythingThrows: Calls to the member functions may throw
|
||||||
template <typename T, NoThrow Flags = NoThrow::kNone>
|
* kNoThrowAllocate: Calls to the member functions will not throw
|
||||||
|
*/
|
||||||
|
enum class AllocSpec {
|
||||||
|
kEverythingThrows = 0,
|
||||||
|
kNoThrowAllocate = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An allocator type which is instrumented to throw at a controlled time, or not
|
||||||
|
* to throw, using AllocSpec. The supported settings are the default of every
|
||||||
|
* function which is allowed to throw in a conforming allocator possibly
|
||||||
|
* throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS
|
||||||
|
* configuration macro.
|
||||||
|
*/
|
||||||
|
template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
|
||||||
class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
||||||
static_assert(Flags == NoThrow::kNone || Flags == NoThrow::kNoThrow,
|
static constexpr bool IsSpecified(AllocSpec spec) {
|
||||||
"Invalid flag");
|
return static_cast<bool>(Spec & spec);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using pointer = T*;
|
using pointer = T*;
|
||||||
@ -577,7 +651,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
using size_type = size_t;
|
using size_type = size_t;
|
||||||
using difference_type = ptrdiff_t;
|
using difference_type = ptrdiff_t;
|
||||||
|
|
||||||
using is_nothrow = std::integral_constant<bool, Flags == NoThrow::kNoThrow>;
|
using is_nothrow =
|
||||||
|
std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
|
||||||
using propagate_on_container_copy_assignment = std::true_type;
|
using propagate_on_container_copy_assignment = std::true_type;
|
||||||
using propagate_on_container_move_assignment = std::true_type;
|
using propagate_on_container_move_assignment = std::true_type;
|
||||||
using propagate_on_container_swap = std::true_type;
|
using propagate_on_container_swap = std::true_type;
|
||||||
@ -589,8 +664,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
ThrowingAllocator( // NOLINT
|
ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept // NOLINT
|
||||||
const ThrowingAllocator<U, Flags>& other) noexcept
|
|
||||||
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
|
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
|
||||||
|
|
||||||
// According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
|
// According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
|
||||||
@ -599,8 +673,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
|
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
ThrowingAllocator( // NOLINT
|
ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept // NOLINT
|
||||||
ThrowingAllocator<U, Flags>&& other) noexcept
|
|
||||||
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {}
|
: TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {}
|
||||||
|
|
||||||
ThrowingAllocator(ThrowingAllocator&& other) noexcept
|
ThrowingAllocator(ThrowingAllocator&& other) noexcept
|
||||||
@ -615,29 +688,30 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
ThrowingAllocator& operator=(
|
ThrowingAllocator& operator=(
|
||||||
const ThrowingAllocator<U, Flags>& other) noexcept {
|
const ThrowingAllocator<U, Spec>& other) noexcept {
|
||||||
dummy_ = other.State();
|
dummy_ = other.State();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
ThrowingAllocator& operator=(ThrowingAllocator<U, Flags>&& other) noexcept {
|
ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
|
||||||
dummy_ = std::move(other.State());
|
dummy_ = std::move(other.State());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
struct rebind {
|
struct rebind {
|
||||||
using other = ThrowingAllocator<U, Flags>;
|
using other = ThrowingAllocator<U, Spec>;
|
||||||
};
|
};
|
||||||
|
|
||||||
pointer allocate(size_type n) noexcept(
|
pointer allocate(size_type n) noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
|
IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||||
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return static_cast<pointer>(::operator new(n * sizeof(T)));
|
return static_cast<pointer>(::operator new(n * sizeof(T)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer allocate(size_type n, const_void_pointer) noexcept(
|
pointer allocate(size_type n, const_void_pointer) noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
|
IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||||
return allocate(n);
|
return allocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +722,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
|
|
||||||
template <typename U, typename... Args>
|
template <typename U, typename... Args>
|
||||||
void construct(U* ptr, Args&&... args) noexcept(
|
void construct(U* ptr, Args&&... args) noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
|
IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||||
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
|
::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@ -664,23 +738,23 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThrowingAllocator select_on_container_copy_construction() noexcept(
|
ThrowingAllocator select_on_container_copy_construction() noexcept(
|
||||||
!exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
|
IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||||
auto& out = *this;
|
auto& out = *this;
|
||||||
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
bool operator==(const ThrowingAllocator<U, Flags>& other) const noexcept {
|
bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
|
||||||
return dummy_ == other.dummy_;
|
return dummy_ == other.dummy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
bool operator!=(const ThrowingAllocator<U, Flags>& other) const noexcept {
|
bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
|
||||||
return dummy_ != other.dummy_;
|
return dummy_ != other.dummy_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U, NoThrow B>
|
template <typename, AllocSpec>
|
||||||
friend class ThrowingAllocator;
|
friend class ThrowingAllocator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -694,7 +768,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReadStateAndMaybeThrow(absl::string_view msg) const {
|
void ReadStateAndMaybeThrow(absl::string_view msg) const {
|
||||||
if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) {
|
if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
|
||||||
exceptions_internal::MaybeThrow(
|
exceptions_internal::MaybeThrow(
|
||||||
absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
|
absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
|
||||||
}
|
}
|
||||||
@ -704,40 +778,24 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
|
|||||||
std::shared_ptr<const int> dummy_;
|
std::shared_ptr<const int> dummy_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, NoThrow Throws>
|
template <typename T, AllocSpec Spec>
|
||||||
int ThrowingAllocator<T, Throws>::next_id_ = 0;
|
int ThrowingAllocator<T, Spec>::next_id_ = 0;
|
||||||
|
|
||||||
// Inspects the constructions and destructions of anything inheriting from
|
|
||||||
// TrackedObject. Place this as a member variable in a test fixture to ensure
|
|
||||||
// that every ThrowingValue was constructed and destroyed correctly. This also
|
|
||||||
// allows us to safely "leak" TrackedObjects, as ConstructorTracker will destroy
|
|
||||||
// everything left over in its destructor.
|
|
||||||
struct ConstructorTracker {
|
|
||||||
ConstructorTracker() = default;
|
|
||||||
~ConstructorTracker() {
|
|
||||||
auto& allocs = exceptions_internal::TrackedObject::GetAllocs();
|
|
||||||
for (const auto& kv : allocs) {
|
|
||||||
ADD_FAILURE() << "Object at address " << static_cast<void*>(kv.first)
|
|
||||||
<< " constructed from " << kv.second << " not destroyed";
|
|
||||||
}
|
|
||||||
allocs.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tests for resource leaks by attempting to construct a T using args repeatedly
|
// Tests for resource leaks by attempting to construct a T using args repeatedly
|
||||||
// until successful, using the countdown method. Side effects can then be
|
// until successful, using the countdown method. Side effects can then be
|
||||||
// tested for resource leaks. If a ConstructorTracker is present in the test
|
// tested for resource leaks.
|
||||||
// fixture, then this will also test that memory resources are not leaked as
|
|
||||||
// long as T allocates TrackedObjects.
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T TestThrowingCtor(Args&&... args) {
|
void TestThrowingCtor(Args&&... args) {
|
||||||
struct Cleanup {
|
struct Cleanup {
|
||||||
~Cleanup() { exceptions_internal::UnsetCountdown(); }
|
~Cleanup() { exceptions_internal::UnsetCountdown(); }
|
||||||
} c;
|
} c;
|
||||||
for (int count = 0;; ++count) {
|
for (int count = 0;; ++count) {
|
||||||
|
exceptions_internal::ConstructorTracker ct(count);
|
||||||
exceptions_internal::SetCountdown(count);
|
exceptions_internal::SetCountdown(count);
|
||||||
try {
|
try {
|
||||||
return T(std::forward<Args>(args)...);
|
T temp(std::forward<Args>(args)...);
|
||||||
|
static_cast<void>(temp);
|
||||||
|
break;
|
||||||
} catch (const exceptions_internal::TestException&) {
|
} catch (const exceptions_internal::TestException&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -859,7 +917,7 @@ class ExceptionSafetyTester {
|
|||||||
* created in order to get an empty Invariants... list.
|
* created in order to get an empty Invariants... list.
|
||||||
*
|
*
|
||||||
* In addition to passing in custom invariant assertion callbacks, this method
|
* In addition to passing in custom invariant assertion callbacks, this method
|
||||||
* accepts `absl::strong_guarantee` as an argument which checks T instances
|
* accepts `testing::strong_guarantee` as an argument which checks T instances
|
||||||
* post-throw against freshly created T instances via operator== to verify
|
* post-throw against freshly created T instances via operator== to verify
|
||||||
* that any state changes made during the execution of the operation were
|
* that any state changes made during the execution of the operation were
|
||||||
* properly rolled back.
|
* properly rolled back.
|
||||||
@ -920,7 +978,7 @@ class ExceptionSafetyTester {
|
|||||||
template <typename, typename, typename...>
|
template <typename, typename, typename...>
|
||||||
friend class ExceptionSafetyTester;
|
friend class ExceptionSafetyTester;
|
||||||
|
|
||||||
friend ExceptionSafetyTester<> absl::MakeExceptionSafetyTester();
|
friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester();
|
||||||
|
|
||||||
ExceptionSafetyTester() {}
|
ExceptionSafetyTester() {}
|
||||||
|
|
||||||
@ -934,6 +992,8 @@ class ExceptionSafetyTester {
|
|||||||
// Starting from 0 and counting upwards until one of the exit conditions is
|
// Starting from 0 and counting upwards until one of the exit conditions is
|
||||||
// hit...
|
// hit...
|
||||||
for (int count = 0;; ++count) {
|
for (int count = 0;; ++count) {
|
||||||
|
exceptions_internal::ConstructorTracker ct(count);
|
||||||
|
|
||||||
// Run the full exception safety test algorithm for the current countdown
|
// Run the full exception safety test algorithm for the current countdown
|
||||||
auto reduced_res =
|
auto reduced_res =
|
||||||
TestAllInvariantsAtCountdown(factory_, selected_operation, count,
|
TestAllInvariantsAtCountdown(factory_, selected_operation, count,
|
||||||
@ -976,6 +1036,6 @@ MakeExceptionSafetyTester() {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace absl
|
} // namespace testing
|
||||||
|
|
||||||
#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
|
#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
|
||||||
|
|||||||
40
third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc
vendored
Normal file
40
third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
#include "absl/base/internal/thread_identity.h"
|
||||||
|
#include "absl/synchronization/internal/create_thread_identity.h"
|
||||||
|
#include "absl/synchronization/internal/per_thread_sem.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void BM_SafeCurrentThreadIdentity(benchmark::State& state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
benchmark::DoNotOptimize(
|
||||||
|
absl::synchronization_internal::GetOrCreateCurrentThreadIdentity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_SafeCurrentThreadIdentity);
|
||||||
|
|
||||||
|
void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
benchmark::DoNotOptimize(
|
||||||
|
absl::base_internal::CurrentThreadIdentityIfPresent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_UnsafeCurrentThreadIdentity);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
15
third_party/abseil-cpp/absl/base/macros.h
vendored
15
third_party/abseil-cpp/absl/base/macros.h
vendored
@ -36,21 +36,20 @@
|
|||||||
|
|
||||||
// ABSL_ARRAYSIZE()
|
// ABSL_ARRAYSIZE()
|
||||||
//
|
//
|
||||||
// Returns the # of elements in an array as a compile-time constant, which can
|
// Returns the number of elements in an array as a compile-time constant, which
|
||||||
// be used in defining new arrays. If you use this macro on a pointer by
|
// can be used in defining new arrays. If you use this macro on a pointer by
|
||||||
// mistake, you will get a compile-time error.
|
// mistake, you will get a compile-time error.
|
||||||
//
|
#define ABSL_ARRAYSIZE(array) \
|
||||||
// Note: this template function declaration is used in defining arraysize.
|
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
||||||
// Note that the function doesn't need an implementation, as we only
|
|
||||||
// use its type.
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace macros_internal {
|
namespace macros_internal {
|
||||||
|
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
|
||||||
|
// The function doesn't need a definition, as we only use its type.
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N>
|
||||||
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
||||||
} // namespace macros_internal
|
} // namespace macros_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
#define ABSL_ARRAYSIZE(array) \
|
|
||||||
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
|
||||||
|
|
||||||
// kLinkerInitialized
|
// kLinkerInitialized
|
||||||
//
|
//
|
||||||
|
|||||||
@ -86,7 +86,7 @@
|
|||||||
// in May, 2010 and includes some functionality used in Google software
|
// in May, 2010 and includes some functionality used in Google software
|
||||||
// (for instance pthread_setname_np):
|
// (for instance pthread_setname_np):
|
||||||
// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
|
// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html
|
||||||
#ifdef __GLIBC_PREREQ
|
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
|
||||||
#if !__GLIBC_PREREQ(2, 12)
|
#if !__GLIBC_PREREQ(2, 12)
|
||||||
#error "Minimum required version of glibc is 2.12."
|
#error "Minimum required version of glibc is 2.12."
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -62,6 +62,17 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "fixed_array_benchmark",
|
||||||
|
srcs = ["fixed_array_benchmark.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"],
|
||||||
|
tags = ["benchmark"],
|
||||||
|
deps = [
|
||||||
|
":fixed_array",
|
||||||
|
"@com_github_google_benchmark//:benchmark",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "inlined_vector",
|
name = "inlined_vector",
|
||||||
hdrs = ["inlined_vector.h"],
|
hdrs = ["inlined_vector.h"],
|
||||||
@ -106,6 +117,19 @@ cc_test(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "inlined_vector_benchmark",
|
||||||
|
srcs = ["inlined_vector_benchmark.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS,
|
||||||
|
tags = ["benchmark"],
|
||||||
|
deps = [
|
||||||
|
":inlined_vector",
|
||||||
|
"//absl/base",
|
||||||
|
"//absl/strings",
|
||||||
|
"@com_github_google_benchmark//:benchmark",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "test_instance_tracker",
|
name = "test_instance_tracker",
|
||||||
testonly = 1,
|
testonly = 1,
|
||||||
|
|||||||
68
third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc
vendored
Normal file
68
third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/container/fixed_array.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// For benchmarking -- simple class with constructor and destructor that
|
||||||
|
// set an int to a constant..
|
||||||
|
class SimpleClass {
|
||||||
|
public:
|
||||||
|
SimpleClass() : i(3) { }
|
||||||
|
~SimpleClass() { i = 0; }
|
||||||
|
private:
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename C, size_t stack_size>
|
||||||
|
void BM_FixedArray(benchmark::State& state) {
|
||||||
|
const int size = state.range(0);
|
||||||
|
for (auto _ : state) {
|
||||||
|
absl::FixedArray<C, stack_size> fa(size);
|
||||||
|
benchmark::DoNotOptimize(fa.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault)
|
||||||
|
->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault)
|
||||||
|
->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault)
|
||||||
|
->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16);
|
||||||
|
BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
376
third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
vendored
Normal file
376
third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc
vendored
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "absl/container/inlined_vector.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using IntVec = absl::InlinedVector<int, 8>;
|
||||||
|
|
||||||
|
void BM_InlinedVectorFill(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
for (auto _ : state) {
|
||||||
|
IntVec v;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
v.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
|
||||||
|
|
||||||
|
void BM_InlinedVectorFillRange(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
std::unique_ptr<int[]> ia(new int[len]);
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
ia[i] = i;
|
||||||
|
}
|
||||||
|
for (auto _ : state) {
|
||||||
|
IntVec v(ia.get(), ia.get() + len);
|
||||||
|
benchmark::DoNotOptimize(v);
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
|
||||||
|
|
||||||
|
void BM_StdVectorFill(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::vector<int> v;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
v.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
|
||||||
|
|
||||||
|
bool StringRepresentedInline(std::string s) {
|
||||||
|
const char* chars = s.data();
|
||||||
|
std::string s1 = std::move(s);
|
||||||
|
return s1.data() != chars;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BM_InlinedVectorFillString(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
std::string strings[4] = {"a quite long string",
|
||||||
|
"another long string",
|
||||||
|
"012345678901234567",
|
||||||
|
"to cause allocation"};
|
||||||
|
for (auto _ : state) {
|
||||||
|
absl::InlinedVector<std::string, 8> v;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
v.push_back(strings[i & 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024);
|
||||||
|
|
||||||
|
void BM_StdVectorFillString(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
std::string strings[4] = {"a quite long string",
|
||||||
|
"another long string",
|
||||||
|
"012345678901234567",
|
||||||
|
"to cause allocation"};
|
||||||
|
for (auto _ : state) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
v.push_back(strings[i & 3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
|
||||||
|
// The purpose of the benchmark is to verify that inlined vector is
|
||||||
|
// efficient when moving is more efficent than copying. To do so, we
|
||||||
|
// use strings that are larger than the small std::string optimization.
|
||||||
|
ABSL_RAW_CHECK(!StringRepresentedInline(strings[0]),
|
||||||
|
"benchmarked with strings that are too small");
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorFillString)->Range(0, 1024);
|
||||||
|
|
||||||
|
struct Buffer { // some arbitrary structure for benchmarking.
|
||||||
|
char* base;
|
||||||
|
int length;
|
||||||
|
int capacity;
|
||||||
|
void* user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void BM_InlinedVectorTenAssignments(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
using BufferVec = absl::InlinedVector<Buffer, 2>;
|
||||||
|
|
||||||
|
BufferVec src;
|
||||||
|
src.resize(len);
|
||||||
|
|
||||||
|
BufferVec dst;
|
||||||
|
for (auto _ : state) {
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
dst = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorTenAssignments)
|
||||||
|
->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20);
|
||||||
|
|
||||||
|
void BM_CreateFromContainer(benchmark::State& state) {
|
||||||
|
for (auto _ : state) {
|
||||||
|
absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3});
|
||||||
|
benchmark::DoNotOptimize(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_CreateFromContainer);
|
||||||
|
|
||||||
|
struct LargeCopyableOnly {
|
||||||
|
LargeCopyableOnly() : d(1024, 17) {}
|
||||||
|
LargeCopyableOnly(const LargeCopyableOnly& o) = default;
|
||||||
|
LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default;
|
||||||
|
|
||||||
|
std::vector<int> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LargeCopyableSwappable {
|
||||||
|
LargeCopyableSwappable() : d(1024, 17) {}
|
||||||
|
LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
|
||||||
|
LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete;
|
||||||
|
|
||||||
|
LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
|
||||||
|
using std::swap;
|
||||||
|
swap(*this, o);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete;
|
||||||
|
|
||||||
|
friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
|
||||||
|
using std::swap;
|
||||||
|
swap(a.d, b.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LargeCopyableMovable {
|
||||||
|
LargeCopyableMovable() : d(1024, 17) {}
|
||||||
|
// Use implicitly defined copy and move.
|
||||||
|
|
||||||
|
std::vector<int> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LargeCopyableMovableSwappable {
|
||||||
|
LargeCopyableMovableSwappable() : d(1024, 17) {}
|
||||||
|
LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) =
|
||||||
|
default;
|
||||||
|
LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default;
|
||||||
|
|
||||||
|
LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) {
|
||||||
|
using std::swap;
|
||||||
|
swap(*this, o);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) =
|
||||||
|
default;
|
||||||
|
|
||||||
|
friend void swap(LargeCopyableMovableSwappable& a,
|
||||||
|
LargeCopyableMovableSwappable& b) {
|
||||||
|
using std::swap;
|
||||||
|
swap(a.d, b.d);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> d;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ElementType>
|
||||||
|
void BM_SwapElements(benchmark::State& state) {
|
||||||
|
const int len = state.range(0);
|
||||||
|
using Vec = absl::InlinedVector<ElementType, 32>;
|
||||||
|
Vec a(len);
|
||||||
|
Vec b;
|
||||||
|
for (auto _ : state) {
|
||||||
|
using std::swap;
|
||||||
|
swap(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024);
|
||||||
|
BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024);
|
||||||
|
BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024);
|
||||||
|
BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable)
|
||||||
|
->Range(0, 1024);
|
||||||
|
|
||||||
|
// The following benchmark is meant to track the efficiency of the vector size
|
||||||
|
// as a function of stored type via the benchmark label. It is not meant to
|
||||||
|
// output useful sizeof operator performance. The loop is a dummy operation
|
||||||
|
// to fulfill the requirement of running the benchmark.
|
||||||
|
template <typename VecType>
|
||||||
|
void BM_Sizeof(benchmark::State& state) {
|
||||||
|
int size = 0;
|
||||||
|
for (auto _ : state) {
|
||||||
|
VecType vec;
|
||||||
|
size = sizeof(vec);
|
||||||
|
}
|
||||||
|
state.SetLabel(absl::StrCat("sz=", size));
|
||||||
|
}
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>);
|
||||||
|
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>);
|
||||||
|
BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
|
||||||
|
|
||||||
|
void BM_InlinedVectorIndexInlined(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
for (auto _ : state) {
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
benchmark::DoNotOptimize(v);
|
||||||
|
benchmark::DoNotOptimize(v[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorIndexInlined);
|
||||||
|
|
||||||
|
void BM_InlinedVectorIndexExternal(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
benchmark::DoNotOptimize(v);
|
||||||
|
benchmark::DoNotOptimize(v[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorIndexExternal);
|
||||||
|
|
||||||
|
void BM_StdVectorIndex(benchmark::State& state) {
|
||||||
|
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
benchmark::DoNotOptimize(v);
|
||||||
|
benchmark::DoNotOptimize(v[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorIndex);
|
||||||
|
|
||||||
|
#define UNROLL_2(x) \
|
||||||
|
benchmark::DoNotOptimize(x); \
|
||||||
|
benchmark::DoNotOptimize(x);
|
||||||
|
|
||||||
|
#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x)
|
||||||
|
#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x)
|
||||||
|
#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x);
|
||||||
|
|
||||||
|
void BM_InlinedVectorDataInlined(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.data());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorDataInlined);
|
||||||
|
|
||||||
|
void BM_InlinedVectorDataExternal(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.data());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorDataExternal);
|
||||||
|
|
||||||
|
void BM_StdVectorData(benchmark::State& state) {
|
||||||
|
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.data());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorData);
|
||||||
|
|
||||||
|
void BM_InlinedVectorSizeInlined(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.size());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorSizeInlined);
|
||||||
|
|
||||||
|
void BM_InlinedVectorSizeExternal(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.size());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorSizeExternal);
|
||||||
|
|
||||||
|
void BM_StdVectorSize(benchmark::State& state) {
|
||||||
|
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.size());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorSize);
|
||||||
|
|
||||||
|
void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.empty());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorEmptyInlined);
|
||||||
|
|
||||||
|
void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
|
||||||
|
absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.empty());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_InlinedVectorEmptyExternal);
|
||||||
|
|
||||||
|
void BM_StdVectorEmpty(benchmark::State& state) {
|
||||||
|
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||||
|
for (auto _ : state) {
|
||||||
|
UNROLL_16(v.empty());
|
||||||
|
}
|
||||||
|
state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
|
||||||
|
}
|
||||||
|
BENCHMARK(BM_StdVectorEmpty);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
BENCHMARK_MAIN();
|
||||||
@ -46,6 +46,7 @@ cc_library(
|
|||||||
"symbolize.cc",
|
"symbolize.cc",
|
||||||
"symbolize_elf.inc",
|
"symbolize_elf.inc",
|
||||||
"symbolize_unimplemented.inc",
|
"symbolize_unimplemented.inc",
|
||||||
|
"symbolize_win32.inc",
|
||||||
],
|
],
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"internal/symbolize.h",
|
"internal/symbolize.h",
|
||||||
@ -93,6 +94,38 @@ cc_library(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "failure_signal_handler",
|
||||||
|
srcs = ["failure_signal_handler.cc"],
|
||||||
|
hdrs = ["failure_signal_handler.h"],
|
||||||
|
copts = ABSL_DEFAULT_COPTS,
|
||||||
|
deps = [
|
||||||
|
":examine_stack",
|
||||||
|
":stacktrace",
|
||||||
|
"//absl/base",
|
||||||
|
"//absl/base:config",
|
||||||
|
"//absl/base:core_headers",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "failure_signal_handler_test",
|
||||||
|
srcs = ["failure_signal_handler_test.cc"],
|
||||||
|
copts = ABSL_TEST_COPTS,
|
||||||
|
linkopts = select({
|
||||||
|
"//absl:windows": [],
|
||||||
|
"//conditions:default": ["-pthread"],
|
||||||
|
}),
|
||||||
|
deps = [
|
||||||
|
":failure_signal_handler",
|
||||||
|
":stacktrace",
|
||||||
|
":symbolize",
|
||||||
|
"//absl/base",
|
||||||
|
"//absl/strings",
|
||||||
|
"@com_google_googletest//:gtest",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "debugging_internal",
|
name = "debugging_internal",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
|||||||
23
third_party/abseil-cpp/absl/debugging/BUILD.gn
vendored
23
third_party/abseil-cpp/absl/debugging/BUILD.gn
vendored
@ -46,6 +46,7 @@ source_set("symbolize") {
|
|||||||
"symbolize.cc",
|
"symbolize.cc",
|
||||||
"symbolize_elf.inc",
|
"symbolize_elf.inc",
|
||||||
"symbolize_unimplemented.inc",
|
"symbolize_unimplemented.inc",
|
||||||
|
"symbolize_win32.inc",
|
||||||
]
|
]
|
||||||
public = [
|
public = [
|
||||||
"internal/symbolize.h",
|
"internal/symbolize.h",
|
||||||
@ -83,6 +84,28 @@ source_set("examine_stack") {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
source_set("failure_signal_handler") {
|
||||||
|
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||||
|
configs += [
|
||||||
|
"//build/config/compiler:no_chromium_code",
|
||||||
|
"//third_party/abseil-cpp:absl_default_cflags_cc",
|
||||||
|
]
|
||||||
|
public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
|
||||||
|
sources = [
|
||||||
|
"failure_signal_handler.cc"
|
||||||
|
]
|
||||||
|
public = [
|
||||||
|
"failure_signal_handler.h"
|
||||||
|
]
|
||||||
|
deps = [
|
||||||
|
":examine_stack",
|
||||||
|
":stacktrace",
|
||||||
|
"../base",
|
||||||
|
"../base:config",
|
||||||
|
"../base:core_headers",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
source_set("debugging_internal") {
|
source_set("debugging_internal") {
|
||||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||||
configs += [
|
configs += [
|
||||||
|
|||||||
@ -15,12 +15,14 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND DEBUGGING_PUBLIC_HEADERS
|
list(APPEND DEBUGGING_PUBLIC_HEADERS
|
||||||
|
"failure_signal_handler.h"
|
||||||
"leak_check.h"
|
"leak_check.h"
|
||||||
"stacktrace.h"
|
"stacktrace.h"
|
||||||
"symbolize.h"
|
"symbolize.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in
|
||||||
|
# Bazel
|
||||||
list(APPEND DEBUGGING_INTERNAL_HEADERS
|
list(APPEND DEBUGGING_INTERNAL_HEADERS
|
||||||
"internal/address_is_readable.h"
|
"internal/address_is_readable.h"
|
||||||
"internal/demangle.h"
|
"internal/demangle.h"
|
||||||
@ -31,12 +33,16 @@ list(APPEND DEBUGGING_INTERNAL_HEADERS
|
|||||||
"internal/vdso_support.h"
|
"internal/vdso_support.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
list(APPEND DEBUGGING_INTERNAL_SRC
|
||||||
list(APPEND STACKTRACE_SRC
|
|
||||||
"stacktrace.cc"
|
|
||||||
"internal/address_is_readable.cc"
|
"internal/address_is_readable.cc"
|
||||||
"internal/elf_mem_image.cc"
|
"internal/elf_mem_image.cc"
|
||||||
"internal/vdso_support.cc"
|
"internal/vdso_support.cc"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
list(APPEND STACKTRACE_SRC
|
||||||
|
"stacktrace.cc"
|
||||||
|
${DEBUGGING_INTERNAL_SRC}
|
||||||
${DEBUGGING_PUBLIC_HEADERS}
|
${DEBUGGING_PUBLIC_HEADERS}
|
||||||
${DEBUGGING_INTERNAL_HEADERS}
|
${DEBUGGING_INTERNAL_HEADERS}
|
||||||
)
|
)
|
||||||
@ -45,9 +51,16 @@ list(APPEND SYMBOLIZE_SRC
|
|||||||
"symbolize.cc"
|
"symbolize.cc"
|
||||||
"symbolize_elf.inc"
|
"symbolize_elf.inc"
|
||||||
"symbolize_unimplemented.inc"
|
"symbolize_unimplemented.inc"
|
||||||
|
"symbolize_win32.inc"
|
||||||
"internal/demangle.cc"
|
"internal/demangle.cc"
|
||||||
${DEBUGGING_PUBLIC_HEADERS}
|
${DEBUGGING_PUBLIC_HEADERS}
|
||||||
${DEBUGGING_INTERNAL_HEADERS}
|
${DEBUGGING_INTERNAL_HEADERS}
|
||||||
|
${DEBUGGING_INTERNAL_SRC}
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FAILURE_SIGNAL_HANDLER_SRC
|
||||||
|
"failure_signal_handler.cc"
|
||||||
|
${DEBUGGING_PUBLIC_HEADERS}
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND EXAMINE_STACK_SRC
|
list(APPEND EXAMINE_STACK_SRC
|
||||||
@ -70,10 +83,24 @@ absl_library(
|
|||||||
absl_symbolize
|
absl_symbolize
|
||||||
SOURCES
|
SOURCES
|
||||||
${SYMBOLIZE_SRC}
|
${SYMBOLIZE_SRC}
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl::base
|
||||||
|
absl_malloc_internal
|
||||||
EXPORT_NAME
|
EXPORT_NAME
|
||||||
symbolize
|
symbolize
|
||||||
)
|
)
|
||||||
|
|
||||||
|
absl_library(
|
||||||
|
TARGET
|
||||||
|
absl_failure_signal_handler
|
||||||
|
SOURCES
|
||||||
|
${FAILURE_SIGNAL_HANDLER_SRC}
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl_base absl::examine_stack absl::stacktrace absl_synchronization
|
||||||
|
EXPORT_NAME
|
||||||
|
failure_signal_handler
|
||||||
|
)
|
||||||
|
|
||||||
# Internal-only. Projects external to Abseil should not depend
|
# Internal-only. Projects external to Abseil should not depend
|
||||||
# directly on this library.
|
# directly on this library.
|
||||||
absl_library(
|
absl_library(
|
||||||
@ -117,13 +144,9 @@ absl_header_library(
|
|||||||
## TESTS
|
## TESTS
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND DEBUGGING_INTERNAL_TEST_HEADERS
|
|
||||||
"internal/stack_consumption.h"
|
|
||||||
)
|
|
||||||
|
|
||||||
list(APPEND STACK_CONSUMPTION_SRC
|
list(APPEND STACK_CONSUMPTION_SRC
|
||||||
"internal/stack_consumption.cc"
|
"internal/stack_consumption.cc"
|
||||||
${DEBUGGING_INTERNAL_TEST_HEADERS}
|
"internal/stack_consumption.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
absl_library(
|
absl_library(
|
||||||
@ -137,10 +160,13 @@ absl_test(
|
|||||||
TARGET
|
TARGET
|
||||||
absl_stack_consumption_test
|
absl_stack_consumption_test
|
||||||
SOURCES
|
SOURCES
|
||||||
${STACK_CONSUMPTION_SRC}
|
"internal/stack_consumption_test.cc"
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl_stack_consumption
|
||||||
|
absl::base
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND DEMANGLE_TEST_SRC "demangle_test.cc")
|
list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc")
|
||||||
|
|
||||||
absl_test(
|
absl_test(
|
||||||
TARGET
|
TARGET
|
||||||
@ -159,7 +185,23 @@ absl_test(
|
|||||||
SOURCES
|
SOURCES
|
||||||
${SYMBOLIZE_TEST_SRC}
|
${SYMBOLIZE_TEST_SRC}
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
absl_symbolize absl_stack_consumption
|
absl::base absl::memory absl_symbolize absl_stack_consumption
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc")
|
||||||
|
|
||||||
|
absl_test(
|
||||||
|
TARGET
|
||||||
|
failure_signal_handler_test
|
||||||
|
SOURCES
|
||||||
|
${FAILURE_SIGNAL_HANDLER_TEST_SRC}
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl_examine_stack
|
||||||
|
absl_failure_signal_handler
|
||||||
|
absl_stacktrace
|
||||||
|
absl_symbolize
|
||||||
|
absl::base
|
||||||
|
absl::strings
|
||||||
)
|
)
|
||||||
|
|
||||||
# test leak_check_test
|
# test leak_check_test
|
||||||
|
|||||||
356
third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
vendored
Normal file
356
third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc
vendored
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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/debugging/failure_signal_handler.h"
|
||||||
|
|
||||||
|
#include "absl/base/config.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_MMAP
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/base/internal/sysinfo.h"
|
||||||
|
#include "absl/debugging/internal/examine_stack.h"
|
||||||
|
#include "absl/debugging/stacktrace.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#define ABSL_HAVE_SIGACTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
|
||||||
|
ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options;
|
||||||
|
|
||||||
|
// Resets the signal handler for signo to the default action for that
|
||||||
|
// signal, then raises the signal.
|
||||||
|
static void RaiseToDefaultHandler(int signo) {
|
||||||
|
signal(signo, SIG_DFL);
|
||||||
|
raise(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FailureSignalData {
|
||||||
|
const int signo;
|
||||||
|
const char* const as_string;
|
||||||
|
#ifdef ABSL_HAVE_SIGACTION
|
||||||
|
struct sigaction previous_action;
|
||||||
|
// StructSigaction is used to silence -Wmissing-field-initializers.
|
||||||
|
using StructSigaction = struct sigaction;
|
||||||
|
#define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction()
|
||||||
|
#else
|
||||||
|
void (*previous_handler)(int);
|
||||||
|
#define FSD_PREVIOUS_INIT SIG_DFL
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = {
|
||||||
|
{SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT},
|
||||||
|
{SIGILL, "SIGILL", FSD_PREVIOUS_INIT},
|
||||||
|
{SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT},
|
||||||
|
{SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT},
|
||||||
|
{SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT},
|
||||||
|
#ifndef _WIN32
|
||||||
|
{SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT},
|
||||||
|
{SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef FSD_PREVIOUS_INIT
|
||||||
|
|
||||||
|
static void RaiseToPreviousHandler(int signo) {
|
||||||
|
// Search for the previous handler.
|
||||||
|
for (const auto& it : failure_signal_data) {
|
||||||
|
if (it.signo == signo) {
|
||||||
|
#ifdef ABSL_HAVE_SIGACTION
|
||||||
|
sigaction(signo, &it.previous_action, nullptr);
|
||||||
|
#else
|
||||||
|
signal(signo, it.previous_handler);
|
||||||
|
#endif
|
||||||
|
raise(signo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found, use the default handler.
|
||||||
|
RaiseToDefaultHandler(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace debugging_internal {
|
||||||
|
|
||||||
|
const char* FailureSignalToString(int signo) {
|
||||||
|
for (const auto& it : failure_signal_data) {
|
||||||
|
if (it.signo == signo) {
|
||||||
|
return it.as_string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace debugging_internal
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
static bool SetupAlternateStackOnce() {
|
||||||
|
const size_t page_mask = getpagesize() - 1;
|
||||||
|
size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask;
|
||||||
|
#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
|
||||||
|
defined(THREAD_SANITIZER)
|
||||||
|
// Account for sanitizer instrumentation requiring additional stack space.
|
||||||
|
stack_size *= 5;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
stack_t sigstk;
|
||||||
|
memset(&sigstk, 0, sizeof(sigstk));
|
||||||
|
sigstk.ss_size = stack_size;
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_MMAP
|
||||||
|
#ifndef MAP_STACK
|
||||||
|
#define MAP_STACK 0
|
||||||
|
#endif
|
||||||
|
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
|
||||||
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
|
#endif
|
||||||
|
sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
|
||||||
|
if (sigstk.ss_sp == MAP_FAILED) {
|
||||||
|
ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sigstk.ss_sp = malloc(sigstk.ss_size);
|
||||||
|
if (sigstk.ss_sp == nullptr) {
|
||||||
|
ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sigaltstack(&sigstk, nullptr) != 0) {
|
||||||
|
ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Sets up an alternate stack for signal handlers once.
|
||||||
|
// Returns the appropriate flag for sig_action.sa_flags
|
||||||
|
// if the system supports using an alternate stack.
|
||||||
|
static int MaybeSetupAlternateStack() {
|
||||||
|
#ifndef _WIN32
|
||||||
|
ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce();
|
||||||
|
return SA_ONSTACK;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_SIGACTION
|
||||||
|
|
||||||
|
static void InstallOneFailureHandler(FailureSignalData* data,
|
||||||
|
void (*handler)(int, siginfo_t*, void*)) {
|
||||||
|
struct sigaction act;
|
||||||
|
memset(&act, 0, sizeof(act));
|
||||||
|
sigemptyset(&act.sa_mask);
|
||||||
|
act.sa_flags |= SA_SIGINFO;
|
||||||
|
// SA_NODEFER is required to handle SIGABRT from
|
||||||
|
// ImmediateAbortSignalHandler().
|
||||||
|
act.sa_flags |= SA_NODEFER;
|
||||||
|
if (fsh_options.use_alternate_stack) {
|
||||||
|
act.sa_flags |= MaybeSetupAlternateStack();
|
||||||
|
}
|
||||||
|
act.sa_sigaction = handler;
|
||||||
|
ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0,
|
||||||
|
"sigaction() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static void InstallOneFailureHandler(FailureSignalData* data,
|
||||||
|
void (*handler)(int)) {
|
||||||
|
data->previous_handler = signal(data->signo, handler);
|
||||||
|
ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void WriteToStderr(const char* data) {
|
||||||
|
int old_errno = errno;
|
||||||
|
absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data));
|
||||||
|
errno = old_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) {
|
||||||
|
char buf[64];
|
||||||
|
const char* const signal_string =
|
||||||
|
debugging_internal::FailureSignalToString(signo);
|
||||||
|
if (signal_string != nullptr && signal_string[0] != '\0') {
|
||||||
|
snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n",
|
||||||
|
signal_string,
|
||||||
|
static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n",
|
||||||
|
signo, static_cast<long>(time(nullptr))); // NOLINT(runtime/int)
|
||||||
|
}
|
||||||
|
writerfn(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// `void*` might not be big enough to store `void(*)(const char*)`.
|
||||||
|
struct WriterFnStruct {
|
||||||
|
void (*writerfn)(const char*);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Many of the absl::debugging_internal::Dump* functions in
|
||||||
|
// examine_stack.h take a writer function pointer that has a void* arg
|
||||||
|
// for historical reasons. failure_signal_handler_writer only takes a
|
||||||
|
// data pointer. This function converts between these types.
|
||||||
|
static void WriterFnWrapper(const char* data, void* arg) {
|
||||||
|
static_cast<WriterFnStruct*>(arg)->writerfn(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal
|
||||||
|
// handlers. "noinline" so that GetStackFrames() skips the top-most stack
|
||||||
|
// frame for this function.
|
||||||
|
ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace(
|
||||||
|
void* ucontext, bool symbolize_stacktrace,
|
||||||
|
void (*writerfn)(const char*, void*), void* writerfn_arg) {
|
||||||
|
constexpr int kNumStackFrames = 32;
|
||||||
|
void* stack[kNumStackFrames];
|
||||||
|
int frame_sizes[kNumStackFrames];
|
||||||
|
int min_dropped_frames;
|
||||||
|
int depth = absl::GetStackFramesWithContext(
|
||||||
|
stack, frame_sizes, kNumStackFrames,
|
||||||
|
1, // Do not include this function in stack trace.
|
||||||
|
ucontext, &min_dropped_frames);
|
||||||
|
absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace(
|
||||||
|
absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes,
|
||||||
|
depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by FailureSignalHandler() to write the failure info. It is
|
||||||
|
// called once with writerfn set to WriteToStderr() and then possibly
|
||||||
|
// with writerfn set to the user provided function.
|
||||||
|
static void WriteFailureInfo(int signo, void* ucontext,
|
||||||
|
void (*writerfn)(const char*)) {
|
||||||
|
WriterFnStruct writerfn_struct{writerfn};
|
||||||
|
WriteSignalMessage(signo, writerfn);
|
||||||
|
WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper,
|
||||||
|
&writerfn_struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
// absl::SleepFor() can't be used here since AbslInternalSleepFor()
|
||||||
|
// may be overridden to do something that isn't async-signal-safe on
|
||||||
|
// some platforms.
|
||||||
|
static void PortableSleepForSeconds(int seconds) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
Sleep(seconds * 1000);
|
||||||
|
#else
|
||||||
|
struct timespec sleep_time;
|
||||||
|
sleep_time.tv_sec = seconds;
|
||||||
|
sleep_time.tv_nsec = 0;
|
||||||
|
while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_ALARM
|
||||||
|
// FailureSignalHandler() installs this as a signal handler for
|
||||||
|
// SIGALRM, then sets an alarm to be delivered to the program after a
|
||||||
|
// set amount of time. If FailureSignalHandler() hangs for more than
|
||||||
|
// the alarm timeout, ImmediateAbortSignalHandler() will abort the
|
||||||
|
// program.
|
||||||
|
static void ImmediateAbortSignalHandler(int) {
|
||||||
|
RaiseToDefaultHandler(SIGABRT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// absl::base_internal::GetTID() returns pid_t on most platforms, but
|
||||||
|
// returns absl::base_internal::pid_t on Windows.
|
||||||
|
using GetTidType = decltype(absl::base_internal::GetTID());
|
||||||
|
ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0);
|
||||||
|
|
||||||
|
#ifndef ABSL_HAVE_SIGACTION
|
||||||
|
static void FailureSignalHandler(int signo) {
|
||||||
|
void* ucontext = nullptr;
|
||||||
|
#else
|
||||||
|
static void FailureSignalHandler(int signo, siginfo_t*,
|
||||||
|
void* ucontext) {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const GetTidType this_tid = absl::base_internal::GetTID();
|
||||||
|
GetTidType previous_failed_tid = 0;
|
||||||
|
if (!failed_tid.compare_exchange_strong(
|
||||||
|
previous_failed_tid, static_cast<intptr_t>(this_tid),
|
||||||
|
std::memory_order_acq_rel, std::memory_order_relaxed)) {
|
||||||
|
ABSL_RAW_LOG(
|
||||||
|
ERROR,
|
||||||
|
"Signal %d raised at PC=%p while already in FailureSignalHandler()",
|
||||||
|
signo, absl::debugging_internal::GetProgramCounter(ucontext));
|
||||||
|
if (this_tid != previous_failed_tid) {
|
||||||
|
// Another thread is already in FailureSignalHandler(), so wait
|
||||||
|
// a bit for it to finish. If the other thread doesn't kill us,
|
||||||
|
// we do so after sleeping.
|
||||||
|
PortableSleepForSeconds(3);
|
||||||
|
RaiseToDefaultHandler(signo);
|
||||||
|
// The recursively raised signal may be blocked until we return.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ABSL_HAVE_ALARM
|
||||||
|
// Set an alarm to abort the program in case this code hangs or deadlocks.
|
||||||
|
if (fsh_options.alarm_on_failure_secs > 0) {
|
||||||
|
alarm(0); // Cancel any existing alarms.
|
||||||
|
signal(SIGALRM, ImmediateAbortSignalHandler);
|
||||||
|
alarm(fsh_options.alarm_on_failure_secs);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// First write to stderr.
|
||||||
|
WriteFailureInfo(signo, ucontext, WriteToStderr);
|
||||||
|
|
||||||
|
// Riskier code (because it is less likely to be async-signal-safe)
|
||||||
|
// goes after this point.
|
||||||
|
if (fsh_options.writerfn != nullptr) {
|
||||||
|
WriteFailureInfo(signo, ucontext, fsh_options.writerfn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsh_options.call_previous_handler) {
|
||||||
|
RaiseToPreviousHandler(signo);
|
||||||
|
} else {
|
||||||
|
RaiseToDefaultHandler(signo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) {
|
||||||
|
fsh_options = options;
|
||||||
|
for (auto& it : failure_signal_data) {
|
||||||
|
InstallOneFailureHandler(&it, FailureSignalHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace absl
|
||||||
117
third_party/abseil-cpp/absl/debugging/failure_signal_handler.h
vendored
Normal file
117
third_party/abseil-cpp/absl/debugging/failure_signal_handler.h
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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: failure_signal_handler.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This file configures the Abseil *failure signal handler* to capture and dump
|
||||||
|
// useful debugging information (such as a stacktrace) upon program failure.
|
||||||
|
//
|
||||||
|
// To use the failure signal handler, call `absl::InstallFailureSignalHandler()`
|
||||||
|
// very early in your program, usually in the first few lines of main():
|
||||||
|
//
|
||||||
|
// int main(int argc, char** argv) {
|
||||||
|
// // Initialize the symbolizer to get a human-readable stack trace
|
||||||
|
// absl::InitializeSymbolizer(argv[0]);
|
||||||
|
//
|
||||||
|
// absl::FailureSignalHandlerOptions options;
|
||||||
|
// absl::InstallFailureSignalHandler(options);
|
||||||
|
// DoSomethingInteresting();
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`,
|
||||||
|
// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the
|
||||||
|
// installed failure signal handler and provide debugging information to stderr.
|
||||||
|
//
|
||||||
|
// Note that you should *not* install the Abseil failure signal handler more
|
||||||
|
// than once. You may, of course, have another (non-Abseil) failure signal
|
||||||
|
// handler installed (which would be triggered if Abseil's failure signal
|
||||||
|
// handler sets `call_previous_handler` to `true`).
|
||||||
|
|
||||||
|
#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
|
||||||
|
#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
|
||||||
|
// FailureSignalHandlerOptions
|
||||||
|
//
|
||||||
|
// Struct for holding `absl::InstallFailureSignalHandler()` configuration
|
||||||
|
// options.
|
||||||
|
struct FailureSignalHandlerOptions {
|
||||||
|
// If true, try to symbolize the stacktrace emitted on failure, provided that
|
||||||
|
// you have initialized a symbolizer for that purpose. (See symbolize.h for
|
||||||
|
// more information.)
|
||||||
|
bool symbolize_stacktrace = true;
|
||||||
|
|
||||||
|
// If true, try to run signal handlers on an alternate stack (if supported on
|
||||||
|
// the given platform). An alternate stack is useful for program crashes due
|
||||||
|
// to a stack overflow; by running on a alternate stack, the signal handler
|
||||||
|
// may run even when normal stack space has been exausted. The downside of
|
||||||
|
// using an alternate stack is that extra memory for the alternate stack needs
|
||||||
|
// to be pre-allocated.
|
||||||
|
bool use_alternate_stack = true;
|
||||||
|
|
||||||
|
// If positive, indicates the number of seconds after which the failure signal
|
||||||
|
// handler is invoked to abort the program. Setting such an alarm is useful in
|
||||||
|
// cases where the failure signal handler itself may become hung or
|
||||||
|
// deadlocked.
|
||||||
|
int alarm_on_failure_secs = 3;
|
||||||
|
|
||||||
|
// If true, call the previously registered signal handler for the signal that
|
||||||
|
// was received (if one was registered) after the existing signal handler
|
||||||
|
// runs. This mechanism can be used to chain signal handlers together.
|
||||||
|
//
|
||||||
|
// If false, the signal is raised to the default handler for that signal
|
||||||
|
// (which normally terminates the program).
|
||||||
|
//
|
||||||
|
// IMPORTANT: If true, the chained fatal signal handlers must not try to
|
||||||
|
// recover from the fatal signal. Instead, they should terminate the program
|
||||||
|
// via some mechanism, like raising the default handler for the signal, or by
|
||||||
|
// calling `_exit()`. Note that the failure signal handler may put parts of
|
||||||
|
// the Abseil library into a state from which they cannot recover.
|
||||||
|
bool call_previous_handler = false;
|
||||||
|
|
||||||
|
// If non-null, indicates a pointer to a callback function that will be called
|
||||||
|
// upon failure, with a std::string argument containing failure data. This function
|
||||||
|
// may be used as a hook to write failure data to a secondary location, such
|
||||||
|
// as a log file. This function may also be called with null data, as a hint
|
||||||
|
// to flush any buffered data before the program may be terminated. Consider
|
||||||
|
// flushing any buffered data in all calls to this function.
|
||||||
|
//
|
||||||
|
// Since this function runs within a signal handler, it should be
|
||||||
|
// async-signal-safe if possible.
|
||||||
|
// See http://man7.org/linux/man-pages/man7/signal-safety.7.html
|
||||||
|
void (*writerfn)(const char*) = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// InstallFailureSignalHandler()
|
||||||
|
//
|
||||||
|
// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`,
|
||||||
|
// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist
|
||||||
|
// on the given platform). The failure signal handler dumps program failure data
|
||||||
|
// useful for debugging in an unspecified format to stderr. This data may
|
||||||
|
// include the program counter, a stacktrace, and register information on some
|
||||||
|
// systems; do not rely on an exact format for the output, as it is subject to
|
||||||
|
// change.
|
||||||
|
void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options);
|
||||||
|
|
||||||
|
namespace debugging_internal {
|
||||||
|
const char* FailureSignalToString(int signo);
|
||||||
|
} // namespace debugging_internal
|
||||||
|
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_
|
||||||
155
third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
vendored
Normal file
155
third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2018 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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/debugging/failure_signal_handler.h"
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
#include "absl/debugging/stacktrace.h"
|
||||||
|
#include "absl/debugging/symbolize.h"
|
||||||
|
#include "absl/strings/match.h"
|
||||||
|
#include "absl/strings/str_cat.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#if GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
|
// For the parameterized death tests. GetParam() returns the signal number.
|
||||||
|
using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>;
|
||||||
|
|
||||||
|
// This function runs in a fork()ed process on most systems.
|
||||||
|
void InstallHandlerAndRaise(int signo) {
|
||||||
|
absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions());
|
||||||
|
raise(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) {
|
||||||
|
const int signo = GetParam();
|
||||||
|
std::string exit_regex = absl::StrCat(
|
||||||
|
"\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
|
||||||
|
" received at time=");
|
||||||
|
#ifndef _WIN32
|
||||||
|
EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo),
|
||||||
|
exit_regex);
|
||||||
|
#else
|
||||||
|
// Windows doesn't have testing::KilledBySignal().
|
||||||
|
EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ABSL_CONST_INIT FILE* error_file = nullptr;
|
||||||
|
|
||||||
|
void WriteToErrorFile(const char* msg) {
|
||||||
|
if (msg != nullptr) {
|
||||||
|
ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1,
|
||||||
|
"fwrite() failed");
|
||||||
|
}
|
||||||
|
ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetTmpDir() {
|
||||||
|
// TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel.
|
||||||
|
static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP",
|
||||||
|
"TEMPDIR", "TMP"};
|
||||||
|
for (const char* const var : kTmpEnvVars) {
|
||||||
|
const char* tmp_dir = std::getenv(var);
|
||||||
|
if (tmp_dir != nullptr) {
|
||||||
|
return tmp_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try something reasonable.
|
||||||
|
return "/tmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function runs in a fork()ed process on most systems.
|
||||||
|
void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) {
|
||||||
|
error_file = fopen(file, "w");
|
||||||
|
ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file");
|
||||||
|
absl::FailureSignalHandlerOptions options;
|
||||||
|
options.writerfn = WriteToErrorFile;
|
||||||
|
absl::InstallFailureSignalHandler(options);
|
||||||
|
raise(signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) {
|
||||||
|
const int signo = GetParam();
|
||||||
|
std::string tmp_dir = GetTmpDir();
|
||||||
|
std::string file = absl::StrCat(tmp_dir, "/signo_", signo);
|
||||||
|
|
||||||
|
std::string exit_regex = absl::StrCat(
|
||||||
|
"\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo),
|
||||||
|
" received at time=");
|
||||||
|
#ifndef _WIN32
|
||||||
|
EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
|
||||||
|
testing::KilledBySignal(signo), exit_regex);
|
||||||
|
#else
|
||||||
|
// Windows doesn't have testing::KilledBySignal().
|
||||||
|
EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo),
|
||||||
|
exit_regex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Open the file in this process and check its contents.
|
||||||
|
std::fstream error_output(file);
|
||||||
|
ASSERT_TRUE(error_output.is_open()) << file;
|
||||||
|
std::string error_line;
|
||||||
|
std::getline(error_output, error_line);
|
||||||
|
EXPECT_TRUE(absl::StartsWith(
|
||||||
|
error_line,
|
||||||
|
absl::StrCat("*** ",
|
||||||
|
absl::debugging_internal::FailureSignalToString(signo),
|
||||||
|
" received at ")));
|
||||||
|
|
||||||
|
if (absl::debugging_internal::StackTraceWorksForTest()) {
|
||||||
|
std::getline(error_output, error_line);
|
||||||
|
EXPECT_TRUE(absl::StartsWith(error_line, "PC: "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int kFailureSignals[] = {
|
||||||
|
SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM,
|
||||||
|
#ifndef _WIN32
|
||||||
|
SIGBUS, SIGTRAP,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) {
|
||||||
|
std::string result = absl::debugging_internal::FailureSignalToString(info.param);
|
||||||
|
if (result.empty()) {
|
||||||
|
result = absl::StrCat(info.param);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest,
|
||||||
|
::testing::ValuesIn(kFailureSignals),
|
||||||
|
SignalParamToString);
|
||||||
|
|
||||||
|
#endif // GTEST_HAS_DEATH_TEST
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
absl::InitializeSymbolizer(argv[0]);
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
@ -121,7 +121,7 @@ const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const {
|
|||||||
return reinterpret_cast<const void *>(sym->st_value);
|
return reinterpret_cast<const void *>(sym->st_value);
|
||||||
}
|
}
|
||||||
ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
|
ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range");
|
||||||
return GetTableElement<char>(ehdr_, 0, 1, sym->st_value) - link_base_;
|
return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
|
const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const {
|
||||||
@ -161,10 +161,6 @@ void ElfMemImage::Init(const void *base) {
|
|||||||
if (!base) {
|
if (!base) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const intptr_t base_as_uintptr_t = reinterpret_cast<uintptr_t>(base);
|
|
||||||
// Fake VDSO has low bit set.
|
|
||||||
const bool fake_vdso = ((base_as_uintptr_t & 1) != 0);
|
|
||||||
base = reinterpret_cast<const void *>(base_as_uintptr_t & ~1);
|
|
||||||
const char *const base_as_char = reinterpret_cast<const char *>(base);
|
const char *const base_as_char = reinterpret_cast<const char *>(base);
|
||||||
if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
|
if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 ||
|
||||||
base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
|
base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) {
|
||||||
@ -224,21 +220,7 @@ void ElfMemImage::Init(const void *base) {
|
|||||||
reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
|
reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr +
|
||||||
relocation);
|
relocation);
|
||||||
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
|
for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) {
|
||||||
ElfW(Xword) value = dynamic_entry->d_un.d_val;
|
const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation;
|
||||||
if (fake_vdso) {
|
|
||||||
// A complication: in the real VDSO, dynamic entries are not relocated
|
|
||||||
// (it wasn't loaded by a dynamic loader). But when testing with a
|
|
||||||
// "fake" dlopen()ed vdso library, the loader relocates some (but
|
|
||||||
// not all!) of them before we get here.
|
|
||||||
if (dynamic_entry->d_tag == DT_VERDEF) {
|
|
||||||
// The only dynamic entry (of the ones we care about) libc-2.3.6
|
|
||||||
// loader doesn't relocate.
|
|
||||||
value += relocation;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Real VDSO. Everything needs to be relocated.
|
|
||||||
value += relocation;
|
|
||||||
}
|
|
||||||
switch (dynamic_entry->d_tag) {
|
switch (dynamic_entry->d_tag) {
|
||||||
case DT_HASH:
|
case DT_HASH:
|
||||||
hash_ = reinterpret_cast<ElfW(Word) *>(value);
|
hash_ = reinterpret_cast<ElfW(Word) *>(value);
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
#include "absl/debugging/internal/address_is_readable.h"
|
#include "absl/debugging/internal/address_is_readable.h"
|
||||||
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
|
#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems
|
||||||
#include "absl/debugging/stacktrace.h"
|
#include "absl/debugging/stacktrace.h"
|
||||||
@ -24,7 +25,7 @@ static const uintptr_t kUnknownFrameSize = 0;
|
|||||||
// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
|
// Returns the address of the VDSO __kernel_rt_sigreturn function, if present.
|
||||||
static const unsigned char* GetKernelRtSigreturnAddress() {
|
static const unsigned char* GetKernelRtSigreturnAddress() {
|
||||||
constexpr uintptr_t kImpossibleAddress = 1;
|
constexpr uintptr_t kImpossibleAddress = 1;
|
||||||
static std::atomic<uintptr_t> memoized{kImpossibleAddress};
|
ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress};
|
||||||
uintptr_t address = memoized.load(std::memory_order_relaxed);
|
uintptr_t address = memoized.load(std::memory_order_relaxed);
|
||||||
if (address != kImpossibleAddress) {
|
if (address != kImpossibleAddress) {
|
||||||
return reinterpret_cast<const unsigned char*>(address);
|
return reinterpret_cast<const unsigned char*>(address);
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "absl/base/port.h" // Needed for string vs std::string
|
||||||
|
|
||||||
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
|
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
|
||||||
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
|
#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set
|
||||||
|
|||||||
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "absl/base/attributes.h"
|
||||||
#include "absl/debugging/internal/elf_mem_image.h"
|
#include "absl/debugging/internal/elf_mem_image.h"
|
||||||
|
|
||||||
#ifdef ABSL_HAVE_ELF_MEM_IMAGE
|
#ifdef ABSL_HAVE_ELF_MEM_IMAGE
|
||||||
@ -132,7 +133,7 @@ class VDSOSupport {
|
|||||||
|
|
||||||
// This function pointer may point to InitAndGetCPU,
|
// This function pointer may point to InitAndGetCPU,
|
||||||
// GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
|
// GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization.
|
||||||
static std::atomic<GetCpuFn> getcpu_fn_;
|
ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_;
|
||||||
|
|
||||||
friend int GetCPU(void); // Needs access to getcpu_fn_.
|
friend int GetCPU(void); // Needs access to getcpu_fn_.
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
//
|
// Copyright 2018 The Abseil Authors.
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,15 +12,14 @@
|
|||||||
// 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.
|
||||||
//
|
//
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// File: leak_check.h
|
// File: leak_check.h
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// This package contains functions that affect leak checking behavior within
|
// This file contains functions that affect leak checking behavior within
|
||||||
// targets built with the LeakSanitizer (LSan), a memory leak detector that is
|
// targets built with the LeakSanitizer (LSan), a memory leak detector that is
|
||||||
// integrated within the AddressSanitizer (ASan) as an additional component, or
|
// integrated within the AddressSanitizer (ASan) as an additional component, or
|
||||||
// which can be used standalone. LSan and ASan are included or can be provided
|
// which can be used standalone. LSan and ASan are included (or can be provided)
|
||||||
// as additional components for most compilers such as Clang, gcc and MSVC.
|
// as additional components for most compilers such as Clang, gcc and MSVC.
|
||||||
// Note: this leak checking API is not yet supported in MSVC.
|
// Note: this leak checking API is not yet supported in MSVC.
|
||||||
// Leak checking is enabled by default in all ASan builds.
|
// Leak checking is enabled by default in all ASan builds.
|
||||||
|
|||||||
174
third_party/abseil-cpp/absl/debugging/stacktrace.h
vendored
174
third_party/abseil-cpp/absl/debugging/stacktrace.h
vendored
@ -1,5 +1,4 @@
|
|||||||
//
|
// Copyright 2018 The Abseil Authors.
|
||||||
// Copyright 2017 The Abseil Authors.
|
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -13,26 +12,37 @@
|
|||||||
// 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.
|
||||||
//
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
// Routines to extract the current stack trace. These functions are
|
// File: stacktrace.h
|
||||||
// thread-safe and async-signal-safe.
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This file contains routines to extract the current stack trace and associated
|
||||||
|
// stack frames. These functions are thread-safe and async-signal-safe.
|
||||||
|
//
|
||||||
// Note that stack trace functionality is platform dependent and requires
|
// Note that stack trace functionality is platform dependent and requires
|
||||||
// additional support from the compiler/build system in many cases. (That is,
|
// additional support from the compiler/build system in most cases. (That is,
|
||||||
// this generally only works on platforms/builds that have been specifically
|
// this functionality generally only works on platforms/builds that have been
|
||||||
// configured to support it.)
|
// specifically configured to support it.)
|
||||||
|
//
|
||||||
|
// Note: stack traces in Abseil that do not utilize a symbolizer will result in
|
||||||
|
// frames consisting of function addresses rather than human-readable function
|
||||||
|
// names. (See symbolize.h for information on symbolizing these values.)
|
||||||
|
|
||||||
#ifndef ABSL_DEBUGGING_STACKTRACE_H_
|
#ifndef ABSL_DEBUGGING_STACKTRACE_H_
|
||||||
#define ABSL_DEBUGGING_STACKTRACE_H_
|
#define ABSL_DEBUGGING_STACKTRACE_H_
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
|
||||||
// Skips the most recent "skip_count" stack frames (also skips the
|
// GetStackFrames()
|
||||||
// frame generated for the "absl::GetStackFrames" routine itself), and then
|
//
|
||||||
// records the pc values for up to the next "max_depth" frames in
|
// Records program counter values for up to `max_depth` frames, skipping the
|
||||||
// "result", and the corresponding stack frame sizes in "sizes".
|
// most recent `skip_count` stack frames, and stores their corresponding values
|
||||||
// Returns the number of values recorded in "result"/"sizes".
|
// and sizes in `results` and `sizes` buffers. (Note that the frame generated
|
||||||
|
// for the `absl::GetStackFrames()` routine itself is also skipped.)
|
||||||
|
// routine itself.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// main() { foo(); }
|
// main() { foo(); }
|
||||||
// foo() { bar(); }
|
// foo() { bar(); }
|
||||||
// bar() {
|
// bar() {
|
||||||
@ -41,41 +51,66 @@ namespace absl {
|
|||||||
// int depth = absl::GetStackFrames(result, sizes, 10, 1);
|
// int depth = absl::GetStackFrames(result, sizes, 10, 1);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The absl::GetStackFrames call will skip the frame for "bar". It will
|
// The current stack frame would consist of three function calls: `bar()`,
|
||||||
// return 2 and will produce pc values that map to the following
|
// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets
|
||||||
// procedures:
|
// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently
|
||||||
// result[0] foo
|
// invoked function call. It will therefore return two program counters and will
|
||||||
// result[1] main
|
// produce values that map to the following function calls:
|
||||||
// (Actually, there may be a few more entries after "main" to account for
|
//
|
||||||
// startup procedures.)
|
// result[0] foo()
|
||||||
// And corresponding stack frame sizes will also be recorded:
|
// result[1] main()
|
||||||
|
//
|
||||||
|
// (Note: in practice, a few more entries after `main()` may be added to account
|
||||||
|
// for startup processes.)
|
||||||
|
//
|
||||||
|
// Corresponding stack frame sizes will also be recorded:
|
||||||
|
//
|
||||||
// sizes[0] 16
|
// sizes[0] 16
|
||||||
// sizes[1] 16
|
// sizes[1] 16
|
||||||
// (Stack frame sizes of 16 above are just for illustration purposes.)
|
//
|
||||||
|
// (Stack frame sizes of `16` above are just for illustration purposes.)
|
||||||
|
//
|
||||||
// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
|
// Stack frame sizes of 0 or less indicate that those frame sizes couldn't
|
||||||
// be identified.
|
// be identified.
|
||||||
//
|
//
|
||||||
// This routine may return fewer stack frame entries than are
|
// This routine may return fewer stack frame entries than are
|
||||||
// available. Also note that "result" and "sizes" must both be non-null.
|
// available. Also note that `result` and `sizes` must both be non-null.
|
||||||
extern int GetStackFrames(void** result, int* sizes, int max_depth,
|
extern int GetStackFrames(void** result, int* sizes, int max_depth,
|
||||||
int skip_count);
|
int skip_count);
|
||||||
|
|
||||||
// Same as above, but to be used from a signal handler. The "uc" parameter
|
// GetStackFramesWithContext()
|
||||||
// should be the pointer to ucontext_t which was passed as the 3rd parameter
|
|
||||||
// to sa_sigaction signal handler. It may help the unwinder to get a
|
|
||||||
// better stack trace under certain conditions. The "uc" may safely be null.
|
|
||||||
//
|
//
|
||||||
// If min_dropped_frames is not null, stores in *min_dropped_frames a
|
// Records program counter values obtained from a signal handler. Records
|
||||||
// lower bound on the number of dropped stack frames. The stored value is
|
// program counter values for up to `max_depth` frames, skipping the most recent
|
||||||
// guaranteed to be >= 0. The number of real stack frames is guaranteed to
|
// `skip_count` stack frames, and stores their corresponding values and sizes in
|
||||||
// be >= skip_count + max_depth + *min_dropped_frames.
|
// `results` and `sizes` buffers. (Note that the frame generated for the
|
||||||
|
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||||
|
//
|
||||||
|
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
|
||||||
|
// passed to a signal handler registered via the `sa_sigaction` field of a
|
||||||
|
// `sigaction` struct. (See
|
||||||
|
// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
|
||||||
|
// help a stack unwinder to provide a better stack trace under certain
|
||||||
|
// conditions. `uc` may safely be null.
|
||||||
|
//
|
||||||
|
// The `min_dropped_frames` output parameter, if non-null, points to the
|
||||||
|
// location to note any dropped stack frames, if any, due to buffer limitations
|
||||||
|
// or other reasons. (This value will be set to `0` if no frames were dropped.)
|
||||||
|
// The number of total stack frames is guaranteed to be >= skip_count +
|
||||||
|
// max_depth + *min_dropped_frames.
|
||||||
extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
|
extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
|
||||||
int skip_count, const void* uc,
|
int skip_count, const void* uc,
|
||||||
int* min_dropped_frames);
|
int* min_dropped_frames);
|
||||||
|
|
||||||
// This is similar to the absl::GetStackFrames routine, except that it returns
|
// GetStackTrace()
|
||||||
// the stack trace only, and not the stack frame sizes as well.
|
//
|
||||||
|
// Records program counter values for up to `max_depth` frames, skipping the
|
||||||
|
// most recent `skip_count` stack frames, and stores their corresponding values
|
||||||
|
// in `results`. Note that this function is similar to `absl::GetStackFrames()`
|
||||||
|
// except that it returns the stack trace only, and not stack frame sizes.
|
||||||
|
//
|
||||||
// Example:
|
// Example:
|
||||||
|
//
|
||||||
// main() { foo(); }
|
// main() { foo(); }
|
||||||
// foo() { bar(); }
|
// foo() { bar(); }
|
||||||
// bar() {
|
// bar() {
|
||||||
@ -84,42 +119,57 @@ extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth,
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// This produces:
|
// This produces:
|
||||||
|
//
|
||||||
// result[0] foo
|
// result[0] foo
|
||||||
// result[1] main
|
// result[1] main
|
||||||
// .... ...
|
// .... ...
|
||||||
//
|
//
|
||||||
// "result" must not be null.
|
// `result` must not be null.
|
||||||
extern int GetStackTrace(void** result, int max_depth, int skip_count);
|
extern int GetStackTrace(void** result, int max_depth, int skip_count);
|
||||||
|
|
||||||
// Same as above, but to be used from a signal handler. The "uc" parameter
|
// GetStackTraceWithContext()
|
||||||
// should be the pointer to ucontext_t which was passed as the 3rd parameter
|
|
||||||
// to sa_sigaction signal handler. It may help the unwinder to get a
|
|
||||||
// better stack trace under certain conditions. The "uc" may safely be null.
|
|
||||||
//
|
//
|
||||||
// If min_dropped_frames is not null, stores in *min_dropped_frames a
|
// Records program counter values obtained from a signal handler. Records
|
||||||
// lower bound on the number of dropped stack frames. The stored value is
|
// program counter values for up to `max_depth` frames, skipping the most recent
|
||||||
// guaranteed to be >= 0. The number of real stack frames is guaranteed to
|
// `skip_count` stack frames, and stores their corresponding values in
|
||||||
// be >= skip_count + max_depth + *min_dropped_frames.
|
// `results`. (Note that the frame generated for the
|
||||||
|
// `absl::GetStackFramesWithContext()` routine itself is also skipped.)
|
||||||
|
//
|
||||||
|
// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value
|
||||||
|
// passed to a signal handler registered via the `sa_sigaction` field of a
|
||||||
|
// `sigaction` struct. (See
|
||||||
|
// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may
|
||||||
|
// help a stack unwinder to provide a better stack trace under certain
|
||||||
|
// conditions. `uc` may safely be null.
|
||||||
|
//
|
||||||
|
// The `min_dropped_frames` output parameter, if non-null, points to the
|
||||||
|
// location to note any dropped stack frames, if any, due to buffer limitations
|
||||||
|
// or other reasons. (This value will be set to `0` if no frames were dropped.)
|
||||||
|
// The number of total stack frames is guaranteed to be >= skip_count +
|
||||||
|
// max_depth + *min_dropped_frames.
|
||||||
extern int GetStackTraceWithContext(void** result, int max_depth,
|
extern int GetStackTraceWithContext(void** result, int max_depth,
|
||||||
int skip_count, const void* uc,
|
int skip_count, const void* uc,
|
||||||
int* min_dropped_frames);
|
int* min_dropped_frames);
|
||||||
|
|
||||||
// Call this to provide a custom function for unwinding stack frames
|
// SetStackUnwinder()
|
||||||
// that will be used every time someone invokes one of the static
|
//
|
||||||
|
// Provides a custom function for unwinding stack frames that will be used in
|
||||||
|
// place of the default stack unwinder when invoking the static
|
||||||
// GetStack{Frames,Trace}{,WithContext}() functions above.
|
// GetStack{Frames,Trace}{,WithContext}() functions above.
|
||||||
//
|
//
|
||||||
// The arguments passed to the unwinder function will match the
|
// The arguments passed to the unwinder function will match the
|
||||||
// arguments passed to absl::GetStackFramesWithContext() except that sizes
|
// arguments passed to `absl::GetStackFramesWithContext()` except that sizes
|
||||||
// will be non-null iff the caller is interested in frame sizes.
|
// will be non-null iff the caller is interested in frame sizes.
|
||||||
//
|
//
|
||||||
// If unwinder is null, we revert to the default stack-tracing behavior.
|
// If unwinder is set to null, we revert to the default stack-tracing behavior.
|
||||||
//
|
//
|
||||||
// ****************************************************************
|
// *****************************************************************************
|
||||||
// WARNINGS
|
// WARNING
|
||||||
|
// *****************************************************************************
|
||||||
//
|
//
|
||||||
// absl::SetStackUnwinder is not suitable for general purpose use. It is
|
// absl::SetStackUnwinder is not suitable for general purpose use. It is
|
||||||
// provided for custom runtimes.
|
// provided for custom runtimes.
|
||||||
// Some things to watch out for when calling absl::SetStackUnwinder:
|
// Some things to watch out for when calling `absl::SetStackUnwinder()`:
|
||||||
//
|
//
|
||||||
// (a) The unwinder may be called from within signal handlers and
|
// (a) The unwinder may be called from within signal handlers and
|
||||||
// therefore must be async-signal-safe.
|
// therefore must be async-signal-safe.
|
||||||
@ -128,23 +178,31 @@ extern int GetStackTraceWithContext(void** result, int max_depth,
|
|||||||
// threads may still be in the process of using that unwinder.
|
// threads may still be in the process of using that unwinder.
|
||||||
// Therefore do not clean up any state that may be needed by an old
|
// Therefore do not clean up any state that may be needed by an old
|
||||||
// unwinder.
|
// unwinder.
|
||||||
// ****************************************************************
|
// *****************************************************************************
|
||||||
extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
|
extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes,
|
||||||
int max_depth, int skip_count,
|
int max_depth, int skip_count,
|
||||||
const void* uc,
|
const void* uc,
|
||||||
int* min_dropped_frames));
|
int* min_dropped_frames));
|
||||||
|
|
||||||
// Function that exposes built-in stack-unwinding behavior, ignoring
|
// DefaultStackUnwinder()
|
||||||
// any calls to absl::SetStackUnwinder().
|
|
||||||
//
|
//
|
||||||
// pcs must NOT be null.
|
// Records program counter values of up to `max_depth` frames, skipping the most
|
||||||
|
// recent `skip_count` stack frames, and stores their corresponding values in
|
||||||
|
// `pcs`. (Note that the frame generated for this call itself is also skipped.)
|
||||||
|
// This function acts as a generic stack-unwinder; prefer usage of the more
|
||||||
|
// specific `GetStack{Trace,Frames}{,WithContext}()` functions above.
|
||||||
//
|
//
|
||||||
// sizes may be null.
|
// If you have set your own stack unwinder (with the `SetStackUnwinder()`
|
||||||
// uc may be null.
|
// function above, you can still get the default stack unwinder by calling
|
||||||
// min_dropped_frames may be null.
|
// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder
|
||||||
|
// and use the default one instead.
|
||||||
//
|
//
|
||||||
// The semantics are the same as the corresponding GetStack*() function in the
|
// Because this function is generic, only `pcs` is guaranteed to be non-null
|
||||||
// case where absl::SetStackUnwinder() was never called. Equivalents are:
|
// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all
|
||||||
|
// be null when called.
|
||||||
|
//
|
||||||
|
// The semantics are the same as the corresponding `GetStack*()` function in the
|
||||||
|
// case where `absl::SetStackUnwinder()` was never called. Equivalents are:
|
||||||
//
|
//
|
||||||
// null sizes | non-nullptr sizes
|
// null sizes | non-nullptr sizes
|
||||||
// |==========================================================|
|
// |==========================================================|
|
||||||
|
|||||||
@ -14,8 +14,15 @@
|
|||||||
|
|
||||||
#include "absl/debugging/symbolize.h"
|
#include "absl/debugging/symbolize.h"
|
||||||
|
|
||||||
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
|
#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE)
|
||||||
#include "absl/debugging/symbolize_elf.inc"
|
#include "absl/debugging/symbolize_elf.inc"
|
||||||
|
#elif defined(_WIN32) && defined(_DEBUG)
|
||||||
|
// The Windows Symbolizer only works in debug mode. Note that _DEBUG
|
||||||
|
// is the macro that defines whether or not MS C-Runtime debug info is
|
||||||
|
// available. Note that the PDB files containing the debug info must
|
||||||
|
// also be available to the program at runtime for the symbolizer to
|
||||||
|
// work.
|
||||||
|
#include "absl/debugging/symbolize_win32.inc"
|
||||||
#else
|
#else
|
||||||
#include "absl/debugging/symbolize_unimplemented.inc"
|
#include "absl/debugging/symbolize_unimplemented.inc"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -11,7 +11,44 @@
|
|||||||
// 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.
|
||||||
|
//
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// File: symbolize.h
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// This file configures the Abseil symbolizer for use in converting instruction
|
||||||
|
// pointer addresses (program counters) into human-readable names (function
|
||||||
|
// calls, etc.) within Abseil code.
|
||||||
|
//
|
||||||
|
// The symbolizer may be invoked from several sources:
|
||||||
|
//
|
||||||
|
// * Implicitly, through the installation of an Abseil failure signal handler.
|
||||||
|
// (See failure_signal_handler.h for more information.)
|
||||||
|
// * By calling `Symbolize()` directly on a program counter you obtain through
|
||||||
|
// `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h
|
||||||
|
// for more information.
|
||||||
|
// * By calling `Symbolize()` directly on a program counter you obtain through
|
||||||
|
// other means (which would be platform-dependent).
|
||||||
|
//
|
||||||
|
// In all of the above cases, the symbolizer must first be initialized before
|
||||||
|
// any program counter values can be symbolized. If you are installing a failure
|
||||||
|
// signal handler, initialize the symbolizer before you do so.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int main(int argc, char** argv) {
|
||||||
|
// // Initialize the Symbolizer before installing the failure signal handler
|
||||||
|
// absl::InitializeSymbolizer(argv[0]);
|
||||||
|
//
|
||||||
|
// // Now you may install the failure signal handler
|
||||||
|
// absl::FailureSignalHandlerOptions options;
|
||||||
|
// absl::InstallFailureSignalHandler(options);
|
||||||
|
//
|
||||||
|
// // Start running your main program
|
||||||
|
// ...
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_
|
#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_
|
||||||
#define ABSL_DEBUGGING_SYMBOLIZE_H_
|
#define ABSL_DEBUGGING_SYMBOLIZE_H_
|
||||||
|
|
||||||
@ -19,15 +56,40 @@
|
|||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
|
||||||
// Initializes this module. Symbolize() may fail prior calling this function.
|
// InitializeSymbolizer()
|
||||||
// `argv0` is the path to this program, which is usually obtained in main()
|
//
|
||||||
// though argv[0].
|
// Initializes the program counter symbolizer, given the path of the program
|
||||||
|
// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer
|
||||||
|
// allows you to read program counters (instruction pointer values) using their
|
||||||
|
// human-readable names within output such as stack traces.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// int main(int argc, char *argv[]) {
|
||||||
|
// absl::InitializeSymbolizer(argv[0]);
|
||||||
|
// // Now you can use the symbolizer
|
||||||
|
// }
|
||||||
void InitializeSymbolizer(const char* argv0);
|
void InitializeSymbolizer(const char* argv0);
|
||||||
|
|
||||||
// Symbolizes a program counter. On success, returns true and write the
|
// Symbolize()
|
||||||
// symbol name to "out". The symbol name is demangled if possible
|
//
|
||||||
// (supports symbols generated by GCC 3.x or newer), may be truncated, and
|
// Symbolizes a program counter (instruction pointer value) `pc` and, on
|
||||||
// will be '\0' terminated. Otherwise, returns false.
|
// success, writes the name to `out`. The symbol name is demangled, if possible.
|
||||||
|
// Note that the symbolized name may be truncated and will be NUL-terminated.
|
||||||
|
// Demangling is supported for symbols generated by GCC 3.x or newer). Returns
|
||||||
|
// `false` on failure.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// // Print a program counter and its symbol name.
|
||||||
|
// static void DumpPCAndSymbol(void *pc) {
|
||||||
|
// char tmp[1024];
|
||||||
|
// const char *symbol = "(unknown)";
|
||||||
|
// if (absl::Symbolize(pc, tmp, sizeof(tmp))) {
|
||||||
|
// symbol = tmp;
|
||||||
|
// }
|
||||||
|
// absl::PrintF("%*p %s\n", pc, symbol);
|
||||||
|
// }
|
||||||
bool Symbolize(const void *pc, char *out, int out_size);
|
bool Symbolize(const void *pc, char *out, int out_size);
|
||||||
|
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|||||||
@ -68,7 +68,7 @@ int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) regular_func() {
|
int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,9 +88,7 @@ static volatile bool volatile_bool = false;
|
|||||||
// Force the binary to be large enough that a THP .text remap will succeed.
|
// Force the binary to be large enough that a THP .text remap will succeed.
|
||||||
static constexpr size_t kHpageSize = 1 << 21;
|
static constexpr size_t kHpageSize = 1 << 21;
|
||||||
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
|
const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(
|
||||||
".text") = "";
|
.text) = "";
|
||||||
|
|
||||||
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
|
|
||||||
|
|
||||||
static char try_symbolize_buffer[4096];
|
static char try_symbolize_buffer[4096];
|
||||||
|
|
||||||
@ -120,6 +118,8 @@ static const char *TrySymbolize(void *pc) {
|
|||||||
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
|
return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE
|
||||||
|
|
||||||
TEST(Symbolize, Cached) {
|
TEST(Symbolize, Cached) {
|
||||||
// Compilers should give us pointers to them.
|
// Compilers should give us pointers to them.
|
||||||
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
|
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
|
||||||
@ -236,9 +236,9 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
|
|||||||
const size_t kPageSize = 64 << 10;
|
const size_t kPageSize = 64 << 10;
|
||||||
// We place a read-only symbols into the .text section and verify that we can
|
// We place a read-only symbols into the .text section and verify that we can
|
||||||
// symbolize them and other symbols after remapping them.
|
// symbolize them and other symbols after remapping them.
|
||||||
const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") =
|
const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
|
||||||
"";
|
"";
|
||||||
const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(".text") =
|
const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) =
|
||||||
"";
|
"";
|
||||||
|
|
||||||
static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
|
static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) {
|
||||||
@ -442,6 +442,45 @@ void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(_WIN32) && defined(_DEBUG)
|
||||||
|
|
||||||
|
TEST(Symbolize, Basics) {
|
||||||
|
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
|
||||||
|
|
||||||
|
// The name of an internal linkage symbol is not specified; allow either a
|
||||||
|
// mangled or an unmangled name here.
|
||||||
|
const char* static_func_symbol = TrySymbolize((void *)(&static_func));
|
||||||
|
ASSERT_TRUE(static_func_symbol != nullptr);
|
||||||
|
EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Symbolize, Truncation) {
|
||||||
|
constexpr char kNonStaticFunc[] = "nonstatic_func";
|
||||||
|
EXPECT_STREQ("nonstatic_func",
|
||||||
|
TrySymbolizeWithLimit((void *)(&nonstatic_func),
|
||||||
|
strlen(kNonStaticFunc) + 1));
|
||||||
|
EXPECT_STREQ("nonstatic_...",
|
||||||
|
TrySymbolizeWithLimit((void *)(&nonstatic_func),
|
||||||
|
strlen(kNonStaticFunc) + 0));
|
||||||
|
EXPECT_STREQ("nonstatic...",
|
||||||
|
TrySymbolizeWithLimit((void *)(&nonstatic_func),
|
||||||
|
strlen(kNonStaticFunc) - 1));
|
||||||
|
EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5));
|
||||||
|
EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4));
|
||||||
|
EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3));
|
||||||
|
EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2));
|
||||||
|
EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1));
|
||||||
|
EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Symbolize, SymbolizeWithDemangling) {
|
||||||
|
const char* result = TrySymbolize((void *)(&Foo::func));
|
||||||
|
ASSERT_TRUE(result != nullptr);
|
||||||
|
EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result;
|
||||||
|
}
|
||||||
|
|
||||||
#else // Symbolizer unimplemented
|
#else // Symbolizer unimplemented
|
||||||
|
|
||||||
TEST(Symbolize, Unimplemented) {
|
TEST(Symbolize, Unimplemented) {
|
||||||
|
|||||||
74
third_party/abseil-cpp/absl/debugging/symbolize_win32.inc
vendored
Normal file
74
third_party/abseil-cpp/absl/debugging/symbolize_win32.inc
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// See "Retrieving Symbol Information by Address":
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <DbgHelp.h>
|
||||||
|
#pragma comment(lib, "DbgHelp")
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "absl/base/internal/raw_logging.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
|
||||||
|
static HANDLE process = NULL;
|
||||||
|
|
||||||
|
void InitializeSymbolizer(const char *argv0) {
|
||||||
|
if (process != nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process = GetCurrentProcess();
|
||||||
|
|
||||||
|
// Symbols are not loaded until a reference is made requiring the
|
||||||
|
// symbols be loaded. This is the fastest, most efficient way to use
|
||||||
|
// the symbol handler.
|
||||||
|
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
|
||||||
|
if (!SymInitialize(process, nullptr, true)) {
|
||||||
|
// GetLastError() returns a Win32 DWORD, but we assign to
|
||||||
|
// unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform
|
||||||
|
// initialization guarantees this is not a narrowing conversion.
|
||||||
|
const unsigned long long error{GetLastError()}; // NOLINT(runtime/int)
|
||||||
|
ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Symbolize(const void *pc, char *out, int out_size) {
|
||||||
|
if (out_size <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME,
|
||||||
|
alignof(SYMBOL_INFO)>::type buf;
|
||||||
|
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf);
|
||||||
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||||
|
if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strncpy(out, symbol->Name, out_size);
|
||||||
|
if (out[out_size - 1] != '\0') {
|
||||||
|
// strncpy() does not '\0' terminate when it truncates.
|
||||||
|
static constexpr char kEllipsis[] = "...";
|
||||||
|
int ellipsis_size =
|
||||||
|
std::min<int>(sizeof(kEllipsis) - 1, out_size - 1);
|
||||||
|
memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size);
|
||||||
|
out[out_size - 1] = '\0';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace absl
|
||||||
@ -32,6 +32,8 @@ list(APPEND TYPE_TRAITS_TEST_SRC
|
|||||||
absl_header_library(
|
absl_header_library(
|
||||||
TARGET
|
TARGET
|
||||||
absl_meta
|
absl_meta
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl::base
|
||||||
EXPORT_NAME
|
EXPORT_NAME
|
||||||
meta
|
meta
|
||||||
)
|
)
|
||||||
@ -42,7 +44,8 @@ absl_test(
|
|||||||
SOURCES
|
SOURCES
|
||||||
${TYPE_TRAITS_TEST_SRC}
|
${TYPE_TRAITS_TEST_SRC}
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
${TYPE_TRAITS_TEST_PUBLIC_LIBRARIES} absl::meta
|
absl::base
|
||||||
|
absl::meta
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -84,6 +84,7 @@ cc_library(
|
|||||||
"internal/utf8.cc",
|
"internal/utf8.cc",
|
||||||
],
|
],
|
||||||
hdrs = [
|
hdrs = [
|
||||||
|
"internal/bits.h",
|
||||||
"internal/char_map.h",
|
"internal/char_map.h",
|
||||||
"internal/ostringstream.h",
|
"internal/ostringstream.h",
|
||||||
"internal/resize_uninitialized.h",
|
"internal/resize_uninitialized.h",
|
||||||
|
|||||||
1
third_party/abseil-cpp/absl/strings/BUILD.gn
vendored
1
third_party/abseil-cpp/absl/strings/BUILD.gn
vendored
@ -76,6 +76,7 @@ source_set("internal") {
|
|||||||
"internal/utf8.cc",
|
"internal/utf8.cc",
|
||||||
]
|
]
|
||||||
public = [
|
public = [
|
||||||
|
"internal/bits.h",
|
||||||
"internal/char_map.h",
|
"internal/char_map.h",
|
||||||
"internal/ostringstream.h",
|
"internal/ostringstream.h",
|
||||||
"internal/resize_uninitialized.h",
|
"internal/resize_uninitialized.h",
|
||||||
|
|||||||
@ -31,6 +31,7 @@ list(APPEND STRINGS_PUBLIC_HEADERS
|
|||||||
|
|
||||||
|
|
||||||
list(APPEND STRINGS_INTERNAL_HEADERS
|
list(APPEND STRINGS_INTERNAL_HEADERS
|
||||||
|
"internal/bits.h"
|
||||||
"internal/char_map.h"
|
"internal/char_map.h"
|
||||||
"internal/memutil.h"
|
"internal/memutil.h"
|
||||||
"internal/ostringstream.h"
|
"internal/ostringstream.h"
|
||||||
|
|||||||
53
third_party/abseil-cpp/absl/strings/internal/bits.h
vendored
Normal file
53
third_party/abseil-cpp/absl/strings/internal/bits.h
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT 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_STRINGS_INTERNAL_BITS_H_
|
||||||
|
#define ABSL_STRINGS_INTERNAL_BITS_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_X64)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
namespace strings_internal {
|
||||||
|
|
||||||
|
// Returns the number of leading 0 bits in a 64-bit value.
|
||||||
|
inline int CountLeadingZeros64(uint64_t n) {
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
|
||||||
|
"__builtin_clzll does not take 64bit arg");
|
||||||
|
return n == 0 ? 64 : __builtin_clzll(n);
|
||||||
|
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||||
|
unsigned long result; // NOLINT(runtime/int)
|
||||||
|
if (_BitScanReverse64(&result, n)) {
|
||||||
|
return 63 - result;
|
||||||
|
}
|
||||||
|
return 64;
|
||||||
|
#else
|
||||||
|
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\0"[n] + zeroes;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace strings_internal
|
||||||
|
} // namespace absl
|
||||||
|
|
||||||
|
#endif // ABSL_STRINGS_INTERNAL_BITS_H_
|
||||||
@ -234,6 +234,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
|||||||
result_size += it->size();
|
result_size += it->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result_size > 0) {
|
||||||
STLStringResizeUninitialized(&result, result_size);
|
STLStringResizeUninitialized(&result, result_size);
|
||||||
|
|
||||||
// Joins strings
|
// Joins strings
|
||||||
@ -247,6 +248,7 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
|||||||
result_buf += it->size();
|
result_buf += it->size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
3
third_party/abseil-cpp/absl/strings/match.h
vendored
3
third_party/abseil-cpp/absl/strings/match.h
vendored
@ -43,8 +43,7 @@ namespace absl {
|
|||||||
//
|
//
|
||||||
// Returns whether a given std::string `haystack` contains the substring `needle`.
|
// Returns whether a given std::string `haystack` contains the substring `needle`.
|
||||||
inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
|
inline bool StrContains(absl::string_view haystack, absl::string_view needle) {
|
||||||
return static_cast<absl::string_view::size_type>(haystack.find(needle, 0)) !=
|
return haystack.find(needle, 0) != haystack.npos;
|
||||||
haystack.npos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartsWith()
|
// StartsWith()
|
||||||
|
|||||||
17
third_party/abseil-cpp/absl/strings/numbers.cc
vendored
17
third_party/abseil-cpp/absl/strings/numbers.cc
vendored
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "absl/base/internal/raw_logging.h"
|
#include "absl/base/internal/raw_logging.h"
|
||||||
#include "absl/strings/ascii.h"
|
#include "absl/strings/ascii.h"
|
||||||
|
#include "absl/strings/internal/bits.h"
|
||||||
#include "absl/strings/internal/memutil.h"
|
#include "absl/strings/internal/memutil.h"
|
||||||
#include "absl/strings/str_cat.h"
|
#include "absl/strings/str_cat.h"
|
||||||
|
|
||||||
@ -302,18 +303,6 @@ char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) {
|
|||||||
return numbers_internal::FastIntToBuffer(u, buffer);
|
return numbers_internal::FastIntToBuffer(u, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of leading 0 bits in a 64-bit value.
|
|
||||||
// TODO(jorg): Replace with builtin_clzll if available.
|
|
||||||
// Are we shipping util/bits in absl?
|
|
||||||
static inline int CountLeadingZeros64(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\0"[n] + zeroes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a 128-bit number expressed as a pair of uint64_t, high half first,
|
// Given a 128-bit number expressed as a pair of uint64_t, high half first,
|
||||||
// return that number multiplied by the given 32-bit value. If the result is
|
// return that number multiplied by the given 32-bit value. If the result is
|
||||||
// too large to fit in a 128-bit number, divide it by 2 until it fits.
|
// too large to fit in a 128-bit number, divide it by 2 until it fits.
|
||||||
@ -351,7 +340,7 @@ static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num,
|
|||||||
uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
|
uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95);
|
||||||
if (bits128_up == 0) return {bits64_127, bits0_63};
|
if (bits128_up == 0) return {bits64_127, bits0_63};
|
||||||
|
|
||||||
int shift = 64 - CountLeadingZeros64(bits128_up);
|
int shift = 64 - strings_internal::CountLeadingZeros64(bits128_up);
|
||||||
uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
|
uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift));
|
||||||
uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
|
uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift));
|
||||||
return {hi, lo};
|
return {hi, lo};
|
||||||
@ -382,7 +371,7 @@ static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) {
|
|||||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
|
||||||
result = Mul32(result, powers_of_five[expfive & 15]);
|
result = Mul32(result, powers_of_five[expfive & 15]);
|
||||||
int shift = CountLeadingZeros64(result.first);
|
int shift = strings_internal::CountLeadingZeros64(result.first);
|
||||||
if (shift != 0) {
|
if (shift != 0) {
|
||||||
result.first = (result.first << shift) + (result.second >> (64 - shift));
|
result.first = (result.first << shift) + (result.second >> (64 - shift));
|
||||||
result.second = (result.second << shift);
|
result.second = (result.second << shift);
|
||||||
|
|||||||
@ -80,7 +80,7 @@ struct AlphaNumBuffer {
|
|||||||
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
|
// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
|
||||||
// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
|
// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value
|
||||||
// would produce hexadecimal strings such as " A"," F".
|
// would produce hexadecimal strings such as " A"," F".
|
||||||
enum PadSpec {
|
enum PadSpec : uint8_t {
|
||||||
kNoPad = 1,
|
kNoPad = 1,
|
||||||
kZeroPad2,
|
kZeroPad2,
|
||||||
kZeroPad3,
|
kZeroPad3,
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <set>
|
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|||||||
@ -22,8 +22,6 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include "absl/strings/internal/memutil.h"
|
#include "absl/strings/internal/memutil.h"
|
||||||
#include "absl/strings/internal/resize_uninitialized.h"
|
|
||||||
#include "absl/strings/match.h"
|
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
using std::string_view;
|
using std::string_view;
|
||||||
};
|
} // namespace absl
|
||||||
|
|
||||||
#else // ABSL_HAVE_STD_STRING_VIEW
|
#else // ABSL_HAVE_STD_STRING_VIEW
|
||||||
|
|
||||||
|
|||||||
@ -94,6 +94,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format,
|
|||||||
assert(target == output->data() + output->size());
|
assert(target == output->data() + output->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char kHexDigits[] = "0123456789abcdef";
|
||||||
Arg::Arg(const void* value) {
|
Arg::Arg(const void* value) {
|
||||||
static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
|
static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2,
|
||||||
"fix sizeof(scratch_)");
|
"fix sizeof(scratch_)");
|
||||||
@ -102,7 +103,6 @@ Arg::Arg(const void* value) {
|
|||||||
} else {
|
} else {
|
||||||
char* ptr = scratch_ + sizeof(scratch_);
|
char* ptr = scratch_ + sizeof(scratch_);
|
||||||
uintptr_t num = reinterpret_cast<uintptr_t>(value);
|
uintptr_t num = reinterpret_cast<uintptr_t>(value);
|
||||||
static const char kHexDigits[] = "0123456789abcdef";
|
|
||||||
do {
|
do {
|
||||||
*--ptr = kHexDigits[num & 0xf];
|
*--ptr = kHexDigits[num & 0xf];
|
||||||
num >>= 4;
|
num >>= 4;
|
||||||
@ -113,5 +113,58 @@ Arg::Arg(const void* value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
|
||||||
|
Arg::Arg(Hex hex) {
|
||||||
|
char* const end = &scratch_[numbers_internal::kFastToBufferSize];
|
||||||
|
char* writer = end;
|
||||||
|
uint64_t value = hex.value;
|
||||||
|
do {
|
||||||
|
*--writer = kHexDigits[value & 0xF];
|
||||||
|
value >>= 4;
|
||||||
|
} while (value != 0);
|
||||||
|
|
||||||
|
char* beg;
|
||||||
|
if (end - writer < hex.width) {
|
||||||
|
beg = end - hex.width;
|
||||||
|
std::fill_n(beg, writer - beg, hex.fill);
|
||||||
|
} else {
|
||||||
|
beg = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
piece_ = absl::string_view(beg, end - beg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jorg): Don't duplicate so much code between here and str_cat.cc
|
||||||
|
Arg::Arg(Dec dec) {
|
||||||
|
assert(dec.width <= numbers_internal::kFastToBufferSize);
|
||||||
|
char* const end = &scratch_[numbers_internal::kFastToBufferSize];
|
||||||
|
char* const minfill = end - dec.width;
|
||||||
|
char* writer = end;
|
||||||
|
uint64_t value = dec.value;
|
||||||
|
bool neg = dec.neg;
|
||||||
|
while (value > 9) {
|
||||||
|
*--writer = '0' + (value % 10);
|
||||||
|
value /= 10;
|
||||||
|
}
|
||||||
|
*--writer = '0' + value;
|
||||||
|
if (neg) *--writer = '-';
|
||||||
|
|
||||||
|
ptrdiff_t fillers = writer - minfill;
|
||||||
|
if (fillers > 0) {
|
||||||
|
// Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
|
||||||
|
// But...: if the fill character is '0', then it's <+/-><fill><digits>
|
||||||
|
bool add_sign_again = false;
|
||||||
|
if (neg && dec.fill == '0') { // If filling with '0',
|
||||||
|
++writer; // ignore the sign we just added
|
||||||
|
add_sign_again = true; // and re-add the sign later.
|
||||||
|
}
|
||||||
|
writer -= fillers;
|
||||||
|
std::fill_n(writer, fillers, dec.fill);
|
||||||
|
if (add_sign_again) *--writer = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
piece_ = absl::string_view(writer, end - writer);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace substitute_internal
|
} // namespace substitute_internal
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|||||||
18
third_party/abseil-cpp/absl/strings/substitute.h
vendored
18
third_party/abseil-cpp/absl/strings/substitute.h
vendored
@ -76,7 +76,7 @@
|
|||||||
#include "absl/strings/ascii.h"
|
#include "absl/strings/ascii.h"
|
||||||
#include "absl/strings/escaping.h"
|
#include "absl/strings/escaping.h"
|
||||||
#include "absl/strings/numbers.h"
|
#include "absl/strings/numbers.h"
|
||||||
#include "absl/strings/str_join.h"
|
#include "absl/strings/str_cat.h"
|
||||||
#include "absl/strings/str_split.h"
|
#include "absl/strings/str_split.h"
|
||||||
#include "absl/strings/string_view.h"
|
#include "absl/strings/string_view.h"
|
||||||
#include "absl/strings/strip.h"
|
#include "absl/strings/strip.h"
|
||||||
@ -113,10 +113,10 @@ class Arg {
|
|||||||
// what to do.
|
// what to do.
|
||||||
Arg(char value) // NOLINT(runtime/explicit)
|
Arg(char value) // NOLINT(runtime/explicit)
|
||||||
: piece_(scratch_, 1) { scratch_[0] = value; }
|
: piece_(scratch_, 1) { scratch_[0] = value; }
|
||||||
Arg(short value) // NOLINT(runtime/explicit)
|
Arg(short value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(unsigned short value) // NOLINT(runtime/explicit)
|
Arg(unsigned short value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(int value) // NOLINT(runtime/explicit)
|
Arg(int value) // NOLINT(runtime/explicit)
|
||||||
@ -125,16 +125,16 @@ class Arg {
|
|||||||
Arg(unsigned int value) // NOLINT(runtime/explicit)
|
Arg(unsigned int value) // NOLINT(runtime/explicit)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(long value) // NOLINT(runtime/explicit)
|
Arg(long value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(unsigned long value) // NOLINT(runtime/explicit)
|
Arg(unsigned long value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(long long value) // NOLINT(runtime/explicit)
|
Arg(long long value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(unsigned long long value) // NOLINT(runtime/explicit)
|
Arg(unsigned long long value) // NOLINT(*)
|
||||||
: piece_(scratch_,
|
: piece_(scratch_,
|
||||||
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {}
|
||||||
Arg(float value) // NOLINT(runtime/explicit)
|
Arg(float value) // NOLINT(runtime/explicit)
|
||||||
@ -145,6 +145,10 @@ class Arg {
|
|||||||
}
|
}
|
||||||
Arg(bool value) // NOLINT(runtime/explicit)
|
Arg(bool value) // NOLINT(runtime/explicit)
|
||||||
: piece_(value ? "true" : "false") {}
|
: piece_(value ? "true" : "false") {}
|
||||||
|
|
||||||
|
Arg(Hex hex); // NOLINT(runtime/explicit)
|
||||||
|
Arg(Dec dec); // NOLINT(runtime/explicit)
|
||||||
|
|
||||||
// `void*` values, with the exception of `char*`, are printed as
|
// `void*` values, with the exception of `char*`, are printed as
|
||||||
// "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
|
// "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed.
|
||||||
Arg(const void* value); // NOLINT(runtime/explicit)
|
Arg(const void* value); // NOLINT(runtime/explicit)
|
||||||
|
|||||||
@ -43,6 +43,24 @@ TEST(SubstituteTest, Substitute) {
|
|||||||
-1234567890, 3234567890U, -1234567890L, 3234567890UL,
|
-1234567890, 3234567890U, -1234567890L, 3234567890UL,
|
||||||
-int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
|
-int64_t{1234567890123456789}, uint64_t{9234567890123456789u}));
|
||||||
|
|
||||||
|
// Hex format
|
||||||
|
EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef",
|
||||||
|
absl::Substitute("$0$1$2$3$4 $5", //
|
||||||
|
absl::Hex(0), absl::Hex(1, absl::kSpacePad2),
|
||||||
|
absl::Hex(0xf, absl::kSpacePad2),
|
||||||
|
absl::Hex(int16_t{-1}, absl::kSpacePad5),
|
||||||
|
absl::Hex(int16_t{-1}, absl::kZeroPad5),
|
||||||
|
absl::Hex(0x123456789abcdef, absl::kZeroPad16)));
|
||||||
|
|
||||||
|
// Dec format
|
||||||
|
EXPECT_EQ("0 115 -1-0001 81985529216486895",
|
||||||
|
absl::Substitute("$0$1$2$3$4 $5", //
|
||||||
|
absl::Dec(0), absl::Dec(1, absl::kSpacePad2),
|
||||||
|
absl::Dec(0xf, absl::kSpacePad2),
|
||||||
|
absl::Dec(int16_t{-1}, absl::kSpacePad5),
|
||||||
|
absl::Dec(int16_t{-1}, absl::kZeroPad5),
|
||||||
|
absl::Dec(0x123456789abcdef, absl::kZeroPad16)));
|
||||||
|
|
||||||
// Pointer.
|
// Pointer.
|
||||||
const int* int_p = reinterpret_cast<const int*>(0x12345);
|
const int* int_p = reinterpret_cast<const int*>(0x12345);
|
||||||
std::string str = absl::Substitute("$0", int_p);
|
std::string str = absl::Substitute("$0", int_p);
|
||||||
|
|||||||
@ -77,6 +77,7 @@ cc_library(
|
|||||||
"//absl/base:dynamic_annotations",
|
"//absl/base:dynamic_annotations",
|
||||||
"//absl/base:malloc_internal",
|
"//absl/base:malloc_internal",
|
||||||
"//absl/debugging:stacktrace",
|
"//absl/debugging:stacktrace",
|
||||||
|
"//absl/debugging:symbolize",
|
||||||
"//absl/time",
|
"//absl/time",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -73,6 +73,7 @@ source_set("synchronization") {
|
|||||||
"../base:dynamic_annotations",
|
"../base:dynamic_annotations",
|
||||||
"../base:malloc_internal",
|
"../base:malloc_internal",
|
||||||
"../debugging:stacktrace",
|
"../debugging:stacktrace",
|
||||||
|
"../debugging:symbolize",
|
||||||
"../time",
|
"../time",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,7 +33,7 @@ list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# syncrhonisation library
|
# synchronization library
|
||||||
list(APPEND SYNCHRONIZATION_SRC
|
list(APPEND SYNCHRONIZATION_SRC
|
||||||
"barrier.cc"
|
"barrier.cc"
|
||||||
"blocking_counter.cc"
|
"blocking_counter.cc"
|
||||||
@ -44,7 +44,8 @@ list(APPEND SYNCHRONIZATION_SRC
|
|||||||
"notification.cc"
|
"notification.cc"
|
||||||
"mutex.cc"
|
"mutex.cc"
|
||||||
)
|
)
|
||||||
set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::time)
|
|
||||||
|
set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
|
||||||
|
|
||||||
absl_library(
|
absl_library(
|
||||||
TARGET
|
TARGET
|
||||||
|
|||||||
@ -50,6 +50,7 @@
|
|||||||
#include "absl/base/internal/thread_identity.h"
|
#include "absl/base/internal/thread_identity.h"
|
||||||
#include "absl/base/port.h"
|
#include "absl/base/port.h"
|
||||||
#include "absl/debugging/stacktrace.h"
|
#include "absl/debugging/stacktrace.h"
|
||||||
|
#include "absl/debugging/symbolize.h"
|
||||||
#include "absl/synchronization/internal/graphcycles.h"
|
#include "absl/synchronization/internal/graphcycles.h"
|
||||||
#include "absl/synchronization/internal/per_thread_sem.h"
|
#include "absl/synchronization/internal/per_thread_sem.h"
|
||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
@ -111,7 +112,8 @@ ABSL_CONST_INIT absl::base_internal::AtomicHook<
|
|||||||
ABSL_CONST_INIT absl::base_internal::AtomicHook<
|
ABSL_CONST_INIT absl::base_internal::AtomicHook<
|
||||||
void (*)(const char *msg, const void *cv)> cond_var_tracer;
|
void (*)(const char *msg, const void *cv)> cond_var_tracer;
|
||||||
ABSL_CONST_INIT absl::base_internal::AtomicHook<
|
ABSL_CONST_INIT absl::base_internal::AtomicHook<
|
||||||
bool (*)(const void *pc, char *out, int out_size)> symbolizer;
|
bool (*)(const void *pc, char *out, int out_size)>
|
||||||
|
symbolizer(absl::Symbolize);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@ -979,6 +979,12 @@ void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv));
|
|||||||
// to 'out.'
|
// to 'out.'
|
||||||
//
|
//
|
||||||
// This has the same memory ordering concerns as RegisterMutexProfiler() above.
|
// This has the same memory ordering concerns as RegisterMutexProfiler() above.
|
||||||
|
//
|
||||||
|
// DEPRECATED: The default symbolizer function is absl::Symbolize() and the
|
||||||
|
// ability to register a different hook for symbolizing stack traces will be
|
||||||
|
// removed on or after 2023-05-01.
|
||||||
|
ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed "
|
||||||
|
"on or after 2023-05-01")
|
||||||
void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
|
void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size));
|
||||||
|
|
||||||
// EnableMutexInvariantDebugging()
|
// EnableMutexInvariantDebugging()
|
||||||
|
|||||||
2
third_party/abseil-cpp/absl/time/BUILD.bazel
vendored
2
third_party/abseil-cpp/absl/time/BUILD.bazel
vendored
@ -51,6 +51,7 @@ cc_library(
|
|||||||
|
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "test_util",
|
name = "test_util",
|
||||||
|
testonly = 1,
|
||||||
srcs = [
|
srcs = [
|
||||||
"internal/test_util.cc",
|
"internal/test_util.cc",
|
||||||
"internal/zoneinfo.inc",
|
"internal/zoneinfo.inc",
|
||||||
@ -64,6 +65,7 @@ cc_library(
|
|||||||
":time",
|
":time",
|
||||||
"//absl/base",
|
"//absl/base",
|
||||||
"//absl/time/internal/cctz:time_zone",
|
"//absl/time/internal/cctz:time_zone",
|
||||||
|
"@com_google_googletest//:gtest",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
3
third_party/abseil-cpp/absl/time/BUILD.gn
vendored
3
third_party/abseil-cpp/absl/time/BUILD.gn
vendored
@ -45,6 +45,7 @@ source_set("time") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source_set("test_util") {
|
source_set("test_util") {
|
||||||
|
testonly = true
|
||||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||||
configs += [
|
configs += [
|
||||||
"//build/config/compiler:no_chromium_code",
|
"//build/config/compiler:no_chromium_code",
|
||||||
@ -62,6 +63,8 @@ source_set("test_util") {
|
|||||||
":time",
|
":time",
|
||||||
"../base",
|
"../base",
|
||||||
"../time/internal/cctz:time_zone",
|
"../time/internal/cctz:time_zone",
|
||||||
|
"//testing/gtest",
|
||||||
|
"//testing/gmock",
|
||||||
]
|
]
|
||||||
visibility = []
|
visibility = []
|
||||||
visibility += [ "../time:*" ]
|
visibility += [ "../time:*" ]
|
||||||
|
|||||||
@ -155,8 +155,7 @@ TEST(ParseTime, Basics) {
|
|||||||
"2013-06-28 19:08:09 -0800", &t, &err))
|
"2013-06-28 19:08:09 -0800", &t, &err))
|
||||||
<< err;
|
<< err;
|
||||||
absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
|
absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false,
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false);
|
||||||
"UTC-8");
|
|
||||||
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,8 +178,7 @@ TEST(ParseTime, WithTimeZone) {
|
|||||||
absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
|
absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
|
||||||
<< e;
|
<< e;
|
||||||
absl::Time::Breakdown bd = t.In(tz);
|
absl::Time::Breakdown bd = t.In(tz);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true,
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true);
|
||||||
"PDT");
|
|
||||||
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
||||||
|
|
||||||
// But the timezone is ignored when a UTC offset is present.
|
// But the timezone is ignored when a UTC offset is present.
|
||||||
@ -188,8 +186,7 @@ TEST(ParseTime, WithTimeZone) {
|
|||||||
"2013-06-28 19:08:09 +0800", tz, &t, &e))
|
"2013-06-28 19:08:09 +0800", tz, &t, &e))
|
||||||
<< e;
|
<< e;
|
||||||
bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
|
bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false,
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false);
|
||||||
"UTC+8");
|
|
||||||
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -80,6 +80,7 @@ cc_test(
|
|||||||
name = "time_zone_format_test",
|
name = "time_zone_format_test",
|
||||||
size = "small",
|
size = "small",
|
||||||
srcs = ["src/time_zone_format_test.cc"],
|
srcs = ["src/time_zone_format_test.cc"],
|
||||||
|
data = [":zoneinfo"],
|
||||||
deps = [
|
deps = [
|
||||||
":civil_time",
|
":civil_time",
|
||||||
":time_zone",
|
":time_zone",
|
||||||
@ -91,6 +92,7 @@ cc_test(
|
|||||||
name = "time_zone_lookup_test",
|
name = "time_zone_lookup_test",
|
||||||
size = "small",
|
size = "small",
|
||||||
srcs = ["src/time_zone_lookup_test.cc"],
|
srcs = ["src/time_zone_lookup_test.cc"],
|
||||||
|
data = [":zoneinfo"],
|
||||||
deps = [
|
deps = [
|
||||||
":civil_time",
|
":civil_time",
|
||||||
":time_zone",
|
":time_zone",
|
||||||
@ -103,3 +105,8 @@ cc_test(
|
|||||||
### examples
|
### examples
|
||||||
|
|
||||||
### binaries
|
### binaries
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "zoneinfo",
|
||||||
|
srcs = glob(["testdata/zoneinfo/**"]),
|
||||||
|
)
|
||||||
|
|||||||
@ -20,8 +20,8 @@
|
|||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
// Disable constexpr support unless we are using clang in C++14 mode.
|
// Disable constexpr support unless we are in C++14 mode.
|
||||||
#if __clang__ && __cpp_constexpr >= 201304
|
#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
|
||||||
#define CONSTEXPR_D constexpr // data
|
#define CONSTEXPR_D constexpr // data
|
||||||
#define CONSTEXPR_F constexpr // function
|
#define CONSTEXPR_F constexpr // function
|
||||||
#define CONSTEXPR_M constexpr // member
|
#define CONSTEXPR_M constexpr // member
|
||||||
|
|||||||
@ -37,7 +37,7 @@ std::string Format(const T& t) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#if __clang__ && __cpp_constexpr >= 201304
|
#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910
|
||||||
// Construction constexpr tests
|
// Construction constexpr tests
|
||||||
|
|
||||||
TEST(CivilTime, Normal) {
|
TEST(CivilTime, Normal) {
|
||||||
@ -319,7 +319,7 @@ TEST(CivilTime, YearDay) {
|
|||||||
constexpr int yd = get_yearday(cd);
|
constexpr int yd = get_yearday(cd);
|
||||||
static_assert(yd == 28, "YearDay");
|
static_assert(yd == 28, "YearDay");
|
||||||
}
|
}
|
||||||
#endif // __clang__ && __cpp_constexpr >= 201304
|
#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910
|
||||||
|
|
||||||
// The remaining tests do not use constexpr.
|
// The remaining tests do not use constexpr.
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace cctz {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// The prefix used for the internal names of fixed-offset zones.
|
// The prefix used for the internal names of fixed-offset zones.
|
||||||
const char kFixedOffsetPrefix[] = "Fixed/";
|
const char kFixedOffsetPrefix[] = "Fixed/UTC";
|
||||||
|
|
||||||
int Parse02d(const char* p) {
|
int Parse02d(const char* p) {
|
||||||
static const char kDigits[] = "0123456789";
|
static const char kDigits[] = "0123456789";
|
||||||
@ -50,13 +50,11 @@ bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) {
|
|||||||
|
|
||||||
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
|
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
|
||||||
const char* const ep = kFixedOffsetPrefix + prefix_len;
|
const char* const ep = kFixedOffsetPrefix + prefix_len;
|
||||||
if (name.size() != prefix_len + 12) // "<prefix>UTC+99:99:99"
|
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
|
||||||
return false;
|
return false;
|
||||||
if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
|
if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
|
||||||
return false;
|
return false;
|
||||||
const char* np = name.data() + prefix_len;
|
const char* np = name.data() + prefix_len;
|
||||||
if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
|
|
||||||
return false;
|
|
||||||
if (np[0] != '+' && np[0] != '-')
|
if (np[0] != '+' && np[0] != '-')
|
||||||
return false;
|
return false;
|
||||||
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
|
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
|
||||||
@ -97,8 +95,8 @@ std::string FixedOffsetToName(const sys_seconds& offset) {
|
|||||||
}
|
}
|
||||||
int hours = minutes / 60;
|
int hours = minutes / 60;
|
||||||
minutes %= 60;
|
minutes %= 60;
|
||||||
char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
|
char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")];
|
||||||
snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
|
snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d",
|
||||||
kFixedOffsetPrefix, sign, hours, minutes, seconds);
|
kFixedOffsetPrefix, sign, hours, minutes, seconds);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
@ -106,22 +104,14 @@ std::string FixedOffsetToName(const sys_seconds& offset) {
|
|||||||
std::string FixedOffsetToAbbr(const sys_seconds& offset) {
|
std::string FixedOffsetToAbbr(const sys_seconds& offset) {
|
||||||
std::string abbr = FixedOffsetToName(offset);
|
std::string abbr = FixedOffsetToName(offset);
|
||||||
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
|
const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
|
||||||
const char* const ep = kFixedOffsetPrefix + prefix_len;
|
if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
|
||||||
if (abbr.size() >= prefix_len) {
|
abbr.erase(0, prefix_len); // +99:99:99
|
||||||
if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
|
abbr.erase(6, 1); // +99:9999
|
||||||
abbr.erase(0, prefix_len);
|
abbr.erase(3, 1); // +999999
|
||||||
if (abbr.size() == 12) { // UTC+99:99:99
|
if (abbr[5] == '0' && abbr[6] == '0') { // +999900
|
||||||
abbr.erase(9, 1); // UTC+99:9999
|
abbr.erase(5, 2); // +9999
|
||||||
abbr.erase(6, 1); // UTC+999999
|
if (abbr[3] == '0' && abbr[4] == '0') { // +9900
|
||||||
if (abbr[8] == '0' && abbr[9] == '0') { // UTC+999900
|
abbr.erase(3, 2); // +99
|
||||||
abbr.erase(8, 2); // UTC+9999
|
|
||||||
if (abbr[6] == '0' && abbr[7] == '0') { // UTC+9900
|
|
||||||
abbr.erase(6, 2); // UTC+99
|
|
||||||
if (abbr[4] == '0') { // UTC+09
|
|
||||||
abbr.erase(4, 1); // UTC+9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -134,6 +134,9 @@ time_zone local_time_zone() {
|
|||||||
|
|
||||||
time_zone tz;
|
time_zone tz;
|
||||||
load_time_zone(name, &tz); // Falls back to UTC.
|
load_time_zone(name, &tz); // Falls back to UTC.
|
||||||
|
// TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
|
||||||
|
// arrange for %z to generate "-0000" when we don't know the local
|
||||||
|
// offset because the load_time_zone() failed and we're using UTC.
|
||||||
return tz;
|
return tz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -415,7 +415,6 @@ const char* const kTimeZoneNames[] = {
|
|||||||
"CST6CDT",
|
"CST6CDT",
|
||||||
"Canada/Atlantic",
|
"Canada/Atlantic",
|
||||||
"Canada/Central",
|
"Canada/Central",
|
||||||
"Canada/East-Saskatchewan",
|
|
||||||
"Canada/Eastern",
|
"Canada/Eastern",
|
||||||
"Canada/Mountain",
|
"Canada/Mountain",
|
||||||
"Canada/Newfoundland",
|
"Canada/Newfoundland",
|
||||||
@ -1119,18 +1118,6 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) {
|
|||||||
auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
|
auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
|
||||||
ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
|
ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
|
||||||
tp += seconds(1);
|
tp += seconds(1);
|
||||||
#ifndef TZDATA_2017B_IS_UBIQUITOUS
|
|
||||||
// The 2017b tzdata release moved the shift from -004430 to +00
|
|
||||||
// from 1972-05-01 to 1972-01-07, so we temporarily accept both
|
|
||||||
// outcomes until 2017b is ubiquitous.
|
|
||||||
if (tz.lookup(tp).offset == -44.5 * 60) {
|
|
||||||
tp = convert(civil_second(1972, 4, 30, 23, 59, 59), tz);
|
|
||||||
ExpectTime(tp, tz, 1972, 4, 30, 23, 59, 59, -44.5 * 60, false, "LRT");
|
|
||||||
tp += seconds(1);
|
|
||||||
ExpectTime(tp, tz, 1972, 5, 1, 0, 44, 30, 0 * 60, false, "GMT");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
|
ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
2018d-2-g8d1dac0
|
2018e-2-g99dd695
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -26,6 +26,12 @@ namespace cctz = absl::time_internal::cctz;
|
|||||||
namespace absl {
|
namespace absl {
|
||||||
namespace time_internal {
|
namespace time_internal {
|
||||||
|
|
||||||
|
#if GTEST_USES_SIMPLE_RE
|
||||||
|
extern const char kZoneAbbrRE[] = ".*"; // just punt
|
||||||
|
#else
|
||||||
|
extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
|
||||||
|
#endif
|
||||||
|
|
||||||
TimeZone LoadTimeZone(const std::string& name) {
|
TimeZone LoadTimeZone(const std::string& name) {
|
||||||
TimeZone tz;
|
TimeZone tz;
|
||||||
ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
|
ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
|
||||||
|
|||||||
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
|
|
||||||
// This helper is a macro so that failed expectations show up with the
|
// This helper is a macro so that failed expectations show up with the
|
||||||
@ -24,7 +26,7 @@
|
|||||||
//
|
//
|
||||||
// This is for internal testing of the Base Time library itself. This is not
|
// This is for internal testing of the Base Time library itself. This is not
|
||||||
// part of a public API.
|
// part of a public API.
|
||||||
#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst, zone) \
|
#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \
|
||||||
do { \
|
do { \
|
||||||
EXPECT_EQ(y, bd.year); \
|
EXPECT_EQ(y, bd.year); \
|
||||||
EXPECT_EQ(m, bd.month); \
|
EXPECT_EQ(m, bd.month); \
|
||||||
@ -34,12 +36,16 @@
|
|||||||
EXPECT_EQ(s, bd.second); \
|
EXPECT_EQ(s, bd.second); \
|
||||||
EXPECT_EQ(off, bd.offset); \
|
EXPECT_EQ(off, bd.offset); \
|
||||||
EXPECT_EQ(isdst, bd.is_dst); \
|
EXPECT_EQ(isdst, bd.is_dst); \
|
||||||
EXPECT_STREQ(zone, bd.zone_abbr); \
|
EXPECT_THAT(bd.zone_abbr, \
|
||||||
|
testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
namespace time_internal {
|
namespace time_internal {
|
||||||
|
|
||||||
|
// A regular expression that matches all zone abbreviations (%Z).
|
||||||
|
extern const char kZoneAbbrRE[];
|
||||||
|
|
||||||
// Loads the named timezone, but dies on any failure.
|
// Loads the named timezone, but dies on any failure.
|
||||||
absl::TimeZone LoadTimeZone(const std::string& name);
|
absl::TimeZone LoadTimeZone(const std::string& name);
|
||||||
|
|
||||||
|
|||||||
4
third_party/abseil-cpp/absl/time/time.cc
vendored
4
third_party/abseil-cpp/absl/time/time.cc
vendored
@ -71,7 +71,7 @@ inline absl::Time::Breakdown InfiniteFutureBreakdown() {
|
|||||||
bd.yearday = 365;
|
bd.yearday = 365;
|
||||||
bd.offset = 0;
|
bd.offset = 0;
|
||||||
bd.is_dst = false;
|
bd.is_dst = false;
|
||||||
bd.zone_abbr = "-0000";
|
bd.zone_abbr = "-00";
|
||||||
return bd;
|
return bd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ inline Time::Breakdown InfinitePastBreakdown() {
|
|||||||
bd.yearday = 1;
|
bd.yearday = 1;
|
||||||
bd.offset = 0;
|
bd.offset = 0;
|
||||||
bd.is_dst = false;
|
bd.is_dst = false;
|
||||||
bd.zone_abbr = "-0000";
|
bd.zone_abbr = "-00";
|
||||||
return bd;
|
return bd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "absl/time/internal/test_util.h"
|
#include "absl/time/internal/test_util.h"
|
||||||
#include "absl/time/time.h"
|
#include "absl/time/time.h"
|
||||||
@ -32,31 +33,31 @@ TEST(TimeNormCase, SimpleOverflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, SimpleUnderflow) {
|
TEST(TimeNormCase, SimpleUnderflow) {
|
||||||
@ -66,31 +67,31 @@ TEST(TimeNormCase, SimpleUnderflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false);
|
||||||
|
|
||||||
tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
|
tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false);
|
||||||
|
|
||||||
tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
|
tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
|
tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
|
tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, MultipleOverflow) {
|
TEST(TimeNormCase, MultipleOverflow) {
|
||||||
@ -99,7 +100,7 @@ TEST(TimeNormCase, MultipleOverflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, MultipleUnderflow) {
|
TEST(TimeNormCase, MultipleUnderflow) {
|
||||||
@ -108,7 +109,7 @@ TEST(TimeNormCase, MultipleUnderflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, OverflowLimits) {
|
TEST(TimeNormCase, OverflowLimits) {
|
||||||
@ -122,7 +123,7 @@ TEST(TimeNormCase, OverflowLimits) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false);
|
||||||
|
|
||||||
const int kintmin = std::numeric_limits<int>::min();
|
const int kintmin = std::numeric_limits<int>::min();
|
||||||
tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
|
tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin,
|
||||||
@ -130,8 +131,7 @@ TEST(TimeNormCase, OverflowLimits) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false,
|
ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false);
|
||||||
"UTC");
|
|
||||||
|
|
||||||
const int64_t max_year = std::numeric_limits<int64_t>::max();
|
const int64_t max_year = std::numeric_limits<int64_t>::max();
|
||||||
tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
|
tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc);
|
||||||
@ -154,31 +154,31 @@ TEST(TimeNormCase, ComplexOverflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, ComplexUnderflow) {
|
TEST(TimeNormCase, ComplexUnderflow) {
|
||||||
@ -189,37 +189,37 @@ TEST(TimeNormCase, ComplexUnderflow) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
|
tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, Mishmash) {
|
TEST(TimeNormCase, Mishmash) {
|
||||||
@ -231,14 +231,14 @@ TEST(TimeNormCase, Mishmash) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
|
tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456,
|
||||||
32 - 1234567, 14 + 123456789, utc);
|
32 - 1234567, 14 + 123456789, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false);
|
||||||
|
|
||||||
// Here is a normalization case we got wrong for a while. Because the
|
// Here is a normalization case we got wrong for a while. Because the
|
||||||
// day is converted to "1" within a 400-year (146097-day) period, we
|
// day is converted to "1" within a 400-year (146097-day) period, we
|
||||||
@ -247,7 +247,7 @@ TEST(TimeNormCase, Mishmash) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false);
|
||||||
|
|
||||||
// Even though the month overflow compensates for the day underflow,
|
// Even though the month overflow compensates for the day underflow,
|
||||||
// this should still be marked as normalized.
|
// this should still be marked as normalized.
|
||||||
@ -255,7 +255,7 @@ TEST(TimeNormCase, Mishmash) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeNormCase, LeapYears) {
|
TEST(TimeNormCase, LeapYears) {
|
||||||
@ -266,25 +266,25 @@ TEST(TimeNormCase, LeapYears) {
|
|||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
absl::Time::Breakdown bd = tc.pre.In(utc);
|
absl::Time::Breakdown bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
|
tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc);
|
||||||
EXPECT_FALSE(tc.normalized);
|
EXPECT_FALSE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
|
tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc);
|
||||||
EXPECT_FALSE(tc.normalized);
|
EXPECT_FALSE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false);
|
||||||
|
|
||||||
tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
|
tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc);
|
||||||
EXPECT_TRUE(tc.normalized);
|
EXPECT_TRUE(tc.normalized);
|
||||||
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind);
|
||||||
bd = tc.pre.In(utc);
|
bd = tc.pre.In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
|
// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31)
|
||||||
|
|||||||
20
third_party/abseil-cpp/absl/time/time_test.cc
vendored
20
third_party/abseil-cpp/absl/time/time_test.cc
vendored
@ -85,7 +85,7 @@ TEST(Time, ValueSemantics) {
|
|||||||
|
|
||||||
TEST(Time, UnixEpoch) {
|
TEST(Time, UnixEpoch) {
|
||||||
absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
|
absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone());
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false);
|
||||||
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
||||||
EXPECT_EQ(4, bd.weekday); // Thursday
|
EXPECT_EQ(4, bd.weekday); // Thursday
|
||||||
}
|
}
|
||||||
@ -96,14 +96,14 @@ TEST(Time, Breakdown) {
|
|||||||
|
|
||||||
// The Unix epoch as seen in NYC.
|
// The Unix epoch as seen in NYC.
|
||||||
absl::Time::Breakdown bd = t.In(tz);
|
absl::Time::Breakdown bd = t.In(tz);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false, "EST");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false);
|
||||||
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
|
||||||
EXPECT_EQ(3, bd.weekday); // Wednesday
|
EXPECT_EQ(3, bd.weekday); // Wednesday
|
||||||
|
|
||||||
// Just before the epoch.
|
// Just before the epoch.
|
||||||
t -= absl::Nanoseconds(1);
|
t -= absl::Nanoseconds(1);
|
||||||
bd = t.In(tz);
|
bd = t.In(tz);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false, "EST");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false);
|
||||||
EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
|
EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond);
|
||||||
EXPECT_EQ(3, bd.weekday); // Wednesday
|
EXPECT_EQ(3, bd.weekday); // Wednesday
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ TEST(Time, Breakdown) {
|
|||||||
t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
|
t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) +
|
||||||
absl::Nanoseconds(9);
|
absl::Nanoseconds(9);
|
||||||
bd = t.In(tz);
|
bd = t.In(tz);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true, "EDT");
|
ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true);
|
||||||
EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
|
EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1));
|
||||||
EXPECT_EQ(2, bd.weekday); // Tuesday
|
EXPECT_EQ(2, bd.weekday); // Tuesday
|
||||||
}
|
}
|
||||||
@ -983,16 +983,18 @@ TEST(Time, ConversionSaturation) {
|
|||||||
// Checks how Time::In() saturates on infinities.
|
// Checks how Time::In() saturates on infinities.
|
||||||
absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
|
absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
|
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23,
|
||||||
59, 59, 0, false, "-0000");
|
59, 59, 0, false);
|
||||||
EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
|
EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond);
|
||||||
EXPECT_EQ(4, bd.weekday); // Thursday
|
EXPECT_EQ(4, bd.weekday); // Thursday
|
||||||
EXPECT_EQ(365, bd.yearday);
|
EXPECT_EQ(365, bd.yearday);
|
||||||
|
EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
|
||||||
bd = absl::InfinitePast().In(utc);
|
bd = absl::InfinitePast().In(utc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
|
ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0,
|
||||||
0, 0, false, "-0000");
|
0, 0, false);
|
||||||
EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
|
EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond);
|
||||||
EXPECT_EQ(7, bd.weekday); // Sunday
|
EXPECT_EQ(7, bd.weekday); // Sunday
|
||||||
EXPECT_EQ(1, bd.yearday);
|
EXPECT_EQ(1, bd.yearday);
|
||||||
|
EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In()
|
||||||
|
|
||||||
// Approach the maximal Time value from below.
|
// Approach the maximal Time value from below.
|
||||||
t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
|
t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc);
|
||||||
@ -1054,13 +1056,11 @@ TEST(Time, ExtendedConversionSaturation) {
|
|||||||
|
|
||||||
// The maximal time converted in each zone.
|
// The maximal time converted in each zone.
|
||||||
bd = max.In(syd);
|
bd = max.In(syd);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true,
|
ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true);
|
||||||
"AEDT");
|
|
||||||
t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
|
t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd);
|
||||||
EXPECT_EQ(max, t);
|
EXPECT_EQ(max, t);
|
||||||
bd = max.In(nyc);
|
bd = max.In(nyc);
|
||||||
ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false,
|
ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false);
|
||||||
"EST");
|
|
||||||
t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
|
t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc);
|
||||||
EXPECT_EQ(max, t);
|
EXPECT_EQ(max, t);
|
||||||
|
|
||||||
|
|||||||
15
third_party/abseil-cpp/absl/types/BUILD.bazel
vendored
15
third_party/abseil-cpp/absl/types/BUILD.bazel
vendored
@ -223,3 +223,18 @@ cc_test(
|
|||||||
"@com_google_googletest//:gtest_main",
|
"@com_google_googletest//:gtest_main",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "variant_exception_safety_test",
|
||||||
|
size = "small",
|
||||||
|
srcs = [
|
||||||
|
"variant_exception_safety_test.cc",
|
||||||
|
],
|
||||||
|
copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG,
|
||||||
|
deps = [
|
||||||
|
":variant",
|
||||||
|
"//absl/base:exception_safety_testing",
|
||||||
|
"//absl/memory",
|
||||||
|
"@com_google_googletest//:gtest_main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|||||||
14
third_party/abseil-cpp/absl/types/CMakeLists.txt
vendored
14
third_party/abseil-cpp/absl/types/CMakeLists.txt
vendored
@ -29,6 +29,9 @@ absl_header_library(
|
|||||||
TARGET
|
TARGET
|
||||||
absl_any
|
absl_any
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
|
absl::bad_any_cast
|
||||||
|
absl::base
|
||||||
|
absl::meta
|
||||||
absl::utility
|
absl::utility
|
||||||
PRIVATE_COMPILE_FLAGS
|
PRIVATE_COMPILE_FLAGS
|
||||||
${ABSL_EXCEPTIONS_FLAG}
|
${ABSL_EXCEPTIONS_FLAG}
|
||||||
@ -59,7 +62,6 @@ absl_library(
|
|||||||
SOURCES
|
SOURCES
|
||||||
${BAD_ANY_CAST_SRC}
|
${BAD_ANY_CAST_SRC}
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
absl::base absl::any
|
|
||||||
EXPORT_NAME
|
EXPORT_NAME
|
||||||
bad_any_cast
|
bad_any_cast
|
||||||
)
|
)
|
||||||
@ -76,7 +78,11 @@ absl_library(
|
|||||||
SOURCES
|
SOURCES
|
||||||
${OPTIONAL_SRC}
|
${OPTIONAL_SRC}
|
||||||
PUBLIC_LIBRARIES
|
PUBLIC_LIBRARIES
|
||||||
|
absl::bad_optional_access
|
||||||
absl::base
|
absl::base
|
||||||
|
absl::memory
|
||||||
|
absl::meta
|
||||||
|
absl::utility
|
||||||
EXPORT_NAME
|
EXPORT_NAME
|
||||||
optional
|
optional
|
||||||
)
|
)
|
||||||
@ -143,7 +149,11 @@ absl_test(
|
|||||||
|
|
||||||
# test any_exception_safety_test
|
# test any_exception_safety_test
|
||||||
set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
|
set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc")
|
||||||
set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES absl::any absl::base absl::base_internal_exception_safety_testing)
|
set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES
|
||||||
|
absl::any
|
||||||
|
absl::base
|
||||||
|
absl_base_internal_exception_safety_testing
|
||||||
|
)
|
||||||
|
|
||||||
absl_test(
|
absl_test(
|
||||||
TARGET
|
TARGET
|
||||||
|
|||||||
@ -20,21 +20,16 @@
|
|||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
#include "absl/base/internal/exception_safety_testing.h"
|
#include "absl/base/internal/exception_safety_testing.h"
|
||||||
|
|
||||||
using Thrower = absl::ThrowingValue<>;
|
using Thrower = testing::ThrowingValue<>;
|
||||||
using NoThrowMoveThrower =
|
using NoThrowMoveThrower =
|
||||||
absl::ThrowingValue<absl::NoThrow::kMoveCtor | absl::NoThrow::kMoveAssign>;
|
testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
|
||||||
using ThrowerList = std::initializer_list<Thrower>;
|
using ThrowerList = std::initializer_list<Thrower>;
|
||||||
using ThrowerVec = std::vector<Thrower>;
|
using ThrowerVec = std::vector<Thrower>;
|
||||||
using ThrowingAlloc = absl::ThrowingAllocator<Thrower>;
|
using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
|
||||||
using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
|
using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class AnyExceptionSafety : public ::testing::Test {
|
|
||||||
private:
|
|
||||||
absl::ConstructorTracker inspector_;
|
|
||||||
};
|
|
||||||
|
|
||||||
testing::AssertionResult AnyInvariants(absl::any* a) {
|
testing::AssertionResult AnyInvariants(absl::any* a) {
|
||||||
using testing::AssertionFailure;
|
using testing::AssertionFailure;
|
||||||
using testing::AssertionSuccess;
|
using testing::AssertionSuccess;
|
||||||
@ -84,30 +79,33 @@ testing::AssertionResult AnyIsEmpty(absl::any* a) {
|
|||||||
<< absl::any_cast<Thrower>(*a).Get();
|
<< absl::any_cast<Thrower>(*a).Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AnyExceptionSafety, Ctors) {
|
TEST(AnyExceptionSafety, Ctors) {
|
||||||
Thrower val(1);
|
Thrower val(1);
|
||||||
auto with_val = absl::TestThrowingCtor<absl::any>(val);
|
testing::TestThrowingCtor<absl::any>(val);
|
||||||
auto copy = absl::TestThrowingCtor<absl::any>(with_val);
|
|
||||||
auto in_place =
|
Thrower copy(val);
|
||||||
absl::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
|
testing::TestThrowingCtor<absl::any>(copy);
|
||||||
auto in_place_list = absl::TestThrowingCtor<absl::any>(
|
|
||||||
absl::in_place_type_t<ThrowerVec>(), ThrowerList{val});
|
testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1);
|
||||||
auto in_place_list_again =
|
|
||||||
absl::TestThrowingCtor<absl::any,
|
testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(),
|
||||||
|
ThrowerList{val});
|
||||||
|
|
||||||
|
testing::TestThrowingCtor<absl::any,
|
||||||
absl::in_place_type_t<ThrowingThrowerVec>,
|
absl::in_place_type_t<ThrowingThrowerVec>,
|
||||||
ThrowerList, ThrowingAlloc>(
|
ThrowerList, ThrowingAlloc>(
|
||||||
absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
|
absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AnyExceptionSafety, Assignment) {
|
TEST(AnyExceptionSafety, Assignment) {
|
||||||
auto original =
|
auto original =
|
||||||
absl::any(absl::in_place_type_t<Thrower>(), 1, absl::no_throw_ctor);
|
absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor);
|
||||||
auto any_is_strong = [original](absl::any* ap) {
|
auto any_is_strong = [original](absl::any* ap) {
|
||||||
return testing::AssertionResult(ap->has_value() &&
|
return testing::AssertionResult(ap->has_value() &&
|
||||||
absl::any_cast<Thrower>(original) ==
|
absl::any_cast<Thrower>(original) ==
|
||||||
absl::any_cast<Thrower>(*ap));
|
absl::any_cast<Thrower>(*ap));
|
||||||
};
|
};
|
||||||
auto any_strong_tester = absl::MakeExceptionSafetyTester()
|
auto any_strong_tester = testing::MakeExceptionSafetyTester()
|
||||||
.WithInitialValue(original)
|
.WithInitialValue(original)
|
||||||
.WithInvariants(AnyInvariants, any_is_strong);
|
.WithInvariants(AnyInvariants, any_is_strong);
|
||||||
|
|
||||||
@ -129,7 +127,7 @@ TEST_F(AnyExceptionSafety, Assignment) {
|
|||||||
return testing::AssertionResult{!ap->has_value()};
|
return testing::AssertionResult{!ap->has_value()};
|
||||||
};
|
};
|
||||||
auto strong_empty_any_tester =
|
auto strong_empty_any_tester =
|
||||||
absl::MakeExceptionSafetyTester()
|
testing::MakeExceptionSafetyTester()
|
||||||
.WithInitialValue(absl::any{})
|
.WithInitialValue(absl::any{})
|
||||||
.WithInvariants(AnyInvariants, empty_any_is_strong);
|
.WithInvariants(AnyInvariants, empty_any_is_strong);
|
||||||
|
|
||||||
@ -139,16 +137,16 @@ TEST_F(AnyExceptionSafety, Assignment) {
|
|||||||
}
|
}
|
||||||
// libstdc++ std::any fails this test
|
// libstdc++ std::any fails this test
|
||||||
#if !defined(ABSL_HAVE_STD_ANY)
|
#if !defined(ABSL_HAVE_STD_ANY)
|
||||||
TEST_F(AnyExceptionSafety, Emplace) {
|
TEST(AnyExceptionSafety, Emplace) {
|
||||||
auto initial_val =
|
auto initial_val =
|
||||||
absl::any{absl::in_place_type_t<Thrower>(), 1, absl::no_throw_ctor};
|
absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor};
|
||||||
auto one_tester = absl::MakeExceptionSafetyTester()
|
auto one_tester = testing::MakeExceptionSafetyTester()
|
||||||
.WithInitialValue(initial_val)
|
.WithInitialValue(initial_val)
|
||||||
.WithInvariants(AnyInvariants, AnyIsEmpty);
|
.WithInvariants(AnyInvariants, AnyIsEmpty);
|
||||||
|
|
||||||
auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
|
auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); };
|
||||||
auto emp_throwervec = [](absl::any* ap) {
|
auto emp_throwervec = [](absl::any* ap) {
|
||||||
std::initializer_list<Thrower> il{Thrower(2, absl::no_throw_ctor)};
|
std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)};
|
||||||
ap->emplace<ThrowerVec>(il);
|
ap->emplace<ThrowerVec>(il);
|
||||||
};
|
};
|
||||||
auto emp_movethrower = [](absl::any* ap) {
|
auto emp_movethrower = [](absl::any* ap) {
|
||||||
|
|||||||
58
third_party/abseil-cpp/absl/types/optional.h
vendored
58
third_party/abseil-cpp/absl/types/optional.h
vendored
@ -776,10 +776,13 @@ class optional : private optional_internal::optional_data<T>,
|
|||||||
// `optional` is empty, behavior is undefined.
|
// `optional` is empty, behavior is undefined.
|
||||||
//
|
//
|
||||||
// If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
|
// If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
|
||||||
const T* operator->() const { return this->pointer(); }
|
const T* operator->() const {
|
||||||
|
assert(this->engaged_);
|
||||||
|
return std::addressof(this->data_);
|
||||||
|
}
|
||||||
T* operator->() {
|
T* operator->() {
|
||||||
assert(this->engaged_);
|
assert(this->engaged_);
|
||||||
return this->pointer();
|
return std::addressof(this->data_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional::operator*()
|
// optional::operator*()
|
||||||
@ -817,6 +820,12 @@ class optional : private optional_internal::optional_data<T>,
|
|||||||
// only if `*this` is empty.
|
// only if `*this` is empty.
|
||||||
constexpr bool has_value() const noexcept { return this->engaged_; }
|
constexpr bool has_value() const noexcept { return this->engaged_; }
|
||||||
|
|
||||||
|
// Suppress bogus warning on MSVC: MSVC complains call to reference() after
|
||||||
|
// throw_bad_optional_access() is unreachable.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4702)
|
||||||
|
#endif // _MSC_VER
|
||||||
// optional::value()
|
// optional::value()
|
||||||
//
|
//
|
||||||
// Returns a reference to an `optional`s underlying value. The constness
|
// Returns a reference to an `optional`s underlying value. The constness
|
||||||
@ -845,6 +854,9 @@ class optional : private optional_internal::optional_data<T>,
|
|||||||
? reference()
|
? reference()
|
||||||
: (optional_internal::throw_bad_optional_access(), reference()));
|
: (optional_internal::throw_bad_optional_access(), reference()));
|
||||||
}
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
// optional::value_or()
|
// optional::value_or()
|
||||||
//
|
//
|
||||||
@ -871,10 +883,6 @@ class optional : private optional_internal::optional_data<T>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Private accessors for internal storage viewed as pointer to T.
|
|
||||||
const T* pointer() const { return std::addressof(this->data_); }
|
|
||||||
T* pointer() { return std::addressof(this->data_); }
|
|
||||||
|
|
||||||
// Private accessors for internal storage viewed as reference to T.
|
// Private accessors for internal storage viewed as reference to T.
|
||||||
constexpr const T& reference() const { return this->data_; }
|
constexpr const T& reference() const { return this->data_; }
|
||||||
T& reference() { return this->data_; }
|
T& reference() { return this->data_; }
|
||||||
@ -958,7 +966,8 @@ constexpr auto operator==(const optional<T>& x, const optional<U>& y)
|
|||||||
-> decltype(optional_internal::convertible_to_bool(*x == *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x == *y)) {
|
||||||
return static_cast<bool>(x) != static_cast<bool>(y)
|
return static_cast<bool>(x) != static_cast<bool>(y)
|
||||||
? false
|
? false
|
||||||
: static_cast<bool>(x) == false ? true : *x == *y;
|
: static_cast<bool>(x) == false ? true
|
||||||
|
: static_cast<bool>(*x == *y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
|
// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
|
||||||
@ -968,31 +977,32 @@ constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
|
|||||||
-> decltype(optional_internal::convertible_to_bool(*x != *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x != *y)) {
|
||||||
return static_cast<bool>(x) != static_cast<bool>(y)
|
return static_cast<bool>(x) != static_cast<bool>(y)
|
||||||
? true
|
? true
|
||||||
: static_cast<bool>(x) == false ? false : *x != *y;
|
: static_cast<bool>(x) == false ? false
|
||||||
|
: static_cast<bool>(*x != *y);
|
||||||
}
|
}
|
||||||
// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
|
// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<(const optional<T>& x, const optional<U>& y)
|
constexpr auto operator<(const optional<T>& x, const optional<U>& y)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x < *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x < *y)) {
|
||||||
return !y ? false : !x ? true : *x < *y;
|
return !y ? false : !x ? true : static_cast<bool>(*x < *y);
|
||||||
}
|
}
|
||||||
// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
|
// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>(const optional<T>& x, const optional<U>& y)
|
constexpr auto operator>(const optional<T>& x, const optional<U>& y)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x > *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x > *y)) {
|
||||||
return !x ? false : !y ? true : *x > *y;
|
return !x ? false : !y ? true : static_cast<bool>(*x > *y);
|
||||||
}
|
}
|
||||||
// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
|
// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
|
constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
|
||||||
return !x ? true : !y ? false : *x <= *y;
|
return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
|
||||||
}
|
}
|
||||||
// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
|
// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
|
constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
|
-> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
|
||||||
return !y ? true : !x ? false : *x >= *y;
|
return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comparison with nullopt [optional.nullops]
|
// Comparison with nullopt [optional.nullops]
|
||||||
@ -1054,62 +1064,62 @@ constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
|
|||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator==(const optional<T>& x, const U& v)
|
constexpr auto operator==(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x == v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x == v)) {
|
||||||
return static_cast<bool>(x) ? *x == v : false;
|
return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator==(const U& v, const optional<T>& x)
|
constexpr auto operator==(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v == *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v == *x)) {
|
||||||
return static_cast<bool>(x) ? v == *x : false;
|
return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator!=(const optional<T>& x, const U& v)
|
constexpr auto operator!=(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x != v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x != v)) {
|
||||||
return static_cast<bool>(x) ? *x != v : true;
|
return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator!=(const U& v, const optional<T>& x)
|
constexpr auto operator!=(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v != *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v != *x)) {
|
||||||
return static_cast<bool>(x) ? v != *x : true;
|
return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<(const optional<T>& x, const U& v)
|
constexpr auto operator<(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x < v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x < v)) {
|
||||||
return static_cast<bool>(x) ? *x < v : true;
|
return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<(const U& v, const optional<T>& x)
|
constexpr auto operator<(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v < *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v < *x)) {
|
||||||
return static_cast<bool>(x) ? v < *x : false;
|
return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<=(const optional<T>& x, const U& v)
|
constexpr auto operator<=(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x <= v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x <= v)) {
|
||||||
return static_cast<bool>(x) ? *x <= v : true;
|
return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator<=(const U& v, const optional<T>& x)
|
constexpr auto operator<=(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v <= *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v <= *x)) {
|
||||||
return static_cast<bool>(x) ? v <= *x : false;
|
return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>(const optional<T>& x, const U& v)
|
constexpr auto operator>(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x > v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x > v)) {
|
||||||
return static_cast<bool>(x) ? *x > v : false;
|
return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>(const U& v, const optional<T>& x)
|
constexpr auto operator>(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v > *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v > *x)) {
|
||||||
return static_cast<bool>(x) ? v > *x : true;
|
return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>=(const optional<T>& x, const U& v)
|
constexpr auto operator>=(const optional<T>& x, const U& v)
|
||||||
-> decltype(optional_internal::convertible_to_bool(*x >= v)) {
|
-> decltype(optional_internal::convertible_to_bool(*x >= v)) {
|
||||||
return static_cast<bool>(x) ? *x >= v : false;
|
return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
|
||||||
}
|
}
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
constexpr auto operator>=(const U& v, const optional<T>& x)
|
constexpr auto operator>=(const U& v, const optional<T>& x)
|
||||||
-> decltype(optional_internal::convertible_to_bool(v >= *x)) {
|
-> decltype(optional_internal::convertible_to_bool(v >= *x)) {
|
||||||
return static_cast<bool>(x) ? v >= *x : true;
|
return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|||||||
21
third_party/abseil-cpp/absl/types/span.h
vendored
21
third_party/abseil-cpp/absl/types/span.h
vendored
@ -290,7 +290,8 @@ class Span {
|
|||||||
constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
|
constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
|
||||||
: Span(a, N) {}
|
: Span(a, N) {}
|
||||||
|
|
||||||
// Explicit reference constructor for a mutable `Span<T>` type
|
// Explicit reference constructor for a mutable `Span<T>` type. Can be
|
||||||
|
// replaced with MakeSpan() to infer the type parameter.
|
||||||
template <typename V, typename = EnableIfConvertibleFrom<V>,
|
template <typename V, typename = EnableIfConvertibleFrom<V>,
|
||||||
typename = EnableIfMutableView<V>>
|
typename = EnableIfMutableView<V>>
|
||||||
explicit Span(V& v) noexcept // NOLINT(runtime/references)
|
explicit Span(V& v) noexcept // NOLINT(runtime/references)
|
||||||
@ -458,10 +459,20 @@ class Span {
|
|||||||
|
|
||||||
// Span::subspan()
|
// Span::subspan()
|
||||||
//
|
//
|
||||||
// Returns a `Span` starting at element `pos` and of length `len`, with
|
// Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
|
||||||
// proper bounds checking to ensure `len` does not exceed the ptr+size of the
|
// and `len` are of type `size_type` and thus non-negative. Parameter `pos`
|
||||||
// original array. (Spans whose `len` would point past the end of the array
|
// must be <= size(). Any `len` value that points past the end of the span
|
||||||
// will throw a `std::out_of_range`.)
|
// will be trimmed to at most size() - `pos`. A default `len` value of `npos`
|
||||||
|
// ensures the returned subspan continues until the end of the span.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// std::vector<int> vec = {10, 11, 12, 13};
|
||||||
|
// absl::MakeSpan(vec).subspan(1, 2); // {11, 12}
|
||||||
|
// absl::MakeSpan(vec).subspan(2, 8); // {12, 13}
|
||||||
|
// absl::MakeSpan(vec).subspan(1); // {11, 12, 13}
|
||||||
|
// absl::MakeSpan(vec).subspan(4); // {}
|
||||||
|
// absl::MakeSpan(vec).subspan(5); // throws std::out_of_range
|
||||||
constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
|
constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
|
||||||
return (pos <= len_)
|
return (pos <= len_)
|
||||||
? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
|
? Span(ptr_ + pos, span_internal::Min(len_ - pos, len))
|
||||||
|
|||||||
2
third_party/abseil-cpp/absl/types/variant.h
vendored
2
third_party/abseil-cpp/absl/types/variant.h
vendored
@ -350,7 +350,7 @@ constexpr const variant_alternative_t<I, variant<Types...>>&& get(
|
|||||||
// get_if()
|
// get_if()
|
||||||
//
|
//
|
||||||
// Returns a pointer to the value currently stored within a given variant, if
|
// Returns a pointer to the value currently stored within a given variant, if
|
||||||
// present, using either a unique alternative type amonst the variant's set of
|
// present, using either a unique alternative type amongst the variant's set of
|
||||||
// alternative types, or the variant's index value. If such a value does not
|
// alternative types, or the variant's index value. If such a value does not
|
||||||
// exist, returns `nullptr`.
|
// exist, returns `nullptr`.
|
||||||
//
|
//
|
||||||
|
|||||||
519
third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc
vendored
Normal file
519
third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc
vendored
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
// Copyright 2017 The Abseil Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include "absl/types/variant.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "absl/base/internal/exception_safety_testing.h"
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
|
||||||
|
namespace absl {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::MakeExceptionSafetyTester;
|
||||||
|
using ::testing::nothrow_guarantee;
|
||||||
|
using ::testing::strong_guarantee;
|
||||||
|
using ::testing::TestThrowingCtor;
|
||||||
|
|
||||||
|
using Thrower = testing::ThrowingValue<>;
|
||||||
|
using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>;
|
||||||
|
using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
|
||||||
|
using ThrowingAlloc = testing::ThrowingAllocator<Thrower>;
|
||||||
|
using ThrowerVec = std::vector<Thrower, ThrowingAlloc>;
|
||||||
|
using ThrowingVariant =
|
||||||
|
absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>;
|
||||||
|
|
||||||
|
struct ConversionException {};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct ExceptionOnConversion {
|
||||||
|
operator T() const { // NOLINT
|
||||||
|
throw ConversionException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forces a variant into the valueless by exception state.
|
||||||
|
void ToValuelessByException(ThrowingVariant& v) { // NOLINT
|
||||||
|
try {
|
||||||
|
v.emplace<Thrower>();
|
||||||
|
v.emplace<Thrower>(ExceptionOnConversion<Thrower>());
|
||||||
|
} catch (ConversionException& /*e*/) {
|
||||||
|
// This space intentionally left blank.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that variant is still in a usable state after an exception is thrown.
|
||||||
|
testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
|
||||||
|
using testing::AssertionFailure;
|
||||||
|
using testing::AssertionSuccess;
|
||||||
|
|
||||||
|
// Try using the active alternative
|
||||||
|
if (absl::holds_alternative<Thrower>(*v)) {
|
||||||
|
auto& t = absl::get<Thrower>(*v);
|
||||||
|
t = Thrower{-100};
|
||||||
|
if (t.Get() != -100) {
|
||||||
|
return AssertionFailure() << "Thrower should be assigned -100";
|
||||||
|
}
|
||||||
|
} else if (absl::holds_alternative<ThrowerVec>(*v)) {
|
||||||
|
auto& tv = absl::get<ThrowerVec>(*v);
|
||||||
|
tv.clear();
|
||||||
|
tv.emplace_back(-100);
|
||||||
|
if (tv.size() != 1 || tv[0].Get() != -100) {
|
||||||
|
return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}";
|
||||||
|
}
|
||||||
|
} else if (absl::holds_alternative<CopyNothrow>(*v)) {
|
||||||
|
auto& t = absl::get<CopyNothrow>(*v);
|
||||||
|
t = CopyNothrow{-100};
|
||||||
|
if (t.Get() != -100) {
|
||||||
|
return AssertionFailure() << "CopyNothrow should be assigned -100";
|
||||||
|
}
|
||||||
|
} else if (absl::holds_alternative<MoveNothrow>(*v)) {
|
||||||
|
auto& t = absl::get<MoveNothrow>(*v);
|
||||||
|
t = MoveNothrow{-100};
|
||||||
|
if (t.Get() != -100) {
|
||||||
|
return AssertionFailure() << "MoveNothrow should be assigned -100";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try making variant valueless_by_exception
|
||||||
|
if (!v->valueless_by_exception()) ToValuelessByException(*v);
|
||||||
|
if (!v->valueless_by_exception()) {
|
||||||
|
return AssertionFailure() << "Variant should be valueless_by_exception";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
auto unused = absl::get<Thrower>(*v);
|
||||||
|
static_cast<void>(unused);
|
||||||
|
return AssertionFailure() << "Variant should not contain Thrower";
|
||||||
|
} catch (absl::bad_variant_access) {
|
||||||
|
} catch (...) {
|
||||||
|
return AssertionFailure() << "Unexpected exception throw from absl::get";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using the variant
|
||||||
|
v->emplace<Thrower>(100);
|
||||||
|
if (!absl::holds_alternative<Thrower>(*v) ||
|
||||||
|
absl::get<Thrower>(*v) != Thrower(100)) {
|
||||||
|
return AssertionFailure() << "Variant should contain Thrower(100)";
|
||||||
|
}
|
||||||
|
v->emplace<ThrowerVec>({Thrower(100)});
|
||||||
|
if (!absl::holds_alternative<ThrowerVec>(*v) ||
|
||||||
|
absl::get<ThrowerVec>(*v)[0] != Thrower(100)) {
|
||||||
|
return AssertionFailure()
|
||||||
|
<< "Variant should contain ThrowerVec{Thrower(100)}";
|
||||||
|
}
|
||||||
|
return AssertionSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Thrower ExpectedThrower() { return Thrower(42); }
|
||||||
|
ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
|
||||||
|
ThrowingVariant ValuelessByException() {
|
||||||
|
ThrowingVariant v;
|
||||||
|
ToValuelessByException(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
ThrowingVariant WithThrower() { return Thrower(39); }
|
||||||
|
ThrowingVariant WithThrowerVec() {
|
||||||
|
return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)};
|
||||||
|
}
|
||||||
|
ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); }
|
||||||
|
ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); }
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, DefaultConstructor) {
|
||||||
|
TestThrowingCtor<ThrowingVariant>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, CopyConstructor) {
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ExpectedThrower());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ExpectedThrowerVec());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(v);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ValuelessByException());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, MoveConstructor) {
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ExpectedThrower());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(std::move(v));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ExpectedThrowerVec());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(std::move(v));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingVariant v(ValuelessByException());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(std::move(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, ValueConstructor) {
|
||||||
|
TestThrowingCtor<ThrowingVariant>(ExpectedThrower());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) {
|
||||||
|
TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{},
|
||||||
|
ExpectedThrower());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{},
|
||||||
|
ExpectedThrowerVec());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) {
|
||||||
|
TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{},
|
||||||
|
ExpectedThrower());
|
||||||
|
TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{},
|
||||||
|
ExpectedThrowerVec());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, CopyAssign) {
|
||||||
|
// variant& operator=(const variant& rhs);
|
||||||
|
// Let j be rhs.index()
|
||||||
|
{
|
||||||
|
// - neither *this nor rhs holds a value
|
||||||
|
const ThrowingVariant rhs = ValuelessByException();
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(ValuelessByException())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// - *this holds a value but rhs does not
|
||||||
|
const ThrowingVariant rhs = ValuelessByException();
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
// - index() == j
|
||||||
|
{
|
||||||
|
const ThrowingVariant rhs(ExpectedThrower());
|
||||||
|
auto tester =
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
|
||||||
|
EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
|
||||||
|
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const ThrowingVariant rhs(ExpectedThrowerVec());
|
||||||
|
auto tester =
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrowerVec())
|
||||||
|
.WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
|
||||||
|
EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test());
|
||||||
|
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
// libstdc++ std::variant has bugs on copy assignment regarding exception
|
||||||
|
// safety.
|
||||||
|
#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
|
||||||
|
// index() != j
|
||||||
|
// if is_nothrow_copy_constructible_v<Tj> or
|
||||||
|
// !is_nothrow_move_constructible<Tj> is true, equivalent to
|
||||||
|
// emplace<j>(get<j>(rhs))
|
||||||
|
{
|
||||||
|
// is_nothrow_copy_constructible_v<Tj> == true
|
||||||
|
// should not throw because emplace() invokes Tj's copy ctor
|
||||||
|
// which should not throw.
|
||||||
|
const ThrowingVariant rhs(CopyNothrow{});
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// is_nothrow_copy_constructible<Tj> == false &&
|
||||||
|
// is_nothrow_move_constructible<Tj> == false
|
||||||
|
// should provide basic guarantee because emplace() invokes Tj's copy ctor
|
||||||
|
// which may throw.
|
||||||
|
const ThrowingVariant rhs(ExpectedThrower());
|
||||||
|
auto tester =
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithCopyNoThrow())
|
||||||
|
.WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
|
||||||
|
EXPECT_TRUE(tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
|
||||||
|
{
|
||||||
|
// is_nothrow_copy_constructible_v<Tj> == false &&
|
||||||
|
// is_nothrow_move_constructible_v<Tj> == true
|
||||||
|
// should provide strong guarantee because it is equivalent to
|
||||||
|
// operator=(variant(rhs)) which creates a temporary then invoke the move
|
||||||
|
// ctor which shouldn't throw.
|
||||||
|
const ThrowingVariant rhs(MoveNothrow{});
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(CheckInvariants, strong_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, MoveAssign) {
|
||||||
|
// variant& operator=(variant&& rhs);
|
||||||
|
// Let j be rhs.index()
|
||||||
|
{
|
||||||
|
// - neither *this nor rhs holds a value
|
||||||
|
ThrowingVariant rhs = ValuelessByException();
|
||||||
|
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(ValuelessByException())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// - *this holds a value but rhs does not
|
||||||
|
ThrowingVariant rhs = ValuelessByException();
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// - index() == j
|
||||||
|
// assign get<j>(std::move(rhs)) to the value contained in *this.
|
||||||
|
// If an exception is thrown during call to Tj's move assignment, the state
|
||||||
|
// of the contained value is as defined by the exception safety guarantee of
|
||||||
|
// Tj's move assignment; index() will be j.
|
||||||
|
ThrowingVariant rhs(ExpectedThrower());
|
||||||
|
size_t j = rhs.index();
|
||||||
|
// Since Thrower's move assignment has basic guarantee, so should variant's.
|
||||||
|
auto tester = MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithOperation([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
});
|
||||||
|
EXPECT_TRUE(tester
|
||||||
|
.WithInvariants(
|
||||||
|
CheckInvariants,
|
||||||
|
[j](ThrowingVariant* lhs) { return lhs->index() == j; })
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// - otherwise (index() != j), equivalent to
|
||||||
|
// emplace<j>(get<j>(std::move(rhs)))
|
||||||
|
// - If an exception is thrown during the call to Tj's move construction
|
||||||
|
// (with j being rhs.index()), the variant will hold no value.
|
||||||
|
ThrowingVariant rhs(CopyNothrow{});
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, ValueAssign) {
|
||||||
|
// template<class T> variant& operator=(T&& t);
|
||||||
|
// Let Tj be the type that is selected by overload resolution to be assigned.
|
||||||
|
{
|
||||||
|
// If *this holds a Tj, assigns std::forward<T>(t) to the value contained in
|
||||||
|
// *this. If an exception is thrown during the assignment of
|
||||||
|
// std::forward<T>(t) to the value contained in *this, the state of the
|
||||||
|
// contained value and t are as defined by the exception safety guarantee of
|
||||||
|
// the assignment expression; valueless_by_exception() will be false.
|
||||||
|
// Since Thrower's copy/move assignment has basic guarantee, so should
|
||||||
|
// variant's.
|
||||||
|
Thrower rhs = ExpectedThrower();
|
||||||
|
// copy assign
|
||||||
|
auto copy_tester =
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; });
|
||||||
|
EXPECT_TRUE(copy_tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return !lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
// move assign
|
||||||
|
auto move_tester = MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithOperation([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
});
|
||||||
|
EXPECT_TRUE(move_tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return !lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
|
||||||
|
EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
// Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj,
|
||||||
|
// T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to
|
||||||
|
// emplace<j>(std::forward<T>(t)).
|
||||||
|
// We simplify the test by letting T = `const Tj&` or `Tj&&`, so we can reuse
|
||||||
|
// the CopyNothrow and MoveNothrow types.
|
||||||
|
|
||||||
|
// if is_nothrow_constructible_v<Tj, T>
|
||||||
|
// (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just
|
||||||
|
// invokes the copy/move constructor and it should not throw.
|
||||||
|
{
|
||||||
|
const CopyNothrow rhs;
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
MoveNothrow rhs;
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
// if is_nothrow_constructible_v<Tj, T> == false &&
|
||||||
|
// is_nothrow_move_constructible<Tj> == false
|
||||||
|
// emplace() invokes the copy/move constructor which may throw so it should
|
||||||
|
// provide basic guarantee and variant object might not hold a value.
|
||||||
|
{
|
||||||
|
Thrower rhs = ExpectedThrower();
|
||||||
|
// copy
|
||||||
|
auto copy_tester =
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithCopyNoThrow())
|
||||||
|
.WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; });
|
||||||
|
EXPECT_TRUE(copy_tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
// move
|
||||||
|
auto move_tester = MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithCopyNoThrow())
|
||||||
|
.WithOperation([rhs](ThrowingVariant* lhs) mutable {
|
||||||
|
*lhs = std::move(rhs);
|
||||||
|
});
|
||||||
|
EXPECT_TRUE(move_tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* lhs) {
|
||||||
|
return lhs->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
// Otherwise (if is_nothrow_constructible_v<Tj, T> == false &&
|
||||||
|
// is_nothrow_move_constructible<Tj> == true),
|
||||||
|
// equivalent to operator=(variant(std::forward<T>(t)))
|
||||||
|
// This should have strong guarantee because it creates a temporary variant
|
||||||
|
// and operator=(variant&&) invokes Tj's move ctor which doesn't throw.
|
||||||
|
// libstdc++ std::variant has bugs on conversion assignment regarding
|
||||||
|
// exception safety.
|
||||||
|
#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
|
||||||
|
{
|
||||||
|
MoveNothrow rhs;
|
||||||
|
EXPECT_TRUE(MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(CheckInvariants, strong_guarantee)
|
||||||
|
.Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
|
||||||
|
}
|
||||||
|
#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__))
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, Emplace) {
|
||||||
|
// If an exception during the initialization of the contained value, the
|
||||||
|
// variant might not hold a value. The standard requires emplace() to provide
|
||||||
|
// only basic guarantee.
|
||||||
|
{
|
||||||
|
Thrower args = ExpectedThrower();
|
||||||
|
auto tester = MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithOperation([&args](ThrowingVariant* v) {
|
||||||
|
v->emplace<Thrower>(args);
|
||||||
|
});
|
||||||
|
EXPECT_TRUE(tester
|
||||||
|
.WithInvariants(CheckInvariants,
|
||||||
|
[](ThrowingVariant* v) {
|
||||||
|
return v->valueless_by_exception();
|
||||||
|
})
|
||||||
|
.Test());
|
||||||
|
EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(VariantExceptionSafetyTest, Swap) {
|
||||||
|
// if both are valueless_by_exception(), no effect
|
||||||
|
{
|
||||||
|
ThrowingVariant rhs = ValuelessByException();
|
||||||
|
EXPECT_TRUE(
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(ValuelessByException())
|
||||||
|
.WithInvariants(nothrow_guarantee)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
|
||||||
|
}
|
||||||
|
// if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
|
||||||
|
// where i is index().
|
||||||
|
{
|
||||||
|
ThrowingVariant rhs = ExpectedThrower();
|
||||||
|
EXPECT_TRUE(
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithThrower())
|
||||||
|
.WithInvariants(CheckInvariants)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
|
||||||
|
}
|
||||||
|
// Otherwise, exchanges the value of rhs and *this. The exception safety
|
||||||
|
// involves variant in moved-from state which is not specified in the
|
||||||
|
// standard, and since swap is 3-step it's impossible for it to provide a
|
||||||
|
// overall strong guarantee. So, we are only checking basic guarantee here.
|
||||||
|
{
|
||||||
|
ThrowingVariant rhs = ExpectedThrower();
|
||||||
|
EXPECT_TRUE(
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithCopyNoThrow())
|
||||||
|
.WithInvariants(CheckInvariants)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ThrowingVariant rhs = ExpectedThrower();
|
||||||
|
EXPECT_TRUE(
|
||||||
|
MakeExceptionSafetyTester()
|
||||||
|
.WithInitialValue(WithCopyNoThrow())
|
||||||
|
.WithInvariants(CheckInvariants)
|
||||||
|
.Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace absl
|
||||||
@ -119,19 +119,9 @@ struct ConversionException {};
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct ExceptionOnConversion {
|
struct ExceptionOnConversion {
|
||||||
// Suppress MSVC 2017 warning "noreturn function has a non-void return type".
|
operator T() const { // NOLINT(runtime/explicit)
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable : 4646)
|
|
||||||
#endif // _MSC_VER
|
|
||||||
|
|
||||||
[[noreturn]] operator T() const { // NOLINT(runtime/explicit)
|
|
||||||
throw ConversionException();
|
throw ConversionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif // _MSC_VER
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forces a variant into the valueless by exception state.
|
// Forces a variant into the valueless by exception state.
|
||||||
|
|||||||
@ -22,6 +22,8 @@ list(APPEND UTILITY_PUBLIC_HEADERS
|
|||||||
absl_header_library(
|
absl_header_library(
|
||||||
TARGET
|
TARGET
|
||||||
absl_utility
|
absl_utility
|
||||||
|
PUBLIC_LIBRARIES
|
||||||
|
absl::base
|
||||||
EXPORT_NAME
|
EXPORT_NAME
|
||||||
utility
|
utility
|
||||||
)
|
)
|
||||||
@ -33,7 +35,12 @@ absl_header_library(
|
|||||||
|
|
||||||
# test utility_test
|
# test utility_test
|
||||||
set(UTILITY_TEST_SRC "utility_test.cc")
|
set(UTILITY_TEST_SRC "utility_test.cc")
|
||||||
set(UTILITY_TEST_PUBLIC_LIBRARIES absl::utility)
|
set(UTILITY_TEST_PUBLIC_LIBRARIES
|
||||||
|
absl::base
|
||||||
|
absl::memory
|
||||||
|
absl::strings
|
||||||
|
absl::utility
|
||||||
|
)
|
||||||
|
|
||||||
absl_test(
|
absl_test(
|
||||||
TARGET
|
TARGET
|
||||||
|
|||||||
22
third_party/abseil-cpp/absl/utility/utility.h
vendored
22
third_party/abseil-cpp/absl/utility/utility.h
vendored
@ -24,6 +24,7 @@
|
|||||||
// * make_index_sequence<N> == std::make_index_sequence<N>
|
// * make_index_sequence<N> == std::make_index_sequence<N>
|
||||||
// * index_sequence_for<Ts...> == std::index_sequence_for<Ts...>
|
// * index_sequence_for<Ts...> == std::index_sequence_for<Ts...>
|
||||||
// * apply<Functor, Tuple> == std::apply<Functor, Tuple>
|
// * apply<Functor, Tuple> == std::apply<Functor, Tuple>
|
||||||
|
// * exchange<T> == std::exchange<T>
|
||||||
//
|
//
|
||||||
// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
|
// This header file also provides the tag types `in_place_t`, `in_place_type_t`,
|
||||||
// and `in_place_index_t`, as well as the constant `in_place`, and
|
// and `in_place_index_t`, as well as the constant `in_place`, and
|
||||||
@ -264,6 +265,27 @@ auto apply(Functor&& functor, Tuple&& t)
|
|||||||
absl::make_index_sequence<std::tuple_size<
|
absl::make_index_sequence<std::tuple_size<
|
||||||
typename std::remove_reference<Tuple>::type>::value>{});
|
typename std::remove_reference<Tuple>::type>::value>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exchange
|
||||||
|
//
|
||||||
|
// Replaces the value of `obj` with `new_value` and returns the old value of
|
||||||
|
// `obj`. `absl::exchange` is designed to be a drop-in replacement for C++14's
|
||||||
|
// `std::exchange`.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// Foo& operator=(Foo&& other) {
|
||||||
|
// ptr1_ = absl::exchange(other.ptr1_, nullptr);
|
||||||
|
// int1_ = absl::exchange(other.int1_, -1);
|
||||||
|
// return *this;
|
||||||
|
// }
|
||||||
|
template <typename T, typename U = T>
|
||||||
|
T exchange(T& obj, U&& new_value) {
|
||||||
|
T old_value = absl::move(obj);
|
||||||
|
obj = absl::forward<U>(new_value);
|
||||||
|
return old_value;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
#endif // ABSL_UTILITY_UTILITY_H_
|
#endif // ABSL_UTILITY_UTILITY_H_
|
||||||
|
|||||||
@ -333,5 +333,13 @@ TEST(ApplyTest, FlipFlop) {
|
|||||||
EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj)));
|
EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ExchangeTest, MoveOnly) {
|
||||||
|
auto a = Factory(1);
|
||||||
|
EXPECT_EQ(1, *a);
|
||||||
|
auto b = absl::exchange(a, Factory(2));
|
||||||
|
EXPECT_EQ(2, *a);
|
||||||
|
EXPECT_EQ(1, *b);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
'<(DEPTH)/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp:*',
|
'<(DEPTH)/chrome/browser/resources/chromeos/select_to_speak/compiled_resources2.gyp:*',
|
||||||
'<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*',
|
'<(DEPTH)/chrome/browser/resources/chromeos/switch_access/compiled_resources2.gyp:*',
|
||||||
'<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*',
|
'<(DEPTH)/chrome/browser/resources/chromeos/sys_internals/compiled_resources2.gyp:*',
|
||||||
'<(DEPTH)/chrome/browser/resources/ntp4/compiled_resources2.gyp:*',
|
|
||||||
'<(DEPTH)/ui/webui/resources/cr_components/compiled_resources2.gyp:*',
|
'<(DEPTH)/ui/webui/resources/cr_components/compiled_resources2.gyp:*',
|
||||||
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
|
'<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:*',
|
||||||
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*',
|
'<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:*',
|
||||||
|
|||||||
3
third_party/closure_compiler/externs/OWNERS
vendored
3
third_party/closure_compiler/externs/OWNERS
vendored
@ -1,3 +1,6 @@
|
|||||||
michaelpg@chromium.org
|
michaelpg@chromium.org
|
||||||
rdevlin.cronin@chromium.org
|
rdevlin.cronin@chromium.org
|
||||||
stevenjb@chromium.org
|
stevenjb@chromium.org
|
||||||
|
|
||||||
|
per-file accessibility_private.js=file://ui/accessibility/OWNERS
|
||||||
|
per-file automation.js=file://ui/accessibility/OWNERS
|
||||||
|
|||||||
@ -285,6 +285,7 @@ chrome.automation.StateType = {
|
|||||||
*/
|
*/
|
||||||
chrome.automation.ActionType = {
|
chrome.automation.ActionType = {
|
||||||
BLUR: 'blur',
|
BLUR: 'blur',
|
||||||
|
CLEAR_ACCESSIBILITY_FOCUS: 'clearAccessibilityFocus',
|
||||||
CUSTOM_ACTION: 'customAction',
|
CUSTOM_ACTION: 'customAction',
|
||||||
DECREMENT: 'decrement',
|
DECREMENT: 'decrement',
|
||||||
DO_DEFAULT: 'doDefault',
|
DO_DEFAULT: 'doDefault',
|
||||||
@ -302,6 +303,7 @@ chrome.automation.ActionType = {
|
|||||||
SCROLL_TO_MAKE_VISIBLE: 'scrollToMakeVisible',
|
SCROLL_TO_MAKE_VISIBLE: 'scrollToMakeVisible',
|
||||||
SCROLL_TO_POINT: 'scrollToPoint',
|
SCROLL_TO_POINT: 'scrollToPoint',
|
||||||
SCROLL_UP: 'scrollUp',
|
SCROLL_UP: 'scrollUp',
|
||||||
|
SET_ACCESSIBILITY_FOCUS: 'setAccessibilityFocus',
|
||||||
SET_SCROLL_OFFSET: 'setScrollOffset',
|
SET_SCROLL_OFFSET: 'setScrollOffset',
|
||||||
SET_SELECTION: 'setSelection',
|
SET_SELECTION: 'setSelection',
|
||||||
SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT: 'setSequentialFocusNavigationStartingPoint',
|
SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT: 'setSequentialFocusNavigationStartingPoint',
|
||||||
|
|||||||
2
third_party/opus/README.chromium
vendored
2
third_party/opus/README.chromium
vendored
@ -16,3 +16,5 @@ Local changes:
|
|||||||
* set 'x' flags: "chmod 750 win32/genversion.bat"
|
* set 'x' flags: "chmod 750 win32/genversion.bat"
|
||||||
* Apply https://git.xiph.org/?p=opus.git;a=commitdiff;h=46560534fcb5710a894a341c2f9526db58fd7087#patch1
|
* Apply https://git.xiph.org/?p=opus.git;a=commitdiff;h=46560534fcb5710a894a341c2f9526db58fd7087#patch1
|
||||||
* Apply https://github.com/xiph/opus/pull/73
|
* Apply https://github.com/xiph/opus/pull/73
|
||||||
|
* Apply https://github.com/xiph/opus/pull/87
|
||||||
|
* Make sure HB_gain is not NaN in an attempt to fix chromium:826914
|
||||||
|
|||||||
3
third_party/opus/src/silk/API.h
vendored
3
third_party/opus/src/silk/API.h
vendored
@ -80,7 +80,8 @@ opus_int silk_Encode( /* O Returns error co
|
|||||||
opus_int nSamplesIn, /* I Number of samples in input vector */
|
opus_int nSamplesIn, /* I Number of samples in input vector */
|
||||||
ec_enc *psRangeEnc, /* I/O Compressor data structure */
|
ec_enc *psRangeEnc, /* I/O Compressor data structure */
|
||||||
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
|
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
|
||||||
const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
|
const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
|
||||||
|
int activity /* I Decision of Opus voice activity detector */
|
||||||
);
|
);
|
||||||
|
|
||||||
/****************************************/
|
/****************************************/
|
||||||
|
|||||||
5
third_party/opus/src/silk/define.h
vendored
5
third_party/opus/src/silk/define.h
vendored
@ -58,6 +58,11 @@ extern "C"
|
|||||||
#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
|
#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
|
||||||
#define DTX_ACTIVITY_THRESHOLD 0.1f
|
#define DTX_ACTIVITY_THRESHOLD 0.1f
|
||||||
|
|
||||||
|
/* VAD decision */
|
||||||
|
#define VAD_NO_DECISION -1
|
||||||
|
#define VAD_NO_ACTIVITY 0
|
||||||
|
#define VAD_ACTIVITY 1
|
||||||
|
|
||||||
/* Maximum sampling frequency */
|
/* Maximum sampling frequency */
|
||||||
#define MAX_FS_KHZ 16
|
#define MAX_FS_KHZ 16
|
||||||
#define MAX_API_FS_KHZ 48
|
#define MAX_API_FS_KHZ 48
|
||||||
|
|||||||
7
third_party/opus/src/silk/enc_API.c
vendored
7
third_party/opus/src/silk/enc_API.c
vendored
@ -144,7 +144,8 @@ opus_int silk_Encode( /* O Returns error co
|
|||||||
opus_int nSamplesIn, /* I Number of samples in input vector */
|
opus_int nSamplesIn, /* I Number of samples in input vector */
|
||||||
ec_enc *psRangeEnc, /* I/O Compressor data structure */
|
ec_enc *psRangeEnc, /* I/O Compressor data structure */
|
||||||
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
|
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
|
||||||
const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
|
const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
|
||||||
|
opus_int activity /* I Decision of Opus voice activity detector */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
|
opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
|
||||||
@ -425,7 +426,7 @@ opus_int silk_Encode( /* O Returns error co
|
|||||||
psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
|
psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
|
||||||
psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
|
psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
|
||||||
}
|
}
|
||||||
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] );
|
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity );
|
||||||
} else {
|
} else {
|
||||||
psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
|
psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
|
||||||
}
|
}
|
||||||
@ -440,7 +441,7 @@ opus_int silk_Encode( /* O Returns error co
|
|||||||
silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
|
silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
|
||||||
silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
|
silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
|
||||||
}
|
}
|
||||||
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] );
|
silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity );
|
||||||
|
|
||||||
/* Encode */
|
/* Encode */
|
||||||
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
|
for( n = 0; n < encControl->nChannelsInternal; n++ ) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user