Commit b56cbdd2 by Abseil Team Committed by Derek Mauro

Abseil LTS b56cbdd2

What's New:
* `absl::StatusOr<T>` has been released. See our [blog
  post](https://abseil.io/blog/2020-091021-status) for more
  information.
* Abseil Flags reflection interfaces have been released.
* Abseil Flags memory usage has been significantly optimized.
* Abseil now supports a "hardened" build mode. This build mode enables
  runtime checks that guard against programming errors that may lead
  to security vulnerabilities.

Notable Fixes:
* Sanitizer dynamic annotations like `AnnotateRWLockCreate` that are
  also defined by the compiler sanitizer implementation are no longer
  also defined by Abseil.
* Sanitizer macros are now prefixed with `ABSL_` to avoid naming collisions.
* Sanitizer usage is now automatically detected and no longer requires
  macros like `ADDRESS_SANITIZER` to be defined on the command line.

Breaking Changes:
* Abseil no longer contains a `dynamic_annotations` library. Users
  using a supported build system (Bazel or CMake) are unaffected by
  this, but users manually specifying link libraries may get an error
  about a missing linker input.

Baseline: 7680a5f8
Cherry picks: None
parent b832dce8
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
Include a clear and concise description of what the problem is, including what
you expected to happen, and what actually happened.
**Steps to reproduce the bug**
It's important that we are able to reproduce the problem that you are
experiencing. Please provide all code and relevant steps to reproduce the
problem, including your `BUILD`/`CMakeLists.txt` file and build commands. Links
to a GitHub branch or [godbolt.org](https://godbolt.org/) that demonstrate the
problem are also helpful.
**What version of Abseil are you using?**
**What operating system and version are you using**
If you are using a Linux distribution please include the name and version of the
distribution as well.
**What compiler and version are you using?**
Please include the output of `gcc -v` or `clang -v`, or the equivalent for your
compiler.
**What build system are you using?**
Please include the output of `bazel --version` or `cmake --version`, or the
equivalent for your build system.
**Additional context**
Add any other context about the problem here.
---
name: Question
about: Have a question? Ask us anything! :-)
title: ''
labels: 'question'
assignees: ''
---
blank_issues_enables: true
#
# Copyright 2020 The Abseil Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0
# Expose license for external usage through bazel.
exports_files([
"AUTHORS",
"LICENSE",
])
...@@ -8,17 +8,18 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -8,17 +8,18 @@ set(ABSL_INTERNAL_DLL_FILES
"base/casts.h" "base/casts.h"
"base/config.h" "base/config.h"
"base/const_init.h" "base/const_init.h"
"base/dynamic_annotations.cc"
"base/dynamic_annotations.h" "base/dynamic_annotations.h"
"base/internal/atomic_hook.h" "base/internal/atomic_hook.h"
"base/internal/bits.h" "base/internal/bits.h"
"base/internal/cycleclock.cc" "base/internal/cycleclock.cc"
"base/internal/cycleclock.h" "base/internal/cycleclock.h"
"base/internal/direct_mmap.h" "base/internal/direct_mmap.h"
"base/internal/dynamic_annotations.h"
"base/internal/endian.h" "base/internal/endian.h"
"base/internal/errno_saver.h" "base/internal/errno_saver.h"
"base/internal/exponential_biased.cc" "base/internal/exponential_biased.cc"
"base/internal/exponential_biased.h" "base/internal/exponential_biased.h"
"base/internal/fast_type_id.h"
"base/internal/hide_ptr.h" "base/internal/hide_ptr.h"
"base/internal/identity.h" "base/internal/identity.h"
"base/internal/invoke.h" "base/internal/invoke.h"
...@@ -35,6 +36,8 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -35,6 +36,8 @@ set(ABSL_INTERNAL_DLL_FILES
"base/internal/scheduling_mode.h" "base/internal/scheduling_mode.h"
"base/internal/scoped_set_env.cc" "base/internal/scoped_set_env.cc"
"base/internal/scoped_set_env.h" "base/internal/scoped_set_env.h"
"base/internal/strerror.h"
"base/internal/strerror.cc"
"base/internal/spinlock.cc" "base/internal/spinlock.cc"
"base/internal/spinlock.h" "base/internal/spinlock.h"
"base/internal/spinlock_wait.cc" "base/internal/spinlock_wait.cc"
...@@ -128,18 +131,16 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -128,18 +131,16 @@ set(ABSL_INTERNAL_DLL_FILES
"random/bit_gen_ref.h" "random/bit_gen_ref.h"
"random/discrete_distribution.cc" "random/discrete_distribution.cc"
"random/discrete_distribution.h" "random/discrete_distribution.h"
"random/distribution_format_traits.h"
"random/distributions.h" "random/distributions.h"
"random/exponential_distribution.h" "random/exponential_distribution.h"
"random/gaussian_distribution.cc" "random/gaussian_distribution.cc"
"random/gaussian_distribution.h" "random/gaussian_distribution.h"
"random/internal/distributions.h"
"random/internal/distribution_caller.h" "random/internal/distribution_caller.h"
"random/internal/fast_uniform_bits.h"
"random/internal/fastmath.h" "random/internal/fastmath.h"
"random/internal/gaussian_distribution_gentables.cc" "random/internal/fast_uniform_bits.h"
"random/internal/generate_real.h" "random/internal/generate_real.h"
"random/internal/iostream_state_saver.h" "random/internal/iostream_state_saver.h"
"random/internal/mock_helpers.h"
"random/internal/nonsecure_base.h" "random/internal/nonsecure_base.h"
"random/internal/pcg_engine.h" "random/internal/pcg_engine.h"
"random/internal/platform.h" "random/internal/platform.h"
...@@ -152,6 +153,7 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -152,6 +153,7 @@ set(ABSL_INTERNAL_DLL_FILES
"random/internal/randen_engine.h" "random/internal/randen_engine.h"
"random/internal/randen_hwaes.cc" "random/internal/randen_hwaes.cc"
"random/internal/randen_hwaes.h" "random/internal/randen_hwaes.h"
"random/internal/randen_round_keys.cc"
"random/internal/randen_slow.cc" "random/internal/randen_slow.cc"
"random/internal/randen_slow.h" "random/internal/randen_slow.h"
"random/internal/randen_traits.h" "random/internal/randen_traits.h"
...@@ -172,8 +174,12 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -172,8 +174,12 @@ set(ABSL_INTERNAL_DLL_FILES
"random/uniform_int_distribution.h" "random/uniform_int_distribution.h"
"random/uniform_real_distribution.h" "random/uniform_real_distribution.h"
"random/zipf_distribution.h" "random/zipf_distribution.h"
"status/internal/status_internal.h"
"status/internal/statusor_internal.h"
"status/status.h" "status/status.h"
"status/status.cc" "status/status.cc"
"status/statusor.h"
"status/statusor.cc"
"status/status_payload_printer.h" "status/status_payload_printer.h"
"status/status_payload_printer.cc" "status/status_payload_printer.cc"
"strings/ascii.cc" "strings/ascii.cc"
...@@ -292,6 +298,8 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -292,6 +298,8 @@ set(ABSL_INTERNAL_DLL_FILES
"types/internal/conformance_aliases.h" "types/internal/conformance_aliases.h"
"types/internal/conformance_archetype.h" "types/internal/conformance_archetype.h"
"types/internal/conformance_profile.h" "types/internal/conformance_profile.h"
"types/internal/parentheses.h"
"types/internal/transform_args.h"
"types/internal/variant.h" "types/internal/variant.h"
"types/optional.h" "types/optional.h"
"types/internal/optional.h" "types/internal/optional.h"
......
...@@ -23,7 +23,9 @@ include(AbseilInstallDirs) ...@@ -23,7 +23,9 @@ include(AbseilInstallDirs)
# project that sets # project that sets
# set_property(GLOBAL PROPERTY USE_FOLDERS ON) # set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# For example, Visual Studio supports folders. # For example, Visual Studio supports folders.
set(ABSL_IDE_FOLDER Abseil) if(NOT DEFINED ABSL_IDE_FOLDER)
set(ABSL_IDE_FOLDER Abseil)
endif()
# absl_cc_library() # absl_cc_library()
# #
......
...@@ -10,11 +10,11 @@ if(absl_VERSION) ...@@ -10,11 +10,11 @@ if(absl_VERSION)
set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}") set(ABSL_SUBDIR "${PROJECT_NAME}_${PROJECT_VERSION}")
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}") set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}") set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${ABSL_SUBDIR}")
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/{ABSL_SUBDIR}") set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/${ABSL_SUBDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}") set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/${ABSL_SUBDIR}")
else() else()
set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}") set(ABSL_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") set(ABSL_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}") set(ABSL_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}")
set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") set(ABSL_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
endif() endif()
\ No newline at end of file
cmake_minimum_required(VERSION 2.8.2) cmake_minimum_required(VERSION 2.8.2)
project(googletest-download NONE) project(googletest-external NONE)
include(ExternalProject) include(ExternalProject)
ExternalProject_Add(googletest if(${ABSL_USE_GOOGLETEST_HEAD})
GIT_REPOSITORY https://github.com/google/googletest.git ExternalProject_Add(googletest
GIT_TAG master GIT_REPOSITORY https://github.com/google/googletest.git
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" GIT_TAG master
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" SOURCE_DIR "${absl_gtest_src_dir}"
CONFIGURE_COMMAND "" BINARY_DIR "${absl_gtest_build_dir}"
BUILD_COMMAND "" CONFIGURE_COMMAND ""
INSTALL_COMMAND "" BUILD_COMMAND ""
TEST_COMMAND "" INSTALL_COMMAND ""
) TEST_COMMAND ""
\ No newline at end of file )
else()
ExternalProject_Add(googletest
SOURCE_DIR "${absl_gtest_src_dir}"
BINARY_DIR "${absl_gtest_build_dir}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
endif()
\ No newline at end of file
# Downloads and unpacks googletest at configure time. Based on the instructions # Integrates googletest at configure time. Based on the instructions at
# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project # https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project
# Download the latest googletest from Github master # Set up the external googletest project, downloading the latest from Github
# master if requested.
configure_file( configure_file(
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in
${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt ${CMAKE_BINARY_DIR}/googletest-external/CMakeLists.txt
) )
set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) set(ABSL_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
...@@ -14,17 +15,17 @@ if (BUILD_SHARED_LIBS) ...@@ -14,17 +15,17 @@ if (BUILD_SHARED_LIBS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_CREATE_SHARED_LIBRARY=1")
endif() endif()
# Configure and build the downloaded googletest source # Configure and build the googletest source.
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external )
if(result) if(result)
message(FATAL_ERROR "CMake step for googletest failed: ${result}") message(FATAL_ERROR "CMake step for googletest failed: ${result}")
endif() endif()
execute_process(COMMAND ${CMAKE_COMMAND} --build . execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-external)
if(result) if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}") message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif() endif()
...@@ -37,6 +38,4 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) ...@@ -37,6 +38,4 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest and gtest_main # Add googletest directly to our build. This defines the gtest and gtest_main
# targets. # targets.
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src add_subdirectory(${absl_gtest_src_dir} ${absl_gtest_build_dir} EXCLUDE_FROM_ALL)
${CMAKE_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
...@@ -93,7 +93,7 @@ absl::flags ...@@ -93,7 +93,7 @@ absl::flags
absl::memory absl::memory
absl::meta absl::meta
absl::numeric absl::numeric
absl::random absl::random_random
absl::strings absl::strings
absl::synchronization absl::synchronization
absl::time absl::time
......
# absl CMake configuration file. # absl CMake configuration file.
include(FindThreads) include(CMakeFindDependencyMacro)
find_dependency(Threads)
@PACKAGE_INIT@ @PACKAGE_INIT@
include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") include ("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
\ No newline at end of file
...@@ -22,13 +22,24 @@ ...@@ -22,13 +22,24 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# Compiler id for Apple Clang is now AppleClang. # Compiler id for Apple Clang is now AppleClang.
cmake_policy(SET CMP0025 NEW) if (POLICY CMP0025)
cmake_policy(SET CMP0025 NEW)
endif (POLICY CMP0025)
# if command can use IN_LIST # if command can use IN_LIST
cmake_policy(SET CMP0057 NEW) if (POLICY CMP0057)
cmake_policy(SET CMP0057 NEW)
endif (POLICY CMP0057)
# Project version variables are the empty std::string if version is unspecified # Project version variables are the empty string if version is unspecified
cmake_policy(SET CMP0048 NEW) if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW)
endif (POLICY CMP0048)
# option() honor variables
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif (POLICY CMP0077)
project(absl CXX) project(absl CXX)
...@@ -41,9 +52,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ...@@ -41,9 +52,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
# in the source tree of a project that uses it, install rules are disabled. # in the source tree of a project that uses it, install rules are disabled.
if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
set(ABSL_ENABLE_INSTALL FALSE) option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
else() else()
set(ABSL_ENABLE_INSTALL TRUE) option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
endif() endif()
list(APPEND CMAKE_MODULE_PATH list(APPEND CMAKE_MODULE_PATH
...@@ -81,25 +92,33 @@ endif() ...@@ -81,25 +92,33 @@ endif()
## pthread ## pthread
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
option(ABSL_USE_EXTERNAL_GOOGLETEST
"If ON, Abseil will assume that the targets for GoogleTest are already provided by the including project. This makes sense when Abseil is used with add_subproject." OFF)
option(ABSL_USE_GOOGLETEST_HEAD option(ABSL_USE_GOOGLETEST_HEAD
"If ON, abseil will download HEAD from googletest at config time." OFF) "If ON, abseil will download HEAD from googletest at config time." OFF)
set(ABSL_LOCAL_GOOGLETEST_DIR "/usr/src/googletest" CACHE PATH
"If ABSL_USE_GOOGLETEST_HEAD is OFF, specifies the directory of a local googletest checkout."
)
option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF) option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF)
if(${ABSL_RUN_TESTS}) if(${ABSL_RUN_TESTS})
# enable CTest. This will set BUILD_TESTING to ON unless otherwise specified # enable CTest. This will set BUILD_TESTING to ON unless otherwise specified
# on the command line # on the command line
include(CTest) include(CTest)
enable_testing()
endif()
## check targets ## check targets
if(BUILD_TESTING) if (NOT ABSL_USE_EXTERNAL_GOOGLETEST)
if(${ABSL_USE_GOOGLETEST_HEAD})
include(CMake/Googletest/DownloadGTest.cmake)
set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build) set(absl_gtest_build_dir ${CMAKE_BINARY_DIR}/googletest-build)
if(${ABSL_USE_GOOGLETEST_HEAD})
set(absl_gtest_src_dir ${CMAKE_BINARY_DIR}/googletest-src)
else()
set(absl_gtest_src_dir ${ABSL_LOCAL_GOOGLETEST_DIR})
endif()
include(CMake/Googletest/DownloadGTest.cmake)
endif() endif()
check_target(gtest) check_target(gtest)
...@@ -152,5 +171,7 @@ if(ABSL_ENABLE_INSTALL) ...@@ -152,5 +171,7 @@ if(ABSL_ENABLE_INSTALL)
FILES_MATCHING FILES_MATCHING
PATTERN "*.inc" PATTERN "*.inc"
PATTERN "*.h" PATTERN "*.h"
) PATTERN "copts" EXCLUDE
PATTERN "testdata" EXCLUDE
)
endif() # ABSL_ENABLE_INSTALL endif() # ABSL_ENABLE_INSTALL
...@@ -13,3 +13,4 @@ The following lists LTS branches and the dates on which they have been released: ...@@ -13,3 +13,4 @@ The following lists LTS branches and the dates on which they have been released:
* [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/) * [LTS Branch December 18, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_12_18/)
* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/) * [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/)
* [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/) * [LTS Branch August 8, 2019](https://github.com/abseil/abseil-cpp/tree/lts_2019_08_08/)
* [LTS Branch February 25, 2020](https://github.com/abseil/abseil-cpp/tree/lts_2020_02_25/)
...@@ -19,10 +19,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") ...@@ -19,10 +19,10 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# GoogleTest/GoogleMock framework. Used by most unit-tests. # GoogleTest/GoogleMock framework. Used by most unit-tests.
http_archive( http_archive(
name = "com_google_googletest", name = "com_google_googletest",
urls = ["https://github.com/google/googletest/archive/b6cd405286ed8635ece71c72f118e659f4ade3fb.zip"], # 2019-01-07 urls = ["https://github.com/google/googletest/archive/8567b09290fe402cf01923e2131c5635b8ed851b.zip"], # 2020-06-12T22:24:28Z
strip_prefix = "googletest-b6cd405286ed8635ece71c72f118e659f4ade3fb", strip_prefix = "googletest-8567b09290fe402cf01923e2131c5635b8ed851b",
sha256 = "ff7a82736e158c077e76188232eac77913a15dac0b22508c390ab3f88e6d6d86", sha256 = "9a8a166eb6a56c7b3d7b19dc2c946fe4778fd6f21c7a12368ad3b836d8f1be48",
) )
# Google benchmark. # Google benchmark.
...@@ -39,7 +39,6 @@ http_archive( ...@@ -39,7 +39,6 @@ http_archive(
sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d", sha256 = "9a446e9dd9c1bb180c86977a8dc1e9e659550ae732ae58bd2e8fd51e15b2c91d",
strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa", strip_prefix = "rules_cc-262ebec3c2296296526740db4aefce68c80de7fa",
urls = [ urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
"https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip", "https://github.com/bazelbuild/rules_cc/archive/262ebec3c2296296526740db4aefce68c80de7fa.zip",
], ],
) )
...@@ -21,7 +21,7 @@ load( ...@@ -21,7 +21,7 @@ load(
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"])
create_llvm_config( create_llvm_config(
name = "llvm_compiler", name = "llvm_compiler",
...@@ -44,9 +44,10 @@ config_setting( ...@@ -44,9 +44,10 @@ config_setting(
config_setting( config_setting(
name = "windows", name = "windows",
values = { constraint_values = [
"cpu": "x64_windows", "@bazel_tools//platforms:x86_64",
}, "@bazel_tools//platforms:windows",
],
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
...@@ -57,3 +58,11 @@ config_setting( ...@@ -57,3 +58,11 @@ config_setting(
}, },
visibility = [":__subpackages__"], visibility = [":__subpackages__"],
) )
config_setting(
name = "wasm",
values = {
"cpu": "wasm32",
},
visibility = [":__subpackages__"],
)
...@@ -24,14 +24,16 @@ load( ...@@ -24,14 +24,16 @@ load(
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"])
cc_library( cc_library(
name = "algorithm", name = "algorithm",
hdrs = ["algorithm.h"], hdrs = ["algorithm.h"],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = ["//absl/base:config"], deps = [
"//absl/base:config",
],
) )
cc_test( cc_test(
......
...@@ -943,9 +943,10 @@ void c_partial_sort( ...@@ -943,9 +943,10 @@ void c_partial_sort(
// c_partial_sort_copy() // c_partial_sort_copy()
// //
// Container-based version of the <algorithm> `std::partial_sort_copy()` // Container-based version of the <algorithm> `std::partial_sort_copy()`
// function to sort elements within a container such that elements before // function to sort the elements in the given range `result` within the larger
// `middle` are sorted in ascending order, and return the result within an // `sequence` in ascending order (and using `result` as the output parameter).
// iterator. // At most min(result.last - result.first, sequence.last - sequence.first)
// elements from the sequence will be stored in the result.
template <typename C, typename RandomAccessContainer> template <typename C, typename RandomAccessContainer>
container_algorithm_internal::ContainerIter<RandomAccessContainer> container_algorithm_internal::ContainerIter<RandomAccessContainer>
c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) {
......
...@@ -24,7 +24,7 @@ load( ...@@ -24,7 +24,7 @@ load(
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"])
cc_library( cc_library(
name = "atomic_hook", name = "atomic_hook",
...@@ -115,11 +115,18 @@ cc_library( ...@@ -115,11 +115,18 @@ cc_library(
cc_library( cc_library(
name = "dynamic_annotations", name = "dynamic_annotations",
srcs = ["dynamic_annotations.cc"], srcs = [
hdrs = ["dynamic_annotations.h"], "internal/dynamic_annotations.h",
],
hdrs = [
"dynamic_annotations.h",
],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"],
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":config",
":core_headers",
],
) )
cc_library( cc_library(
...@@ -154,6 +161,7 @@ cc_library( ...@@ -154,6 +161,7 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = select({ linkopts = select({
"//absl:windows": [], "//absl:windows": [],
"//absl:wasm": [],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS, }) + ABSL_DEFAULT_LINKOPTS,
visibility = [ visibility = [
...@@ -215,6 +223,7 @@ cc_library( ...@@ -215,6 +223,7 @@ cc_library(
"//absl:windows": [ "//absl:windows": [
"-DEFAULTLIB:advapi32.lib", "-DEFAULTLIB:advapi32.lib",
], ],
"//absl:wasm": [],
"//conditions:default": ["-pthread"], "//conditions:default": ["-pthread"],
}) + ABSL_DEFAULT_LINKOPTS, }) + ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
...@@ -307,6 +316,7 @@ cc_test( ...@@ -307,6 +316,7 @@ cc_test(
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":errno_saver", ":errno_saver",
":strerror",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
...@@ -405,6 +415,7 @@ cc_library( ...@@ -405,6 +415,7 @@ cc_library(
deps = [ deps = [
":base", ":base",
":base_internal", ":base_internal",
":config",
":core_headers", ":core_headers",
"//absl/synchronization", "//absl/synchronization",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
...@@ -421,6 +432,7 @@ cc_test( ...@@ -421,6 +432,7 @@ cc_test(
deps = [ deps = [
":base", ":base",
":base_internal", ":base_internal",
":config",
":core_headers", ":core_headers",
"//absl/synchronization", "//absl/synchronization",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
...@@ -451,6 +463,7 @@ cc_binary( ...@@ -451,6 +463,7 @@ cc_binary(
testonly = 1, testonly = 1,
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":spinlock_benchmark_common", ":spinlock_benchmark_common",
...@@ -539,7 +552,10 @@ cc_test( ...@@ -539,7 +552,10 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["no_test_ios_x86_64"], tags = ["no_test_ios_x86_64"],
deps = [":malloc_internal"], deps = [
":malloc_internal",
"//absl/container:node_hash_map",
],
) )
cc_test( cc_test(
...@@ -705,3 +721,98 @@ cc_test( ...@@ -705,3 +721,98 @@ cc_test(
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
cc_library(
name = "strerror",
srcs = ["internal/strerror.cc"],
hdrs = ["internal/strerror.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
":core_headers",
":errno_saver",
],
)
cc_test(
name = "strerror_test",
size = "small",
srcs = ["internal/strerror_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":strerror",
"//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_binary(
name = "strerror_benchmark",
testonly = 1,
srcs = ["internal/strerror_benchmark.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
tags = ["benchmark"],
visibility = ["//visibility:private"],
deps = [
":strerror",
"@com_github_google_benchmark//:benchmark_main",
],
)
cc_library(
name = "fast_type_id",
hdrs = ["internal/fast_type_id.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
visibility = [
"//absl:__subpackages__",
],
deps = [
":config",
],
)
cc_test(
name = "fast_type_id_test",
size = "small",
srcs = ["internal/fast_type_id_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":fast_type_id",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "unique_small_name_test",
size = "small",
srcs = ["internal/unique_small_name_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
linkstatic = 1,
deps = [
":core_headers",
"//absl/strings",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "optimization_test",
size = "small",
srcs = ["optimization_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":core_headers",
"//absl/types:optional",
"@com_google_googletest//:gtest_main",
],
)
...@@ -105,11 +105,11 @@ absl_cc_library( ...@@ -105,11 +105,11 @@ absl_cc_library(
HDRS HDRS
"dynamic_annotations.h" "dynamic_annotations.h"
SRCS SRCS
"dynamic_annotations.cc" "internal/dynamic_annotations.h"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEFINES DEPS
"__CLANG_SUPPORT_DYN_ANNOTATION__" absl::config
PUBLIC PUBLIC
) )
...@@ -191,7 +191,7 @@ absl_cc_library( ...@@ -191,7 +191,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
LINKOPTS LINKOPTS
${ABSL_DEFAULT_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS}
$<$<BOOL:${LIBRT}>:${LIBRT}> $<$<BOOL:${LIBRT}>:-lrt>
$<$<BOOL:${MINGW}>:"advapi32"> $<$<BOOL:${MINGW}>:"advapi32">
DEPS DEPS
absl::atomic_hook absl::atomic_hook
...@@ -326,6 +326,7 @@ absl_cc_test( ...@@ -326,6 +326,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::errno_saver absl::errno_saver
absl::strerror
gmock gmock
gtest_main gtest_main
) )
...@@ -383,6 +384,7 @@ absl_cc_library( ...@@ -383,6 +384,7 @@ absl_cc_library(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::base absl::base
absl::config
absl::base_internal absl::base_internal
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
...@@ -401,6 +403,7 @@ absl_cc_test( ...@@ -401,6 +403,7 @@ absl_cc_test(
DEPS DEPS
absl::base absl::base
absl::base_internal absl::base_internal
absl::config
absl::core_headers absl::core_headers
absl::synchronization absl::synchronization
gtest_main gtest_main
...@@ -496,6 +499,7 @@ absl_cc_test( ...@@ -496,6 +499,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::malloc_internal absl::malloc_internal
absl::node_hash_map
Threads::Threads Threads::Threads
) )
...@@ -642,3 +646,72 @@ absl_cc_test( ...@@ -642,3 +646,72 @@ absl_cc_test(
gmock gmock
gtest_main gtest_main
) )
absl_cc_library(
NAME
strerror
SRCS
"internal/strerror.cc"
HDRS
"internal/strerror.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
absl::core_headers
absl::errno_saver
)
absl_cc_test(
NAME
strerror_test
SRCS
"internal/strerror_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::strerror
absl::strings
gmock
gtest_main
)
absl_cc_library(
NAME
fast_type_id
HDRS
"internal/fast_type_id.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::config
)
absl_cc_test(
NAME
fast_type_id_test
SRCS
"internal/fast_type_id_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::fast_type_id
gtest_main
)
absl_cc_test(
NAME
optimization_test
SRCS
"optimization_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::core_headers
absl::optional
gtest_main
)
...@@ -32,34 +32,12 @@ ...@@ -32,34 +32,12 @@
// of them are not supported in older version of Clang. Thus, we check // of them are not supported in older version of Clang. Thus, we check
// `__has_attribute()` first. If the check fails, we check if we are on GCC and // `__has_attribute()` first. If the check fails, we check if we are on GCC and
// assume the attribute exists on GCC (which is verified on GCC 4.7). // assume the attribute exists on GCC (which is verified on GCC 4.7).
//
// -----------------------------------------------------------------------------
// Sanitizer Attributes
// -----------------------------------------------------------------------------
//
// Sanitizer-related attributes are not "defined" in this file (and indeed
// are not defined as such in any file). To utilize the following
// sanitizer-related attributes within your builds, define the following macros
// within your build using a `-D` flag, along with the given value for
// `-fsanitize`:
//
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
//
// Example:
//
// // Enable branches in the Abseil code that are tagged for ASan:
// $ 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
// for `__GNUC__` (GCC or Clang) and the above macros.
#ifndef ABSL_BASE_ATTRIBUTES_H_ #ifndef ABSL_BASE_ATTRIBUTES_H_
#define ABSL_BASE_ATTRIBUTES_H_ #define ABSL_BASE_ATTRIBUTES_H_
#include "absl/base/config.h"
// ABSL_HAVE_ATTRIBUTE // ABSL_HAVE_ATTRIBUTE
// //
// A function-like feature checking macro that is a wrapper around // A function-like feature checking macro that is a wrapper around
...@@ -234,7 +212,7 @@ ...@@ -234,7 +212,7 @@
// out of bounds or does other scary things with memory. // out of bounds or does other scary things with memory.
// NOTE: GCC supports AddressSanitizer(asan) since 4.8. // NOTE: GCC supports AddressSanitizer(asan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html // https://gcc.gnu.org/gcc-4.8/changes.html
#if defined(__GNUC__) #if ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else #else
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS #define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
...@@ -242,13 +220,13 @@ ...@@ -242,13 +220,13 @@
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
// //
// Tells the MemorySanitizer to relax the handling of a given function. All // Tells the MemorySanitizer to relax the handling of a given function. All "Use
// "Use of uninitialized value" warnings from such functions will be suppressed, // of uninitialized value" warnings from such functions will be suppressed, and
// and all values loaded from memory will be considered fully initialized. // all values loaded from memory will be considered fully initialized. This
// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals // attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
// with initialized-ness rather than addressability issues. // above, but deals with initialized-ness rather than addressability issues.
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC. // NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
#if defined(__clang__) #if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else #else
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY #define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
...@@ -259,7 +237,7 @@ ...@@ -259,7 +237,7 @@
// Tells the ThreadSanitizer to not instrument a given function. // Tells the ThreadSanitizer to not instrument a given function.
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8. // NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
// https://gcc.gnu.org/gcc-4.8/changes.html // https://gcc.gnu.org/gcc-4.8/changes.html
#if defined(__GNUC__) #if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else #else
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD #define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
...@@ -271,8 +249,10 @@ ...@@ -271,8 +249,10 @@
// where certain behavior (eg. division by zero) is being used intentionally. // where certain behavior (eg. division by zero) is being used intentionally.
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9. // NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
// https://gcc.gnu.org/gcc-4.9/changes.html // https://gcc.gnu.org/gcc-4.9/changes.html
#if defined(__GNUC__) && \ #if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER)) #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize_undefined))
#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ #define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined"))) __attribute__((no_sanitize("undefined")))
#else #else
...@@ -283,7 +263,7 @@ ...@@ -283,7 +263,7 @@
// //
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function. // Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. // See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY) #if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else #else
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI #define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
...@@ -293,7 +273,7 @@ ...@@ -293,7 +273,7 @@
// //
// Tells the SafeStack to not instrument a given function. // Tells the SafeStack to not instrument a given function.
// See https://clang.llvm.org/docs/SafeStack.html for details. // See https://clang.llvm.org/docs/SafeStack.html for details.
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER) #if ABSL_HAVE_ATTRIBUTE(no_sanitize)
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \ #define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
__attribute__((no_sanitize("safe-stack"))) __attribute__((no_sanitize("safe-stack")))
#else #else
...@@ -507,8 +487,10 @@ ...@@ -507,8 +487,10 @@
// packages/targets, as this may lead to conflicting definitions of functions at // packages/targets, as this may lead to conflicting definitions of functions at
// link-time. // link-time.
// //
// XRay isn't currently supported on Android:
// https://github.com/android/ndk/issues/368
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \ #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
!defined(ABSL_NO_XRAY_ATTRIBUTES) !defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] #define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] #define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args) #if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
...@@ -592,6 +574,85 @@ ...@@ -592,6 +574,85 @@
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) #define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif #endif
// ABSL_FALLTHROUGH_INTENDED
//
// Annotates implicit fall-through between switch labels, allowing a case to
// indicate intentional fallthrough and turn off warnings about any lack of a
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
// a semicolon and can be used in most places where `break` can, provided that
// no statements exist between it and the next switch label.
//
// Example:
//
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
// // in comments
// } else {
// return x;
// }
// case 42:
// ...
//
// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
// when performing switch labels fall-through diagnostic
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
// for details:
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
//
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
// has no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code.
#ifdef ABSL_FALLTHROUGH_INTENDED
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
#endif
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
#if defined(__clang__) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#endif
#elif defined(__GNUC__) && __GNUC__ >= 7
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#endif
#ifndef ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED \
do { \
} while (0)
#endif
// ABSL_DEPRECATED()
//
// Marks a deprecated class, struct, enum, function, method and variable
// declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative).
//
// Examples:
//
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
//
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
//
// template <typename T>
// ABSL_DEPRECATED("Use DoThat() instead")
// void DoThis();
//
// Every usage of a deprecated entity will trigger a warning when compiled with
// clang's `-Wdeprecated-declarations` option. This option is turned off by
// default, but the warnings will be reported by clang-tidy.
#if defined(__clang__) && __cplusplus >= 201103L
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#ifndef ABSL_DEPRECATED
#define ABSL_DEPRECATED(message)
#endif
// ABSL_CONST_INIT // ABSL_CONST_INIT
// //
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will // A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
......
...@@ -175,7 +175,7 @@ void CallOnceImpl(std::atomic<uint32_t>* control, ...@@ -175,7 +175,7 @@ void CallOnceImpl(std::atomic<uint32_t>* control,
std::memory_order_relaxed) || std::memory_order_relaxed) ||
base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans,
scheduling_mode) == kOnceInit) { scheduling_mode) == kOnceInit) {
base_internal::Invoke(std::forward<Callable>(fn), base_internal::invoke(std::forward<Callable>(fn),
std::forward<Args>(args)...); std::forward<Args>(args)...);
// The call to SpinLockWake below is an optimization, because the waiter // The call to SpinLockWake below is an optimization, because the waiter
// in SpinLockWait is waiting with a short timeout. The atomic load/store // in SpinLockWait is waiting with a short timeout. The atomic load/store
......
...@@ -159,16 +159,19 @@ inline Dest bit_cast(const Source& source) { ...@@ -159,16 +159,19 @@ inline Dest bit_cast(const Source& source) {
return dest; return dest;
} }
// NOTE: This overload is only picked if the requirements of bit_cast are not // NOTE: This overload is only picked if the requirements of bit_cast are
// met. It is therefore UB, but is provided temporarily as previous versions of // not met. It is therefore UB, but is provided temporarily as previous
// this function template were unchecked. Do not use this in new code. // versions of this function template were unchecked. Do not use this in
// new code.
template < template <
typename Dest, typename Source, typename Dest, typename Source,
typename std::enable_if< typename std::enable_if<
!internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0> !internal_casts::is_bitcastable<Dest, Source>::value,
int>::type = 0>
ABSL_DEPRECATED( ABSL_DEPRECATED(
"absl::bit_cast type requirements were violated. Update the types being " "absl::bit_cast type requirements were violated. Update the types "
"used such that they are the same size and are both TriviallyCopyable.") "being used such that they are the same size and are both "
"TriviallyCopyable.")
inline Dest bit_cast(const Source& source) { inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source), static_assert(sizeof(Dest) == sizeof(Source),
"Source and destination types should have equal sizes."); "Source and destination types should have equal sizes.");
......
...@@ -154,6 +154,12 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -154,6 +154,12 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#define ABSL_INTERNAL_HAS_KEYWORD(x) 0 #define ABSL_INTERNAL_HAS_KEYWORD(x) 0
#endif #endif
#ifdef __has_feature
#define ABSL_HAVE_FEATURE(f) __has_feature(f)
#else
#define ABSL_HAVE_FEATURE(f) 0
#endif
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported. // ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
// We assume __thread is supported on Linux when compiled with Clang or compiled // We assume __thread is supported on Linux when compiled with Clang or compiled
// against libstdc++ with _GLIBCXX_HAVE_TLS defined. // against libstdc++ with _GLIBCXX_HAVE_TLS defined.
...@@ -226,11 +232,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -226,11 +232,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
// * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator // * Xcode 9.3 started disallowing `thread_local` for 32-bit iOS simulator
// targeting iOS 9.x. // targeting iOS 9.x.
// * Xcode 10 moves the deployment target check for iOS < 9.0 to link time // * Xcode 10 moves the deployment target check for iOS < 9.0 to link time
// making __has_feature unreliable there. // making ABSL_HAVE_FEATURE unreliable there.
// //
// Otherwise, `__has_feature` is only supported by Clang so it has be inside #if ABSL_HAVE_FEATURE(cxx_thread_local) && \
// `defined(__APPLE__)` check.
#if __has_feature(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define ABSL_HAVE_THREAD_LOCAL 1 #define ABSL_HAVE_THREAD_LOCAL 1
#endif #endif
...@@ -262,13 +266,6 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -262,13 +266,6 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#endif #endif
#endif // defined(__ANDROID__) && defined(__clang__) #endif // defined(__ANDROID__) && defined(__clang__)
// Emscripten doesn't yet support `thread_local` or `__thread`.
// https://github.com/emscripten-core/emscripten/issues/3502
#if defined(__EMSCRIPTEN__)
#undef ABSL_HAVE_TLS
#undef ABSL_HAVE_THREAD_LOCAL
#endif // defined(__EMSCRIPTEN__)
// ABSL_HAVE_INTRINSIC_INT128 // ABSL_HAVE_INTRINSIC_INT128
// //
// Checks whether the __int128 compiler extension for a 128-bit integral type is // Checks whether the __int128 compiler extension for a 128-bit integral type is
...@@ -319,15 +316,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -319,15 +316,15 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) #if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
// Clang >= 3.6 // Clang >= 3.6
#if __has_feature(cxx_exceptions) #if ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1 #define ABSL_HAVE_EXCEPTIONS 1
#endif // __has_feature(cxx_exceptions) #endif // ABSL_HAVE_FEATURE(cxx_exceptions)
#else #else
// Clang < 3.6 // Clang < 3.6
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro // http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) #if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#define ABSL_HAVE_EXCEPTIONS 1 #define ABSL_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) #endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
#endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) #endif // __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6)
// Handle remaining special cases and default to exceptions being supported. // Handle remaining special cases and default to exceptions being supported.
...@@ -477,9 +474,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -477,9 +474,9 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 120000) || \ __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 50000)) __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else #else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
...@@ -668,4 +665,50 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' || ...@@ -668,4 +665,50 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#define ABSL_DLL #define ABSL_DLL
#endif // defined(_MSC_VER) #endif // defined(_MSC_VER)
// ABSL_HAVE_MEMORY_SANITIZER
//
// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
// a compiler instrumentation module and a run-time library.
#ifdef ABSL_HAVE_MEMORY_SANITIZER
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
#elif defined(MEMORY_SANITIZER)
// The MEMORY_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_MEMORY_SANITIZER 1
#elif defined(__SANITIZE_MEMORY__)
#define ABSL_HAVE_MEMORY_SANITIZER 1
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
#define ABSL_HAVE_MEMORY_SANITIZER 1
#endif
// ABSL_HAVE_THREAD_SANITIZER
//
// ThreadSanitizer (TSan) is a fast data race detector.
#ifdef ABSL_HAVE_THREAD_SANITIZER
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
#elif defined(THREAD_SANITIZER)
// The THREAD_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_THREAD_SANITIZER 1
#elif defined(__SANITIZE_THREAD__)
#define ABSL_HAVE_THREAD_SANITIZER 1
#elif ABSL_HAVE_FEATURE(thread_sanitizer)
#define ABSL_HAVE_THREAD_SANITIZER 1
#endif
// ABSL_HAVE_ADDRESS_SANITIZER
//
// AddressSanitizer (ASan) is a fast memory error detector.
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
#elif defined(ADDRESS_SANITIZER)
// The ADDRESS_SANITIZER macro is deprecated but we will continue to honor it
// for now.
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif defined(__SANITIZE_ADDRESS__)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#elif ABSL_HAVE_FEATURE(address_sanitizer)
#define ABSL_HAVE_ADDRESS_SANITIZER 1
#endif
#endif // ABSL_BASE_CONFIG_H_ #endif // ABSL_BASE_CONFIG_H_
// Copyright 2017 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "absl/base/dynamic_annotations.h"
#ifndef __has_feature
#define __has_feature(x) 0
#endif
/* Compiler-based ThreadSanitizer defines
DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
and provides its own definitions of the functions. */
#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
#endif
/* Each function is empty and called (via a macro) only in debug mode.
The arguments are captured by dynamic tools at runtime. */
#if DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__)
#if __has_feature(memory_sanitizer)
#include <sanitizer/msan_interface.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
void AnnotateRWLockCreate(const char *, int,
const volatile void *){}
void AnnotateRWLockDestroy(const char *, int,
const volatile void *){}
void AnnotateRWLockAcquired(const char *, int,
const volatile void *, long){}
void AnnotateRWLockReleased(const char *, int,
const volatile void *, long){}
void AnnotateBenignRace(const char *, int,
const volatile void *,
const char *){}
void AnnotateBenignRaceSized(const char *, int,
const volatile void *,
size_t,
const char *) {}
void AnnotateThreadName(const char *, int,
const char *){}
void AnnotateIgnoreReadsBegin(const char *, int){}
void AnnotateIgnoreReadsEnd(const char *, int){}
void AnnotateIgnoreWritesBegin(const char *, int){}
void AnnotateIgnoreWritesEnd(const char *, int){}
void AnnotateEnableRaceDetection(const char *, int, int){}
void AnnotateMemoryIsInitialized(const char *, int,
const volatile void *mem, size_t size) {
#if __has_feature(memory_sanitizer)
__msan_unpoison(mem, size);
#else
(void)mem;
(void)size;
#endif
}
void AnnotateMemoryIsUninitialized(const char *, int,
const volatile void *mem, size_t size) {
#if __has_feature(memory_sanitizer)
__msan_allocated_memory(mem, size);
#else
(void)mem;
(void)size;
#endif
}
static int GetRunningOnValgrind(void) {
#ifdef RUNNING_ON_VALGRIND
if (RUNNING_ON_VALGRIND) return 1;
#endif
char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
if (running_on_valgrind_str) {
return strcmp(running_on_valgrind_str, "0") != 0;
}
return 0;
}
/* See the comments in dynamic_annotations.h */
int RunningOnValgrind(void) {
static volatile int running_on_valgrind = -1;
int local_running_on_valgrind = running_on_valgrind;
/* C doesn't have thread-safe initialization of statics, and we
don't want to depend on pthread_once here, so hack it. */
ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack");
if (local_running_on_valgrind == -1)
running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
return local_running_on_valgrind;
}
/* See the comments in dynamic_annotations.h */
double ValgrindSlowdown(void) {
/* Same initialization hack as in RunningOnValgrind(). */
static volatile double slowdown = 0.0;
double local_slowdown = slowdown;
ANNOTATE_BENIGN_RACE(&slowdown, "safe hack");
if (RunningOnValgrind() == 0) {
return 1.0;
}
if (local_slowdown == 0.0) {
char *env = getenv("VALGRIND_SLOWDOWN");
slowdown = local_slowdown = env ? atof(env) : 50.0;
}
return local_slowdown;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
// Clang on Windows has __builtin_clzll; otherwise we need to use the // Clang on Windows has __builtin_clzll; otherwise we need to use the
// windows intrinsic functions. // windows intrinsic functions.
#if defined(_MSC_VER) #if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h> #include <intrin.h>
#if defined(_M_X64) #if defined(_M_X64)
#pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_BitScanReverse64)
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#if defined(_MSC_VER) #if defined(_MSC_VER) && !defined(__clang__)
// We can achieve something similar to attribute((always_inline)) with MSVC by // We can achieve something similar to attribute((always_inline)) with MSVC by
// using the __forceinline keyword, however this is not perfect. MSVC is // using the __forceinline keyword, however this is not perfect. MSVC is
// much less aggressive about inlining, and even with the __forceinline keyword. // much less aggressive about inlining, and even with the __forceinline keyword.
...@@ -73,24 +73,25 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) { ...@@ -73,24 +73,25 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) {
} }
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64) #if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64. // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) { if (_BitScanReverse64(&result, n)) {
return 63 - result; return 63 - result;
} }
return 64; return 64;
#elif defined(_MSC_VER) #elif defined(_MSC_VER) && !defined(__clang__)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, n >> 32)) { if ((n >> 32) &&
_BitScanReverse(&result, static_cast<unsigned long>(n >> 32))) {
return 31 - result; return 31 - result;
} }
if (_BitScanReverse(&result, n)) { if (_BitScanReverse(&result, static_cast<unsigned long>(n))) {
return 63 - result; return 63 - result;
} }
return 64; return 64;
#elif defined(__GNUC__) #elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clzll, which uses the following instructions: // Use __builtin_clzll, which uses the following instructions:
// x86: bsr // x86: bsr
// ARM64: clz // ARM64: clz
...@@ -126,13 +127,13 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) { ...@@ -126,13 +127,13 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32Slow(uint64_t n) {
} }
ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) { ABSL_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros32(uint32_t n) {
#if defined(_MSC_VER) #if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse(&result, n)) { if (_BitScanReverse(&result, n)) {
return 31 - result; return 31 - result;
} }
return 32; return 32;
#elif defined(__GNUC__) #elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clz, which uses the following instructions: // Use __builtin_clz, which uses the following instructions:
// x86: bsr // x86: bsr
// ARM64: clz // ARM64: clz
...@@ -163,19 +164,19 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) { ...@@ -163,19 +164,19 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64Slow(uint64_t n) {
} }
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) { ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64) #if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward64(&result, n); _BitScanForward64(&result, n);
return result; return result;
#elif defined(_MSC_VER) #elif defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if (static_cast<uint32_t>(n) == 0) { if (static_cast<uint32_t>(n) == 0) {
_BitScanForward(&result, n >> 32); _BitScanForward(&result, static_cast<unsigned long>(n >> 32));
return result + 32; return result + 32;
} }
_BitScanForward(&result, n); _BitScanForward(&result, static_cast<unsigned long>(n));
return result; return result;
#elif defined(__GNUC__) #elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_ctzll does not take 64-bit arg"); "__builtin_ctzll does not take 64-bit arg");
return __builtin_ctzll(n); return __builtin_ctzll(n);
...@@ -196,11 +197,11 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) { ...@@ -196,11 +197,11 @@ ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32Slow(uint32_t n) {
} }
ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) { ABSL_BASE_INTERNAL_FORCEINLINE int CountTrailingZerosNonZero32(uint32_t n) {
#if defined(_MSC_VER) #if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward(&result, n); _BitScanForward(&result, n);
return result; return result;
#elif defined(__GNUC__) #elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(int) == sizeof(n), static_assert(sizeof(int) == sizeof(n),
"__builtin_ctz does not take 32-bit arg"); "__builtin_ctz does not take 32-bit arg");
return __builtin_ctz(n); return __builtin_ctz(n);
......
...@@ -61,6 +61,10 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); ...@@ -61,6 +61,10 @@ extern "C" void* __mmap2(void*, size_t, int, int, int, size_t);
#endif #endif
#endif // __BIONIC__ #endif // __BIONIC__
#if defined(__NR_mmap2) && !defined(SYS_mmap2)
#define SYS_mmap2 __NR_mmap2
#endif
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
...@@ -72,6 +76,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, ...@@ -72,6 +76,7 @@ inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd,
#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \
(defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \
(defined(__PPC__) && !defined(__PPC64__)) || \ (defined(__PPC__) && !defined(__PPC64__)) || \
(defined(__riscv) && __riscv_xlen == 32) || \
(defined(__s390__) && !defined(__s390x__)) (defined(__s390__) && !defined(__s390x__))
// On these architectures, implement mmap with mmap2. // On these architectures, implement mmap with mmap2.
static int pagesize = 0; static int pagesize = 0;
......
...@@ -54,24 +54,22 @@ const uint32_t k32ValueBE{0x67452301}; ...@@ -54,24 +54,22 @@ const uint32_t k32ValueBE{0x67452301};
const uint16_t k16ValueBE{0x2301}; const uint16_t k16ValueBE{0x2301};
#endif #endif
template<typename T> std::vector<uint16_t> GenerateAllUint16Values() {
std::vector<T> GenerateAllValuesForType() { std::vector<uint16_t> result;
std::vector<T> result; result.reserve(size_t{1} << (sizeof(uint16_t) * 8));
T next = std::numeric_limits<T>::min(); for (uint32_t i = std::numeric_limits<uint16_t>::min();
while (true) { i <= std::numeric_limits<uint16_t>::max(); ++i) {
result.push_back(next); result.push_back(static_cast<uint16_t>(i));
if (next == std::numeric_limits<T>::max()) {
return result;
}
++next;
} }
return result;
} }
template<typename T> template<typename T>
std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) { std::vector<T> GenerateRandomIntegers(size_t num_values_to_test) {
std::vector<T> result; std::vector<T> result;
result.reserve(num_values_to_test);
std::mt19937_64 rng(kRandomSeed); std::mt19937_64 rng(kRandomSeed);
for (size_t i = 0; i < numValuesToTest; ++i) { for (size_t i = 0; i < num_values_to_test; ++i) {
result.push_back(rng()); result.push_back(rng());
} }
return result; return result;
...@@ -148,7 +146,7 @@ void Swap64(char* bytes) { ...@@ -148,7 +146,7 @@ void Swap64(char* bytes) {
} }
TEST(EndianessTest, Uint16) { TEST(EndianessTest, Uint16) {
GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16); GBSwapHelper(GenerateAllUint16Values(), &Swap16);
} }
TEST(EndianessTest, Uint32) { TEST(EndianessTest, Uint32) {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/internal/strerror.h"
namespace { namespace {
using ::testing::Eq; using ::testing::Eq;
...@@ -26,7 +27,7 @@ struct ErrnoPrinter { ...@@ -26,7 +27,7 @@ struct ErrnoPrinter {
int no; int no;
}; };
std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) { std::ostream &operator<<(std::ostream &os, ErrnoPrinter ep) {
return os << strerror(ep.no) << " [" << ep.no << "]"; return os << absl::base_internal::StrError(ep.no) << " [" << ep.no << "]";
} }
bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; } bool operator==(ErrnoPrinter one, ErrnoPrinter two) { return one.no == two.no; }
......
//
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
#define ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
template <typename Type>
struct FastTypeTag {
constexpr static char dummy_var = 0;
};
template <typename Type>
constexpr char FastTypeTag<Type>::dummy_var;
// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the
// passed-in type. These are meant to be good match for keys into maps or
// straight up comparisons.
using FastTypeIdType = const void*;
template <typename Type>
constexpr inline FastTypeIdType FastTypeId() {
return &FastTypeTag<Type>::dummy_var;
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_FAST_TYPE_ID_H_
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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/fast_type_id.h"
#include <cstdint>
#include <map>
#include <vector>
#include "gtest/gtest.h"
namespace {
namespace bi = absl::base_internal;
// NOLINTNEXTLINE
#define PRIM_TYPES(A) \
A(bool) \
A(short) \
A(unsigned short) \
A(int) \
A(unsigned int) \
A(long) \
A(unsigned long) \
A(long long) \
A(unsigned long long) \
A(float) \
A(double) \
A(long double)
TEST(FastTypeIdTest, PrimitiveTypes) {
bi::FastTypeIdType type_ids[] = {
#define A(T) bi::FastTypeId<T>(),
PRIM_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<const T>(),
PRIM_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<volatile T>(),
PRIM_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<const volatile T>(),
PRIM_TYPES(A)
#undef A
};
size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
for (int i = 0; i < total_type_ids; ++i) {
EXPECT_EQ(type_ids[i], type_ids[i]);
for (int j = 0; j < i; ++j) {
EXPECT_NE(type_ids[i], type_ids[j]);
}
}
}
#define FIXED_WIDTH_TYPES(A) \
A(int8_t) \
A(uint8_t) \
A(int16_t) \
A(uint16_t) \
A(int32_t) \
A(uint32_t) \
A(int64_t) \
A(uint64_t)
TEST(FastTypeIdTest, FixedWidthTypes) {
bi::FastTypeIdType type_ids[] = {
#define A(T) bi::FastTypeId<T>(),
FIXED_WIDTH_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<const T>(),
FIXED_WIDTH_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<volatile T>(),
FIXED_WIDTH_TYPES(A)
#undef A
#define A(T) bi::FastTypeId<const volatile T>(),
FIXED_WIDTH_TYPES(A)
#undef A
};
size_t total_type_ids = sizeof(type_ids) / sizeof(bi::FastTypeIdType);
for (int i = 0; i < total_type_ids; ++i) {
EXPECT_EQ(type_ids[i], type_ids[i]);
for (int j = 0; j < i; ++j) {
EXPECT_NE(type_ids[i], type_ids[j]);
}
}
}
TEST(FastTypeIdTest, AliasTypes) {
using int_alias = int;
EXPECT_EQ(bi::FastTypeId<int_alias>(), bi::FastTypeId<int>());
}
TEST(FastTypeIdTest, TemplateSpecializations) {
EXPECT_NE(bi::FastTypeId<std::vector<int>>(),
bi::FastTypeId<std::vector<long>>());
EXPECT_NE((bi::FastTypeId<std::map<int, float>>()),
(bi::FastTypeId<std::map<int, double>>()));
}
struct Base {};
struct Derived : Base {};
struct PDerived : private Base {};
TEST(FastTypeIdTest, Inheritance) {
EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<Derived>());
EXPECT_NE(bi::FastTypeId<Base>(), bi::FastTypeId<PDerived>());
}
} // namespace
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// //
// absl::base_internal::Invoke(f, args...) is an implementation of // absl::base_internal::invoke(f, args...) is an implementation of
// INVOKE(f, args...) from section [func.require] of the C++ standard. // INVOKE(f, args...) from section [func.require] of the C++ standard.
// //
// [func.require] // [func.require]
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
// is not one of the types described in the previous item; // is not one of the types described in the previous item;
// 5. f(t1, t2, ..., tN) in all other cases. // 5. f(t1, t2, ..., tN) in all other cases.
// //
// The implementation is SFINAE-friendly: substitution failure within Invoke() // The implementation is SFINAE-friendly: substitution failure within invoke()
// isn't an error. // isn't an error.
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_ #ifndef ABSL_BASE_INTERNAL_INVOKE_H_
...@@ -170,13 +170,13 @@ struct Invoker { ...@@ -170,13 +170,13 @@ struct Invoker {
// The result type of Invoke<F, Args...>. // The result type of Invoke<F, Args...>.
template <typename F, typename... Args> template <typename F, typename... Args>
using InvokeT = decltype(Invoker<F, Args...>::type::Invoke( using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
std::declval<F>(), std::declval<Args>()...)); std::declval<F>(), std::declval<Args>()...));
// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
// [func.require] of the C++ standard. // [func.require] of the C++ standard.
template <typename F, typename... Args> template <typename F, typename... Args>
InvokeT<F, Args...> Invoke(F&& f, Args&&... args) { invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
......
...@@ -598,7 +598,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { ...@@ -598,7 +598,7 @@ static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) {
section.Leave(); section.Leave();
result = &s->levels; result = &s->levels;
} }
ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request); ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request);
return result; return result;
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "absl/container/node_hash_map.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
...@@ -75,7 +77,7 @@ static bool using_low_level_alloc = false; ...@@ -75,7 +77,7 @@ static bool using_low_level_alloc = false;
// allocations and deallocations are reported via the MallocHook // allocations and deallocations are reported via the MallocHook
// interface. // interface.
static void Test(bool use_new_arena, bool call_malloc_hook, int n) { static void Test(bool use_new_arena, bool call_malloc_hook, int n) {
typedef std::unordered_map<int, BlockDesc> AllocMap; typedef absl::node_hash_map<int, BlockDesc> AllocMap;
AllocMap allocated; AllocMap allocated;
AllocMap::iterator it; AllocMap::iterator it;
BlockDesc block_desc; BlockDesc block_desc;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ #define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
#include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/scheduling_mode.h" #include "absl/base/internal/scheduling_mode.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
...@@ -29,6 +30,13 @@ extern "C" void __google_enable_rescheduling(bool disable_result); ...@@ -29,6 +30,13 @@ extern "C" void __google_enable_rescheduling(bool disable_result);
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
class CondVar;
class Mutex;
namespace synchronization_internal {
int MutexDelay(int32_t c, int mode);
} // namespace synchronization_internal
namespace base_internal { namespace base_internal {
class SchedulingHelper; // To allow use of SchedulingGuard. class SchedulingHelper; // To allow use of SchedulingGuard.
...@@ -76,9 +84,23 @@ class SchedulingGuard { ...@@ -76,9 +84,23 @@ class SchedulingGuard {
bool disabled; bool disabled;
}; };
// Access to SchedulingGuard is explicitly white-listed. // A scoped helper to enable rescheduling temporarily.
// REQUIRES: destructor must run in same thread as constructor.
class ScopedEnable {
public:
ScopedEnable();
~ScopedEnable();
private:
int scheduling_disabled_depth_;
};
// Access to SchedulingGuard is explicitly permitted.
friend class absl::CondVar;
friend class absl::Mutex;
friend class SchedulingHelper; friend class SchedulingHelper;
friend class SpinLock; friend class SpinLock;
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
SchedulingGuard(const SchedulingGuard&) = delete; SchedulingGuard(const SchedulingGuard&) = delete;
SchedulingGuard& operator=(const SchedulingGuard&) = delete; SchedulingGuard& operator=(const SchedulingGuard&) = delete;
...@@ -100,6 +122,12 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { ...@@ -100,6 +122,12 @@ inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
return; return;
} }
inline SchedulingGuard::ScopedEnable::ScopedEnable()
: scheduling_disabled_depth_(0) {}
inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
}
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
......
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. // TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a // Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a
// whitelisted set of platforms for which we expect not to be able to raw log. // selected set of platforms for which we expect not to be able to raw log.
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook< ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static absl::base_internal::AtomicHook<
absl::raw_logging_internal::LogPrefixHook> absl::raw_logging_internal::LogPrefixHook>
...@@ -227,7 +227,7 @@ bool RawLoggingFullySupported() { ...@@ -227,7 +227,7 @@ bool RawLoggingFullySupported() {
#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
} }
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
absl::base_internal::AtomicHook<InternalLogFunction> absl::base_internal::AtomicHook<InternalLogFunction>
internal_log_function(DefaultInternalLog); internal_log_function(DefaultInternalLog);
......
...@@ -72,10 +72,12 @@ ...@@ -72,10 +72,12 @@
// //
// The API is a subset of the above: each macro only takes two arguments. Use // The API is a subset of the above: each macro only takes two arguments. Use
// StrCat if you need to build a richer message. // StrCat if you need to build a richer message.
#define ABSL_INTERNAL_LOG(severity, message) \ #define ABSL_INTERNAL_LOG(severity, message) \
do { \ do { \
::absl::raw_logging_internal::internal_log_function( \ constexpr const char* absl_raw_logging_internal_filename = __FILE__; \
ABSL_RAW_LOGGING_INTERNAL_##severity, __FILE__, __LINE__, message); \ ::absl::raw_logging_internal::internal_log_function( \
ABSL_RAW_LOGGING_INTERNAL_##severity, \
absl_raw_logging_internal_filename, __LINE__, message); \
} while (0) } while (0)
#define ABSL_INTERNAL_CHECK(condition, message) \ #define ABSL_INTERNAL_CHECK(condition, message) \
...@@ -170,7 +172,7 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity, ...@@ -170,7 +172,7 @@ using InternalLogFunction = void (*)(absl::LogSeverity severity,
const char* file, int line, const char* file, int line,
const std::string& message); const std::string& message);
ABSL_DLL ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES extern base_internal::AtomicHook< ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
InternalLogFunction> InternalLogFunction>
internal_log_function; internal_log_function;
......
...@@ -66,35 +66,19 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, ...@@ -66,35 +66,19 @@ void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
submit_profile_data.Store(fn); submit_profile_data.Store(fn);
} }
// Static member variable definitions.
constexpr uint32_t SpinLock::kSpinLockHeld;
constexpr uint32_t SpinLock::kSpinLockCooperative;
constexpr uint32_t SpinLock::kSpinLockDisabledScheduling;
constexpr uint32_t SpinLock::kSpinLockSleeper;
constexpr uint32_t SpinLock::kWaitTimeMask;
// Uncommon constructors. // Uncommon constructors.
SpinLock::SpinLock(base_internal::SchedulingMode mode) SpinLock::SpinLock(base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) { : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
} }
SpinLock::SpinLock(base_internal::LinkerInitialized,
base_internal::SchedulingMode mode) {
ABSL_TSAN_MUTEX_CREATE(this, 0);
if (IsCooperative(mode)) {
InitLinkerInitializedAndCooperative();
}
// Otherwise, lockword_ is already initialized.
}
// Static (linker initialized) spinlocks always start life as functional
// non-cooperative locks. When their static constructor does run, it will call
// this initializer to augment the lockword with the cooperative bit. By
// actually taking the lock when we do this we avoid the need for an atomic
// operation in the regular unlock path.
//
// SlowLock() must be careful to re-test for this bit so that any outstanding
// waiters may be upgraded to cooperative status.
void SpinLock::InitLinkerInitializedAndCooperative() {
Lock();
lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
Unlock();
}
// Monitor the lock to see if its value changes within some time period // Monitor the lock to see if its value changes within some time period
// (adaptive_spin_count loop iterations). The last value read from the lock // (adaptive_spin_count loop iterations). The last value read from the lock
// is returned from the method. // is returned from the method.
...@@ -121,6 +105,14 @@ void SpinLock::SlowLock() { ...@@ -121,6 +105,14 @@ void SpinLock::SlowLock() {
if ((lock_value & kSpinLockHeld) == 0) { if ((lock_value & kSpinLockHeld) == 0) {
return; return;
} }
base_internal::SchedulingMode scheduling_mode;
if ((lock_value & kSpinLockCooperative) != 0) {
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
} else {
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
}
// The lock was not obtained initially, so this thread needs to wait for // The lock was not obtained initially, so this thread needs to wait for
// it. Record the current timestamp in the local variable wait_start_time // it. Record the current timestamp in the local variable wait_start_time
// so the total wait time can be stored in the lockword once this thread // so the total wait time can be stored in the lockword once this thread
...@@ -151,12 +143,6 @@ void SpinLock::SlowLock() { ...@@ -151,12 +143,6 @@ void SpinLock::SlowLock() {
} }
} }
base_internal::SchedulingMode scheduling_mode;
if ((lock_value & kSpinLockCooperative) != 0) {
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
} else {
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
}
// SpinLockDelay() calls into fiber scheduler, we need to see // SpinLockDelay() calls into fiber scheduler, we need to see
// synchronization there to avoid false positives. // synchronization there to avoid false positives.
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
...@@ -190,30 +176,32 @@ void SpinLock::SlowUnlock(uint32_t lock_value) { ...@@ -190,30 +176,32 @@ void SpinLock::SlowUnlock(uint32_t lock_value) {
// We use the upper 29 bits of the lock word to store the time spent waiting to // We use the upper 29 bits of the lock word to store the time spent waiting to
// acquire this lock. This is reported by contentionz profiling. Since the // acquire this lock. This is reported by contentionz profiling. Since the
// lower bits of the cycle counter wrap very quickly on high-frequency // lower bits of the cycle counter wrap very quickly on high-frequency
// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT // processors we divide to reduce the granularity to 2^kProfileTimestampShift
// sized units. On a 4Ghz machine this will lose track of wait times greater // sized units. On a 4Ghz machine this will lose track of wait times greater
// than (2^29/4 Ghz)*128 =~ 17.2 seconds. Such waits should be extremely rare. // than (2^29/4 Ghz)*128 =~ 17.2 seconds. Such waits should be extremely rare.
enum { PROFILE_TIMESTAMP_SHIFT = 7 }; static constexpr int kProfileTimestampShift = 7;
enum { LOCKWORD_RESERVED_SHIFT = 3 }; // We currently reserve the lower 3 bits.
// We currently reserve the lower 3 bits.
static constexpr int kLockwordReservedShift = 3;
uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time, uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time,
int64_t wait_end_time) { int64_t wait_end_time) {
static const int64_t kMaxWaitTime = static const int64_t kMaxWaitTime =
std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT; std::numeric_limits<uint32_t>::max() >> kLockwordReservedShift;
int64_t scaled_wait_time = int64_t scaled_wait_time =
(wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT; (wait_end_time - wait_start_time) >> kProfileTimestampShift;
// Return a representation of the time spent waiting that can be stored in // Return a representation of the time spent waiting that can be stored in
// the lock word's upper bits. // the lock word's upper bits.
uint32_t clamped = static_cast<uint32_t>( uint32_t clamped = static_cast<uint32_t>(
std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT); std::min(scaled_wait_time, kMaxWaitTime) << kLockwordReservedShift);
if (clamped == 0) { if (clamped == 0) {
return kSpinLockSleeper; // Just wake waiters, but don't record contention. return kSpinLockSleeper; // Just wake waiters, but don't record contention.
} }
// Bump up value if necessary to avoid returning kSpinLockSleeper. // Bump up value if necessary to avoid returning kSpinLockSleeper.
const uint32_t kMinWaitTime = const uint32_t kMinWaitTime =
kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); kSpinLockSleeper + (1 << kLockwordReservedShift);
if (clamped == kSpinLockSleeper) { if (clamped == kSpinLockSleeper) {
return kMinWaitTime; return kMinWaitTime;
} }
...@@ -224,8 +212,7 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { ...@@ -224,8 +212,7 @@ uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) {
// Cast to uint32_t first to ensure bits [63:32] are cleared. // Cast to uint32_t first to ensure bits [63:32] are cleared.
const uint64_t scaled_wait_time = const uint64_t scaled_wait_time =
static_cast<uint32_t>(lock_value & kWaitTimeMask); static_cast<uint32_t>(lock_value & kWaitTimeMask);
return scaled_wait_time return scaled_wait_time << (kProfileTimestampShift - kLockwordReservedShift);
<< (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT);
} }
} // namespace base_internal } // namespace base_internal
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <atomic> #include <atomic>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/dynamic_annotations.h" #include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/low_level_scheduling.h" #include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
...@@ -55,29 +56,22 @@ class ABSL_LOCKABLE SpinLock { ...@@ -55,29 +56,22 @@ class ABSL_LOCKABLE SpinLock {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
} }
// Special constructor for use with static SpinLock objects. E.g.,
//
// static SpinLock lock(base_internal::kLinkerInitialized);
//
// When initialized using this constructor, we depend on the fact
// that the linker has already initialized the memory appropriately. The lock
// is initialized in non-cooperative mode.
//
// A SpinLock constructed like this can be freely used from global
// initializers without worrying about the order in which global
// initializers run.
explicit SpinLock(base_internal::LinkerInitialized) {
// Does nothing; lockword_ is already initialized
ABSL_TSAN_MUTEX_CREATE(this, 0);
}
// Constructors that allow non-cooperative spinlocks to be created for use // Constructors that allow non-cooperative spinlocks to be created for use
// inside thread schedulers. Normal clients should not use these. // inside thread schedulers. Normal clients should not use these.
explicit SpinLock(base_internal::SchedulingMode mode); explicit SpinLock(base_internal::SchedulingMode mode);
SpinLock(base_internal::LinkerInitialized,
base_internal::SchedulingMode mode);
// Constructor for global SpinLock instances. See absl/base/const_init.h.
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
// For global SpinLock instances prefer trivial destructor when possible.
// Default but non-trivial destructor in some build configurations causes an
// extra static initializer.
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
#else
~SpinLock() = default;
#endif
// Acquire this SpinLock. // Acquire this SpinLock.
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
...@@ -148,12 +142,13 @@ class ABSL_LOCKABLE SpinLock { ...@@ -148,12 +142,13 @@ class ABSL_LOCKABLE SpinLock {
// bit[1] encodes whether a lock uses cooperative scheduling. // bit[1] encodes whether a lock uses cooperative scheduling.
// bit[2] encodes whether a lock disables scheduling. // bit[2] encodes whether a lock disables scheduling.
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int. // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
enum { kSpinLockHeld = 1 }; static constexpr uint32_t kSpinLockHeld = 1;
enum { kSpinLockCooperative = 2 }; static constexpr uint32_t kSpinLockCooperative = 2;
enum { kSpinLockDisabledScheduling = 4 }; static constexpr uint32_t kSpinLockDisabledScheduling = 4;
enum { kSpinLockSleeper = 8 }; static constexpr uint32_t kSpinLockSleeper = 8;
enum { kWaitTimeMask = // Includes kSpinLockSleeper. // Includes kSpinLockSleeper.
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) }; static constexpr uint32_t kWaitTimeMask =
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
// Returns true if the provided scheduling mode is cooperative. // Returns true if the provided scheduling mode is cooperative.
static constexpr bool IsCooperative( static constexpr bool IsCooperative(
...@@ -162,7 +157,6 @@ class ABSL_LOCKABLE SpinLock { ...@@ -162,7 +157,6 @@ class ABSL_LOCKABLE SpinLock {
} }
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles); uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
void InitLinkerInitializedAndCooperative();
void SlowLock() ABSL_ATTRIBUTE_COLD; void SlowLock() ABSL_ATTRIBUTE_COLD;
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
uint32_t SpinLoop(); uint32_t SpinLoop();
......
...@@ -46,6 +46,14 @@ static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int), ...@@ -46,6 +46,14 @@ static_assert(sizeof(std::atomic<uint32_t>) == sizeof(int),
#endif #endif
#endif #endif
#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
#define SYS_futex_time64 __NR_futex_time64
#endif
#if defined(SYS_futex_time64) && !defined(SYS_futex)
#define SYS_futex SYS_futex_time64
#endif
extern "C" { extern "C" {
ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay(
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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/strerror.h"
#include <array>
#include <cerrno>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include <type_traits>
#include "absl/base/internal/errno_saver.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
namespace {
const char* StrErrorAdaptor(int errnum, char* buf, size_t buflen) {
#if defined(_WIN32)
int rc = strerror_s(buf, buflen, errnum);
buf[buflen - 1] = '\0'; // guarantee NUL termination
if (rc == 0 && strncmp(buf, "Unknown error", buflen) == 0) *buf = '\0';
return buf;
#else
// The type of `ret` is platform-specific; both of these branches must compile
// either way but only one will execute on any given platform:
auto ret = strerror_r(errnum, buf, buflen);
if (std::is_same<decltype(ret), int>::value) {
// XSI `strerror_r`; `ret` is `int`:
if (ret) *buf = '\0';
return buf;
} else {
// GNU `strerror_r`; `ret` is `char *`:
return reinterpret_cast<const char*>(ret);
}
#endif
}
std::string StrErrorInternal(int errnum) {
absl::base_internal::ErrnoSaver errno_saver;
char buf[100];
const char* str = StrErrorAdaptor(errnum, buf, sizeof buf);
if (*str == '\0') {
snprintf(buf, sizeof buf, "Unknown error %d", errnum);
str = buf;
}
return str;
}
// kSysNerr is the number of errors from a recent glibc. `StrError()` falls back
// to `StrErrorAdaptor()` if the value is larger than this.
constexpr int kSysNerr = 135;
std::array<std::string, kSysNerr>* NewStrErrorTable() {
auto* table = new std::array<std::string, kSysNerr>;
for (int i = 0; i < static_cast<int>(table->size()); ++i) {
(*table)[i] = StrErrorInternal(i);
}
return table;
}
} // namespace
std::string StrError(int errnum) {
static const auto* table = NewStrErrorTable();
if (errnum >= 0 && errnum < static_cast<int>(table->size())) {
return (*table)[errnum];
}
return StrErrorInternal(errnum);
}
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ABSL_BASE_INTERNAL_STRERROR_H_
#define ABSL_BASE_INTERNAL_STRERROR_H_
#include <string>
#include "absl/base/config.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
// A portable and thread-safe alternative to C89's `strerror`.
//
// The C89 specification of `strerror` is not suitable for use in a
// multi-threaded application as the returned string may be changed by calls to
// `strerror` from another thread. The many non-stdlib alternatives differ
// enough in their names, availability, and semantics to justify this wrapper
// around them. `errno` will not be modified by a call to `absl::StrError`.
std::string StrError(int errnum);
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_BASE_INTERNAL_STRERROR_H_
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 <cerrno>
#include <cstdio>
#include <string>
#include "absl/base/internal/strerror.h"
#include "benchmark/benchmark.h"
namespace {
void BM_AbslStrError(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(absl::base_internal::StrError(ERANGE));
}
}
BENCHMARK(BM_AbslStrError);
} // namespace
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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/strerror.h"
#include <atomic>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <string>
#include <thread> // NOLINT(build/c++11)
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/match.h"
namespace {
using ::testing::AnyOf;
using ::testing::Eq;
TEST(StrErrorTest, ValidErrorCode) {
errno = ERANGE;
EXPECT_THAT(absl::base_internal::StrError(EDOM), Eq(strerror(EDOM)));
EXPECT_THAT(errno, Eq(ERANGE));
}
TEST(StrErrorTest, InvalidErrorCode) {
errno = ERANGE;
EXPECT_THAT(absl::base_internal::StrError(-1),
AnyOf(Eq("No error information"), Eq("Unknown error -1")));
EXPECT_THAT(errno, Eq(ERANGE));
}
TEST(StrErrorTest, MultipleThreads) {
// In this test, we will start up 2 threads and have each one call
// StrError 1000 times, each time with a different errnum. We
// expect that StrError(errnum) will return a string equal to the
// one returned by strerror(errnum), if the code is known. Since
// strerror is known to be thread-hostile, collect all the expected
// strings up front.
const int kNumCodes = 1000;
std::vector<std::string> expected_strings(kNumCodes);
for (int i = 0; i < kNumCodes; ++i) {
expected_strings[i] = strerror(i);
}
std::atomic_int counter(0);
auto thread_fun = [&]() {
for (int i = 0; i < kNumCodes; ++i) {
++counter;
errno = ERANGE;
const std::string value = absl::base_internal::StrError(i);
// Only the GNU implementation is guaranteed to provide the
// string "Unknown error nnn". POSIX doesn't say anything.
if (!absl::StartsWith(value, "Unknown error ")) {
EXPECT_THAT(absl::base_internal::StrError(i), Eq(expected_strings[i]));
}
EXPECT_THAT(errno, Eq(ERANGE));
}
};
const int kNumThreads = 100;
std::vector<std::thread> threads;
for (int i = 0; i < kNumThreads; ++i) {
threads.push_back(std::thread(thread_fun));
}
for (auto& thread : threads) {
thread.join();
}
EXPECT_THAT(counter, Eq(kNumThreads * kNumCodes));
}
} // namespace
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#endif #endif
#include <string.h> #include <string.h>
#include <cassert> #include <cassert>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
...@@ -50,9 +51,11 @@ ...@@ -50,9 +51,11 @@
#include <vector> #include <vector>
#include "absl/base/call_once.h" #include "absl/base/call_once.h"
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/base/internal/spinlock.h" #include "absl/base/internal/spinlock.h"
#include "absl/base/internal/unscaledcycleclock.h" #include "absl/base/internal/unscaledcycleclock.h"
#include "absl/base/thread_annotations.h"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
...@@ -72,6 +75,12 @@ static int GetNumCPUs() { ...@@ -72,6 +75,12 @@ static int GetNumCPUs() {
#if defined(_WIN32) #if defined(_WIN32)
static double GetNominalCPUFrequency() { static double GetNominalCPUFrequency() {
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// UWP apps don't have access to the registry and currently don't provide an
// API informing about CPU nominal frequency.
return 1.0;
#else
#pragma comment(lib, "advapi32.lib") // For Reg* functions. #pragma comment(lib, "advapi32.lib") // For Reg* functions.
HKEY key; HKEY key;
// Use the Reg* functions rather than the SH functions because shlwapi.dll // Use the Reg* functions rather than the SH functions because shlwapi.dll
...@@ -91,6 +100,7 @@ static double GetNominalCPUFrequency() { ...@@ -91,6 +100,7 @@ static double GetNominalCPUFrequency() {
} }
} }
return 1.0; return 1.0;
#endif // WINAPI_PARTITION_APP && !WINAPI_PARTITION_DESKTOP
} }
#elif defined(CTL_HW) && defined(HW_CPU_FREQ) #elif defined(CTL_HW) && defined(HW_CPU_FREQ)
...@@ -336,15 +346,16 @@ pid_t GetTID() { ...@@ -336,15 +346,16 @@ pid_t GetTID() {
#else #else
// Fallback implementation of GetTID using pthread_getspecific. // Fallback implementation of GetTID using pthread_getspecific.
static once_flag tid_once; ABSL_CONST_INIT static once_flag tid_once;
static pthread_key_t tid_key; ABSL_CONST_INIT static pthread_key_t tid_key;
static absl::base_internal::SpinLock tid_lock( ABSL_CONST_INIT static absl::base_internal::SpinLock tid_lock(
absl::base_internal::kLinkerInitialized); absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
// We set a bit per thread in this array to indicate that an ID is in // We set a bit per thread in this array to indicate that an ID is in
// use. ID 0 is unused because it is the default value returned by // use. ID 0 is unused because it is the default value returned by
// pthread_getspecific(). // pthread_getspecific().
static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr; ABSL_CONST_INIT static std::vector<uint32_t> *tid_array
ABSL_GUARDED_BY(tid_lock) = nullptr;
static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. static constexpr int kBitsPerWord = 32; // tid_array is uint32_t.
// Returns the TID to tid_array. // Returns the TID to tid_array.
...@@ -411,6 +422,18 @@ pid_t GetTID() { ...@@ -411,6 +422,18 @@ pid_t GetTID() {
#endif #endif
// GetCachedTID() caches the thread ID in thread-local storage (which is a
// userspace construct) to avoid unnecessary system calls. Without this caching,
// it can take roughly 98ns, while it takes roughly 1ns with this caching.
pid_t GetCachedTID() {
#if ABSL_HAVE_THREAD_LOCAL
static thread_local pid_t thread_id = GetTID();
return thread_id;
#else
return GetTID();
#endif // ABSL_HAVE_THREAD_LOCAL
}
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <cstdint> #include <cstdint>
#include "absl/base/config.h"
#include "absl/base/port.h" #include "absl/base/port.h"
namespace absl { namespace absl {
...@@ -59,6 +60,13 @@ using pid_t = uint32_t; ...@@ -59,6 +60,13 @@ using pid_t = uint32_t;
#endif #endif
pid_t GetTID(); pid_t GetTID();
// Like GetTID(), but caches the result in thread-local storage in order
// to avoid unnecessary system calls. Note that there are some cases where
// one must call through to GetTID directly, which is why this exists as a
// separate function. For example, GetCachedTID() is not safe to call in
// an asynchronous signal-handling context nor right after a call to fork().
pid_t GetCachedTID();
} // namespace base_internal } // namespace base_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/internal/spinlock.h" #include "absl/base/internal/spinlock.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/internal/per_thread_sem.h" #include "absl/synchronization/internal/per_thread_sem.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
...@@ -29,10 +30,9 @@ ABSL_NAMESPACE_BEGIN ...@@ -29,10 +30,9 @@ ABSL_NAMESPACE_BEGIN
namespace base_internal { namespace base_internal {
namespace { namespace {
// protects num_identities_reused ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
static absl::base_internal::SpinLock map_lock( absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
absl::base_internal::kLinkerInitialized); ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
static int num_identities_reused;
static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1); static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
...@@ -75,7 +75,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { ...@@ -75,7 +75,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
// - If a thread implementation chooses to recycle threads, that // - If a thread implementation chooses to recycle threads, that
// correct re-initialization occurs. // correct re-initialization occurs.
static const int kNumLoops = 3; static const int kNumLoops = 3;
static const int kNumThreads = 400; static const int kNumThreads = 32;
for (int iter = 0; iter < kNumLoops; iter++) { for (int iter = 0; iter < kNumLoops; iter++) {
std::vector<std::thread> threads; std::vector<std::thread> threads;
for (int i = 0; i < kNumThreads; ++i) { for (int i = 0; i < kNumThreads; ++i) {
...@@ -90,6 +90,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { ...@@ -90,6 +90,7 @@ TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
// We should have recycled ThreadIdentity objects above; while (external) // We should have recycled ThreadIdentity objects above; while (external)
// library threads allocating their own identities may preclude some // library threads allocating their own identities may preclude some
// reuse, we should have sufficient repetitions to exclude this. // reuse, we should have sufficient repetitions to exclude this.
absl::base_internal::SpinLockHolder l(&map_lock);
EXPECT_LT(kNumThreads, num_identities_reused); EXPECT_LT(kNumThreads, num_identities_reused);
} }
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ #ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ #define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
#include "absl/base/config.h"
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE // ABSL_INTERNAL_HAVE_TSAN_INTERFACE
// Macro intended only for internal use. // Macro intended only for internal use.
// //
...@@ -28,7 +30,7 @@ ...@@ -28,7 +30,7 @@
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set." #error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
#endif #endif
#if defined(THREAD_SANITIZER) && defined(__has_include) #if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
#if __has_include(<sanitizer/tsan_interface.h>) #if __has_include(<sanitizer/tsan_interface.h>)
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1 #define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
#endif #endif
......
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
// (namespaces, inline) which are absent or incompatible in C. // (namespaces, inline) which are absent or incompatible in C.
#if defined(__cplusplus) #if defined(__cplusplus)
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\ #if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \
defined(MEMORY_SANITIZER) defined(ABSL_HAVE_THREAD_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
// Consider we have an unaligned load/store of 4 bytes from address 0x...05. // Consider we have an unaligned load/store of 4 bytes from address 0x...05.
// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and // AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
// will miss a bug if 08 is the first unaddressable byte. // will miss a bug if 08 is the first unaddressable byte.
......
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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 "gtest/gtest.h"
#include "absl/base/optimization.h"
#include "absl/strings/string_view.h"
// This test by itself does not do anything fancy, but it serves as binary I can
// query in shell test.
namespace {
template <class T>
void DoNotOptimize(const T& var) {
#ifdef __GNUC__
asm volatile("" : "+m"(const_cast<T&>(var)));
#else
std::cout << (void*)&var;
#endif
}
int very_long_int_variable_name ABSL_INTERNAL_UNIQUE_SMALL_NAME() = 0;
char very_long_str_variable_name[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = "abc";
TEST(UniqueSmallName, NonAutomaticVar) {
EXPECT_EQ(very_long_int_variable_name, 0);
EXPECT_EQ(absl::string_view(very_long_str_variable_name), "abc");
}
int VeryLongFreeFunctionName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
TEST(UniqueSmallName, FreeFunction) {
DoNotOptimize(&VeryLongFreeFunctionName);
EXPECT_EQ(VeryLongFreeFunctionName(), 456);
}
int VeryLongFreeFunctionName() { return 456; }
struct VeryLongStructName {
explicit VeryLongStructName(int i);
int VeryLongMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
static int VeryLongStaticMethodName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
private:
int fld;
};
TEST(UniqueSmallName, Struct) {
VeryLongStructName var(10);
DoNotOptimize(var);
DoNotOptimize(&VeryLongStructName::VeryLongMethodName);
DoNotOptimize(&VeryLongStructName::VeryLongStaticMethodName);
EXPECT_EQ(var.VeryLongMethodName(), 10);
EXPECT_EQ(VeryLongStructName::VeryLongStaticMethodName(), 123);
}
VeryLongStructName::VeryLongStructName(int i) : fld(i) {}
int VeryLongStructName::VeryLongMethodName() { return fld; }
int VeryLongStructName::VeryLongStaticMethodName() { return 123; }
} // namespace
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
// UnscaledCycleClock // UnscaledCycleClock
// An UnscaledCycleClock yields the value and frequency of a cycle counter // An UnscaledCycleClock yields the value and frequency of a cycle counter
// that increments at a rate that is approximately constant. // that increments at a rate that is approximately constant.
// This class is for internal / whitelisted use only, you should consider // This class is for internal use only, you should consider using CycleClock
// using CycleClock instead. // instead.
// //
// Notes: // Notes:
// The cycle counter frequency is not necessarily the core clock frequency. // The cycle counter frequency is not necessarily the core clock frequency.
...@@ -109,7 +109,7 @@ class UnscaledCycleClock { ...@@ -109,7 +109,7 @@ class UnscaledCycleClock {
// value. // value.
static double Frequency(); static double Frequency();
// Whitelisted friends. // Allowed users
friend class base_internal::CycleClock; friend class base_internal::CycleClock;
friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime; friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime;
friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency; friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency;
......
...@@ -86,71 +86,73 @@ struct FlipFlop { ...@@ -86,71 +86,73 @@ struct FlipFlop {
int member; int member;
}; };
// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending // CallMaybeWithArg(f) resolves either to invoke(f) or invoke(f, 42), depending
// on which one is valid. // on which one is valid.
template <typename F> template <typename F>
decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) { decltype(base_internal::invoke(std::declval<const F&>())) CallMaybeWithArg(
return Invoke(f); const F& f) {
return base_internal::invoke(f);
} }
template <typename F> template <typename F>
decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) { decltype(base_internal::invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(
return Invoke(f, 42); const F& f) {
return base_internal::invoke(f, 42);
} }
TEST(InvokeTest, Function) { TEST(InvokeTest, Function) {
EXPECT_EQ(1, Invoke(Function, 3, 2)); EXPECT_EQ(1, base_internal::invoke(Function, 3, 2));
EXPECT_EQ(1, Invoke(&Function, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Function, 3, 2));
} }
TEST(InvokeTest, NonCopyableArgument) { TEST(InvokeTest, NonCopyableArgument) {
EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42))); EXPECT_EQ(42, base_internal::invoke(Sink, make_unique<int>(42)));
} }
TEST(InvokeTest, NonCopyableResult) { TEST(InvokeTest, NonCopyableResult) {
EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42)); EXPECT_THAT(base_internal::invoke(Factory, 42), ::testing::Pointee(42));
} }
TEST(InvokeTest, VoidResult) { TEST(InvokeTest, VoidResult) { base_internal::invoke(NoOp); }
Invoke(NoOp);
}
TEST(InvokeTest, ConstFunctor) { TEST(InvokeTest, ConstFunctor) {
EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(ConstFunctor(), 3, 2));
} }
TEST(InvokeTest, MutableFunctor) { TEST(InvokeTest, MutableFunctor) {
MutableFunctor f; MutableFunctor f;
EXPECT_EQ(1, Invoke(f, 3, 2)); EXPECT_EQ(1, base_internal::invoke(f, 3, 2));
EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(MutableFunctor(), 3, 2));
} }
TEST(InvokeTest, EphemeralFunctor) { TEST(InvokeTest, EphemeralFunctor) {
EphemeralFunctor f; EphemeralFunctor f;
EXPECT_EQ(1, Invoke(std::move(f), 3, 2)); EXPECT_EQ(1, base_internal::invoke(std::move(f), 3, 2));
EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(EphemeralFunctor(), 3, 2));
} }
TEST(InvokeTest, OverloadedFunctor) { TEST(InvokeTest, OverloadedFunctor) {
OverloadedFunctor f; OverloadedFunctor f;
const OverloadedFunctor& cf = f; const OverloadedFunctor& cf = f;
EXPECT_EQ("&", Invoke(f)); EXPECT_EQ("&", base_internal::invoke(f));
EXPECT_EQ("& 42", Invoke(f, " 42")); EXPECT_EQ("& 42", base_internal::invoke(f, " 42"));
EXPECT_EQ("const&", base_internal::invoke(cf));
EXPECT_EQ("const& 42", base_internal::invoke(cf, " 42"));
EXPECT_EQ("const&", Invoke(cf)); EXPECT_EQ("&&", base_internal::invoke(std::move(f)));
EXPECT_EQ("const& 42", Invoke(cf, " 42"));
EXPECT_EQ("&&", Invoke(std::move(f))); OverloadedFunctor f2;
EXPECT_EQ("&& 42", Invoke(std::move(f), " 42")); EXPECT_EQ("&& 42", base_internal::invoke(std::move(f2), " 42"));
} }
TEST(InvokeTest, ReferenceWrapper) { TEST(InvokeTest, ReferenceWrapper) {
ConstFunctor cf; ConstFunctor cf;
MutableFunctor mf; MutableFunctor mf;
EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2)); EXPECT_EQ(1, base_internal::invoke(std::cref(cf), 3, 2));
EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2)); EXPECT_EQ(1, base_internal::invoke(std::ref(cf), 3, 2));
EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2)); EXPECT_EQ(1, base_internal::invoke(std::ref(mf), 3, 2));
} }
TEST(InvokeTest, MemberFunction) { TEST(InvokeTest, MemberFunction) {
...@@ -158,58 +160,62 @@ TEST(InvokeTest, MemberFunction) { ...@@ -158,58 +160,62 @@ TEST(InvokeTest, MemberFunction) {
std::unique_ptr<const Class> cp(new Class); std::unique_ptr<const Class> cp(new Class);
std::unique_ptr<volatile Class> vp(new Class); std::unique_ptr<volatile Class> vp(new Class);
EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::Method, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::Method, p.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, *p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::Method, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::RefMethod, p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::RefMethod, p.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, p.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::RefMethod, *p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::RefMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::RefRefMethod, std::move(*p), 3, 2)); // NOLINT EXPECT_EQ(1, base_internal::invoke(&Class::RefRefMethod, std::move(*p), 3,
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p, 3, 2)); 2)); // NOLINT
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, p.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::NoExceptMethod, *p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, p.get(), 3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::NoExceptMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, p.get(), 3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, cp.get(), 3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, *cp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, p.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *p, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, p.get(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *p, 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, vp.get(), 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::VolatileMethod, *vp, 3, 2)); EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, vp.get(), 3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::VolatileMethod, *vp, 3, 2));
EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2)); EXPECT_EQ(1,
EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2)); base_internal::invoke(&Class::Method, make_unique<Class>(), 3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod, make_unique<Class>(),
3, 2));
EXPECT_EQ(1, base_internal::invoke(&Class::ConstMethod,
make_unique<const Class>(), 3, 2));
} }
TEST(InvokeTest, DataMember) { TEST(InvokeTest, DataMember) {
std::unique_ptr<Class> p(new Class{42}); std::unique_ptr<Class> p(new Class{42});
std::unique_ptr<const Class> cp(new Class{42}); std::unique_ptr<const Class> cp(new Class{42});
EXPECT_EQ(42, Invoke(&Class::member, p)); EXPECT_EQ(42, base_internal::invoke(&Class::member, p));
EXPECT_EQ(42, Invoke(&Class::member, *p)); EXPECT_EQ(42, base_internal::invoke(&Class::member, *p));
EXPECT_EQ(42, Invoke(&Class::member, p.get())); EXPECT_EQ(42, base_internal::invoke(&Class::member, p.get()));
Invoke(&Class::member, p) = 42; base_internal::invoke(&Class::member, p) = 42;
Invoke(&Class::member, p.get()) = 42; base_internal::invoke(&Class::member, p.get()) = 42;
EXPECT_EQ(42, Invoke(&Class::member, cp)); EXPECT_EQ(42, base_internal::invoke(&Class::member, cp));
EXPECT_EQ(42, Invoke(&Class::member, *cp)); EXPECT_EQ(42, base_internal::invoke(&Class::member, *cp));
EXPECT_EQ(42, Invoke(&Class::member, cp.get())); EXPECT_EQ(42, base_internal::invoke(&Class::member, cp.get()));
} }
TEST(InvokeTest, FlipFlop) { TEST(InvokeTest, FlipFlop) {
FlipFlop obj = {42}; FlipFlop obj = {42};
// This call could resolve to (obj.*&FlipFlop::ConstMethod)() or // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or
// ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former. // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former.
EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj)); EXPECT_EQ(42, base_internal::invoke(&FlipFlop::ConstMethod, obj));
EXPECT_EQ(42, Invoke(&FlipFlop::member, obj)); EXPECT_EQ(42, base_internal::invoke(&FlipFlop::member, obj));
} }
TEST(InvokeTest, SfinaeFriendly) { TEST(InvokeTest, SfinaeFriendly) {
......
...@@ -53,7 +53,7 @@ TEST(StreamTest, Works) { ...@@ -53,7 +53,7 @@ TEST(StreamTest, Works) {
} }
static_assert( static_assert(
absl::flags_internal::IsAtomicFlagTypeTrait<absl::LogSeverity>::value, absl::flags_internal::FlagUseOneWordStorage<absl::LogSeverity>::value,
"Flags of type absl::LogSeverity ought to be lock-free."); "Flags of type absl::LogSeverity ought to be lock-free.");
using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>; using ParseFlagFromOutOfRangeIntegerTest = TestWithParam<int64_t>;
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <cstddef> #include <cstddef>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/base/port.h" #include "absl/base/port.h"
...@@ -54,115 +55,6 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; ...@@ -54,115 +55,6 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
} // namespace absl } // namespace absl
// kLinkerInitialized
//
// An enum used only as a constructor argument to indicate that a variable has
// static storage duration, and that the constructor should do nothing to its
// state. Use of this macro indicates to the reader that it is legal to
// declare a static instance of the class, provided the constructor is given
// the absl::base_internal::kLinkerInitialized argument.
//
// Normally, it is unsafe to declare a static variable that has a constructor or
// a destructor because invocation order is undefined. However, if the type can
// be zero-initialized (which the loader does for static variables) into a valid
// state and the type's destructor does not affect storage, then a constructor
// for static initialization can be declared.
//
// Example:
// // Declaration
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
//
// // Invocation
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace base_internal {
enum LinkerInitialized {
kLinkerInitialized = 0,
};
} // namespace base_internal
ABSL_NAMESPACE_END
} // namespace absl
// ABSL_FALLTHROUGH_INTENDED
//
// Annotates implicit fall-through between switch labels, allowing a case to
// indicate intentional fallthrough and turn off warnings about any lack of a
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
// a semicolon and can be used in most places where `break` can, provided that
// no statements exist between it and the next switch label.
//
// Example:
//
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
// // in comments
// } else {
// return x;
// }
// case 42:
// ...
//
// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
// when performing switch labels fall-through diagnostic
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
// for details:
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
//
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro
// has no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code.
#ifdef ABSL_FALLTHROUGH_INTENDED
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
#endif
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
#if defined(__clang__) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#endif
#elif defined(__GNUC__) && __GNUC__ >= 7
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#endif
#ifndef ABSL_FALLTHROUGH_INTENDED
#define ABSL_FALLTHROUGH_INTENDED \
do { \
} while (0)
#endif
// ABSL_DEPRECATED()
//
// Marks a deprecated class, struct, enum, function, method and variable
// declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative).
//
// Examples:
//
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
//
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
//
// template <typename T>
// ABSL_DEPRECATED("Use DoThat() instead")
// void DoThis();
//
// Every usage of a deprecated entity will trigger a warning when compiled with
// clang's `-Wdeprecated-declarations` option. This option is turned off by
// default, but the warnings will be reported by clang-tidy.
#if defined(__clang__) && __cplusplus >= 201103L
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#ifndef ABSL_DEPRECATED
#define ABSL_DEPRECATED(message)
#endif
// ABSL_BAD_CALL_IF() // ABSL_BAD_CALL_IF()
// //
// Used on a function overload to trap bad calls: any call that matches the // Used on a function overload to trap bad calls: any call that matches the
...@@ -207,6 +99,41 @@ ABSL_NAMESPACE_END ...@@ -207,6 +99,41 @@ ABSL_NAMESPACE_END
: [] { assert(false && #expr); }()) // NOLINT : [] { assert(false && #expr); }()) // NOLINT
#endif #endif
// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
// aborts the program in release mode (when NDEBUG is defined). The
// implementation should abort the program as quickly as possible and ideally it
// should not be possible to ignore the abort request.
#if (ABSL_HAVE_BUILTIN(__builtin_trap) && \
ABSL_HAVE_BUILTIN(__builtin_unreachable)) || \
(defined(__GNUC__) && !defined(__clang__))
#define ABSL_INTERNAL_HARDENING_ABORT() \
do { \
__builtin_trap(); \
__builtin_unreachable(); \
} while (false)
#else
#define ABSL_INTERNAL_HARDENING_ABORT() abort()
#endif
// ABSL_HARDENING_ASSERT()
//
// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
// runtime assertions that should be enabled in hardened builds even when
// `NDEBUG` is defined.
//
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
// `ABSL_ASSERT()`.
//
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
// hardened mode.
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
#define ABSL_HARDENING_ASSERT(expr) \
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
#else
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
#endif
#ifdef ABSL_HAVE_EXCEPTIONS #ifdef ABSL_HAVE_EXCEPTIONS
#define ABSL_INTERNAL_TRY try #define ABSL_INTERNAL_TRY try
#define ABSL_INTERNAL_CATCH_ANY catch (...) #define ABSL_INTERNAL_CATCH_ANY catch (...)
......
...@@ -171,11 +171,71 @@ ...@@ -171,11 +171,71 @@
// to yield performance improvements. // to yield performance improvements.
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \ #if ABSL_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__)) (defined(__GNUC__) && !defined(__clang__))
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0)) #define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true)) #define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
#else #else
#define ABSL_PREDICT_FALSE(x) (x) #define ABSL_PREDICT_FALSE(x) (x)
#define ABSL_PREDICT_TRUE(x) (x) #define ABSL_PREDICT_TRUE(x) (x)
#endif #endif
// ABSL_INTERNAL_ASSUME(cond)
// Informs the compiler than a condition is always true and that it can assume
// it to be true for optimization purposes. The call has undefined behavior if
// the condition is false.
// In !NDEBUG mode, the condition is checked with an assert().
// NOTE: The expression must not have side effects, as it will only be evaluated
// in some compilation modes and not others.
//
// Example:
//
// int x = ...;
// ABSL_INTERNAL_ASSUME(x >= 0);
// // The compiler can optimize the division to a simple right shift using the
// // assumption specified above.
// int y = x / 16;
//
#if !defined(NDEBUG)
#define ABSL_INTERNAL_ASSUME(cond) assert(cond)
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
#define ABSL_INTERNAL_ASSUME(cond) __builtin_assume(cond)
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
#define ABSL_INTERNAL_ASSUME(cond) \
do { \
if (!(cond)) __builtin_unreachable(); \
} while (0)
#elif defined(_MSC_VER)
#define ABSL_INTERNAL_ASSUME(cond) __assume(cond)
#else
#define ABSL_INTERNAL_ASSUME(cond) \
do { \
static_cast<void>(false && (cond)); \
} while (0)
#endif
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
// This macro forces small unique name on a static file level symbols like
// static local variables or static functions. This is intended to be used in
// macro definitions to optimize the cost of generated code. Do NOT use it on
// symbols exported from translation unit since it may casue a link time
// conflict.
//
// Example:
//
// #define MY_MACRO(txt)
// namespace {
// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
// const char* VeryVeryLongFuncName() { return txt; }
// }
//
#if defined(__GNUC__)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
#else
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
#endif
#endif // ABSL_BASE_OPTIMIZATION_H_ #endif // ABSL_BASE_OPTIMIZATION_H_
// Copyright 2020 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT 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/optimization.h"
#include "gtest/gtest.h"
#include "absl/types/optional.h"
namespace {
// Tests for the ABSL_PREDICT_TRUE and ABSL_PREDICT_FALSE macros.
// The tests only verify that the macros are functionally correct - i.e. code
// behaves as if they weren't used. They don't try to check their impact on
// optimization.
TEST(PredictTest, PredictTrue) {
EXPECT_TRUE(ABSL_PREDICT_TRUE(true));
EXPECT_FALSE(ABSL_PREDICT_TRUE(false));
EXPECT_TRUE(ABSL_PREDICT_TRUE(1 == 1));
EXPECT_FALSE(ABSL_PREDICT_TRUE(1 == 2));
if (ABSL_PREDICT_TRUE(false)) ADD_FAILURE();
if (!ABSL_PREDICT_TRUE(true)) ADD_FAILURE();
EXPECT_TRUE(ABSL_PREDICT_TRUE(true) && true);
EXPECT_TRUE(ABSL_PREDICT_TRUE(true) || false);
}
TEST(PredictTest, PredictFalse) {
EXPECT_TRUE(ABSL_PREDICT_FALSE(true));
EXPECT_FALSE(ABSL_PREDICT_FALSE(false));
EXPECT_TRUE(ABSL_PREDICT_FALSE(1 == 1));
EXPECT_FALSE(ABSL_PREDICT_FALSE(1 == 2));
if (ABSL_PREDICT_FALSE(false)) ADD_FAILURE();
if (!ABSL_PREDICT_FALSE(true)) ADD_FAILURE();
EXPECT_TRUE(ABSL_PREDICT_FALSE(true) && true);
EXPECT_TRUE(ABSL_PREDICT_FALSE(true) || false);
}
TEST(PredictTest, OneEvaluation) {
// Verify that the expression is only evaluated once.
int x = 0;
if (ABSL_PREDICT_TRUE((++x) == 0)) ADD_FAILURE();
EXPECT_EQ(x, 1);
if (ABSL_PREDICT_FALSE((++x) == 0)) ADD_FAILURE();
EXPECT_EQ(x, 2);
}
TEST(PredictTest, OperatorOrder) {
// Verify that operator order inside and outside the macro behaves well.
// These would fail for a naive '#define ABSL_PREDICT_TRUE(x) x'
EXPECT_TRUE(ABSL_PREDICT_TRUE(1 && 2) == true);
EXPECT_TRUE(ABSL_PREDICT_FALSE(1 && 2) == true);
EXPECT_TRUE(!ABSL_PREDICT_TRUE(1 == 2));
EXPECT_TRUE(!ABSL_PREDICT_FALSE(1 == 2));
}
TEST(PredictTest, Pointer) {
const int x = 3;
const int *good_intptr = &x;
const int *null_intptr = nullptr;
EXPECT_TRUE(ABSL_PREDICT_TRUE(good_intptr));
EXPECT_FALSE(ABSL_PREDICT_TRUE(null_intptr));
EXPECT_TRUE(ABSL_PREDICT_FALSE(good_intptr));
EXPECT_FALSE(ABSL_PREDICT_FALSE(null_intptr));
}
TEST(PredictTest, Optional) {
// Note: An optional's truth value is the value's existence, not its truth.
absl::optional<bool> has_value(false);
absl::optional<bool> no_value;
EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value));
EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value));
EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
EXPECT_FALSE(ABSL_PREDICT_FALSE(no_value));
}
class ImplictlyConvertibleToBool {
public:
explicit ImplictlyConvertibleToBool(bool value) : value_(value) {}
operator bool() const { // NOLINT(google-explicit-constructor)
return value_;
}
private:
bool value_;
};
TEST(PredictTest, ImplicitBoolConversion) {
const ImplictlyConvertibleToBool is_true(true);
const ImplictlyConvertibleToBool is_false(false);
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
}
class ExplictlyConvertibleToBool {
public:
explicit ExplictlyConvertibleToBool(bool value) : value_(value) {}
explicit operator bool() const { return value_; }
private:
bool value_;
};
TEST(PredictTest, ExplicitBoolConversion) {
const ExplictlyConvertibleToBool is_true(true);
const ExplictlyConvertibleToBool is_false(false);
if (!ABSL_PREDICT_TRUE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_TRUE(is_false)) ADD_FAILURE();
if (!ABSL_PREDICT_FALSE(is_true)) ADD_FAILURE();
if (ABSL_PREDICT_FALSE(is_false)) ADD_FAILURE();
}
} // namespace
#ifndef ABSL_BASE_OPTIONS_H_
#define ABSL_BASE_OPTIONS_H_
// Copyright 2019 The Abseil Authors. // Copyright 2019 The Abseil Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
...@@ -67,6 +64,9 @@ ...@@ -67,6 +64,9 @@
// proper Abseil implementation at compile-time, which will not be sufficient // proper Abseil implementation at compile-time, which will not be sufficient
// to guarantee ABI stability to package managers. // to guarantee ABI stability to package managers.
#ifndef ABSL_BASE_OPTIONS_H_
#define ABSL_BASE_OPTIONS_H_
// Include a standard library header to allow configuration based on the // Include a standard library header to allow configuration based on the
// standard library in use. // standard library in use.
#ifdef __cplusplus #ifdef __cplusplus
...@@ -206,6 +206,33 @@ ...@@ -206,6 +206,33 @@
// allowed. // allowed.
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1 #define ABSL_OPTION_USE_INLINE_NAMESPACE 1
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_02_25 #define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_2020_09_23
// ABSL_OPTION_HARDENED
//
// This option enables a "hardened" build in release mode (in this context,
// release mode is defined as a build where the `NDEBUG` macro is defined).
//
// A value of 0 means that "hardened" mode is not enabled.
//
// A value of 1 means that "hardened" mode is enabled.
//
// Hardened builds have additional security checks enabled when `NDEBUG` is
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
// no-op, as well as disabling other bespoke program consistency checks. By
// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
// release mode. These checks guard against programming errors that may lead to
// security vulnerabilities. In release mode, when one of these programming
// errors is encountered, the program will immediately abort, possibly without
// any attempt at logging.
//
// The checks enabled by this option are not free; they do incur runtime cost.
//
// The checks enabled by this option are always active when `NDEBUG` is not
// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
// checks enabled by this option may abort the program in a different way and
// log additional information when `NDEBUG` is not defined.
#define ABSL_OPTION_HARDENED 0
#endif // ABSL_BASE_OPTIONS_H_ #endif // ABSL_BASE_OPTIONS_H_
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#endif #endif
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Compiler Check // Toolchain Check
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// We support MSVC++ 14.0 update 2 and later. // We support MSVC++ 14.0 update 2 and later.
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#include <limits> #include <limits>
#include <random> #include <random>
#include <thread> // NOLINT(build/c++11) #include <thread> // NOLINT(build/c++11)
#include <type_traits>
#include <vector> #include <vector>
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/base/internal/low_level_scheduling.h" #include "absl/base/internal/low_level_scheduling.h"
#include "absl/base/internal/scheduling_mode.h" #include "absl/base/internal/scheduling_mode.h"
#include "absl/base/internal/spinlock.h" #include "absl/base/internal/spinlock.h"
...@@ -56,12 +58,10 @@ namespace { ...@@ -56,12 +58,10 @@ namespace {
static constexpr int kArrayLength = 10; static constexpr int kArrayLength = 10;
static uint32_t values[kArrayLength]; static uint32_t values[kArrayLength];
static SpinLock static_spinlock(base_internal::kLinkerInitialized); ABSL_CONST_INIT static SpinLock static_cooperative_spinlock(
static SpinLock static_cooperative_spinlock( absl::kConstInit, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL);
base_internal::kLinkerInitialized, ABSL_CONST_INIT static SpinLock static_noncooperative_spinlock(
base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
static SpinLock static_noncooperative_spinlock(
base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY);
// Simple integer hash function based on the public domain lookup2 hash. // Simple integer hash function based on the public domain lookup2 hash.
// http://burtleburtle.net/bob/c/lookup2.c // http://burtleburtle.net/bob/c/lookup2.c
...@@ -105,6 +105,10 @@ static void ThreadedTest(SpinLock* spinlock) { ...@@ -105,6 +105,10 @@ static void ThreadedTest(SpinLock* spinlock) {
} }
} }
#ifndef ABSL_HAVE_THREAD_SANITIZER
static_assert(std::is_trivially_destructible<SpinLock>(), "");
#endif
TEST(SpinLock, StackNonCooperativeDisablesScheduling) { TEST(SpinLock, StackNonCooperativeDisablesScheduling) {
SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY);
spinlock.Lock(); spinlock.Lock();
...@@ -191,10 +195,6 @@ TEST(SpinLock, WaitCyclesEncoding) { ...@@ -191,10 +195,6 @@ TEST(SpinLock, WaitCyclesEncoding) {
EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
} }
TEST(SpinLockWithThreads, StaticSpinLock) {
ThreadedTest(&static_spinlock);
}
TEST(SpinLockWithThreads, StackSpinLock) { TEST(SpinLockWithThreads, StackSpinLock) {
SpinLock spinlock; SpinLock spinlock;
ThreadedTest(&spinlock); ThreadedTest(&spinlock);
......
...@@ -34,16 +34,11 @@ ...@@ -34,16 +34,11 @@
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
#define ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_
#include "absl/base/attributes.h"
#include "absl/base/config.h" #include "absl/base/config.h"
// TODO(mbonadei): Remove after the backward compatibility period. // TODO(mbonadei): Remove after the backward compatibility period.
#include "absl/base/internal/thread_annotations.h" // IWYU pragma: export #include "absl/base/internal/thread_annotations.h" // IWYU pragma: export
#if defined(__clang__)
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) __attribute__((x))
#else
#define ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(x) // no-op
#endif
// ABSL_GUARDED_BY() // ABSL_GUARDED_BY()
// //
// Documents if a shared field or global variable needs to be protected by a // Documents if a shared field or global variable needs to be protected by a
...@@ -61,8 +56,11 @@ ...@@ -61,8 +56,11 @@
// int p1_ ABSL_GUARDED_BY(mu_); // int p1_ ABSL_GUARDED_BY(mu_);
// ... // ...
// }; // };
#define ABSL_GUARDED_BY(x) \ #if ABSL_HAVE_ATTRIBUTE(guarded_by)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(guarded_by(x)) #define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
#else
#define ABSL_GUARDED_BY(x)
#endif
// ABSL_PT_GUARDED_BY() // ABSL_PT_GUARDED_BY()
// //
...@@ -84,8 +82,11 @@ ...@@ -84,8 +82,11 @@
// // `q_`, guarded by `mu1_`, points to a shared memory location that is // // `q_`, guarded by `mu1_`, points to a shared memory location that is
// // guarded by `mu2_`: // // guarded by `mu2_`:
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_); // int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
#define ABSL_PT_GUARDED_BY(x) \ #if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(pt_guarded_by(x)) #define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
#else
#define ABSL_PT_GUARDED_BY(x)
#endif
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE() // ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
// //
...@@ -102,11 +103,17 @@ ...@@ -102,11 +103,17 @@
// //
// Mutex m1_; // Mutex m1_;
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_); // Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
#define ABSL_ACQUIRED_AFTER(...) \ #if ABSL_HAVE_ATTRIBUTE(acquired_after)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_after(__VA_ARGS__)) #define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_AFTER(...)
#endif
#define ABSL_ACQUIRED_BEFORE(...) \ #if ABSL_HAVE_ATTRIBUTE(acquired_before)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(acquired_before(__VA_ARGS__)) #define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#else
#define ABSL_ACQUIRED_BEFORE(...)
#endif
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED() // ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
// //
...@@ -131,33 +138,50 @@ ...@@ -131,33 +138,50 @@
// //
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... } // void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... } // void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \ #if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ #define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
exclusive_locks_required(__VA_ARGS__)) __attribute__((exclusive_locks_required(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
#define ABSL_SHARED_LOCKS_REQUIRED(...) \ #define ABSL_SHARED_LOCKS_REQUIRED(...) \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_locks_required(__VA_ARGS__)) __attribute__((shared_locks_required(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCKS_REQUIRED(...)
#endif
// ABSL_LOCKS_EXCLUDED() // ABSL_LOCKS_EXCLUDED()
// //
// Documents the locks acquired in the body of the function. These locks // Documents the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as Abseil's `Mutex` locks are // cannot be held when calling this function (as Abseil's `Mutex` locks are
// non-reentrant). // non-reentrant).
#define ABSL_LOCKS_EXCLUDED(...) \ #if ABSL_HAVE_ATTRIBUTE(locks_excluded)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(locks_excluded(__VA_ARGS__)) #define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
#else
#define ABSL_LOCKS_EXCLUDED(...)
#endif
// ABSL_LOCK_RETURNED() // ABSL_LOCK_RETURNED()
// //
// Documents a function that returns a mutex without acquiring it. For example, // Documents a function that returns a mutex without acquiring it. For example,
// a public getter method that returns a pointer to a private mutex should // a public getter method that returns a pointer to a private mutex should
// be annotated with ABSL_LOCK_RETURNED. // be annotated with ABSL_LOCK_RETURNED.
#define ABSL_LOCK_RETURNED(x) \ #if ABSL_HAVE_ATTRIBUTE(lock_returned)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lock_returned(x)) #define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
#else
#define ABSL_LOCK_RETURNED(x)
#endif
// ABSL_LOCKABLE // ABSL_LOCKABLE
// //
// Documents if a class/type is a lockable type (such as the `Mutex` class). // Documents if a class/type is a lockable type (such as the `Mutex` class).
#define ABSL_LOCKABLE ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(lockable) #if ABSL_HAVE_ATTRIBUTE(lockable)
#define ABSL_LOCKABLE __attribute__((lockable))
#else
#define ABSL_LOCKABLE
#endif
// ABSL_SCOPED_LOCKABLE // ABSL_SCOPED_LOCKABLE
// //
...@@ -166,30 +190,43 @@ ...@@ -166,30 +190,43 @@
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no // acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
// arguments; the analysis will assume that the destructor unlocks whatever the // arguments; the analysis will assume that the destructor unlocks whatever the
// constructor locked. // constructor locked.
#define ABSL_SCOPED_LOCKABLE \ #if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(scoped_lockable) #define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
#else
#define ABSL_SCOPED_LOCKABLE
#endif
// ABSL_EXCLUSIVE_LOCK_FUNCTION() // ABSL_EXCLUSIVE_LOCK_FUNCTION()
// //
// Documents functions that acquire a lock in the body of a function, and do // Documents functions that acquire a lock in the body of a function, and do
// not release it. // not release it.
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \ #if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ #define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
exclusive_lock_function(__VA_ARGS__)) __attribute__((exclusive_lock_function(__VA_ARGS__)))
#else
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
#endif
// ABSL_SHARED_LOCK_FUNCTION() // ABSL_SHARED_LOCK_FUNCTION()
// //
// Documents functions that acquire a shared (reader) lock in the body of a // Documents functions that acquire a shared (reader) lock in the body of a
// function, and do not release it. // function, and do not release it.
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
#define ABSL_SHARED_LOCK_FUNCTION(...) \ #define ABSL_SHARED_LOCK_FUNCTION(...) \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(shared_lock_function(__VA_ARGS__)) __attribute__((shared_lock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_LOCK_FUNCTION(...)
#endif
// ABSL_UNLOCK_FUNCTION() // ABSL_UNLOCK_FUNCTION()
// //
// Documents functions that expect a lock to be held on entry to the function, // Documents functions that expect a lock to be held on entry to the function,
// and release it in the body of the function. // and release it in the body of the function.
#define ABSL_UNLOCK_FUNCTION(...) \ #if ABSL_HAVE_ATTRIBUTE(unlock_function)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(unlock_function(__VA_ARGS__)) #define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
#else
#define ABSL_UNLOCK_FUNCTION(...)
#endif
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION() // ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
// //
...@@ -199,31 +236,49 @@ ...@@ -199,31 +236,49 @@
// success, or `false` for functions that return `false` on success. The second // success, or `false` for functions that return `false` on success. The second
// argument specifies the mutex that is locked on success. If unspecified, this // argument specifies the mutex that is locked on success. If unspecified, this
// mutex is assumed to be `this`. // mutex is assumed to be `this`.
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ #define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ __attribute__((exclusive_trylock_function(__VA_ARGS__)))
exclusive_trylock_function(__VA_ARGS__)) #else
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
#endif
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \ #if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE( \ #define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
shared_trylock_function(__VA_ARGS__)) __attribute__((shared_trylock_function(__VA_ARGS__)))
#else
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
#endif
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK() // ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
// //
// Documents functions that dynamically check to see if a lock is held, and fail // Documents functions that dynamically check to see if a lock is held, and fail
// if it is not held. // if it is not held.
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \ #define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_exclusive_lock(__VA_ARGS__)) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
#endif
#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
#define ABSL_ASSERT_SHARED_LOCK(...) \ #define ABSL_ASSERT_SHARED_LOCK(...) \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(assert_shared_lock(__VA_ARGS__)) __attribute__((assert_shared_lock(__VA_ARGS__)))
#else
#define ABSL_ASSERT_SHARED_LOCK(...)
#endif
// ABSL_NO_THREAD_SAFETY_ANALYSIS // ABSL_NO_THREAD_SAFETY_ANALYSIS
// //
// Turns off thread safety checking within the body of a particular function. // Turns off thread safety checking within the body of a particular function.
// This annotation is used to mark functions that are known to be correct, but // This annotation is used to mark functions that are known to be correct, but
// the locking behavior is more complicated than the analyzer can handle. // the locking behavior is more complicated than the analyzer can handle.
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \ #define ABSL_NO_THREAD_SAFETY_ANALYSIS \
ABSL_INTERNAL_THREAD_ANNOTATION_ATTRIBUTE(no_thread_safety_analysis) __attribute__((no_thread_safety_analysis))
#else
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Tool-Supplied Annotations // Tool-Supplied Annotations
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
# #
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
load( load(
"//absl:copts/configure_copts.bzl", "//absl:copts/configure_copts.bzl",
"ABSL_DEFAULT_COPTS", "ABSL_DEFAULT_COPTS",
...@@ -24,7 +24,7 @@ load( ...@@ -24,7 +24,7 @@ load(
package(default_visibility = ["//visibility:public"]) package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # Apache 2.0 licenses(["notice"])
cc_library( cc_library(
name = "compressed_tuple", name = "compressed_tuple",
...@@ -60,6 +60,7 @@ cc_library( ...@@ -60,6 +60,7 @@ cc_library(
deps = [ deps = [
":compressed_tuple", ":compressed_tuple",
"//absl/algorithm", "//absl/algorithm",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:dynamic_annotations", "//absl/base:dynamic_annotations",
"//absl/base:throw_delegate", "//absl/base:throw_delegate",
...@@ -73,7 +74,9 @@ cc_test( ...@@ -73,7 +74,9 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
":counting_allocator",
":fixed_array", ":fixed_array",
"//absl/base:config",
"//absl/base:exception_testing", "//absl/base:exception_testing",
"//absl/hash:hash_testing", "//absl/hash:hash_testing",
"//absl/memory", "//absl/memory",
...@@ -153,6 +156,7 @@ cc_test( ...@@ -153,6 +156,7 @@ cc_test(
":counting_allocator", ":counting_allocator",
":inlined_vector", ":inlined_vector",
":test_instance_tracker", ":test_instance_tracker",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:exception_testing", "//absl/base:exception_testing",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
...@@ -255,6 +259,7 @@ cc_test( ...@@ -255,6 +259,7 @@ cc_test(
":unordered_map_lookup_test", ":unordered_map_lookup_test",
":unordered_map_members_test", ":unordered_map_members_test",
":unordered_map_modifiers_test", ":unordered_map_modifiers_test",
"//absl/base:raw_logging_internal",
"//absl/types:any", "//absl/types:any",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
...@@ -288,6 +293,7 @@ cc_test( ...@@ -288,6 +293,7 @@ cc_test(
":unordered_set_lookup_test", ":unordered_set_lookup_test",
":unordered_set_members_test", ":unordered_set_members_test",
":unordered_set_modifiers_test", ":unordered_set_modifiers_test",
"//absl/base:raw_logging_internal",
"//absl/memory", "//absl/memory",
"//absl/strings", "//absl/strings",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
...@@ -363,7 +369,9 @@ cc_library( ...@@ -363,7 +369,9 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
"//absl/base:config",
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits",
"//absl/utility", "//absl/utility",
], ],
) )
...@@ -376,6 +384,7 @@ cc_test( ...@@ -376,6 +384,7 @@ cc_test(
tags = NOTEST_TAGS_NONMOBILE, tags = NOTEST_TAGS_NONMOBILE,
deps = [ deps = [
":container_memory", ":container_memory",
":test_instance_tracker",
"//absl/strings", "//absl/strings",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
...@@ -390,6 +399,7 @@ cc_library( ...@@ -390,6 +399,7 @@ cc_library(
"//absl/base:config", "//absl/base:config",
"//absl/hash", "//absl/hash",
"//absl/strings", "//absl/strings",
"//absl/strings:cord",
], ],
) )
...@@ -402,7 +412,10 @@ cc_test( ...@@ -402,7 +412,10 @@ cc_test(
deps = [ deps = [
":hash_function_defaults", ":hash_function_defaults",
"//absl/hash", "//absl/hash",
"//absl/random",
"//absl/strings", "//absl/strings",
"//absl/strings:cord",
"//absl/strings:cord_test_helpers",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )
...@@ -609,6 +622,7 @@ cc_test( ...@@ -609,6 +622,7 @@ cc_test(
":hashtable_debug", ":hashtable_debug",
":raw_hash_set", ":raw_hash_set",
"//absl/base", "//absl/base",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/strings", "//absl/strings",
...@@ -636,6 +650,7 @@ cc_library( ...@@ -636,6 +650,7 @@ cc_library(
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS, linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [ deps = [
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/strings", "//absl/strings",
...@@ -654,6 +669,7 @@ cc_test( ...@@ -654,6 +669,7 @@ cc_test(
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
deps = [ deps = [
":layout", ":layout",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:raw_logging_internal", "//absl/base:raw_logging_internal",
"//absl/types:span", "//absl/types:span",
...@@ -828,6 +844,7 @@ cc_library( ...@@ -828,6 +844,7 @@ cc_library(
"//absl/memory", "//absl/memory",
"//absl/meta:type_traits", "//absl/meta:type_traits",
"//absl/strings", "//absl/strings",
"//absl/strings:cord",
"//absl/types:compare", "//absl/types:compare",
"//absl/utility", "//absl/utility",
], ],
...@@ -844,6 +861,7 @@ cc_library( ...@@ -844,6 +861,7 @@ cc_library(
":btree", ":btree",
":flat_hash_set", ":flat_hash_set",
"//absl/strings", "//absl/strings",
"//absl/strings:cord",
"//absl/time", "//absl/time",
], ],
) )
...@@ -895,6 +913,7 @@ cc_binary( ...@@ -895,6 +913,7 @@ cc_binary(
"//absl/flags:flag", "//absl/flags:flag",
"//absl/hash", "//absl/hash",
"//absl/memory", "//absl/memory",
"//absl/strings:cord",
"//absl/strings:str_format", "//absl/strings:str_format",
"//absl/time", "//absl/time",
"@com_github_google_benchmark//:benchmark_main", "@com_github_google_benchmark//:benchmark_main",
......
...@@ -40,6 +40,7 @@ absl_cc_library( ...@@ -40,6 +40,7 @@ absl_cc_library(
absl::compare absl::compare
absl::compressed_tuple absl::compressed_tuple
absl::container_memory absl::container_memory
absl::cord
absl::core_headers absl::core_headers
absl::layout absl::layout
absl::memory absl::memory
...@@ -60,6 +61,7 @@ absl_cc_library( ...@@ -60,6 +61,7 @@ absl_cc_library(
${ABSL_DEFAULT_LINKOPTS} ${ABSL_DEFAULT_LINKOPTS}
DEPS DEPS
absl::btree absl::btree
absl::cord
absl::flat_hash_set absl::flat_hash_set
absl::strings absl::strings
absl::time absl::time
...@@ -129,6 +131,7 @@ absl_cc_library( ...@@ -129,6 +131,7 @@ absl_cc_library(
DEPS DEPS
absl::compressed_tuple absl::compressed_tuple
absl::algorithm absl::algorithm
absl::config
absl::core_headers absl::core_headers
absl::dynamic_annotations absl::dynamic_annotations
absl::throw_delegate absl::throw_delegate
...@@ -145,6 +148,8 @@ absl_cc_test( ...@@ -145,6 +148,8 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::fixed_array absl::fixed_array
absl::counting_allocator
absl::config
absl::exception_testing absl::exception_testing
absl::hash_testing absl::hash_testing
absl::memory absl::memory
...@@ -219,6 +224,7 @@ absl_cc_test( ...@@ -219,6 +224,7 @@ absl_cc_test(
absl::counting_allocator absl::counting_allocator
absl::inlined_vector absl::inlined_vector
absl::test_instance_tracker absl::test_instance_tracker
absl::config
absl::core_headers absl::core_headers
absl::exception_testing absl::exception_testing
absl::hash_testing absl::hash_testing
...@@ -299,6 +305,7 @@ absl_cc_test( ...@@ -299,6 +305,7 @@ absl_cc_test(
absl::unordered_map_members_test absl::unordered_map_members_test
absl::unordered_map_modifiers_test absl::unordered_map_modifiers_test
absl::any absl::any
absl::raw_logging_internal
gmock_main gmock_main
) )
...@@ -335,6 +342,7 @@ absl_cc_test( ...@@ -335,6 +342,7 @@ absl_cc_test(
absl::unordered_set_members_test absl::unordered_set_members_test
absl::unordered_set_modifiers_test absl::unordered_set_modifiers_test
absl::memory absl::memory
absl::raw_logging_internal
absl::strings absl::strings
gmock_main gmock_main
) )
...@@ -416,7 +424,9 @@ absl_cc_library( ...@@ -416,7 +424,9 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::config
absl::memory absl::memory
absl::type_traits
absl::utility absl::utility
PUBLIC PUBLIC
) )
...@@ -431,6 +441,7 @@ absl_cc_test( ...@@ -431,6 +441,7 @@ absl_cc_test(
DEPS DEPS
absl::container_memory absl::container_memory
absl::strings absl::strings
absl::test_instance_tracker
gmock_main gmock_main
) )
...@@ -443,6 +454,7 @@ absl_cc_library( ...@@ -443,6 +454,7 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::config absl::config
absl::cord
absl::hash absl::hash
absl::strings absl::strings
PUBLIC PUBLIC
...@@ -456,8 +468,11 @@ absl_cc_test( ...@@ -456,8 +468,11 @@ absl_cc_test(
COPTS COPTS
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::cord
absl::cord_test_helpers
absl::hash_function_defaults absl::hash_function_defaults
absl::hash absl::hash
absl::random_random
absl::strings absl::strings
gmock_main gmock_main
) )
...@@ -683,6 +698,7 @@ absl_cc_test( ...@@ -683,6 +698,7 @@ absl_cc_test(
absl::hashtable_debug absl::hashtable_debug
absl::raw_hash_set absl::raw_hash_set
absl::base absl::base
absl::config
absl::core_headers absl::core_headers
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
...@@ -711,6 +727,7 @@ absl_cc_library( ...@@ -711,6 +727,7 @@ absl_cc_library(
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
DEPS DEPS
absl::config
absl::core_headers absl::core_headers
absl::meta absl::meta
absl::strings absl::strings
...@@ -728,6 +745,7 @@ absl_cc_test( ...@@ -728,6 +745,7 @@ absl_cc_test(
${ABSL_TEST_COPTS} ${ABSL_TEST_COPTS}
DEPS DEPS
absl::layout absl::layout
absl::config
absl::core_headers absl::core_headers
absl::raw_logging_internal absl::raw_logging_internal
absl::span absl::span
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "absl/flags/flag.h" #include "absl/flags/flag.h"
#include "absl/hash/hash.h" #include "absl/hash/hash.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/strings/cord.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/time/time.h" #include "absl/time/time.h"
#include "benchmark/benchmark.h" #include "benchmark/benchmark.h"
...@@ -133,6 +134,27 @@ void BM_InsertEnd(benchmark::State& state) { ...@@ -133,6 +134,27 @@ void BM_InsertEnd(benchmark::State& state) {
} }
} }
// Benchmark inserting the first few elements in a container. In b-tree, this is
// when the root node grows.
template <typename T>
void BM_InsertSmall(benchmark::State& state) {
using V = typename remove_pair_const<typename T::value_type>::type;
const int kSize = 8;
std::vector<V> values = GenerateValues<V>(kSize);
T container;
while (state.KeepRunningBatch(kSize)) {
for (int i = 0; i < kSize; ++i) {
benchmark::DoNotOptimize(container.insert(values[i]));
}
state.PauseTiming();
// Do not measure the time it takes to clear the container.
container.clear();
state.ResumeTiming();
}
}
template <typename T> template <typename T>
void BM_LookupImpl(benchmark::State& state, bool sorted) { void BM_LookupImpl(benchmark::State& state, bool sorted) {
using V = typename remove_pair_const<typename T::value_type>::type; using V = typename remove_pair_const<typename T::value_type>::type;
...@@ -438,6 +460,7 @@ using StdString = std::string; ...@@ -438,6 +460,7 @@ using StdString = std::string;
STL_ORDERED_TYPES(int32_t); STL_ORDERED_TYPES(int32_t);
STL_ORDERED_TYPES(int64_t); STL_ORDERED_TYPES(int64_t);
STL_ORDERED_TYPES(StdString); STL_ORDERED_TYPES(StdString);
STL_ORDERED_TYPES(Cord);
STL_ORDERED_TYPES(Time); STL_ORDERED_TYPES(Time);
#define STL_UNORDERED_TYPES(value) \ #define STL_UNORDERED_TYPES(value) \
...@@ -458,6 +481,8 @@ STL_ORDERED_TYPES(Time); ...@@ -458,6 +481,8 @@ STL_ORDERED_TYPES(Time);
using stl_unordered_multimap_##value = \ using stl_unordered_multimap_##value = \
std::unordered_multimap<value, intptr_t, hash> std::unordered_multimap<value, intptr_t, hash>
STL_UNORDERED_TYPES_CUSTOM_HASH(Cord, absl::Hash<absl::Cord>);
STL_UNORDERED_TYPES(int32_t); STL_UNORDERED_TYPES(int32_t);
STL_UNORDERED_TYPES(int64_t); STL_UNORDERED_TYPES(int64_t);
STL_UNORDERED_TYPES(StdString); STL_UNORDERED_TYPES(StdString);
...@@ -478,6 +503,7 @@ STL_UNORDERED_TYPES_CUSTOM_HASH(Time, absl::Hash<absl::Time>); ...@@ -478,6 +503,7 @@ STL_UNORDERED_TYPES_CUSTOM_HASH(Time, absl::Hash<absl::Time>);
BTREE_TYPES(int32_t); BTREE_TYPES(int32_t);
BTREE_TYPES(int64_t); BTREE_TYPES(int64_t);
BTREE_TYPES(StdString); BTREE_TYPES(StdString);
BTREE_TYPES(Cord);
BTREE_TYPES(Time); BTREE_TYPES(Time);
#define MY_BENCHMARK4(type, func) \ #define MY_BENCHMARK4(type, func) \
...@@ -488,6 +514,7 @@ BTREE_TYPES(Time); ...@@ -488,6 +514,7 @@ BTREE_TYPES(Time);
MY_BENCHMARK4(type, Insert); \ MY_BENCHMARK4(type, Insert); \
MY_BENCHMARK4(type, InsertSorted); \ MY_BENCHMARK4(type, InsertSorted); \
MY_BENCHMARK4(type, InsertEnd); \ MY_BENCHMARK4(type, InsertEnd); \
MY_BENCHMARK4(type, InsertSmall); \
MY_BENCHMARK4(type, Lookup); \ MY_BENCHMARK4(type, Lookup); \
MY_BENCHMARK4(type, FullLookup); \ MY_BENCHMARK4(type, FullLookup); \
MY_BENCHMARK4(type, Delete); \ MY_BENCHMARK4(type, Delete); \
...@@ -526,6 +553,7 @@ BTREE_TYPES(Time); ...@@ -526,6 +553,7 @@ BTREE_TYPES(Time);
MY_BENCHMARK(int32_t); MY_BENCHMARK(int32_t);
MY_BENCHMARK(int64_t); MY_BENCHMARK(int64_t);
MY_BENCHMARK(StdString); MY_BENCHMARK(StdString);
MY_BENCHMARK(Cord);
MY_BENCHMARK(Time); MY_BENCHMARK(Time);
// Define a type whose size and cost of moving are independently customizable. // Define a type whose size and cost of moving are independently customizable.
...@@ -538,19 +566,19 @@ struct BigType { ...@@ -538,19 +566,19 @@ struct BigType {
BigType() : BigType(0) {} BigType() : BigType(0) {}
explicit BigType(int x) { std::iota(values.begin(), values.end(), x); } explicit BigType(int x) { std::iota(values.begin(), values.end(), x); }
void Copy(const BigType& x) { void Copy(const BigType& other) {
for (int i = 0; i < Size && i < Copies; ++i) values[i] = x.values[i]; for (int i = 0; i < Size && i < Copies; ++i) values[i] = other.values[i];
// If Copies > Size, do extra copies. // If Copies > Size, do extra copies.
for (int i = Size, idx = 0; i < Copies; ++i) { for (int i = Size, idx = 0; i < Copies; ++i) {
int64_t tmp = x.values[idx]; int64_t tmp = other.values[idx];
benchmark::DoNotOptimize(tmp); benchmark::DoNotOptimize(tmp);
idx = idx + 1 == Size ? 0 : idx + 1; idx = idx + 1 == Size ? 0 : idx + 1;
} }
} }
BigType(const BigType& x) { Copy(x); } BigType(const BigType& other) { Copy(other); }
BigType& operator=(const BigType& x) { BigType& operator=(const BigType& other) {
Copy(x); Copy(other);
return *this; return *this;
} }
...@@ -641,14 +669,14 @@ struct BigTypePtr { ...@@ -641,14 +669,14 @@ struct BigTypePtr {
explicit BigTypePtr(int x) { explicit BigTypePtr(int x) {
ptr = absl::make_unique<BigType<Size, Size>>(x); ptr = absl::make_unique<BigType<Size, Size>>(x);
} }
BigTypePtr(const BigTypePtr& x) { BigTypePtr(const BigTypePtr& other) {
ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr); ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
} }
BigTypePtr(BigTypePtr&& x) noexcept = default; BigTypePtr(BigTypePtr&& other) noexcept = default;
BigTypePtr& operator=(const BigTypePtr& x) { BigTypePtr& operator=(const BigTypePtr& other) {
ptr = absl::make_unique<BigType<Size, Size>>(*x.ptr); ptr = absl::make_unique<BigType<Size, Size>>(*other.ptr);
} }
BigTypePtr& operator=(BigTypePtr&& x) noexcept = default; BigTypePtr& operator=(BigTypePtr&& other) noexcept = default;
bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; } bool operator<(const BigTypePtr& other) const { return *ptr < *other.ptr; }
bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; } bool operator==(const BigTypePtr& other) const { return *ptr == *other.ptr; }
......
...@@ -185,7 +185,7 @@ class btree_map ...@@ -185,7 +185,7 @@ class btree_map
// template <typename K> size_type erase(const K& key): // template <typename K> size_type erase(const K& key):
// //
// Erases the element with the matching key, if it exists, returning the // Erases the element with the matching key, if it exists, returning the
// number of elements erased. // number of elements erased (0 or 1).
using Base::erase; using Base::erase;
// btree_map::insert() // btree_map::insert()
...@@ -318,13 +318,18 @@ class btree_map ...@@ -318,13 +318,18 @@ class btree_map
// Extracts the element at the indicated position and returns a node handle // Extracts the element at the indicated position and returns a node handle
// owning that extracted data. // owning that extracted data.
// //
// template <typename K> node_type extract(const K& x): // template <typename K> node_type extract(const K& k):
// //
// Extracts the element with the key matching the passed key value and // Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_map` // returns a node handle owning that extracted data. If the `btree_map`
// does not contain an element with a matching key, this function returns an // does not contain an element with a matching key, this function returns an
// empty node handle. // empty node handle.
// //
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a // NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative // move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle). // containers (https://en.cppreference.com/w/cpp/container/node_handle).
...@@ -645,13 +650,18 @@ class btree_multimap ...@@ -645,13 +650,18 @@ class btree_multimap
// Extracts the element at the indicated position and returns a node handle // Extracts the element at the indicated position and returns a node handle
// owning that extracted data. // owning that extracted data.
// //
// template <typename K> node_type extract(const K& x): // template <typename K> node_type extract(const K& k):
// //
// Extracts the element with the key matching the passed key value and // Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multimap` // returns a node handle owning that extracted data. If the `btree_multimap`
// does not contain an element with a matching key, this function returns an // does not contain an element with a matching key, this function returns an
// empty node handle. // empty node handle.
// //
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
//
// NOTE: In this context, `node_type` refers to the C++17 concept of a // NOTE: In this context, `node_type` refers to the C++17 concept of a
// move-only type that owns and provides access to the elements in associative // move-only type that owns and provides access to the elements in associative
// containers (https://en.cppreference.com/w/cpp/container/node_handle). // containers (https://en.cppreference.com/w/cpp/container/node_handle).
......
...@@ -183,7 +183,7 @@ class btree_set ...@@ -183,7 +183,7 @@ class btree_set
// template <typename K> size_type erase(const K& key): // template <typename K> size_type erase(const K& key):
// //
// Erases the element with the matching key, if it exists, returning the // Erases the element with the matching key, if it exists, returning the
// number of elements erased. // number of elements erased (0 or 1).
using Base::erase; using Base::erase;
// btree_set::insert() // btree_set::insert()
...@@ -263,7 +263,7 @@ class btree_set ...@@ -263,7 +263,7 @@ class btree_set
// Extracts the element at the indicated position and returns a node handle // Extracts the element at the indicated position and returns a node handle
// owning that extracted data. // owning that extracted data.
// //
// template <typename K> node_type extract(const K& x): // template <typename K> node_type extract(const K& k):
// //
// Extracts the element with the key matching the passed key value and // Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_set` // returns a node handle owning that extracted data. If the `btree_set`
...@@ -567,7 +567,7 @@ class btree_multiset ...@@ -567,7 +567,7 @@ class btree_multiset
// Extracts the element at the indicated position and returns a node handle // Extracts the element at the indicated position and returns a node handle
// owning that extracted data. // owning that extracted data.
// //
// template <typename K> node_type extract(const K& x): // template <typename K> node_type extract(const K& k):
// //
// Extracts the element with the key matching the passed key value and // Extracts the element with the key matching the passed key value and
// returns a node handle owning that extracted data. If the `btree_multiset` // returns a node handle owning that extracted data. If the `btree_multiset`
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "absl/container/btree_map.h" #include "absl/container/btree_map.h"
#include "absl/container/btree_set.h" #include "absl/container/btree_set.h"
#include "absl/container/flat_hash_set.h" #include "absl/container/flat_hash_set.h"
#include "absl/strings/cord.h"
#include "absl/time/time.h" #include "absl/time/time.h"
namespace absl { namespace absl {
...@@ -100,6 +101,16 @@ struct Generator<std::string> { ...@@ -100,6 +101,16 @@ struct Generator<std::string> {
} }
}; };
template <>
struct Generator<Cord> {
int maxval;
explicit Generator(int m) : maxval(m) {}
Cord operator()(int i) const {
char buf[16];
return Cord(GenerateDigits(buf, i, maxval));
}
};
template <typename T, typename U> template <typename T, typename U>
struct Generator<std::pair<T, U> > { struct Generator<std::pair<T, U> > {
Generator<typename remove_pair_const<T>::type> tgen; Generator<typename remove_pair_const<T>::type> tgen;
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <type_traits> #include <type_traits>
#include "absl/algorithm/algorithm.h" #include "absl/algorithm/algorithm.h"
#include "absl/base/config.h"
#include "absl/base/dynamic_annotations.h" #include "absl/base/dynamic_annotations.h"
#include "absl/base/internal/throw_delegate.h" #include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
...@@ -106,13 +107,13 @@ class FixedArray { ...@@ -106,13 +107,13 @@ class FixedArray {
public: public:
using allocator_type = typename AllocatorTraits::allocator_type; using allocator_type = typename AllocatorTraits::allocator_type;
using value_type = typename allocator_type::value_type; using value_type = typename AllocatorTraits::value_type;
using pointer = typename allocator_type::pointer; using pointer = typename AllocatorTraits::pointer;
using const_pointer = typename allocator_type::const_pointer; using const_pointer = typename AllocatorTraits::const_pointer;
using reference = typename allocator_type::reference; using reference = value_type&;
using const_reference = typename allocator_type::const_reference; using const_reference = const value_type&;
using size_type = typename allocator_type::size_type; using size_type = typename AllocatorTraits::size_type;
using difference_type = typename allocator_type::difference_type; using difference_type = typename AllocatorTraits::difference_type;
using iterator = pointer; using iterator = pointer;
using const_iterator = const_pointer; using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
...@@ -217,7 +218,7 @@ class FixedArray { ...@@ -217,7 +218,7 @@ class FixedArray {
// Returns a reference the ith element of the fixed array. // Returns a reference the ith element of the fixed array.
// REQUIRES: 0 <= i < size() // REQUIRES: 0 <= i < size()
reference operator[](size_type i) { reference operator[](size_type i) {
assert(i < size()); ABSL_HARDENING_ASSERT(i < size());
return data()[i]; return data()[i];
} }
...@@ -225,7 +226,7 @@ class FixedArray { ...@@ -225,7 +226,7 @@ class FixedArray {
// ith element of the fixed array. // ith element of the fixed array.
// REQUIRES: 0 <= i < size() // REQUIRES: 0 <= i < size()
const_reference operator[](size_type i) const { const_reference operator[](size_type i) const {
assert(i < size()); ABSL_HARDENING_ASSERT(i < size());
return data()[i]; return data()[i];
} }
...@@ -252,20 +253,32 @@ class FixedArray { ...@@ -252,20 +253,32 @@ class FixedArray {
// FixedArray::front() // FixedArray::front()
// //
// Returns a reference to the first element of the fixed array. // Returns a reference to the first element of the fixed array.
reference front() { return *begin(); } reference front() {
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}
// Overload of FixedArray::front() to return a reference to the first element // Overload of FixedArray::front() to return a reference to the first element
// of a fixed array of const values. // of a fixed array of const values.
const_reference front() const { return *begin(); } const_reference front() const {
ABSL_HARDENING_ASSERT(!empty());
return data()[0];
}
// FixedArray::back() // FixedArray::back()
// //
// Returns a reference to the last element of the fixed array. // Returns a reference to the last element of the fixed array.
reference back() { return *(end() - 1); } reference back() {
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}
// Overload of FixedArray::back() to return a reference to the last element // Overload of FixedArray::back() to return a reference to the last element
// of a fixed array of const values. // of a fixed array of const values.
const_reference back() const { return *(end() - 1); } const_reference back() const {
ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
}
// FixedArray::begin() // FixedArray::begin()
// //
...@@ -410,15 +423,15 @@ class FixedArray { ...@@ -410,15 +423,15 @@ class FixedArray {
void AnnotateConstruct(size_type n); void AnnotateConstruct(size_type n);
void AnnotateDestruct(size_type n); void AnnotateDestruct(size_type n);
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
void* RedzoneBegin() { return &redzone_begin_; } void* RedzoneBegin() { return &redzone_begin_; }
void* RedzoneEnd() { return &redzone_end_ + 1; } void* RedzoneEnd() { return &redzone_end_ + 1; }
#endif // ADDRESS_SANITIZER #endif // ABSL_HAVE_ADDRESS_SANITIZER
private: private:
ADDRESS_SANITIZER_REDZONE(redzone_begin_); ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])]; alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
ADDRESS_SANITIZER_REDZONE(redzone_end_); ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
}; };
class EmptyInlinedStorage { class EmptyInlinedStorage {
...@@ -491,22 +504,26 @@ constexpr typename FixedArray<T, N, A>::size_type ...@@ -491,22 +504,26 @@ constexpr typename FixedArray<T, N, A>::size_type
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct( void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
typename FixedArray<T, N, A>::size_type n) { typename FixedArray<T, N, A>::size_type n) {
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return; if (!n) return;
ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n); ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin()); data() + n);
#endif // ADDRESS_SANITIZER ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
RedzoneBegin());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode static_cast<void>(n); // Mark used when not in asan mode
} }
template <typename T, size_t N, typename A> template <typename T, size_t N, typename A>
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct( void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
typename FixedArray<T, N, A>::size_type n) { typename FixedArray<T, N, A>::size_type n) {
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
if (!n) return; if (!n) return;
ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd()); ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data()); RedzoneEnd());
#endif // ADDRESS_SANITIZER ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
data());
#endif // ABSL_HAVE_ADDRESS_SANITIZER
static_cast<void>(n); // Mark used when not in asan mode static_cast<void>(n); // Mark used when not in asan mode
} }
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
...@@ -150,8 +150,7 @@ TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) { ...@@ -150,8 +150,7 @@ TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
template <typename FixedArrT> template <typename FixedArrT>
testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) { testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
// Marked volatile to prevent optimization. Used for running asan tests. int sum = 0;
volatile int sum = 0;
for (const auto& thrower : *fixed_arr) { for (const auto& thrower : *fixed_arr) {
sum += thrower.Get(); sum += thrower.Get();
} }
......
...@@ -27,7 +27,10 @@ ...@@ -27,7 +27,10 @@
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/base/internal/exception_testing.h" #include "absl/base/internal/exception_testing.h"
#include "absl/base/options.h"
#include "absl/container/internal/counting_allocator.h"
#include "absl/hash/hash_testing.h" #include "absl/hash/hash_testing.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
...@@ -188,6 +191,21 @@ TEST(FixedArrayTest, AtThrows) { ...@@ -188,6 +191,21 @@ TEST(FixedArrayTest, AtThrows) {
"failed bounds check"); "failed bounds check");
} }
TEST(FixedArrayTest, Hardened) {
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
absl::FixedArray<int> a = {1, 2, 3};
EXPECT_EQ(a[2], 3);
EXPECT_DEATH_IF_SUPPORTED(a[3], "");
EXPECT_DEATH_IF_SUPPORTED(a[-1], "");
absl::FixedArray<int> empty(0);
EXPECT_DEATH_IF_SUPPORTED(empty[0], "");
EXPECT_DEATH_IF_SUPPORTED(empty[-1], "");
EXPECT_DEATH_IF_SUPPORTED(empty.front(), "");
EXPECT_DEATH_IF_SUPPORTED(empty.back(), "");
#endif
}
TEST(FixedArrayRelationalsTest, EqualArrays) { TEST(FixedArrayRelationalsTest, EqualArrays) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
absl::FixedArray<int, 5> a1(i); absl::FixedArray<int, 5> a1(i);
...@@ -622,70 +640,9 @@ TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) { ...@@ -622,70 +640,9 @@ TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) {
} }
#endif // __GNUC__ #endif // __GNUC__
// This is a stateful allocator, but the state lives outside of the
// allocator (in whatever test is using the allocator). This is odd
// but helps in tests where the allocator is propagated into nested
// containers - that chain of allocators uses the same state and is
// thus easier to query for aggregate allocation information.
template <typename T>
class CountingAllocator : public std::allocator<T> {
public:
using Alloc = std::allocator<T>;
using pointer = typename Alloc::pointer;
using size_type = typename Alloc::size_type;
CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {}
explicit CountingAllocator(int64_t* b)
: bytes_used_(b), instance_count_(nullptr) {}
CountingAllocator(int64_t* b, int64_t* a)
: bytes_used_(b), instance_count_(a) {}
template <typename U>
explicit CountingAllocator(const CountingAllocator<U>& x)
: Alloc(x),
bytes_used_(x.bytes_used_),
instance_count_(x.instance_count_) {}
pointer allocate(size_type n, const void* const hint = nullptr) {
assert(bytes_used_ != nullptr);
*bytes_used_ += n * sizeof(T);
return Alloc::allocate(n, hint);
}
void deallocate(pointer p, size_type n) {
Alloc::deallocate(p, n);
assert(bytes_used_ != nullptr);
*bytes_used_ -= n * sizeof(T);
}
template <typename... Args>
void construct(pointer p, Args&&... args) {
Alloc::construct(p, absl::forward<Args>(args)...);
if (instance_count_) {
*instance_count_ += 1;
}
}
void destroy(pointer p) {
Alloc::destroy(p);
if (instance_count_) {
*instance_count_ -= 1;
}
}
template <typename U>
class rebind {
public:
using other = CountingAllocator<U>;
};
int64_t* bytes_used_;
int64_t* instance_count_;
};
TEST(AllocatorSupportTest, CountInlineAllocations) { TEST(AllocatorSupportTest, CountInlineAllocations) {
constexpr size_t inlined_size = 4; constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>; using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0; int64_t allocated = 0;
...@@ -706,7 +663,7 @@ TEST(AllocatorSupportTest, CountInlineAllocations) { ...@@ -706,7 +663,7 @@ TEST(AllocatorSupportTest, CountInlineAllocations) {
TEST(AllocatorSupportTest, CountOutoflineAllocations) { TEST(AllocatorSupportTest, CountOutoflineAllocations) {
constexpr size_t inlined_size = 4; constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>; using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated = 0; int64_t allocated = 0;
...@@ -727,7 +684,7 @@ TEST(AllocatorSupportTest, CountOutoflineAllocations) { ...@@ -727,7 +684,7 @@ TEST(AllocatorSupportTest, CountOutoflineAllocations) {
TEST(AllocatorSupportTest, CountCopyInlineAllocations) { TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
constexpr size_t inlined_size = 4; constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>; using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0; int64_t allocated1 = 0;
...@@ -755,7 +712,7 @@ TEST(AllocatorSupportTest, CountCopyInlineAllocations) { ...@@ -755,7 +712,7 @@ TEST(AllocatorSupportTest, CountCopyInlineAllocations) {
TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) { TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) {
constexpr size_t inlined_size = 4; constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>; using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
int64_t allocated1 = 0; int64_t allocated1 = 0;
...@@ -787,7 +744,7 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) { ...@@ -787,7 +744,7 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
using testing::SizeIs; using testing::SizeIs;
constexpr size_t inlined_size = 4; constexpr size_t inlined_size = 4;
using Alloc = CountingAllocator<int>; using Alloc = absl::container_internal::CountingAllocator<int>;
using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>;
{ {
...@@ -811,16 +768,16 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) { ...@@ -811,16 +768,16 @@ TEST(AllocatorSupportTest, SizeValAllocConstructor) {
} }
} }
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
TEST(FixedArrayTest, AddressSanitizerAnnotations1) { TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
absl::FixedArray<int, 32> a(10); absl::FixedArray<int, 32> a(10);
int* raw = a.data(); int* raw = a.data();
raw[0] = 0; raw[0] = 0;
raw[9] = 0; raw[9] = 0;
EXPECT_DEATH(raw[-2] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-2] = 0, "container-overflow");
EXPECT_DEATH(raw[-1] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
EXPECT_DEATH(raw[10] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[10] = 0, "container-overflow");
EXPECT_DEATH(raw[31] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[31] = 0, "container-overflow");
} }
TEST(FixedArrayTest, AddressSanitizerAnnotations2) { TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
...@@ -828,10 +785,10 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations2) { ...@@ -828,10 +785,10 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
char* raw = a.data(); char* raw = a.data();
raw[0] = 0; raw[0] = 0;
raw[11] = 0; raw[11] = 0;
EXPECT_DEATH(raw[-7] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-7] = 0, "container-overflow");
EXPECT_DEATH(raw[-1] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
EXPECT_DEATH(raw[12] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[12] = 0, "container-overflow");
EXPECT_DEATH(raw[17] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[17] = 0, "container-overflow");
} }
TEST(FixedArrayTest, AddressSanitizerAnnotations3) { TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
...@@ -839,8 +796,8 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations3) { ...@@ -839,8 +796,8 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
uint64_t* raw = a.data(); uint64_t* raw = a.data();
raw[0] = 0; raw[0] = 0;
raw[19] = 0; raw[19] = 0;
EXPECT_DEATH(raw[-1] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-1] = 0, "container-overflow");
EXPECT_DEATH(raw[20] = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[20] = 0, "container-overflow");
} }
TEST(FixedArrayTest, AddressSanitizerAnnotations4) { TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
...@@ -852,13 +809,13 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) { ...@@ -852,13 +809,13 @@ TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
// there is only a 8-byte red zone before the container range, so we only // there is only a 8-byte red zone before the container range, so we only
// access the last 4 bytes of the struct to make sure it stays within the red // access the last 4 bytes of the struct to make sure it stays within the red
// zone. // zone.
EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[-1].z_ = 0, "container-overflow");
EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[10] = ThreeInts(), "container-overflow");
// The actual size of storage is kDefaultBytes=256, 21*12 = 252, // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
// so reading raw[21] should still trigger the correct warning. // so reading raw[21] should still trigger the correct warning.
EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow"); EXPECT_DEATH_IF_SUPPORTED(raw[21] = ThreeInts(), "container-overflow");
} }
#endif // ADDRESS_SANITIZER #endif // ABSL_HAVE_ADDRESS_SANITIZER
TEST(FixedArrayTest, AbslHashValueWorks) { TEST(FixedArrayTest, AbslHashValueWorks) {
using V = absl::FixedArray<int>; using V = absl::FixedArray<int>;
......
...@@ -234,7 +234,8 @@ class flat_hash_map : public absl::container_internal::raw_hash_map< ...@@ -234,7 +234,8 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
// //
// size_type erase(const key_type& key): // size_type erase(const key_type& key):
// //
// Erases the element with the matching key, if it exists. // Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase; using Base::erase;
// flat_hash_map::insert() // flat_hash_map::insert()
...@@ -383,6 +384,11 @@ class flat_hash_map : public absl::container_internal::raw_hash_map< ...@@ -383,6 +384,11 @@ class flat_hash_map : public absl::container_internal::raw_hash_map<
// key value and returns a node handle owning that extracted data. If the // key value and returns a node handle owning that extracted data. If the
// `flat_hash_map` does not contain an element with a matching key, this // `flat_hash_map` does not contain an element with a matching key, this
// function returns an empty node handle. // function returns an empty node handle.
//
// NOTE: when compiled in an earlier version of C++ than C++17,
// `node_type::key()` returns a const reference to the key instead of a
// mutable reference. We cannot safely return a mutable reference without
// std::launder (which is not available before C++17).
using Base::extract; using Base::extract;
// flat_hash_map::merge() // flat_hash_map::merge()
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <memory> #include <memory>
#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_map_constructor_test.h" #include "absl/container/internal/unordered_map_constructor_test.h"
#include "absl/container/internal/unordered_map_lookup_test.h" #include "absl/container/internal/unordered_map_lookup_test.h"
...@@ -34,6 +35,19 @@ using ::testing::IsEmpty; ...@@ -34,6 +35,19 @@ using ::testing::IsEmpty;
using ::testing::Pair; using ::testing::Pair;
using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAre;
// Check that absl::flat_hash_map works in a global constructor.
struct BeforeMain {
BeforeMain() {
absl::flat_hash_map<int, int> x;
x.insert({1, 1});
ABSL_RAW_CHECK(x.find(0) == x.end(), "x should not contain 0");
auto it = x.find(1);
ABSL_RAW_CHECK(it != x.end(), "x should contain 1");
ABSL_RAW_CHECK(it->second, "1 should map to 1");
}
};
const BeforeMain before_main;
template <class K, class V> template <class K, class V>
using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual, using Map = flat_hash_map<K, V, StatefulTestingHash, StatefulTestingEqual,
Alloc<std::pair<const K, V>>>; Alloc<std::pair<const K, V>>>;
...@@ -253,6 +267,21 @@ TEST(FlatHashMap, EraseIf) { ...@@ -253,6 +267,21 @@ TEST(FlatHashMap, EraseIf) {
} }
} }
// This test requires std::launder for mutable key access in node handles.
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
TEST(FlatHashMap, NodeHandleMutableKeyAccess) {
flat_hash_map<std::string, std::string> map;
map["key1"] = "mapped";
auto nh = map.extract(map.begin());
nh.key().resize(3);
map.insert(std::move(nh));
EXPECT_THAT(map, testing::ElementsAre(Pair("key", "mapped")));
}
#endif
} // namespace } // namespace
} // namespace container_internal } // namespace container_internal
ABSL_NAMESPACE_END ABSL_NAMESPACE_END
......
...@@ -227,7 +227,8 @@ class flat_hash_set ...@@ -227,7 +227,8 @@ class flat_hash_set
// //
// size_type erase(const key_type& key): // size_type erase(const key_type& key):
// //
// Erases the element with the matching key, if it exists. // Erases the element with the matching key, if it exists, returning the
// number of elements erased (0 or 1).
using Base::erase; using Base::erase;
// flat_hash_set::insert() // flat_hash_set::insert()
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <vector> #include <vector>
#include "absl/base/internal/raw_logging.h"
#include "absl/container/internal/hash_generator_testing.h" #include "absl/container/internal/hash_generator_testing.h"
#include "absl/container/internal/unordered_set_constructor_test.h" #include "absl/container/internal/unordered_set_constructor_test.h"
#include "absl/container/internal/unordered_set_lookup_test.h" #include "absl/container/internal/unordered_set_lookup_test.h"
...@@ -36,6 +37,17 @@ using ::testing::Pointee; ...@@ -36,6 +37,17 @@ using ::testing::Pointee;
using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray; using ::testing::UnorderedElementsAreArray;
// Check that absl::flat_hash_set works in a global constructor.
struct BeforeMain {
BeforeMain() {
absl::flat_hash_set<int> x;
x.insert(1);
ABSL_RAW_CHECK(!x.contains(0), "x should not contain 0");
ABSL_RAW_CHECK(x.contains(1), "x should contain 1");
}
};
const BeforeMain before_main;
template <class T> template <class T>
using Set = using Set =
absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>; absl::flat_hash_set<T, StatefulTestingHash, StatefulTestingEqual, Alloc<T>>;
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "absl/algorithm/algorithm.h" #include "absl/algorithm/algorithm.h"
#include "absl/base/internal/throw_delegate.h" #include "absl/base/internal/throw_delegate.h"
#include "absl/base/macros.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/base/port.h" #include "absl/base/port.h"
#include "absl/container/internal/inlined_vector.h" #include "absl/container/internal/inlined_vector.h"
...@@ -63,7 +64,7 @@ ABSL_NAMESPACE_BEGIN ...@@ -63,7 +64,7 @@ ABSL_NAMESPACE_BEGIN
// `std::vector` for use cases where the vector's size is sufficiently small // `std::vector` for use cases where the vector's size is sufficiently small
// that it can be inlined. If the inlined vector does grow beyond its estimated // that it can be inlined. If the inlined vector does grow beyond its estimated
// capacity, it will trigger an initial allocation on the heap, and will behave // capacity, it will trigger an initial allocation on the heap, and will behave
// as a `std:vector`. The API of the `absl::InlinedVector` within this file is // as a `std::vector`. The API of the `absl::InlinedVector` within this file is
// designed to cover the same API footprint as covered by `std::vector`. // designed to cover the same API footprint as covered by `std::vector`.
template <typename T, size_t N, typename A = std::allocator<T>> template <typename T, size_t N, typename A = std::allocator<T>>
class InlinedVector { class InlinedVector {
...@@ -307,16 +308,14 @@ class InlinedVector { ...@@ -307,16 +308,14 @@ class InlinedVector {
// //
// Returns a `reference` to the `i`th element of the inlined vector. // Returns a `reference` to the `i`th element of the inlined vector.
reference operator[](size_type i) { reference operator[](size_type i) {
assert(i < size()); ABSL_HARDENING_ASSERT(i < size());
return data()[i]; return data()[i];
} }
// Overload of `InlinedVector::operator[](...)` that returns a // Overload of `InlinedVector::operator[](...)` that returns a
// `const_reference` to the `i`th element of the inlined vector. // `const_reference` to the `i`th element of the inlined vector.
const_reference operator[](size_type i) const { const_reference operator[](size_type i) const {
assert(i < size()); ABSL_HARDENING_ASSERT(i < size());
return data()[i]; return data()[i];
} }
...@@ -331,7 +330,6 @@ class InlinedVector { ...@@ -331,7 +330,6 @@ class InlinedVector {
base_internal::ThrowStdOutOfRange( base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type)` failed bounds check"); "`InlinedVector::at(size_type)` failed bounds check");
} }
return data()[i]; return data()[i];
} }
...@@ -345,7 +343,6 @@ class InlinedVector { ...@@ -345,7 +343,6 @@ class InlinedVector {
base_internal::ThrowStdOutOfRange( base_internal::ThrowStdOutOfRange(
"`InlinedVector::at(size_type) const` failed bounds check"); "`InlinedVector::at(size_type) const` failed bounds check");
} }
return data()[i]; return data()[i];
} }
...@@ -353,34 +350,30 @@ class InlinedVector { ...@@ -353,34 +350,30 @@ class InlinedVector {
// //
// Returns a `reference` to the first element of the inlined vector. // Returns a `reference` to the first element of the inlined vector.
reference front() { reference front() {
assert(!empty()); ABSL_HARDENING_ASSERT(!empty());
return data()[0];
return at(0);
} }
// Overload of `InlinedVector::front()` that returns a `const_reference` to // Overload of `InlinedVector::front()` that returns a `const_reference` to
// the first element of the inlined vector. // the first element of the inlined vector.
const_reference front() const { const_reference front() const {
assert(!empty()); ABSL_HARDENING_ASSERT(!empty());
return data()[0];
return at(0);
} }
// `InlinedVector::back()` // `InlinedVector::back()`
// //
// Returns a `reference` to the last element of the inlined vector. // Returns a `reference` to the last element of the inlined vector.
reference back() { reference back() {
assert(!empty()); ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
return at(size() - 1);
} }
// Overload of `InlinedVector::back()` that returns a `const_reference` to the // Overload of `InlinedVector::back()` that returns a `const_reference` to the
// last element of the inlined vector. // last element of the inlined vector.
const_reference back() const { const_reference back() const {
assert(!empty()); ABSL_HARDENING_ASSERT(!empty());
return data()[size() - 1];
return at(size() - 1);
} }
// `InlinedVector::begin()` // `InlinedVector::begin()`
...@@ -531,7 +524,7 @@ class InlinedVector { ...@@ -531,7 +524,7 @@ class InlinedVector {
void assign(InputIterator first, InputIterator last) { void assign(InputIterator first, InputIterator last) {
size_type i = 0; size_type i = 0;
for (; i < size() && first != last; ++i, static_cast<void>(++first)) { for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
at(i) = *first; data()[i] = *first;
} }
erase(data() + i, data() + size()); erase(data() + i, data() + size());
...@@ -542,9 +535,12 @@ class InlinedVector { ...@@ -542,9 +535,12 @@ class InlinedVector {
// //
// Resizes the inlined vector to contain `n` elements. // Resizes the inlined vector to contain `n` elements.
// //
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are value-initialized. // is larger than `size()`, new elements are value-initialized.
void resize(size_type n) { storage_.Resize(DefaultValueAdapter(), n); } void resize(size_type n) {
ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(DefaultValueAdapter(), n);
}
// Overload of `InlinedVector::resize(...)` that resizes the inlined vector to // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
// contain `n` elements. // contain `n` elements.
...@@ -552,6 +548,7 @@ class InlinedVector { ...@@ -552,6 +548,7 @@ class InlinedVector {
// NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n` // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
// is larger than `size()`, new elements are copied-constructed from `v`. // is larger than `size()`, new elements are copied-constructed from `v`.
void resize(size_type n, const_reference v) { void resize(size_type n, const_reference v) {
ABSL_HARDENING_ASSERT(n <= max_size());
storage_.Resize(CopyValueAdapter(v), n); storage_.Resize(CopyValueAdapter(v), n);
} }
...@@ -573,8 +570,8 @@ class InlinedVector { ...@@ -573,8 +570,8 @@ class InlinedVector {
// of `v` starting at `pos`, returning an `iterator` pointing to the first of // of `v` starting at `pos`, returning an `iterator` pointing to the first of
// the newly inserted elements. // the newly inserted elements.
iterator insert(const_iterator pos, size_type n, const_reference v) { iterator insert(const_iterator pos, size_type n, const_reference v) {
assert(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
assert(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
if (ABSL_PREDICT_TRUE(n != 0)) { if (ABSL_PREDICT_TRUE(n != 0)) {
value_type dealias = v; value_type dealias = v;
...@@ -600,8 +597,8 @@ class InlinedVector { ...@@ -600,8 +597,8 @@ class InlinedVector {
EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr> EnableIfAtLeastForwardIterator<ForwardIterator>* = nullptr>
iterator insert(const_iterator pos, ForwardIterator first, iterator insert(const_iterator pos, ForwardIterator first,
ForwardIterator last) { ForwardIterator last) {
assert(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
assert(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
if (ABSL_PREDICT_TRUE(first != last)) { if (ABSL_PREDICT_TRUE(first != last)) {
return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first), return storage_.Insert(pos, IteratorValueAdapter<ForwardIterator>(first),
...@@ -619,8 +616,8 @@ class InlinedVector { ...@@ -619,8 +616,8 @@ class InlinedVector {
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
iterator insert(const_iterator pos, InputIterator first, InputIterator last) { iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
assert(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
assert(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
size_type index = std::distance(cbegin(), pos); size_type index = std::distance(cbegin(), pos);
for (size_type i = index; first != last; ++i, static_cast<void>(++first)) { for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
...@@ -636,8 +633,8 @@ class InlinedVector { ...@@ -636,8 +633,8 @@ class InlinedVector {
// `pos`, returning an `iterator` pointing to the newly emplaced element. // `pos`, returning an `iterator` pointing to the newly emplaced element.
template <typename... Args> template <typename... Args>
iterator emplace(const_iterator pos, Args&&... args) { iterator emplace(const_iterator pos, Args&&... args) {
assert(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
assert(pos <= end()); ABSL_HARDENING_ASSERT(pos <= end());
value_type dealias(std::forward<Args>(args)...); value_type dealias(std::forward<Args>(args)...);
return storage_.Insert(pos, return storage_.Insert(pos,
...@@ -670,7 +667,7 @@ class InlinedVector { ...@@ -670,7 +667,7 @@ class InlinedVector {
// //
// Destroys the element at `back()`, reducing the size by `1`. // Destroys the element at `back()`, reducing the size by `1`.
void pop_back() noexcept { void pop_back() noexcept {
assert(!empty()); ABSL_HARDENING_ASSERT(!empty());
AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1)); AllocatorTraits::destroy(*storage_.GetAllocPtr(), data() + (size() - 1));
storage_.SubtractSize(1); storage_.SubtractSize(1);
...@@ -683,8 +680,8 @@ class InlinedVector { ...@@ -683,8 +680,8 @@ class InlinedVector {
// //
// NOTE: may return `end()`, which is not dereferencable. // NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator pos) { iterator erase(const_iterator pos) {
assert(pos >= begin()); ABSL_HARDENING_ASSERT(pos >= begin());
assert(pos < end()); ABSL_HARDENING_ASSERT(pos < end());
return storage_.Erase(pos, pos + 1); return storage_.Erase(pos, pos + 1);
} }
...@@ -695,9 +692,9 @@ class InlinedVector { ...@@ -695,9 +692,9 @@ class InlinedVector {
// //
// NOTE: may return `end()`, which is not dereferencable. // NOTE: may return `end()`, which is not dereferencable.
iterator erase(const_iterator from, const_iterator to) { iterator erase(const_iterator from, const_iterator to) {
assert(from >= begin()); ABSL_HARDENING_ASSERT(from >= begin());
assert(from <= to); ABSL_HARDENING_ASSERT(from <= to);
assert(to <= end()); ABSL_HARDENING_ASSERT(to <= end());
if (ABSL_PREDICT_TRUE(from != to)) { if (ABSL_PREDICT_TRUE(from != to)) {
return storage_.Erase(from, to); return storage_.Erase(from, to);
......
...@@ -83,7 +83,7 @@ int GetNonShortStringOptimizationSize() { ...@@ -83,7 +83,7 @@ int GetNonShortStringOptimizationSize() {
} }
ABSL_RAW_LOG( ABSL_RAW_LOG(
FATAL, FATAL,
"Failed to find a std::string larger than the short std::string optimization"); "Failed to find a string larger than the short string optimization");
return -1; return -1;
} }
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "absl/base/internal/exception_testing.h" #include "absl/base/internal/exception_testing.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/options.h"
#include "absl/container/internal/counting_allocator.h" #include "absl/container/internal/counting_allocator.h"
#include "absl/container/internal/test_instance_tracker.h" #include "absl/container/internal/test_instance_tracker.h"
#include "absl/hash/hash_testing.h" #include "absl/hash/hash_testing.h"
...@@ -247,6 +248,16 @@ TEST(IntVec, Erase) { ...@@ -247,6 +248,16 @@ TEST(IntVec, Erase) {
} }
} }
TEST(IntVec, Hardened) {
IntVec v;
Fill(&v, 10);
EXPECT_EQ(v[9], 9);
#if !defined(NDEBUG) || ABSL_OPTION_HARDENED
EXPECT_DEATH_IF_SUPPORTED(v[10], "");
EXPECT_DEATH_IF_SUPPORTED(v[-1], "");
#endif
}
// At the end of this test loop, the elements between [erase_begin, erase_end) // At the end of this test loop, the elements between [erase_begin, erase_end)
// should have reference counts == 0, and all others elements should have // should have reference counts == 0, and all others elements should have
// reference counts == 1. // reference counts == 1.
...@@ -780,7 +791,7 @@ TEST(IntVec, Reserve) { ...@@ -780,7 +791,7 @@ TEST(IntVec, Reserve) {
TEST(StringVec, SelfRefPushBack) { TEST(StringVec, SelfRefPushBack) {
std::vector<std::string> std_v; std::vector<std::string> std_v;
absl::InlinedVector<std::string, 4> v; absl::InlinedVector<std::string, 4> v;
const std::string s = "A quite long std::string to ensure heap."; const std::string s = "A quite long string to ensure heap.";
std_v.push_back(s); std_v.push_back(s);
v.push_back(s); v.push_back(s);
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
...@@ -795,7 +806,7 @@ TEST(StringVec, SelfRefPushBack) { ...@@ -795,7 +806,7 @@ TEST(StringVec, SelfRefPushBack) {
TEST(StringVec, SelfRefPushBackWithMove) { TEST(StringVec, SelfRefPushBackWithMove) {
std::vector<std::string> std_v; std::vector<std::string> std_v;
absl::InlinedVector<std::string, 4> v; absl::InlinedVector<std::string, 4> v;
const std::string s = "A quite long std::string to ensure heap."; const std::string s = "A quite long string to ensure heap.";
std_v.push_back(s); std_v.push_back(s);
v.push_back(s); v.push_back(s);
for (int i = 0; i < 20; ++i) { for (int i = 0; i < 20; ++i) {
...@@ -808,7 +819,7 @@ TEST(StringVec, SelfRefPushBackWithMove) { ...@@ -808,7 +819,7 @@ TEST(StringVec, SelfRefPushBackWithMove) {
} }
TEST(StringVec, SelfMove) { TEST(StringVec, SelfMove) {
const std::string s = "A quite long std::string to ensure heap."; const std::string s = "A quite long string to ensure heap.";
for (int len = 0; len < 20; len++) { for (int len = 0; len < 20; len++) {
SCOPED_TRACE(len); SCOPED_TRACE(len);
absl::InlinedVector<std::string, 8> v; absl::InlinedVector<std::string, 8> v;
......
...@@ -138,6 +138,7 @@ class node_handle<Policy, PolicyTraits, Alloc, ...@@ -138,6 +138,7 @@ class node_handle<Policy, PolicyTraits, Alloc,
absl::void_t<typename Policy::mapped_type>> absl::void_t<typename Policy::mapped_type>>
: public node_handle_base<PolicyTraits, Alloc> { : public node_handle_base<PolicyTraits, Alloc> {
using Base = node_handle_base<PolicyTraits, Alloc>; using Base = node_handle_base<PolicyTraits, Alloc>;
using slot_type = typename PolicyTraits::slot_type;
public: public:
using key_type = typename Policy::key_type; using key_type = typename Policy::key_type;
...@@ -145,8 +146,11 @@ class node_handle<Policy, PolicyTraits, Alloc, ...@@ -145,8 +146,11 @@ class node_handle<Policy, PolicyTraits, Alloc,
constexpr node_handle() {} constexpr node_handle() {}
auto key() const -> decltype(PolicyTraits::key(this->slot())) { // When C++17 is available, we can use std::launder to provide mutable
return PolicyTraits::key(this->slot()); // access to the key. Otherwise, we provide const access.
auto key() const
-> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
return PolicyTraits::mutable_key(this->slot());
} }
mapped_type& mapped() const { mapped_type& mapped() const {
......
...@@ -169,9 +169,33 @@ constexpr bool ShouldAnyUseBase() { ...@@ -169,9 +169,33 @@ constexpr bool ShouldAnyUseBase() {
} }
template <typename T, typename V> template <typename T, typename V>
using TupleMoveConstructible = typename std::conditional< using TupleElementMoveConstructible =
std::is_reference<T>::value, std::is_convertible<V, T>, typename std::conditional<std::is_reference<T>::value,
std::is_constructible<T, V&&>>::type; std::is_convertible<V, T>,
std::is_constructible<T, V&&>>::type;
template <bool SizeMatches, class T, class... Vs>
struct TupleMoveConstructible : std::false_type {};
template <class... Ts, class... Vs>
struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
: std::integral_constant<
bool, absl::conjunction<
TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
template <typename T>
struct compressed_tuple_size;
template <typename... Es>
struct compressed_tuple_size<CompressedTuple<Es...>>
: public std::integral_constant<std::size_t, sizeof...(Es)> {};
template <class T, class... Vs>
struct TupleItemsMoveConstructible
: std::integral_constant<
bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
sizeof...(Vs),
T, Vs...>::value> {};
} // namespace internal_compressed_tuple } // namespace internal_compressed_tuple
...@@ -217,17 +241,18 @@ class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple ...@@ -217,17 +241,18 @@ class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
explicit constexpr CompressedTuple(const Ts&... base) explicit constexpr CompressedTuple(const Ts&... base)
: CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {} : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
template <typename... Vs, template <typename First, typename... Vs,
absl::enable_if_t< absl::enable_if_t<
absl::conjunction< absl::conjunction<
// Ensure we are not hiding default copy/move constructors. // Ensure we are not hiding default copy/move constructors.
absl::negation<std::is_same<void(CompressedTuple), absl::negation<std::is_same<void(CompressedTuple),
void(absl::decay_t<Vs>...)>>, void(absl::decay_t<First>)>>,
internal_compressed_tuple::TupleMoveConstructible< internal_compressed_tuple::TupleItemsMoveConstructible<
Ts, Vs&&>...>::value, CompressedTuple<Ts...>, First, Vs...>>::value,
bool> = true> bool> = true>
explicit constexpr CompressedTuple(Vs&&... base) explicit constexpr CompressedTuple(First&& first, Vs&&... base)
: CompressedTuple::CompressedTupleImpl(absl::in_place, : CompressedTuple::CompressedTupleImpl(absl::in_place,
absl::forward<First>(first),
absl::forward<Vs>(base)...) {} absl::forward<Vs>(base)...) {}
template <int I> template <int I>
......
...@@ -277,11 +277,11 @@ TEST(CompressedTupleTest, Nested) { ...@@ -277,11 +277,11 @@ TEST(CompressedTupleTest, Nested) {
TEST(CompressedTupleTest, Reference) { TEST(CompressedTupleTest, Reference) {
int i = 7; int i = 7;
std::string s = "Very long std::string that goes in the heap"; std::string s = "Very long string that goes in the heap";
CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s); CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s);
// Sanity check. We should have not moved from `s` // Sanity check. We should have not moved from `s`
EXPECT_EQ(s, "Very long std::string that goes in the heap"); EXPECT_EQ(s, "Very long string that goes in the heap");
EXPECT_EQ(x.get<0>(), x.get<1>()); EXPECT_EQ(x.get<0>(), x.get<1>());
EXPECT_NE(&x.get<0>(), &x.get<1>()); EXPECT_NE(&x.get<0>(), &x.get<1>());
......
...@@ -15,28 +15,34 @@ ...@@ -15,28 +15,34 @@
#ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ #ifndef ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_ #define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
#ifdef ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif
#ifdef MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <new>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/base/config.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
#include "absl/meta/type_traits.h"
#include "absl/utility/utility.h" #include "absl/utility/utility.h"
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif
#ifdef ABSL_HAVE_MEMORY_SANITIZER
#include <sanitizer/msan_interface.h>
#endif
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
namespace container_internal { namespace container_internal {
template <size_t Alignment>
struct alignas(Alignment) AlignedType {};
// Allocates at least n bytes aligned to the specified alignment. // Allocates at least n bytes aligned to the specified alignment.
// Alignment must be a power of 2. It must be positive. // Alignment must be a power of 2. It must be positive.
// //
...@@ -48,11 +54,14 @@ template <size_t Alignment, class Alloc> ...@@ -48,11 +54,14 @@ template <size_t Alignment, class Alloc>
void* Allocate(Alloc* alloc, size_t n) { void* Allocate(Alloc* alloc, size_t n) {
static_assert(Alignment > 0, ""); static_assert(Alignment > 0, "");
assert(n && "n must be positive"); assert(n && "n must be positive");
struct alignas(Alignment) M {}; using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>; using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>; using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc); // On macOS, "mem_alloc" is a #define with one argument defined in
void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M)); // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
// with the "foo(bar)" syntax.
A my_mem_alloc(*alloc);
void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 && assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
"allocator does not respect alignment"); "allocator does not respect alignment");
return p; return p;
...@@ -64,11 +73,14 @@ template <size_t Alignment, class Alloc> ...@@ -64,11 +73,14 @@ template <size_t Alignment, class Alloc>
void Deallocate(Alloc* alloc, void* p, size_t n) { void Deallocate(Alloc* alloc, void* p, size_t n) {
static_assert(Alignment > 0, ""); static_assert(Alignment > 0, "");
assert(n && "n must be positive"); assert(n && "n must be positive");
struct alignas(Alignment) M {}; using M = AlignedType<Alignment>;
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>; using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>; using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc); // On macOS, "mem_alloc" is a #define with one argument defined in
AT::deallocate(mem_alloc, static_cast<M*>(p), // rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
// with the "foo(bar)" syntax.
A my_mem_alloc(*alloc);
AT::deallocate(my_mem_alloc, static_cast<M*>(p),
(n + sizeof(M) - 1) / sizeof(M)); (n + sizeof(M) - 1) / sizeof(M));
} }
...@@ -205,10 +217,10 @@ DecomposeValue(F&& f, Arg&& arg) { ...@@ -205,10 +217,10 @@ DecomposeValue(F&& f, Arg&& arg) {
// Helper functions for asan and msan. // Helper functions for asan and msan.
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(m, s); ASAN_POISON_MEMORY_REGION(m, s);
#endif #endif
#ifdef MEMORY_SANITIZER #ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_poison(m, s); __msan_poison(m, s);
#endif #endif
(void)m; (void)m;
...@@ -216,10 +228,10 @@ inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) { ...@@ -216,10 +228,10 @@ inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
} }
inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) { inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER #ifdef ABSL_HAVE_ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(m, s); ASAN_UNPOISON_MEMORY_REGION(m, s);
#endif #endif
#ifdef MEMORY_SANITIZER #ifdef ABSL_HAVE_MEMORY_SANITIZER
__msan_unpoison(m, s); __msan_unpoison(m, s);
#endif #endif
(void)m; (void)m;
...@@ -246,8 +258,8 @@ namespace memory_internal { ...@@ -246,8 +258,8 @@ namespace memory_internal {
// type, which is non-portable. // type, which is non-portable.
template <class Pair, class = std::true_type> template <class Pair, class = std::true_type>
struct OffsetOf { struct OffsetOf {
static constexpr size_t kFirst = -1; static constexpr size_t kFirst = static_cast<size_t>(-1);
static constexpr size_t kSecond = -1; static constexpr size_t kSecond = static_cast<size_t>(-1);
}; };
template <class Pair> template <class Pair>
...@@ -316,11 +328,12 @@ union map_slot_type { ...@@ -316,11 +328,12 @@ union map_slot_type {
map_slot_type() {} map_slot_type() {}
~map_slot_type() = delete; ~map_slot_type() = delete;
using value_type = std::pair<const K, V>; using value_type = std::pair<const K, V>;
using mutable_value_type = std::pair<K, V>; using mutable_value_type =
std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
value_type value; value_type value;
mutable_value_type mutable_value; mutable_value_type mutable_value;
K key; absl::remove_const_t<K> key;
}; };
template <class K, class V> template <class K, class V>
...@@ -346,6 +359,20 @@ struct map_slot_policy { ...@@ -346,6 +359,20 @@ struct map_slot_policy {
return slot->value; return slot->value;
} }
// When C++17 is available, we can use std::launder to provide mutable
// access to the key for use in node handle.
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
static K& mutable_key(slot_type* slot) {
// Still check for kMutableKeys so that we can avoid calling std::launder
// unless necessary because it can interfere with optimizations.
return kMutableKeys::value ? slot->key
: *std::launder(const_cast<K*>(
std::addressof(slot->value.first)));
}
#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
static const K& mutable_key(slot_type* slot) { return key(slot); }
#endif
static const K& key(const slot_type* slot) { static const K& key(const slot_type* slot) {
return kMutableKeys::value ? slot->key : slot->value.first; return kMutableKeys::value ? slot->key : slot->value.first;
} }
...@@ -424,13 +451,6 @@ struct map_slot_policy { ...@@ -424,13 +451,6 @@ struct map_slot_policy {
std::move(src->value)); std::move(src->value));
} }
} }
template <class Allocator>
static void move(Allocator* alloc, slot_type* first, slot_type* last,
slot_type* result) {
for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
move(alloc, src, dest);
}
}; };
} // namespace container_internal } // namespace container_internal
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment